Lock an entity to a plane

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Lock an entity to a plane

Post by mcmonkey »

I'm trying to lock certain entities into a 2D environment

Code: Select all

            TheClient.PhysicsWorld.Add(Body);
            popj = new PointOnPlaneJoint(Body, Body, new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 0, 0));
            TheClient.PhysicsWorld.Add(popj);
            raj = new RevoluteAngularJoint(Body, Body, new Vector3(0, 0, 1));
            TheClient.PhysicsWorld.Add(raj);
doesn't seem to work, as the entity keeps falling off the plane of existence. I also question why a theoretically 1-body'd joint would take two bodies as input, which heavily implies I'm doing this wrong. What's the proper way to do this?

Note: An ideal solution would keep the center of the entity ( (0,0,0) relative to the entity) perfectly along the plane... in this case, ensuring z always == 0, no matter what happens.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Lock an entity to a plane

Post by Norbo »

One body of the PointOnPlaneJoint holds the basis of the plane, and the other holds the point which is stuck to the plane. Having the same body for both parameters won't work, but you can pass null in for the first parameter for both constraints. When null is passed into a two entity constraint as a connection, the constraint connects to a kinematic 'world' entity.

However, constraints are not perfectly rigid. If you need zero error, you will have to add in a post-correction step that manually removes the error. Because there's a constraint handling most of the velocity level stuff, just forcefully setting the position/orientation every frame shouldn't cause any noticeable issues.

Also, depending on the simulation, you may be able to get away with just directly correcting the velocities rather than using constraints. It won't be as robust in the face of complex interactions, though.
mcmonkey
Posts: 92
Joined: Fri Apr 17, 2015 11:42 pm

Re: Lock an entity to a plane

Post by mcmonkey »

Norbo wrote:Having the same body for both parameters won't work, but you can pass null in for the first parameter for both constraints. When null is passed into a two entity constraint as a connection, the constraint connects to a kinematic 'world' entity.
That sets Position.Z = ~20 and Velocity.Z = -110 consistently. Like, they're trying to move from that position and you can see it in the way the values change but it gets forced into those two values. Are you sure null as the first parameter is right?

I guess I don't need perfection but... I kinda expect them to at least stay in the right general area with like 0.1 or so... perhaps one of my other parameters is wrong, EG those Vector3(0,0,0)s shouldn't be like that?

EDIT: I changed unrelated code and the precise values changed... I'm very very confused...

EDIT2: The server wants the player at (x,y,50) and is maintaining that... the client wants to be at (x,y,0) and is fighting the server strongly. The server/client code is the same though...

EDIT3: The player sets the position to 50 on spawn and then adjusts back to 0... apparently it's current position at the time of jointing is what's used, not any of the parameters of the function call. Why is it not a param of the function?

EDIT4: An unrelated entity just fell over the edge, despite sharing the code... wot.
EDIT4.5: Yeah this constraint... is not effectively constraining much of anything... this box will consistently fall over the edge if I give it a proper force. I guess I gotta force-set the angles and position every tick. Can I do that without it activating?
EDIT 4.6: I suppose only force-setting if it's actually checked as exceeding the limits beforehand would suffice to avoid unintended activation.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Lock an entity to a plane

Post by Norbo »

Here's a modified WallDemo from the BEPUphysicsDemos, where the wall is constrained to the X/Y plane aligned with the origin.

Code: Select all

        public WallDemo(DemosGame game)
            : base(game)
        {
            int width = 10;
            int height = 10;
            float blockWidth = 2f;
            float blockHeight = 1f;
            float blockLength = 1f;

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    var toAdd =
                        new Box(
                            new Vector3(
                                i * blockWidth + .5f * blockWidth * (j % 2) - width * blockWidth * .5f,
                                blockHeight * .5f + j * (blockHeight),
                                0),
                            blockWidth, blockHeight, blockLength, 10);
                    Space.Add(toAdd);

                    var pointOnPlaneJoint = new PointOnPlaneJoint(null, toAdd, new Vector3(), new Vector3(0, 0, -1), toAdd.Position);
                    Space.Add(pointOnPlaneJoint);
                    var angularJoint = new RevoluteAngularJoint(null, toAdd, new Vector3(0, 0, -1));
                    Space.Add(angularJoint);
                }
            }

            Box ground = new Box(new Vector3(0, -.5f, 0), 50, 1, 50);
            Space.Add(ground);
            game.Camera.Position = new Vector3(0, 6, 15);
        }
Note that all constraint constructor parameters are in world space. So, the PointOnPlaneJoint's point is picked as the current position of the entity, not (0,0,0).
Post Reply