How to implement Mororised grabber approach on doors?

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
ole_92
Posts: 35
Joined: Fri Apr 06, 2012 12:08 pm

How to implement Mororised grabber approach on doors?

Post by ole_92 »

Hi again Norbo

So far, I have only seen grabber shift it's corresponding entity towards the goal position, but how about rotating? The door needs to be rotated, right?
Also, to avoid the crusher-of-everything-in-the-way door, I should give it some mass, but then it would be vulnerable if another object hit it, and could literally move out of the door frame (very undesirable).

Could you give me a hint on what the correct approach should be?

Thank you
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: How to implement Mororised grabber approach on doors?

Post by Norbo »

The door could be held in place with a RevoluteJoint. If you don't want the door opening backward, activate the RevoluteJoint.Limit and configure it so that it can only open one way. With a sufficiently hard limit, the door won't be able to budge beyond the defined values.

If the user grabs the constrained door, the door will rotate in response since that's all it can do. Try grabbing the robot arm in the RobotArmDemo to see how it responds.
ole_92
Posts: 35
Joined: Fri Apr 06, 2012 12:08 pm

Re: How to implement Mororised grabber approach on doors?

Post by ole_92 »

So how do I actually set it up?
I've tried a few different approaches like

Code: Select all

doorJoint = new RevoluteJoint(door, room, door.Position, Vector3.Right);
doorJoint.IsActive = true;
doorJoint.Motor.IsActive = true;
space.Add(doorJoint);
but it freezes my character's moving controls.

What should I constrain it to? The room?
ole_92
Posts: 35
Joined: Fri Apr 06, 2012 12:08 pm

Re: How to implement Mororised grabber approach on doors?

Post by ole_92 »

Oops, I still have the door as a kinematic entity, I should change that first.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: How to implement Mororised grabber approach on doors?

Post by Norbo »

Here's one possible example implementation:

Code: Select all

            var door = new Box(new Vector3(0, 1.55f, 5), 2, 3, .5f, 10);
            RevoluteJoint revoluteJoint = new RevoluteJoint(null, door, door.Position + new Vector3(-1, 0, 0), Vector3.Up);
            //The revolute joint's BallSocketJoint and RevoluteAngularJoint are active by default.  Its RevoluteLimit, however, is not.
            revoluteJoint.Limit.IsActive = true;

            //The RevoluteJoint constructor configures itself on a guess.  Since we're connecting to null, this guess isn't so great.
            //Configure the bases of the joints to match our expectations.
            //The first parameter in the basis corresponds to the axis of rotation.
            //The second parameter defines the angle which we pick to represent 0.
            //The basis is attached to entity A, or in this case, null (the world).
            revoluteJoint.Limit.Basis.SetWorldAxes(Vector3.Up, Vector3.Right);

            //The test axis is attached to the second entity.  This is used to measure the current angle to determine if the limit has been violated.
            //We'll align it with the 0 angle direction we picked before.
            revoluteJoint.Limit.TestAxis = Vector3.Right;

            //Set up the minimum and maximum angles.
            revoluteJoint.Limit.MinimumAngle = -MathHelper.Pi;
            revoluteJoint.Limit.MaximumAngle = 0;

            Space.Add(door);
            Space.Add(revoluteJoint);
There's more examples of configuring constraints in the demos, too.
ole_92
Posts: 35
Joined: Fri Apr 06, 2012 12:08 pm

Re: How to implement Mororised grabber approach on doors?

Post by ole_92 »

That's almost perfect now, the only thing that is wrong, is that the door can now also twist a little bit around forward axis.
And when I let it go, it returns back to the normal position, I don't know why.
Does it have something to do with my other code?

Code: Select all

public Door(Space s, string modelName, int mass, Vector3 pos, int specialDoor, int modelsIndex, Game game) {

            Game = game;
            space = s;
            position = pos;
            special = specialDoor;
            speed = 1;
            doorstate = DoorState.shut;
            moveState = MoveState.still;

            Model temp = ((Game1)Game).Content.Load<Model>("Models/" + modelName);
            Vector3[] vertices;
            int[] indices;

            TriangleMesh.GetVerticesAndIndicesFromModel(temp, out vertices, out indices);
            ConvexHull ch = new ConvexHull(vertices);

            ch.Tag = "door";

            ch.IsAffectedByGravity = false;

            float offset = 17;

            ch.CollisionInformation.LocalPosition = new Vector3(offset, 0, 0);
            ch.Tag = "door";
            ch.CollisionInformation.Tag = "" + modelsIndex;
            ch.Mass = 100;

            cModel = new CModel(temp, Matrix.CreateTranslation(-ch.Position + ch.CollisionInformation.LocalPosition), ((Game1)Game), ch);
            
            ch.Position += position;


            space.Add(ch);



            RevoluteJoint revoluteJoint = new RevoluteJoint(null, space.Entities[space.Entities.Count - 1], space.Entities[space.Entities.Count - 1].Position + new Vector3(-1, 0, 0), Vector3.Up);
            //The revolute joint's BallSocketJoint and RevoluteAngularJoint are active by default.  Its RevoluteLimit, however, is not.
            revoluteJoint.Limit.IsActive = true;

            //The RevoluteJoint constructor configures itself on a guess.  Since we're connecting to null, this guess isn't so great.
            //Configure the bases of the joints to match our expectations.
            //The first parameter in the basis corresponds to the axis of rotation.
            //The second parameter defines the angle which we pick to represent 0.
            //The basis is attached to entity A, or in this case, null (the world).
            revoluteJoint.Limit.Basis.SetWorldAxes(Vector3.Up, Vector3.Right);

            //The test axis is attached to the second entity.  This is used to measure the current angle to determine if the limit has been violated.
            //We'll align it with the 0 angle direction we picked before.
            revoluteJoint.Limit.TestAxis = Vector3.Right;

            //Set up the minimum and maximum angles.
            revoluteJoint.Limit.MinimumAngle = -MathHelper.Pi;
            revoluteJoint.Limit.MaximumAngle = 0;

            space.Add(revoluteJoint);
            
        }
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: How to implement Mororised grabber approach on doors?

Post by Norbo »

The door's mass is 100 in your example, and 10 in mine. If your grabber scales its strength based upon the mass of the object like the BEPUphysicsDemos one does, then it's applying 10x more force to the door. The hinge holding the door is springlike- applying 10x more force will shove it out of place more easily since the spring isn't any stronger.

So, do at least one of the following:
1) Strengthen the door constraints. Here's an example of how to strengthen the hinge itself:

Code: Select all

            revoluteJoint.AngularJoint.SpringSettings.DampingConstant *= 10;
            revoluteJoint.AngularJoint.SpringSettings.StiffnessConstant *= 10;
2) Lower the door mass.
3) Don't scale the grabber strength by the picked object's mass.
ole_92
Posts: 35
Joined: Fri Apr 06, 2012 12:08 pm

Re: How to implement Mororised grabber approach on doors?

Post by ole_92 »

Ah, that's what it was! Ok, now it's acting a little weird, because it collides with the house (I think)

Is it possible to remove collision detection between a door and a house?
I was going to use

Code: Select all

CollisionRules.AddRule(ch, space.Entities[roomIndex], CollisionRule.NoBroadPhase);
but then I realized the static geometry isn't in .Entities list.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: How to implement Mororised grabber approach on doors?

Post by Norbo »

That method is indeed what you'd want to use. A StaticMesh can be passed as a parameter- it takes any object which owns a CollisionRules instance, directly or indirectly.
Post Reply