Example #1
0
 /// <summary>
 /// Constructs a new horizontal motion constraint.
 /// </summary>
 /// <param name="characterBody">Character body to be governed by this constraint.</param>
 /// <param name="supportFinder">Helper used to find supports for the character.</param>
 public HorizontalMotionConstraint(Entity characterBody, SupportFinder supportFinder)
 {
     this.characterBody = characterBody;
     this.supportFinder = supportFinder;
     CollectInvolvedEntities();
     MaximumAccelerationForce = float.MaxValue;
 }
 public override void OnRemovalFromSpace(Space oldSpace)
 {
     //Remove any supplements from the space too.
     oldSpace.Remove(Body);
     oldSpace.Remove(HorizontalMotionConstraint);
     oldSpace.Remove(VerticalMotionConstraint);
     //This character controller requires the standard implementation of Space.
     oldSpace.BoundingBoxUpdater.Finishing -= ExpandBoundingBox;
     SupportFinder.ClearSupportData();
     Body.AngularVelocity = new Vector3();
     Body.LinearVelocity  = new Vector3();
 }
Example #3
0
 bool IsDownStepObstructed(ref QuickList <CharacterContact> sideContacts)
 {
     //A contact is considered obstructive if its projected depth is deeper than any existing contact along the existing contacts' normals.
     for (int i = 0; i < sideContacts.Count; i++)
     {
         if (SupportFinder.IsSideContactObstructive(ref sideContacts.Elements[i].Contact))
         {
             return(true);
         }
     }
     return(false);
 }
Example #4
0
 /// <summary>
 /// Constructs a new step manager for a character.
 /// </summary>
 /// <param name="characterBody">The character's body.</param>
 /// <param name="contactCategorizer">Contact categorizer used by the character.</param>
 /// <param name="supportFinder">Support finder used by the character.</param>
 /// <param name="queryManager">Query provider to use in checking for obstructions.</param>
 /// <param name="horizontalMotionConstraint">Horizontal motion constraint used by the character. Source of 3d movement direction.</param>
 public StepManager(Cylinder characterBody, CharacterContactCategorizer contactCategorizer, SupportFinder supportFinder, QueryManager queryManager, HorizontalMotionConstraint horizontalMotionConstraint)
 {
     this.characterBody         = characterBody;
     currentQueryObject         = new ConvexCollidable <CylinderShape>(characterBody.CollisionInformation.Shape);
     ContactCategorizer         = contactCategorizer;
     SupportFinder              = supportFinder;
     QueryManager               = queryManager;
     HorizontalMotionConstraint = horizontalMotionConstraint;
     //The minimum step height is just barely above where the character would generally find the ground.
     //This helps avoid excess tests.
     minimumUpStepHeight = CollisionDetectionSettings.AllowedPenetration * 1.1f;// Math.Max(0, -.01f + character.Body.CollisionInformation.Shape.CollisionMargin * (1 - character.SupportFinder.sinMaximumSlope));
 }
        /// <summary>
        /// Constructs a new character controller.
        /// </summary>
        /// <param name="position">Initial position of the character.</param>
        /// <param name="height">Height of the character body while standing.</param>
        /// <param name="crouchingHeight">Height of the character body while crouching.</param>
        /// <param name="proneHeight">Height of the character body while prone.</param>
        /// <param name="radius">Radius of the character body.</param>
        /// <param name="margin">Radius of 'rounding' applied to the cylindrical body. Higher values make the cylinder's edges more rounded.
        /// The margin is contained within the cylinder's height and radius, so it must not exceed the radius or height of the cylinder.
        /// To change the collision margin later, use the CharacterController.CollisionMargin property.</param>
        /// <param name="mass">Mass of the character body.</param>
        /// <param name="maximumTractionSlope">Steepest slope, in radians, that the character can maintain traction on.</param>
        /// <param name="maximumSupportSlope">Steepest slope, in radians, that the character can consider a support.</param>
        /// <param name="standingSpeed">Speed at which the character will try to move while crouching with a support that provides traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="crouchingSpeed">Speed at which the character will try to move while crouching with a support that provides traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="proneSpeed">Speed at which the character will try to move while prone with a support that provides traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="tractionForce">Maximum force that the character can apply while on a support which provides traction.</param>
        /// <param name="slidingSpeed">Speed at which the character will try to move while on a support that does not provide traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="slidingForce">Maximum force that the character can apply while on a support which does not provide traction</param>
        /// <param name="airSpeed">Speed at which the character will try to move with no support.
        /// The character will not be decelerated while airborne.</param>
        /// <param name="airForce">Maximum force that the character can apply with no support.</param>
        /// <param name="jumpSpeed">Speed at which the character leaves the ground when it jumps</param>
        /// <param name="slidingJumpSpeed">Speed at which the character leaves the ground when it jumps without traction</param>
        /// <param name="maximumGlueForce">Maximum force the vertical motion constraint is allowed to apply in an attempt to keep the character on the ground.</param>
        public CharacterController(
            Vector3 position           = new Vector3(),
            float height               = 1.7f, float crouchingHeight = 1.7f * .7f, float proneHeight = 1.7f * 0.3f, float radius = 0.6f, float margin = 0.1f, float mass = 10f,
            float maximumTractionSlope = 0.8f, float maximumSupportSlope = 1.3f,
            float standingSpeed        = 8f, float crouchingSpeed     = 3f, float proneSpeed = 1.5f, float tractionForce = 1000, float slidingSpeed = 6, float slidingForce = 50, float airSpeed = 1, float airForce = 250,
            float jumpSpeed            = 4.5f, float slidingJumpSpeed = 3,
            float maximumGlueForce     = 5000
            )
        {
            if (margin > radius || margin > crouchingHeight || margin > height)
            {
                throw new ArgumentException("Margin must not be larger than the character's radius or height.");
            }

            Body = new Cylinder(position, height, radius, mass);
            Body.IgnoreShapeChanges = true; //Wouldn't want inertia tensor recomputations to occur when crouching and such.
            Body.CollisionInformation.Shape.CollisionMargin = margin;
            //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;
            ContactCategorizer         = new CharacterContactCategorizer(maximumTractionSlope, maximumSupportSlope);
            QueryManager               = new QueryManager(Body, ContactCategorizer);
            SupportFinder              = new SupportFinder(Body, QueryManager, ContactCategorizer);
            HorizontalMotionConstraint = new HorizontalMotionConstraint(Body, SupportFinder);
            HorizontalMotionConstraint.PositionAnchorDistanceThreshold = radius * 0.25f;
            VerticalMotionConstraint = new VerticalMotionConstraint(Body, SupportFinder, maximumGlueForce);
            StepManager   = new StepManager(Body, ContactCategorizer, SupportFinder, QueryManager, HorizontalMotionConstraint);
            StanceManager = new StanceManager(Body, crouchingHeight, proneHeight, QueryManager, SupportFinder);
            PairLocker    = new CharacterPairLocker(Body);

            StandingSpeed    = standingSpeed;
            CrouchingSpeed   = crouchingSpeed;
            ProneSpeed       = proneSpeed;
            TractionForce    = tractionForce;
            SlidingSpeed     = slidingSpeed;
            SlidingForce     = slidingForce;
            AirSpeed         = airSpeed;
            AirForce         = airForce;
            JumpSpeed        = jumpSpeed;
            SlidingJumpSpeed = slidingJumpSpeed;

            //Enable multithreading for the characters.
            IsUpdatedSequentially = false;
            //Link the character body to the character controller so that it can be identified by the locker.
            //Any object which replaces this must implement the ICharacterTag for locking to work properly.
            Body.CollisionInformation.Tag = new CharacterSynchronizer(Body);
        }
Example #6
0
        /// <summary>
        /// Constructs a stance manager for a character.
        /// </summary>
        /// <param name="characterBody">The character's body entity.</param>
        /// <param name="crouchingHeight">Crouching height of the character.</param>
        /// <param name="proneHeight">Prone height of the character.</param>
        /// <param name="queryManager">Provider of queries used by the stance manager to test if it is okay to change stances.</param>
        /// <param name="supportFinder">Support finder used by the character.</param>
        public StanceManager(Cylinder characterBody, float crouchingHeight, float proneHeight, QueryManager queryManager, SupportFinder supportFinder)
        {
            this.QueryManager  = queryManager;
            this.SupportFinder = supportFinder;
            this.characterBody = characterBody;
            standingHeight     = characterBody.Height;
            if (crouchingHeight < standingHeight)
            {
                this.crouchingHeight = crouchingHeight;
            }
            else
            {
                throw new ArgumentException("Crouching height must be less than standing height.");
            }
            if (proneHeight < crouchingHeight)
            {
                this.proneHeight = proneHeight;
            }
            else
            {
                throw new ArgumentException("Prone height must be less than crouching height.");
            }

            //We can share the real shape with the query objects.
            currentQueryObject  = new ConvexCollidable <CylinderShape>(characterBody.CollisionInformation.Shape);
            standingQueryObject = new ConvexCollidable <CylinderShape>(new CylinderShape(StandingHeight, characterBody.Radius)
            {
                CollisionMargin = currentQueryObject.Shape.CollisionMargin
            });
            crouchingQueryObject = new ConvexCollidable <CylinderShape>(new CylinderShape(CrouchingHeight, characterBody.Radius)
            {
                CollisionMargin = currentQueryObject.Shape.CollisionMargin
            });
            proneQueryObject = new ConvexCollidable <CylinderShape>(new CylinderShape(proneHeight, characterBody.Radius)
            {
                CollisionMargin = currentQueryObject.Shape.CollisionMargin
            });
            //Share the collision rules between the main body and its query objects.  That way, the character's queries return valid results.
            currentQueryObject.CollisionRules   = characterBody.CollisionInformation.CollisionRules;
            standingQueryObject.CollisionRules  = characterBody.CollisionInformation.CollisionRules;
            crouchingQueryObject.CollisionRules = characterBody.CollisionInformation.CollisionRules;
            proneQueryObject.CollisionRules     = characterBody.CollisionInformation.CollisionRules;
        }
        /// <summary>
        /// Constructs a new character controller.
        /// </summary>
        /// <param name="position">Initial position of the character.</param>
        /// <param name="radius">Radius of the character body.</param>
        /// <param name="mass">Mass of the character body.</param>
        /// <param name="maximumTractionSlope">Steepest slope, in radians, that the character can maintain traction on.</param>
        /// <param name="maximumSupportSlope">Steepest slope, in radians, that the character can consider a support.</param>
        /// <param name="speed">Speed at which the character will try to move while crouching with a support that provides traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="tractionForce">Maximum force that the character can apply while on a support which provides traction.</param>
        /// <param name="slidingSpeed">Speed at which the character will try to move while on a support that does not provide traction.
        /// Relative velocities with a greater magnitude will be decelerated.</param>
        /// <param name="slidingForce">Maximum force that the character can apply while on a support which does not provide traction</param>
        /// <param name="airSpeed">Speed at which the character will try to move with no support.
        /// The character will not be decelerated while airborne.</param>
        /// <param name="airForce">Maximum force that the character can apply with no support.</param>
        /// <param name="jumpSpeed">Speed at which the character leaves the ground when it jumps</param>
        /// <param name="slidingJumpSpeed">Speed at which the character leaves the ground when it jumps without traction</param>
        /// <param name="maximumGlueForce">Maximum force the vertical motion constraint is allowed to apply in an attempt to keep the character on the ground.</param>
        public SphereCharacterController(
            Vector3 position           = new Vector3(),
            float radius               = .85f, float mass = 10f,
            float maximumTractionSlope = 0.8f, float maximumSupportSlope = 1.3f,
            float speed            = 8f, float tractionForce      = 1000, float slidingSpeed = 6, float slidingForce = 50, float airSpeed = 1, float airForce = 250,
            float jumpSpeed        = 4.5f, float slidingJumpSpeed = 3,
            float maximumGlueForce = 5000)
        {
            Body = new Sphere(position, radius, mass);
            Body.IgnoreShapeChanges = true; //Wouldn't want inertia tensor recomputations to occur if the shape changes.
            //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;
            ContactCategorizer         = new CharacterContactCategorizer(maximumTractionSlope, maximumSupportSlope);
            QueryManager               = new QueryManager(Body, ContactCategorizer);
            SupportFinder              = new SupportFinder(Body, QueryManager, ContactCategorizer);
            HorizontalMotionConstraint = new HorizontalMotionConstraint(Body, SupportFinder);
            HorizontalMotionConstraint.PositionAnchorDistanceThreshold = (3f / 17f) * radius;
            VerticalMotionConstraint = new VerticalMotionConstraint(Body, SupportFinder, maximumGlueForce);
            PairLocker = new CharacterPairLocker(Body);

            Speed            = speed;
            TractionForce    = tractionForce;
            SlidingSpeed     = slidingSpeed;
            SlidingForce     = slidingForce;
            AirSpeed         = airSpeed;
            AirForce         = airForce;
            JumpSpeed        = jumpSpeed;
            SlidingJumpSpeed = slidingJumpSpeed;

            //Enable multithreading for the sphere characters.
            //See the bottom of the Update method for more information about using multithreading with this character.
            IsUpdatedSequentially = false;

            //Link the character body to the character controller so that it can be identified by the locker.
            //Any object which replaces this must implement the ICharacterTag for locking to work properly.
            Body.CollisionInformation.Tag = new CharacterSynchronizer(Body);
        }
Example #8
0
 /// <summary>
 /// Constructs a new vertical motion constraint.
 /// </summary>
 /// <param name="characterBody">Character body governed by the constraint.</param>
 /// <param name="supportFinder">Support finder used by the character.</param>
 /// <param name="maximumGlueForce">Maximum force the vertical motion constraint is allowed to apply in an attempt to keep the character on the ground.</param>
 public VerticalMotionConstraint(Entity characterBody, SupportFinder supportFinder, float maximumGlueForce = 5000)
 {
     this.characterBody = characterBody;
     this.supportFinder = supportFinder;
     MaximumGlueForce   = maximumGlueForce;
 }