Example #1
0
 /// <summary>
 /// Constructs a new character controller with the default configuration.
 /// </summary>
 public CharacterController()
 {
     Body = new Cylinder(Vector3.Zero, 1.7f, .6f, 10);
     Body.IgnoreShapeChanges = true; //Wouldn't want inertia tensor recomputations to occur when crouching and such.
     Body.CollisionInformation.Shape.CollisionMargin = .1f;
     //Making the character a continuous object prevents it from flying through walls which would be pretty jarring from a player's perspective.
     Body.PositionUpdateMode        = PositionUpdateMode.Continuous;
     Body.LocalInertiaTensorInverse = new Matrix3X3();
     //TODO: In v0.16.2, compound bodies would override the material properties that get set in the CreatingPair event handler.
     //In a future version where this is changed, change this to conceptually minimally required CreatingPair.
     Body.CollisionInformation.Events.DetectingInitialCollision += RemoveFriction;
     Body.LinearDamping         = 0;
     SupportFinder              = new SupportFinder(this);
     HorizontalMotionConstraint = new HorizontalMotionConstraint(this);
     VerticalMotionConstraint   = new VerticalMotionConstraint(this);
     StepManager   = new StepManager(this);
     StanceManager = new StanceManager(this);
     QueryManager  = new QueryManager(this);
 }
Example #2
0
        void IBeforeSolverUpdateable.Update(float dt)
        {
            CorrectContacts();

            bool hadTraction = SupportFinder.HasTraction;

            var supportData = CollectSupportData();


            //Compute the initial velocities relative to the support.
            Vector3 relativeVelocity;

            ComputeRelativeVelocity(ref supportData, out relativeVelocity);
            float   verticalVelocity   = Vector3.Dot(supportData.Normal, relativeVelocity);
            Vector3 horizontalVelocity = relativeVelocity - supportData.Normal * verticalVelocity;



            //Don't attempt to use an object as support if we are flying away from it (and we were never standing on it to begin with).
            if (SupportFinder.HasTraction && !hadTraction && verticalVelocity < 0)
            {
                SupportFinder.ClearSupportData();
                HorizontalMotionConstraint.SupportData = new SupportData();
            }

            //If we can compute that we're separating faster than we can handle, take off.
            if (SupportFinder.HasTraction && verticalVelocity < -VerticalMotionConstraint.MaximumGlueForce * dt / VerticalMotionConstraint.EffectiveMass)
            {
                SupportFinder.ClearSupportData();
                supportData = new SupportData();
            }

            //Attempt to jump.
            if (tryToJump && StanceManager.CurrentStance != Stance.Crouching) //Jumping while crouching would be a bit silly.
            {
                //In the following, note that the jumping velocity changes are computed such that the separating velocity is specifically achieved,
                //rather than just adding some speed along an arbitrary direction.  This avoids some cases where the character could otherwise increase
                //the jump speed, which may not be desired.
                if (SupportFinder.HasTraction)
                {
                    //The character has traction, so jump straight up.
                    float currentUpVelocity = Vector3.Dot(Body.OrientationMatrix.Up, relativeVelocity);
                    //Target velocity is JumpSpeed.
                    float velocityChange = Math.Max(jumpSpeed - currentUpVelocity, 0);
                    ApplyJumpVelocity(ref supportData, Body.OrientationMatrix.Up * velocityChange, ref relativeVelocity);


                    //Prevent any old contacts from hanging around and coming back with a negative depth.
                    foreach (var pair in Body.CollisionInformation.Pairs)
                    {
                        pair.ClearContacts();
                    }
                    SupportFinder.ClearSupportData();
                    supportData = new SupportData();
                }
                else if (SupportFinder.HasSupport)
                {
                    //The character does not have traction, so jump along the surface normal instead.
                    float currentNormalVelocity = Vector3.Dot(supportData.Normal, relativeVelocity);
                    //Target velocity is JumpSpeed.
                    float velocityChange = Math.Max(slidingJumpSpeed - currentNormalVelocity, 0);
                    ApplyJumpVelocity(ref supportData, supportData.Normal * -velocityChange, ref relativeVelocity);

                    //Prevent any old contacts from hanging around and coming back with a negative depth.
                    foreach (var pair in Body.CollisionInformation.Pairs)
                    {
                        pair.ClearContacts();
                    }
                    SupportFinder.ClearSupportData();
                    supportData = new SupportData();
                }
            }
            tryToJump = false;


            //Try to step!
            Vector3 newPosition;

            if (StepManager.TryToStepDown(out newPosition) ||
                StepManager.TryToStepUp(out newPosition))
            {
                TeleportToPosition(newPosition, dt);
            }

            if (StanceManager.UpdateStance(out newPosition))
            {
                TeleportToPosition(newPosition, dt);
            }

            //if (SupportFinder.HasTraction && SupportFinder.Supports.Count == 0)
            //{
            //There's another way to step down that is a lot cheaper, but less robust.
            //This modifies the velocity of the character to make it fall faster.
            //Impacts with the ground will be harder, so it will apply superfluous force to supports.
            //Additionally, it will not be consistent with instant up-stepping.
            //However, because it does not do any expensive queries, it is very fast!

            ////We are being supported by a ray cast, but we're floating.
            ////Let's try to get to the ground faster.
            ////How fast?  Try picking an arbitrary velocity and setting our relative vertical velocity to that value.
            ////Don't go farther than the maximum distance, though.
            //float maxVelocity = (SupportFinder.SupportRayData.Value.HitData.T - SupportFinder.RayLengthToBottom);
            //if (maxVelocity > 0)
            //{
            //    maxVelocity = (maxVelocity + .01f) / dt;

            //    float targetVerticalVelocity = -3;
            //    verticalVelocity = Vector3.Dot(Body.OrientationMatrix.Up, relativeVelocity);
            //    float change = MathHelper.Clamp(targetVerticalVelocity - verticalVelocity, -maxVelocity, 0);
            //    ChangeVelocityUnilaterally(Body.OrientationMatrix.Up * change, ref relativeVelocity);
            //}
            //}



            //Warning:
            //Changing a constraint's support data is not thread safe; it modifies simulation islands!
            //If your game can guarantee that character controllers will be the only ones performing such shared modifications
            //while this updateable stage runs, then addressing this is fairly simple.  Wrap this section (minimally, the SupportData property sets)
            //in a critical section.  A single contended resource isn't great, but then again, the lock will be fairly brief compared to the stepping
            //and support queries performed above.  Implementing such parallelization is probably only it worth when the number of characters gets fairly high.
            //These characters seem to cost about 50-400 microseconds a piece on a single core of a [email protected], with 400 microseconds being a temporary worst case.
            HorizontalMotionConstraint.SupportData = supportData;
            //Vertical support data is different because it has the capacity to stop the character from moving unless
            //contacts are pruned appropriately.
            SupportData verticalSupportData;
            Vector3     movement3d = new Vector3(HorizontalMotionConstraint.MovementDirection.X, 0, HorizontalMotionConstraint.MovementDirection.Y);

            SupportFinder.GetTractionInDirection(ref movement3d, out verticalSupportData);
            VerticalMotionConstraint.SupportData = verticalSupportData;
        }