예제 #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);

            //Enable multithreading for the sphere characters.
            //See the bottom of the Update method for more information about using multithreading with this character.
            IsUpdatedSequentially = false;
        }
예제 #2
0
        void IBeforeSolverUpdateable.Update(float dt)
        {
            CorrectContacts();

            bool hadTraction = SupportFinder.HasTraction;

            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();
                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);
            //}
            //}



            //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);


            //Warning:
            //Changing a constraint's support data is not thread safe; it modifies simulation islands!
            //If something other than a CharacterController can modify simulation islands is running
            //simultaneously (in the IBeforeSolverUpdateable.Update stage), it will need to be synchronized.
            ConstraintAccessLocker.Enter();
            HorizontalMotionConstraint.SupportData = supportData;
            VerticalMotionConstraint.SupportData   = verticalSupportData;
            ConstraintAccessLocker.Exit();
        }