예제 #1
0
        public LimitedHingeJoint(World world, RigidBody body1, RigidBody body2, JVector position, JVector hingeAxis, float hingeFwdAngle, float hingeBckAngle) : base(world)
        {
            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= 0.5f;

            var pos1 = position;

            JVector.Add(pos1, hingeAxis, out pos1);
            var pos2 = position;

            JVector.Subtract(pos2, hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1);
            worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2);

            hingeAxis = JVector.Normalize(hingeAxis);

            var perpDir = JVector.Up;

            if (JVector.Dot(perpDir, hingeAxis) > 0.1f)
            {
                perpDir = JVector.Right;
            }

            var sideAxis = JVector.Cross(hingeAxis, perpDir);

            perpDir = JVector.Cross(sideAxis, hingeAxis);
            perpDir = JVector.Normalize(perpDir);

            float len = 10.0f * 3;

            var hingeRelAnchorPos0 = perpDir * len;

            float angleToMiddle      = 0.5f * (hingeFwdAngle - hingeBckAngle);
            var   hingeRelAnchorPos1 = JVector.Transform(hingeRelAnchorPos0, JMatrix.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * JMath.Pi));

            float hingeHalfAngle  = 0.5f * (hingeFwdAngle + hingeBckAngle);
            float allowedDistance = len * 2.0f * (float)System.Math.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * JMath.Pi);

            var hingePos = body1.Position;
            var relPos0c = hingePos + hingeRelAnchorPos0;
            var relPos1c = hingePos + hingeRelAnchorPos1;

            DistanceConstraint = new PointPointDistance(body1, body2, relPos0c, relPos1c)
            {
                Distance = allowedDistance,
                Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance
            };
        }
예제 #2
0
        public void PreStep(float timeStep)
        {
            float vel = car.LinearVelocity.Length();

            SideFriction    = 2.5f - JMath.Clamp(vel / 20.0f, 0.0f, 1.4f);
            ForwardFriction = 5.5f - JMath.Clamp(vel / 20.0f, 0.0f, 5.4f);

            JVector force = JVector.Zero;

            JVector worldAxis = JVector.Transform(JVector.Up, car.Orientation);
            JVector worldPos  = car.Position + JVector.Transform(Position, car.Orientation);

            JVector forward = new JVector(-car.Orientation.M31, -car.Orientation.M32, -car.Orientation.M33);

            JVector wheelFwd  = JVector.Transform(forward, JMatrix.CreateFromAxisAngle(JVector.Up, SteerAngle / 360 * 2 * JMath.Pi));
            JVector wheelLeft = JVector.Cross(JVector.Up, wheelFwd); wheelLeft.Normalize();
            JVector wheelUp   = JVector.Cross(wheelFwd, wheelLeft);

            float rayLen = 2.0f * Radius + WheelTravel;

            JVector wheelRayStart = worldPos;
            JVector wheelDelta    = -Radius * worldAxis;
            JVector wheelRayEnd   = worldPos + wheelDelta;

            float deltaFwd      = (2.0f * Radius) / (NumberOfRays + 1);
            float deltaFwdStart = deltaFwd;

            lastDisplacement = displacement;
            displacement     = 0.0f;

            lastOnFloor = false;

            JVector rayOrigin = car.Position + JVector.Transform(Position, car.Orientation);

            JVector   groundNormal = JVector.Zero;
            JVector   groundPos    = JVector.Zero;
            float     deepestFrac  = float.MaxValue;
            RigidBody worldBody    = null;

            for (int i = 0; i < NumberOfRays; i++)
            {
                float distFwd = (deltaFwdStart + i * deltaFwd) - Radius;
                float zOffset = Radius * (1.0f - (float)Math.Cos(Math.PI / 4 * (distFwd / Radius)));

                JVector newOrigin = wheelRayStart + distFwd * wheelFwd + zOffset * wheelUp;

                RigidBody body; JVector normal; float frac;
                bool      result = world.CollisionSystem.Raycast(newOrigin, wheelDelta,
                                                                 raycast, out body, out normal, out frac);



                if (result && frac <= 1.0f)
                {
                    if (frac < deepestFrac)
                    {
                        deepestFrac  = frac;
                        groundPos    = rayOrigin + frac * wheelDelta;
                        worldBody    = body;
                        groundNormal = normal;
                    }

                    lastOnFloor = true;
                }
            }

            if (!lastOnFloor)
            {
                return;
            }

            if (groundNormal.LengthSquared() > 0.0f)
            {
                groundNormal.Normalize();
            }

            // System.Diagnostics.Debug.WriteLine(groundPos.ToString());


            displacement = rayLen * (1.0f - deepestFrac);
            displacement = JMath.Clamp(displacement, 0.0f, WheelTravel);

            float displacementForceMag = displacement * Spring;

            // reduce force when suspension is par to ground
            displacementForceMag *= Math.Abs(JVector.Dot(groundNormal, worldAxis));

            // apply damping
            float dampingForceMag = upSpeed * Damping;

            float totalForceMag = displacementForceMag + dampingForceMag;

            if (totalForceMag < 0.0f)
            {
                totalForceMag = 0.0f;
            }

            JVector extraForce = totalForceMag * worldAxis;

            force += extraForce;

            JVector groundUp   = groundNormal;
            JVector groundLeft = JVector.Cross(groundNormal, wheelFwd);

            if (groundLeft.LengthSquared() > 0.0f)
            {
                groundLeft.Normalize();
            }

            JVector groundFwd = JVector.Cross(groundLeft, groundUp);

            JVector wheelPointVel = car.LinearVelocity +
                                    JVector.Cross(car.AngularVelocity, JVector.Transform(Position, car.Orientation));

            // rimVel=(wxr)*v
            JVector rimVel = angVel * JVector.Cross(wheelLeft, groundPos - worldPos);

            wheelPointVel += rimVel;

            JVector worldVel = worldBody.LinearVelocity +
                               JVector.Cross(worldBody.AngularVelocity, groundPos - worldBody.Position);

            wheelPointVel -= worldVel;

            // sideways forces
            float noslipVel  = 0.1f;
            float slipVel    = 0.1f;
            float slipFactor = 0.7f;

            float smallVel = 3;
            float friction = SideFriction;

            float sideVel = JVector.Dot(wheelPointVel, groundLeft);

            if ((sideVel > slipVel) || (sideVel < -slipVel))
            {
                friction *= slipFactor;
            }
            else
            if ((sideVel > noslipVel) || (sideVel < -noslipVel))
            {
                friction *= 1.0f - (1.0f - slipFactor) * (System.Math.Abs(sideVel) - noslipVel) / (slipVel - noslipVel);
            }

            if (sideVel < 0.0f)
            {
                friction *= -1.0f;
            }

            if (System.Math.Abs(sideVel) < smallVel)
            {
                friction *= System.Math.Abs(sideVel) / smallVel;
            }

            float sideForce = -friction * totalForceMag;

            extraForce = sideForce * groundLeft;
            force     += extraForce;

            // fwd/back forces
            friction = ForwardFriction;
            float fwdVel = JVector.Dot(wheelPointVel, groundFwd);

            if ((fwdVel > slipVel) || (fwdVel < -slipVel))
            {
                friction *= slipFactor;
            }
            else
            if ((fwdVel > noslipVel) || (fwdVel < -noslipVel))
            {
                friction *= 1.0f - (1.0f - slipFactor) * (System.Math.Abs(fwdVel) - noslipVel) / (slipVel - noslipVel);
            }

            if (fwdVel < 0.0f)
            {
                friction *= -1.0f;
            }

            if (System.Math.Abs(fwdVel) < smallVel)
            {
                friction *= System.Math.Abs(fwdVel) / smallVel;
            }

            float fwdForce = -friction * totalForceMag;

            extraForce = fwdForce * groundFwd;
            force     += extraForce;

            // fwd force also spins the wheel
            JVector wheelCentreVel = car.LinearVelocity +
                                     JVector.Cross(car.AngularVelocity, JVector.Transform(Position, car.Orientation));

            angVelForGrip = JVector.Dot(wheelCentreVel, groundFwd) / Radius;
            torque       += -fwdForce * Radius;

            // add force to car
            car.AddForce(force, groundPos + 0.5f * JVector.Up);

            // add force to the world
            if (!worldBody.IsStatic)
            {
                worldBody.AddForce(force * (-1) * 0.01f, groundPos);
            }
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the HingeJoint class.
        /// </summary>
        /// <param name="world">The world class where the constraints get added to.</param>
        /// <param name="body1">The first body connected to the second one.</param>
        /// <param name="body2">The second body connected to the first one.</param>
        /// <param name="position">The position in world space where both bodies get connected.</param>
        /// <param name="hingeAxis">The axis if the hinge.</param>
        public LimitedHingeJoint(JitterWorld world, RigidBody body1, RigidBody body2, JVector position, JVector hingeAxis,
                                 float hingeFwdAngle, float hingeBckAngle)
            : base(world)
        {
            // Create the hinge first, two point constraints

            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= 0.5f;

            JVector pos1 = position; JVector.Add(ref pos1, ref hingeAxis, out pos1);
            JVector pos2 = position; JVector.Subtract(ref pos2, ref hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1);
            worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2);


            // Now the limit, one max distance constraint

            hingeAxis.Normalize();

            // choose a direction that is perpendicular to the hinge
            JVector perpDir = JVector.Up;

            if (JVector.Dot(perpDir, hingeAxis) > 0.1f)
            {
                perpDir = JVector.Right;
            }

            // now make it perpendicular to the hinge
            JVector sideAxis = JVector.Cross(hingeAxis, perpDir);

            perpDir = JVector.Cross(sideAxis, hingeAxis);
            perpDir.Normalize();

            // the length of the "arm" TODO take this as a parameter? what's
            // the effect of changing it?
            float len = 10.0f * 3;

            // Choose a position using that dir. this will be the anchor point
            // for body 0. relative to hinge
            JVector hingeRelAnchorPos0 = perpDir * len;


            // anchor point for body 2 is chosen to be in the middle of the
            // angle range.  relative to hinge
            float   angleToMiddle      = 0.5f * (hingeFwdAngle - hingeBckAngle);
            JVector hingeRelAnchorPos1 = JVector.Transform(hingeRelAnchorPos0, JMatrix.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * JMath.Pi));

            // work out the "string" length
            float hingeHalfAngle  = 0.5f * (hingeFwdAngle + hingeBckAngle);
            float allowedDistance = len * 2.0f * (float)System.Math.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * JMath.Pi);

            JVector hingePos = body1.Position;
            JVector relPos0c = hingePos + hingeRelAnchorPos0;
            JVector relPos1c = hingePos + hingeRelAnchorPos1;

            distance          = new PointPointDistance(body1, body2, relPos0c, relPos1c);
            distance.Distance = allowedDistance;
            distance.Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance;
        }