Page 1 of 1

How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 10:08 am
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

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 2:28 pm
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.

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 3:17 pm
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?

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 3:25 pm
by ole_92
Oops, I still have the door as a kinematic entity, I should change that first.

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 3:40 pm
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.

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 5:17 pm
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);
            
        }

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 6:03 pm
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.

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 10:56 pm
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.

Re: How to implement Mororised grabber approach on doors?

Posted: Tue May 08, 2012 11:20 pm
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.