Constrains two entities to rotate only around a single axis. Acts like the angular portion of a hinge joint.
Inheritance: BEPUphysics.Constraints.TwoEntity.Joints.Joint, I2DImpulseConstraintWithError, I2DJacobianConstraint
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public SuspensionCarDemo2(DemosGame game)
            : base(game)
        {
            game.Camera.Position = new Vector3(0, 2, 15);

            Space.Add(new Box(new Vector3(0, -5, 0), 20, 1, 20));

            var body = new Box(new Vector3(0, 0, 0), 2, .5f, 3, 20);
            body.CollisionInformation.LocalPosition = new Vector3(0, 1f, 0);
            Space.Add(body);
            
            AddBackWheel(new Vector3(-1f, .55f, 1.3f), body, true);
            AddBackWheel(new Vector3(1f, .55f, 1.3f), body, false);
            Box suspensionLeg1, suspensionLeg2;
            AddDriveWheel(new Vector3(-1f, .55f, -1.3f), body, true, out drivingMotor1, out steeringMotor1, out suspensionLeg1);
            AddDriveWheel(new Vector3(1f, .55f, -1.3f), body, false, out drivingMotor2, out steeringMotor2, out suspensionLeg2);

            //Add a stabilizer so that the wheels can't point different directions.
            var steeringStabilizer = new RevoluteAngularJoint(suspensionLeg1, suspensionLeg2, Vector3.Right);
            Space.Add(steeringStabilizer);


            //x and y, in terms of heightmaps, refer to their local x and y coordinates.  In world space, they correspond to x and z.
            //Setup the heights of the terrain.
            int xLength = 180;
            int zLength = 180;

            float xSpacing = 8f;
            float zSpacing = 8f;
            var heights = new float[xLength, zLength];
            for (int i = 0; i < xLength; i++)
            {
                for (int j = 0; j < zLength; j++)
                {
                    float x = i - xLength / 2;
                    float z = j - zLength / 2;
                    //heights[i,j] = (float)(x * y / 1000f);
                    heights[i, j] = (float)(10 * (Math.Sin(x / 8) + Math.Sin(z / 8)));
                    //heights[i,j] = 3 * (float)Math.Sin(x * y / 100f);
                    //heights[i,j] = (x * x * x * y - y * y * y * x) / 1000f;
                }
            }
            //Create the terrain.
            var terrain = new Terrain(heights, new AffineTransform(
                    new Vector3(xSpacing, 1, zSpacing),
                    Quaternion.Identity,
                    new Vector3(-xLength * xSpacing / 2, -10, -zLength * zSpacing / 2)));

            //terrain.Thickness = 5; //Uncomment this and shoot some things at the bottom of the terrain! They'll be sucked up through the ground.

            Space.Add(terrain);

            game.ModelDrawer.Add(terrain);
        }
 /// <summary>
 /// Constructs a new constraint which restricts two degrees of linear freedom and two degrees of angular freedom between two entities.
 /// This constructs the internal constraints, but does not configure them.  Before using a constraint constructed in this manner,
 /// ensure that its active constituent constraints are properly configured.  The entire group as well as all internal constraints are initially inactive (IsActive = false).
 /// </summary>
 public LineSliderJoint()
 {
     IsActive = false;
     PointOnLineJoint = new PointOnLineJoint();
     AngularJoint = new RevoluteAngularJoint();
     Limit = new LinearAxisLimit();
     Motor = new LinearAxisMotor();
     Add(PointOnLineJoint);
     Add(AngularJoint);
     Add(Limit);
     Add(Motor);
 }
Exemple #3
0
        /// <summary>
        /// Constructs a new constraint which restricts three degrees of linear freedom and two degrees of angular freedom between two entities.
        /// This constructs the internal constraints, but does not configure them.  Before using a constraint constructed in this manner,
        /// ensure that its active constituent constraints are properly configured.  The entire group as well as all internal constraints are initially inactive (IsActive = false).
        /// </summary>
        public RevoluteJoint()
        {
            IsActive = false;
            BallSocketJoint = new BallSocketJoint();
            AngularJoint = new RevoluteAngularJoint();
            Limit = new RevoluteLimit();
            Motor = new RevoluteMotor();

            Add(BallSocketJoint);
            Add(AngularJoint);
            Add(Limit);
            Add(Motor);
        }
Exemple #4
0
        /// <summary>
        /// Constructs a new constraint which restricts three degrees of linear freedom and two degrees of angular freedom between two entities.
        /// </summary>
        /// <param name="connectionA">First entity of the constraint pair.</param>
        /// <param name="connectionB">Second entity of the constraint pair.</param>
        /// <param name="anchor">Point around which both entities rotate.</param>
        /// <param name="freeAxis">Axis around which the hinge can rotate.</param>
        public RevoluteJoint(Entity connectionA, Entity connectionB, Vector3 anchor, Vector3 freeAxis)
        {
            if (connectionA == null)
                connectionA = TwoEntityConstraint.WorldEntity;
            if (connectionB == null)
                connectionB = TwoEntityConstraint.WorldEntity;
            BallSocketJoint = new BallSocketJoint(connectionA, connectionB, anchor);
            AngularJoint = new RevoluteAngularJoint(connectionA, connectionB, freeAxis);
            Limit = new RevoluteLimit(connectionA, connectionB);
            Motor = new RevoluteMotor(connectionA, connectionB, freeAxis);
            Limit.IsActive = false;
            Motor.IsActive = false;

            //Ensure that the base and test direction is perpendicular to the free axis.
            Vector3 baseAxis = anchor - connectionA.position;
            if (baseAxis.LengthSquared() < Toolbox.BigEpsilon) //anchor and connection a in same spot, so try the other way.
                baseAxis = connectionB.position - anchor;
            baseAxis -= Vector3.Dot(baseAxis, freeAxis) * freeAxis;
            if (baseAxis.LengthSquared() < Toolbox.BigEpsilon)
            {
                //However, if the free axis is totally aligned (like in an axis constraint), pick another reasonable direction.
                baseAxis = Vector3.Cross(freeAxis, Vector3.Up);
                if (baseAxis.LengthSquared() < Toolbox.BigEpsilon)
                {
                    baseAxis = Vector3.Cross(freeAxis, Vector3.Right);
                }
            }
            Limit.Basis.SetWorldAxes(freeAxis, baseAxis, connectionA.orientationMatrix);
            Motor.Basis.SetWorldAxes(freeAxis, baseAxis, connectionA.orientationMatrix);

            baseAxis = connectionB.position - anchor;
            baseAxis -= Vector3.Dot(baseAxis, freeAxis) * freeAxis;
            if (baseAxis.LengthSquared() < Toolbox.BigEpsilon)
            {
                //However, if the free axis is totally aligned (like in an axis constraint), pick another reasonable direction.
                baseAxis = Vector3.Cross(freeAxis, Vector3.Up);
                if (baseAxis.LengthSquared() < Toolbox.BigEpsilon)
                {
                    baseAxis = Vector3.Cross(freeAxis, Vector3.Right);
                }
            }
            Limit.TestAxis = baseAxis;
            Motor.TestAxis = baseAxis;


            Add(BallSocketJoint);
            Add(AngularJoint);
            Add(Limit);
            Add(Motor);
        }
        MarsRoverMovement roverMovement = new MarsRoverMovement(); // creates the aspects of the rovers movement

        #endregion Fields

        #region Constructors

        public MarsRover()
            : base()
        {
            laserShot = Game1.Instance.Content.Load<SoundEffect>("lasershot");
            explosionSound = Game1.Instance.Content.Load<SoundEffect>("explosion-01");
            cameraArm = new BepuEntity();
            drillArm = new BepuEntity();

            //construct mars rover ase body
            roverBase = marsRoverBody.AddBox(new Vector3(260, 45, -260));

            //create arms to hold both drill and camera/laser
            drillArm = marsRoverBody.AddCylinder("cylinder", new Vector3(267, 44, -244), false);
            cameraArm = marsRoverBody.AddCylinder("cylinder", new Vector3(254, 54, -252), true);

            //Create joint between rover body and drill arm
            roverMovement.CreateRevoluteJoint(out roverMovement.bodyDrillJoint, roverBase, drillArm, new Vector3(267, 44, -250), 3500, Vector3.Right);
            roverMovement.roverJoints.Add(roverMovement.bodyDrillJoint);

            //Create joint between rover body and camera/laser arm
            roverMovement.CreateRevoluteJoint(out roverMovement.bodyCameraCylinderJoint, roverBase, cameraArm, cameraArm.body.Position, 1500, Vector3.Up);
            roverMovement.roverJoints.Add(roverMovement.bodyCameraCylinderJoint);

            //create container for camera/laser
            cameraLaserContainer = marsRoverBody.AddCylinder("cube", new Vector3(254, 61, -252), true);

            //Create joint between camera/laser arm and container for camera/laser
            roverMovement.CreateRevoluteJoint(out roverMovement.cameraLaserContainerXaxisRotation, cameraArm, cameraLaserContainer, cameraLaserContainer.body.Position, 2500, -Vector3.Right);
            roverMovement.roverJoints.Add(roverMovement.cameraLaserContainerXaxisRotation);

            //create the four back wheels of the rover and connect them to the body
            Entity backWheel1 = marsRoverBody.AddWheel(new Vector3(250, 42, -267), roverBase.body);
            roverMovement.ConnectWheelBody(backWheel1, roverBase);
            Entity backWheel2 = marsRoverBody.AddWheel(new Vector3(270, 42, -267), roverBase.body);
            roverMovement.ConnectWheelBody(backWheel2, roverBase);
            Entity backWheel3 = marsRoverBody.AddWheel(new Vector3(250, 42, -260), roverBase.body);
            roverMovement.ConnectWheelBody(backWheel3, roverBase);
            Entity backWheel4 = marsRoverBody.AddWheel(new Vector3(270, 42, -260), roverBase.body);
            roverMovement.ConnectWheelBody(backWheel4, roverBase);

            //Create the two driving wheels and connect them to the body
            var wheel1 = marsRoverBody.AddWheel(new Vector3(270, 42, -255), roverBase.body);
            roverMovement.SetUpFrontMotorWheels(roverBase, wheel1, out roverMovement.drivingMotor1, out roverMovement.steeringMotor1);
            var wheel2 = marsRoverBody.AddWheel(new Vector3(250, 42, -255), roverBase.body);
            roverMovement.SetUpFrontMotorWheels(roverBase, wheel2, out roverMovement.drivingMotor2, out roverMovement.steeringMotor2);

            var steeringStabilizer = new RevoluteAngularJoint(wheel1, wheel2, Vector3.Right);
            Game1.Instance.Space.Add(steeringStabilizer);
        }
 /// <summary>
 /// Constructs a new constraint which restricts two degrees of linear freedom and two degrees of angular freedom between two entities.
 /// </summary>
 /// <param name="connectionA">First entity of the constraint pair.</param>
 /// <param name="connectionB">Second entity of the constraint pair.</param>
 /// <param name="lineAnchor">Location of the anchor for the line to be attached to connectionA in world space.</param>
 /// <param name="lineDirection">Axis in world space to be attached to connectionA along which connectionB can move and rotate.</param>
 /// <param name="pointAnchor">Location of the anchor for the point to be attached to connectionB in world space.</param>
 public LineSliderJoint(Entity connectionA, Entity connectionB, Vector3 lineAnchor, Vector3 lineDirection, Vector3 pointAnchor)
 {
     if (connectionA == null)
         connectionA = TwoEntityConstraint.WorldEntity;
     if (connectionB == null)
         connectionB = TwoEntityConstraint.WorldEntity;
     PointOnLineJoint = new PointOnLineJoint(connectionA, connectionB, lineAnchor, lineDirection, pointAnchor);
     AngularJoint = new RevoluteAngularJoint(connectionA, connectionB, lineDirection);
     Limit = new LinearAxisLimit(connectionA, connectionB, lineAnchor, pointAnchor, lineDirection, 0, 0);
     Motor = new LinearAxisMotor(connectionA, connectionB, lineAnchor, pointAnchor, lineDirection);
     Limit.IsActive = false;
     Motor.IsActive = false;
     Add(PointOnLineJoint);
     Add(AngularJoint);
     Add(Limit);
     Add(Motor);
 }
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public ReverseTrikeDemo(DemosGame game)
            : base(game)
        {
            game.Camera.Position = new Vector3(0, 2, 15);

            Space.Add(new Box(new Vector3(0, -5, 0), 20, 1, 20));

            var body = new Box(new Vector3(0, 0, 0), 2, 1, 3, 10);
            body.CollisionInformation.LocalPosition = new Vector3(0, .8f, 0);
            Space.Add(body);

            #region First Wheel

            var wheel = new Cylinder(body.Position + new Vector3(-1.3f, 0, -1.5f), .2f, .5f, 4);
            wheel.Material = new Material(1.5f, 1.5f, 0);
            wheel.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);

            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(body, wheel, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            var ballSocketJoint = new BallSocketJoint(body, wheel, wheel.Position);
            var swivelHingeAngularJoint = new SwivelHingeAngularJoint(body, wheel, Vector3.Up, Vector3.Right);
            //Motorize the wheel.
            drivingMotor1 = new RevoluteMotor(body, wheel, Vector3.Left);
            drivingMotor1.Settings.VelocityMotor.Softness = .2f;
            //Let it roll when the user isn't giving specific commands.
            drivingMotor1.IsActive = false;
            steeringMotor1 = new RevoluteMotor(body, wheel, Vector3.Up);
            steeringMotor1.Settings.Mode = MotorMode.Servomechanism;
            //The constructor makes a guess about how to set up the constraint.
            //It can't always be right since it doesn't have all the information;
            //in this case, it chooses the basis and test axis incorrectly.
            //This leads to a 'flipping' behavior when the wheel is rolling
            //(the test axis is 'rolling' with the wheel, and passes over
            //a singularity which causes a flip).

            //To fix this, we configure the constraint directly.
            //The basis is aligned with how the wheel is set up; we choose 'up' as 
            //the motorized axis, and right/forward to define the angle measurement plane.
            //The test axis is set to be perpendicular to the wheel's rotation so that
            //it only measures the steering angle.

            //If you're curious, the angle measurement is just a Math.Atan2.
            //The current world test axis is dotted against the two plane axes (Right and Forward here).
            //This gives an x and y value.  These can be plugged into Atan2 just like when
            //you compute an angle on a normal 2d graph.
            steeringMotor1.Basis.SetWorldAxes(Vector3.Up, Vector3.Right);
            steeringMotor1.TestAxis = Vector3.Right;


            //Add the wheel and connection to the space.
            Space.Add(wheel);
            Space.Add(ballSocketJoint);
            Space.Add(swivelHingeAngularJoint);
            Space.Add(drivingMotor1);
            Space.Add(steeringMotor1);

            #endregion

            #region Second Wheel

            wheel = new Cylinder(body.Position + new Vector3(1.3f, 0, -1.5f), .2f, .5f, 4);
            wheel.Material = new Material(1.5f, 1.5f, 0);
            wheel.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);


            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(body, wheel, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            ballSocketJoint = new BallSocketJoint(body, wheel, wheel.Position);
            swivelHingeAngularJoint = new SwivelHingeAngularJoint(body, wheel, Vector3.Up, Vector3.Right);
            //Motorize the wheel.
            drivingMotor2 = new RevoluteMotor(body, wheel, Vector3.Left);
            drivingMotor2.Settings.VelocityMotor.Softness = .2f;
            //Let it roll when the user isn't giving specific commands.
            drivingMotor2.IsActive = false;
            steeringMotor2 = new RevoluteMotor(body, wheel, Vector3.Up);
            steeringMotor2.Settings.Mode = MotorMode.Servomechanism;
            //Configure the motor.  See wheel 1 for more description.
            steeringMotor2.Basis.SetWorldAxes(Vector3.Up, Vector3.Right);
            steeringMotor2.TestAxis = Vector3.Right;


            //Add the wheel and connection to the space.
            Space.Add(wheel);
            Space.Add(ballSocketJoint);
            Space.Add(swivelHingeAngularJoint);
            Space.Add(drivingMotor2);
            Space.Add(steeringMotor2);

            #endregion

            #region Third Wheel

            wheel = new Cylinder(body.Position + new Vector3(0, -.3f, 1.5f), .2f, .5f, 4);
            wheel.Material = new Material(1.5f, 1.5f, 0);
            wheel.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);

            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(body, wheel, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            ballSocketJoint = new BallSocketJoint(body, wheel, wheel.Position);
            //Notice that the third wheel isn't a swivel hinge, it's just a revolute axis.
            //This lets it roll, but prevents flopping around like the wheels of a grocery cart.
            //Could have used a RevoluteJoint solver group here, but this shows it's possible to do
            //the same things without using the combo-constraints.
            var revoluteAngularJoint = new RevoluteAngularJoint(body, wheel, Vector3.Right);

            //Add the wheel and connection to the space.
            Space.Add(wheel);
            Space.Add(ballSocketJoint);
            Space.Add(revoluteAngularJoint);

            #endregion

            int xLength = 180;
            int zLength = 180;

            float xSpacing = 8f;
            float zSpacing = 8f;
            var heights = new float[xLength, zLength];
            for (int i = 0; i < xLength; i++)
            {
                for (int j = 0; j < zLength; j++)
                {
                    float x = i - xLength / 2;
                    float z = j - zLength / 2;
                    //heights[i,j] = (float)(x * y / 1000f);
                    heights[i, j] = (float)(10 * (Math.Sin(x / 8) + Math.Sin(z / 8)));
                    //heights[i,j] = 3 * (float)Math.Sin(x * y / 100f);
                    //heights[i,j] = (x * x * x * y - y * y * y * x) / 1000f;
                }
            }
            //Create the terrain.
            var terrain = new Terrain(heights, new AffineTransform(
                new Vector3(xSpacing, 1, zSpacing), 
                Quaternion.Identity, 
                new Vector3(-xLength * xSpacing / 2, -10, -zLength * zSpacing / 2)));
            Space.Add(terrain);

            game.ModelDrawer.Add(terrain);
        }
        void AddBackWheel(Vector3 wheelOffset, Entity body)
        {
            var wheel = new Cylinder(body.Position + wheelOffset, .4f, .5f, 5f);
            wheel.Material.KineticFriction = 2.5f;
            wheel.Material.StaticFriction = 3.5f;
            wheel.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);

            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(wheel, body, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            var pointOnLineJoint = new PointOnLineJoint(body, wheel, wheel.Position, Vector3.Down, wheel.Position);
            var suspensionLimit = new LinearAxisLimit(body, wheel, wheel.Position, wheel.Position, Vector3.Down, -1, 0);
            //This linear axis motor will give the suspension its springiness by pushing the wheels outward.
            var suspensionSpring = new LinearAxisMotor(body, wheel, wheel.Position, wheel.Position, Vector3.Down);
            suspensionSpring.Settings.Mode = MotorMode.Servomechanism;
            suspensionSpring.Settings.Servo.Goal = 0;
            suspensionSpring.Settings.Servo.SpringSettings.Stiffness = 300;
            suspensionSpring.Settings.Servo.SpringSettings.Damping = 70;

            var revoluteAngularJoint = new RevoluteAngularJoint(body, wheel, Vector3.Right);

            //Add the wheel and connection to the space.
            Space.Add(wheel);
            Space.Add(pointOnLineJoint);
            Space.Add(suspensionLimit);
            Space.Add(suspensionSpring);
            Space.Add(revoluteAngularJoint);
        }
        public JointLimitTestDemo(DemosGame game)
            : base(game)
        {
            float bounciness = 1;
            float baseMass = 100;
            float armMass = 10;
            //DistanceLimit
            Box boxA = new Box(new Vector3(-21, 4, 0), 3, 3, 3, baseMass);
            Box boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            var distanceLimit = new DistanceLimit(boxA, boxB, boxA.Position, boxB.Position - new Vector3(0, 2, 0), 1, 6);
            distanceLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(distanceLimit);

            //EllipseSwingLimit
            boxA = new Box(new Vector3(-14, 4, 0), 3, 3, 3, baseMass);
            boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            var ballSocketJoint = new BallSocketJoint(boxA, boxB, boxB.Position + new Vector3(0, -2, 0));
            var ellipseSwingLimit = new EllipseSwingLimit(boxA, boxB, Vector3.Up, MathHelper.Pi / 1.5f, MathHelper.Pi / 3);
            ellipseSwingLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(ballSocketJoint);
            Space.Add(ellipseSwingLimit);

            //LinearAxisLimit
            boxA = new Box(new Vector3(-7, 4, 0), 3, 3, 3, baseMass);
            boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            var pointOnLineJoint = new PointOnLineJoint(boxA, boxB, boxA.Position, Vector3.Up, boxB.Position + new Vector3(0, -2, 0));
            var linearAxisLimit = new LinearAxisLimit(boxA, boxB, boxA.Position, boxB.Position + new Vector3(0, -2, 0), Vector3.Up, 0, 4);
            linearAxisLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(pointOnLineJoint);
            Space.Add(linearAxisLimit);

            //RevoluteLimit
            boxA = new Box(new Vector3(0, 4, 0), 3, 3, 3, baseMass);
            boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            ballSocketJoint = new BallSocketJoint(boxA, boxB, boxB.Position + new Vector3(0, -2, 0));
            var revoluteAngularJoint = new RevoluteAngularJoint(boxA, boxB, Vector3.Forward);
            var revoluteLimit = new RevoluteLimit(boxA, boxB, Vector3.Forward, Vector3.Up, -MathHelper.PiOver4, MathHelper.PiOver4);
            revoluteLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(ballSocketJoint);
            Space.Add(revoluteAngularJoint);
            Space.Add(revoluteLimit);

            //SwingLimit
            boxA = new Box(new Vector3(7, 4, 0), 3, 3, 3, baseMass);
            boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            ballSocketJoint = new BallSocketJoint(boxA, boxB, boxB.Position + new Vector3(0, -2, 0));
            var swingLimit = new SwingLimit(boxA, boxB, Vector3.Up, Vector3.Up, MathHelper.PiOver4);
            swingLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(ballSocketJoint);
            Space.Add(swingLimit);

            //TwistLimit
            boxA = new Box(new Vector3(14, 4, 0), 3, 3, 3, baseMass);
            boxB = new Box(boxA.Position + new Vector3(0, 5, 0), 1, 4, 1, armMass);
            CollisionRules.AddRule(boxA, boxB, CollisionRule.NoBroadPhase);
            boxB.ActivityInformation.IsAlwaysActive = true;

            ballSocketJoint = new BallSocketJoint(boxA, boxB, boxB.Position + new Vector3(0, -2, 0));
            revoluteAngularJoint = new RevoluteAngularJoint(boxA, boxB, Vector3.Up);
            var twistLimit = new TwistLimit(boxA, boxB, Vector3.Up, Vector3.Up, -MathHelper.PiOver4, MathHelper.PiOver4);
            twistLimit.Bounciness = bounciness;

            Space.Add(boxA);
            Space.Add(boxB);
            Space.Add(ballSocketJoint);
            Space.Add(revoluteAngularJoint);
            Space.Add(twistLimit);

            Space.Add(new Box(new Vector3(0, 0, 0), 60, 1, 60));
            game.Camera.Position = new Vector3(0, 6, 15);
        }
        public TreadSegment(Vector3 segmentPosition, Entity body, TreadSegmentDescription treadSegmentDescription)
        {
            Entity = new Cylinder(segmentPosition, treadSegmentDescription.Width, treadSegmentDescription.Radius, treadSegmentDescription.Mass);

            Entity.Material.KineticFriction = treadSegmentDescription.Friction;
            Entity.Material.StaticFriction = treadSegmentDescription.Friction;
            Entity.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);

            //Preventing the occasional pointless collision pair can speed things up.
            CollisionRules.AddRule(Entity, body, CollisionRule.NoBroadPhase);

            //Connect the wheel to the body.
            SuspensionAxisJoint = new PointOnLineJoint(body, Entity, Entity.Position, Vector3.Down, Entity.Position);
            SuspensionLengthLimit = new LinearAxisLimit(body, Entity, Entity.Position, Entity.Position, Vector3.Down, -treadSegmentDescription.SuspensionLength, 0);
            //This linear axis motor will give the suspension its springiness by pushing the wheels outward.
            SuspensionSpring = new LinearAxisMotor(body, Entity, Entity.Position, Entity.Position, Vector3.Down);
            SuspensionSpring.Settings.Mode = MotorMode.Servomechanism;
            SuspensionSpring.Settings.Servo.Goal = 0;
            SuspensionSpring.Settings.Servo.SpringSettings.Stiffness = treadSegmentDescription.SuspensionStiffness;
            SuspensionSpring.Settings.Servo.SpringSettings.Damping = treadSegmentDescription.SuspensionDamping;

            SuspensionAngularJoint = new RevoluteAngularJoint(body, Entity, Vector3.Right);
            //Make the joint extremely rigid.  There are going to be extreme conditions when the wheels get up to speed;
            //we don't want the forces involved to torque the wheel off the frame!
            SuspensionAngularJoint.SpringSettings.Damping *= Entity.Mass * 50;
            SuspensionAngularJoint.SpringSettings.Stiffness *= Entity.Mass * 50;
            //Motorize the wheel.
            Motor = new RevoluteMotor(body, Entity, Vector3.Left);
            Motor.Settings.VelocityMotor.Softness = treadSegmentDescription.MotorSoftness;
            Motor.Settings.MaximumForce = treadSegmentDescription.MotorMaximumForce;

        }