/// <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; }
/// <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; }
/// <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); }
.1f; //There's a little extra space above the maximum step height to start the obstruction and downcast test rays. Helps when a step is very close to the max step height. /// <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 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) { QueryManager = queryManager; 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); }