1
This commit is contained in:
@@ -0,0 +1,817 @@
|
||||
using UnityEngine;
|
||||
using Lightbug.CharacterControllerPro.Core;
|
||||
using Lightbug.Utilities;
|
||||
using Lightbug.CharacterControllerPro.Implementation;
|
||||
|
||||
namespace Lightbug.CharacterControllerPro.Demo
|
||||
{
|
||||
[AddComponentMenu("Character Controller Pro/Demo/Character/States/Normal Movement")]
|
||||
public class NormalMovement : CharacterState
|
||||
{
|
||||
|
||||
[Space(10)]
|
||||
|
||||
public PlanarMovementParameters planarMovementParameters = new PlanarMovementParameters();
|
||||
|
||||
public VerticalMovementParameters verticalMovementParameters = new VerticalMovementParameters();
|
||||
|
||||
public CrouchParameters crouchParameters = new CrouchParameters();
|
||||
|
||||
public LookingDirectionParameters lookingDirectionParameters = new LookingDirectionParameters();
|
||||
|
||||
|
||||
[Header("Animation")]
|
||||
|
||||
[SerializeField]
|
||||
protected string groundedParameter = "Grounded";
|
||||
|
||||
[SerializeField]
|
||||
protected string stableParameter = "Stable";
|
||||
|
||||
[SerializeField]
|
||||
protected string verticalSpeedParameter = "VerticalSpeed";
|
||||
|
||||
[SerializeField]
|
||||
protected string planarSpeedParameter = "PlanarSpeed";
|
||||
|
||||
[SerializeField]
|
||||
protected string horizontalAxisParameter = "HorizontalAxis";
|
||||
|
||||
[SerializeField]
|
||||
protected string verticalAxisParameter = "VerticalAxis";
|
||||
|
||||
[SerializeField]
|
||||
protected string heightParameter = "Height";
|
||||
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the character jumps.
|
||||
/// </summary>
|
||||
public event System.Action OnJumpPerformed;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the character jumps from the ground.
|
||||
/// </summary>
|
||||
public event System.Action<bool> OnGroundedJumpPerformed;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the character jumps while.
|
||||
/// </summary>
|
||||
public event System.Action<int> OnNotGroundedJumpPerformed;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
protected MaterialController materialController = null;
|
||||
protected int notGroundedJumpsLeft = 0;
|
||||
protected bool isAllowedToCancelJump = false;
|
||||
protected bool wantToRun = false;
|
||||
protected float currentPlanarSpeedLimit = 0f;
|
||||
|
||||
protected bool groundedJumpAvailable = true;
|
||||
protected Vector3 jumpDirection = default(Vector3);
|
||||
|
||||
protected Vector3 targetLookingDirection = default(Vector3);
|
||||
protected float targetHeight = 1f;
|
||||
|
||||
protected bool wantToCrouch = false;
|
||||
protected bool isCrouched = false;
|
||||
|
||||
protected PlanarMovementParameters.PlanarMovementProperties currentMotion = new PlanarMovementParameters.PlanarMovementProperties();
|
||||
bool reducedAirControlFlag = false;
|
||||
float reducedAirControlInitialTime = 0f;
|
||||
float reductionDuration = 0.5f;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
notGroundedJumpsLeft = verticalMovementParameters.availableNotGroundedJumps;
|
||||
|
||||
materialController = this.GetComponentInBranch<CharacterActor, MaterialController>();
|
||||
}
|
||||
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
verticalMovementParameters.OnValidate();
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
targetHeight = CharacterActor.DefaultBodySize.y;
|
||||
|
||||
float minCrouchHeightRatio = CharacterActor.BodySize.x / CharacterActor.BodySize.y;
|
||||
crouchParameters.heightRatio = Mathf.Max(minCrouchHeightRatio, crouchParameters.heightRatio);
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
CharacterActor.OnTeleport += OnTeleport;
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
CharacterActor.OnTeleport -= OnTeleport;
|
||||
}
|
||||
|
||||
public override string GetInfo()
|
||||
{
|
||||
return "This state serves as a multi purpose movement based state. It is responsible for handling gravity and jump, walk and run, crouch, " +
|
||||
"react to the different material properties, etc. Basically it covers all the common movements involved " +
|
||||
"in a typical game, from a 3D platformer to a first person walking simulator.";
|
||||
}
|
||||
|
||||
void OnTeleport(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
targetLookingDirection = CharacterActor.Forward;
|
||||
isAllowedToCancelJump = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the useGravity toggle. Use this property to enable/disable the effect of gravity on the character.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool UseGravity
|
||||
{
|
||||
get => verticalMovementParameters.useGravity;
|
||||
set => verticalMovementParameters.useGravity = value;
|
||||
}
|
||||
|
||||
public override void CheckExitTransition()
|
||||
{
|
||||
|
||||
if (CharacterActions.jetPack.value)
|
||||
{
|
||||
CharacterStateController.EnqueueTransition<JetPack>();
|
||||
}
|
||||
else if (CharacterActions.dash.Started)
|
||||
{
|
||||
CharacterStateController.EnqueueTransition<Dash>();
|
||||
}
|
||||
else if (CharacterActor.Triggers.Count != 0)
|
||||
{
|
||||
CharacterStateController.EnqueueTransition<LadderClimbing>();
|
||||
CharacterStateController.EnqueueTransition<RopeClimbing>();
|
||||
}
|
||||
else if (!CharacterActor.IsGrounded)
|
||||
{
|
||||
if (!CharacterActions.crouch.value)
|
||||
CharacterStateController.EnqueueTransition<WallSlide>();
|
||||
|
||||
CharacterStateController.EnqueueTransition<LedgeHanging>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExitBehaviour(float dt, CharacterState toState)
|
||||
{
|
||||
reducedAirControlFlag = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reduces the amount of acceleration and deceleration (not grounded state) until the character reaches the apex of the jump
|
||||
/// (vertical velocity close to zero). This can be useful to prevent the character from accelerating/decelerating too quickly (e.g. right after performing a wall jump).
|
||||
/// </summary>
|
||||
public void ReduceAirControl(float reductionDuration = 0.5f)
|
||||
{
|
||||
reducedAirControlFlag = true;
|
||||
reducedAirControlInitialTime = Time.time;
|
||||
this.reductionDuration = reductionDuration;
|
||||
}
|
||||
|
||||
void SetMotionValues(Vector3 targetPlanarVelocity)
|
||||
{
|
||||
float angleCurrentTargetVelocity = Vector3.Angle(CharacterActor.PlanarVelocity, targetPlanarVelocity);
|
||||
|
||||
switch (CharacterActor.CurrentState)
|
||||
{
|
||||
case CharacterActorState.StableGrounded:
|
||||
|
||||
currentMotion.acceleration = planarMovementParameters.stableGroundedAcceleration;
|
||||
currentMotion.deceleration = planarMovementParameters.stableGroundedDeceleration;
|
||||
currentMotion.angleAccelerationMultiplier = planarMovementParameters.stableGroundedAngleAccelerationBoost.Evaluate(angleCurrentTargetVelocity);
|
||||
|
||||
break;
|
||||
|
||||
case CharacterActorState.UnstableGrounded:
|
||||
currentMotion.acceleration = planarMovementParameters.unstableGroundedAcceleration;
|
||||
currentMotion.deceleration = planarMovementParameters.unstableGroundedDeceleration;
|
||||
currentMotion.angleAccelerationMultiplier = planarMovementParameters.unstableGroundedAngleAccelerationBoost.Evaluate(angleCurrentTargetVelocity);
|
||||
|
||||
break;
|
||||
|
||||
case CharacterActorState.NotGrounded:
|
||||
|
||||
if (reducedAirControlFlag)
|
||||
{
|
||||
float time = Time.time - reducedAirControlInitialTime;
|
||||
if (time <= reductionDuration)
|
||||
{
|
||||
currentMotion.acceleration = (planarMovementParameters.notGroundedAcceleration / reductionDuration) * time;
|
||||
currentMotion.deceleration = (planarMovementParameters.notGroundedDeceleration / reductionDuration) * time;
|
||||
}
|
||||
else
|
||||
{
|
||||
reducedAirControlFlag = false;
|
||||
|
||||
currentMotion.acceleration = planarMovementParameters.notGroundedAcceleration;
|
||||
currentMotion.deceleration = planarMovementParameters.notGroundedDeceleration;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
currentMotion.acceleration = planarMovementParameters.notGroundedAcceleration;
|
||||
currentMotion.deceleration = planarMovementParameters.notGroundedDeceleration;
|
||||
}
|
||||
|
||||
currentMotion.angleAccelerationMultiplier = planarMovementParameters.notGroundedAngleAccelerationBoost.Evaluate(angleCurrentTargetVelocity);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Material values
|
||||
if (materialController != null)
|
||||
{
|
||||
if (CharacterActor.IsGrounded)
|
||||
{
|
||||
currentMotion.acceleration *= materialController.CurrentSurface.accelerationMultiplier * materialController.CurrentVolume.accelerationMultiplier;
|
||||
currentMotion.deceleration *= materialController.CurrentSurface.decelerationMultiplier * materialController.CurrentVolume.decelerationMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentMotion.acceleration *= materialController.CurrentVolume.accelerationMultiplier;
|
||||
currentMotion.deceleration *= materialController.CurrentVolume.decelerationMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Processes the lateral movement of the character (stable and unstable state), that is, walk, run, crouch, etc.
|
||||
/// This movement is tied directly to the "movement" character action.
|
||||
/// </summary>
|
||||
protected virtual void ProcessPlanarMovement(float dt)
|
||||
{
|
||||
//SetMotionValues();
|
||||
|
||||
float speedMultiplier = materialController != null ?
|
||||
materialController.CurrentSurface.speedMultiplier * materialController.CurrentVolume.speedMultiplier : 1f;
|
||||
|
||||
|
||||
bool needToAccelerate = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, currentPlanarSpeedLimit).sqrMagnitude >= CharacterActor.PlanarVelocity.sqrMagnitude;
|
||||
|
||||
Vector3 targetPlanarVelocity = default;
|
||||
switch (CharacterActor.CurrentState)
|
||||
{
|
||||
case CharacterActorState.NotGrounded:
|
||||
|
||||
if (CharacterActor.WasGrounded)
|
||||
currentPlanarSpeedLimit = Mathf.Max(CharacterActor.PlanarVelocity.magnitude, planarMovementParameters.baseSpeedLimit);
|
||||
|
||||
|
||||
//needToAccelerate = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, currentPlanarSpeedLimit).sqrMagnitude >= CharacterActor.PlanarVelocity.sqrMagnitude;
|
||||
targetPlanarVelocity = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, speedMultiplier, currentPlanarSpeedLimit);
|
||||
|
||||
//GetAccelerationBoost(targetPlanarVelocity)
|
||||
break;
|
||||
case CharacterActorState.StableGrounded:
|
||||
|
||||
|
||||
// Run ------------------------------------------------------------
|
||||
if (planarMovementParameters.runInputMode == InputMode.Toggle)
|
||||
{
|
||||
if (CharacterActions.run.Started)
|
||||
wantToRun = !wantToRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantToRun = CharacterActions.run.value;
|
||||
}
|
||||
|
||||
if (wantToCrouch || !planarMovementParameters.canRun)
|
||||
wantToRun = false;
|
||||
|
||||
|
||||
if (isCrouched)
|
||||
{
|
||||
currentPlanarSpeedLimit = planarMovementParameters.baseSpeedLimit * crouchParameters.speedMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPlanarSpeedLimit = wantToRun ? planarMovementParameters.boostSpeedLimit : planarMovementParameters.baseSpeedLimit;
|
||||
}
|
||||
|
||||
targetPlanarVelocity = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, speedMultiplier, currentPlanarSpeedLimit);
|
||||
|
||||
//needToAccelerate = CharacterStateController.InputMovementReference != Vector3.zero;
|
||||
|
||||
|
||||
break;
|
||||
case CharacterActorState.UnstableGrounded:
|
||||
|
||||
currentPlanarSpeedLimit = planarMovementParameters.baseSpeedLimit;
|
||||
|
||||
//needToAccelerate = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, currentPlanarSpeedLimit).sqrMagnitude >= CharacterActor.PlanarVelocity.sqrMagnitude;
|
||||
targetPlanarVelocity = CustomUtilities.Multiply(CharacterStateController.InputMovementReference, speedMultiplier, currentPlanarSpeedLimit);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SetMotionValues(targetPlanarVelocity);
|
||||
|
||||
|
||||
float acceleration = currentMotion.acceleration;
|
||||
if (needToAccelerate)
|
||||
{
|
||||
acceleration *= currentMotion.angleAccelerationMultiplier;
|
||||
|
||||
// Affect acceleration based on the angle between target velocity and current velocity
|
||||
//float angleCurrentTargetVelocity = Vector3.Angle(CharacterActor.PlanarVelocity, targetPlanarVelocity);
|
||||
//float accelerationBoost = 20f * (angleCurrentTargetVelocity / 180f);
|
||||
//acceleration += accelerationBoost;
|
||||
}
|
||||
else
|
||||
{
|
||||
acceleration = currentMotion.deceleration;
|
||||
}
|
||||
|
||||
CharacterActor.PlanarVelocity = Vector3.MoveTowards(
|
||||
CharacterActor.PlanarVelocity,
|
||||
targetPlanarVelocity,
|
||||
acceleration * dt
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void ProcessGravity(float dt)
|
||||
{
|
||||
if (!verticalMovementParameters.useGravity)
|
||||
return;
|
||||
|
||||
|
||||
verticalMovementParameters.UpdateParameters();
|
||||
|
||||
|
||||
float gravityMultiplier = 1f;
|
||||
|
||||
if (materialController != null)
|
||||
gravityMultiplier = CharacterActor.LocalVelocity.y >= 0 ?
|
||||
materialController.CurrentVolume.gravityAscendingMultiplier :
|
||||
materialController.CurrentVolume.gravityDescendingMultiplier;
|
||||
|
||||
float gravity = gravityMultiplier * verticalMovementParameters.gravity;
|
||||
|
||||
|
||||
if (!CharacterActor.IsStable)
|
||||
CharacterActor.VerticalVelocity += CustomUtilities.Multiply(-CharacterActor.Up, gravity, dt);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected bool UnstableGroundedJumpAvailable => !verticalMovementParameters.canJumpOnUnstableGround && CharacterActor.CurrentState == CharacterActorState.UnstableGrounded;
|
||||
|
||||
|
||||
|
||||
public enum JumpResult
|
||||
{
|
||||
Invalid,
|
||||
Grounded,
|
||||
NotGrounded
|
||||
}
|
||||
|
||||
JumpResult CanJump()
|
||||
{
|
||||
JumpResult jumpResult = JumpResult.Invalid;
|
||||
|
||||
if (!verticalMovementParameters.canJump)
|
||||
return jumpResult;
|
||||
|
||||
if (isCrouched)
|
||||
return jumpResult;
|
||||
|
||||
|
||||
switch (CharacterActor.CurrentState)
|
||||
{
|
||||
case CharacterActorState.StableGrounded:
|
||||
|
||||
if (CharacterActions.jump.StartedElapsedTime <= verticalMovementParameters.preGroundedJumpTime && groundedJumpAvailable)
|
||||
jumpResult = JumpResult.Grounded;
|
||||
|
||||
break;
|
||||
case CharacterActorState.NotGrounded:
|
||||
|
||||
if (CharacterActions.jump.Started)
|
||||
{
|
||||
// First check if the "grounded jump" is available. If so, execute a "coyote jump".
|
||||
if (CharacterActor.NotGroundedTime <= verticalMovementParameters.postGroundedJumpTime && groundedJumpAvailable)
|
||||
{
|
||||
jumpResult = JumpResult.Grounded;
|
||||
}
|
||||
else if (notGroundedJumpsLeft != 0) // Do a not grounded jump
|
||||
{
|
||||
jumpResult = JumpResult.NotGrounded;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CharacterActorState.UnstableGrounded:
|
||||
|
||||
if (CharacterActions.jump.StartedElapsedTime <= verticalMovementParameters.preGroundedJumpTime && verticalMovementParameters.canJumpOnUnstableGround)
|
||||
jumpResult = JumpResult.Grounded;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return jumpResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void ProcessJump(float dt)
|
||||
{
|
||||
ProcessRegularJump(dt);
|
||||
ProcessJumpDown(dt);
|
||||
}
|
||||
|
||||
#region JumpDown
|
||||
|
||||
protected virtual bool ProcessJumpDown(float dt)
|
||||
{
|
||||
if (!verticalMovementParameters.canJumpDown)
|
||||
return false;
|
||||
|
||||
if (!CharacterActor.IsStable)
|
||||
return false;
|
||||
|
||||
if (!CharacterActor.IsGroundAOneWayPlatform)
|
||||
return false;
|
||||
|
||||
if (verticalMovementParameters.filterByTag)
|
||||
{
|
||||
if (!CharacterActor.GroundObject.CompareTag(verticalMovementParameters.jumpDownTag))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ProcessJumpDownAction())
|
||||
return false;
|
||||
|
||||
JumpDown(dt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected virtual bool ProcessJumpDownAction()
|
||||
{
|
||||
return isCrouched && CharacterActions.jump.Started;
|
||||
}
|
||||
|
||||
|
||||
protected virtual void JumpDown(float dt)
|
||||
{
|
||||
|
||||
float groundDisplacementExtraDistance = 0f;
|
||||
|
||||
Vector3 groundDisplacement = CustomUtilities.Multiply(CharacterActor.GroundVelocity, dt);
|
||||
// bool CharacterActor.transform.InverseTransformVectorUnscaled( Vector3.Project( groundDisplacement , CharacterActor.Up ) ).y
|
||||
|
||||
if (!CharacterActor.IsGroundAscending)
|
||||
groundDisplacementExtraDistance = groundDisplacement.magnitude;
|
||||
|
||||
CharacterActor.ForceNotGrounded();
|
||||
|
||||
CharacterActor.Position -=
|
||||
CustomUtilities.Multiply(
|
||||
CharacterActor.Up,
|
||||
CharacterConstants.ColliderMinBottomOffset + verticalMovementParameters.jumpDownDistance + groundDisplacementExtraDistance
|
||||
);
|
||||
|
||||
CharacterActor.VerticalVelocity -= CustomUtilities.Multiply(CharacterActor.Up, verticalMovementParameters.jumpDownVerticalVelocity);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Jump
|
||||
|
||||
protected virtual void ProcessRegularJump(float dt)
|
||||
{
|
||||
if (CharacterActor.IsGrounded)
|
||||
{
|
||||
notGroundedJumpsLeft = verticalMovementParameters.availableNotGroundedJumps;
|
||||
|
||||
groundedJumpAvailable = true;
|
||||
}
|
||||
|
||||
|
||||
if (isAllowedToCancelJump)
|
||||
{
|
||||
if (verticalMovementParameters.cancelJumpOnRelease)
|
||||
{
|
||||
if (CharacterActions.jump.StartedElapsedTime >= verticalMovementParameters.cancelJumpMaxTime || CharacterActor.IsFalling)
|
||||
{
|
||||
isAllowedToCancelJump = false;
|
||||
}
|
||||
else if (!CharacterActions.jump.value && CharacterActions.jump.StartedElapsedTime >= verticalMovementParameters.cancelJumpMinTime)
|
||||
{
|
||||
// Get the velocity mapped onto the current jump direction
|
||||
Vector3 projectedJumpVelocity = Vector3.Project(CharacterActor.Velocity, jumpDirection);
|
||||
|
||||
CharacterActor.Velocity -= CustomUtilities.Multiply(projectedJumpVelocity, 1f - verticalMovementParameters.cancelJumpMultiplier);
|
||||
|
||||
isAllowedToCancelJump = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JumpResult jumpResult = CanJump();
|
||||
|
||||
switch (jumpResult)
|
||||
{
|
||||
case JumpResult.Grounded:
|
||||
groundedJumpAvailable = false;
|
||||
|
||||
break;
|
||||
case JumpResult.NotGrounded:
|
||||
notGroundedJumpsLeft--;
|
||||
|
||||
break;
|
||||
|
||||
case JumpResult.Invalid:
|
||||
return;
|
||||
}
|
||||
|
||||
// Events ---------------------------------------------------
|
||||
if (CharacterActor.IsGrounded)
|
||||
{
|
||||
|
||||
if (OnGroundedJumpPerformed != null)
|
||||
OnGroundedJumpPerformed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnNotGroundedJumpPerformed != null)
|
||||
OnNotGroundedJumpPerformed(notGroundedJumpsLeft);
|
||||
}
|
||||
|
||||
if (OnJumpPerformed != null)
|
||||
OnJumpPerformed();
|
||||
|
||||
// Define the jump direction ---------------------------------------------------
|
||||
jumpDirection = SetJumpDirection();
|
||||
|
||||
// Force "not grounded" state.
|
||||
if (CharacterActor.IsGrounded)
|
||||
CharacterActor.ForceNotGrounded();
|
||||
|
||||
// First remove any velocity associated with the jump direction.
|
||||
CharacterActor.Velocity -= Vector3.Project(CharacterActor.Velocity, jumpDirection);
|
||||
CharacterActor.Velocity += CustomUtilities.Multiply(jumpDirection, verticalMovementParameters.jumpSpeed);
|
||||
|
||||
if (verticalMovementParameters.cancelJumpOnRelease)
|
||||
isAllowedToCancelJump = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the jump direction vector whenever the jump action is started.
|
||||
/// </summary>
|
||||
protected virtual Vector3 SetJumpDirection()
|
||||
{
|
||||
return CharacterActor.Up;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
void ProcessVerticalMovement(float dt)
|
||||
{
|
||||
ProcessGravity(dt);
|
||||
ProcessJump(dt);
|
||||
}
|
||||
|
||||
|
||||
public override void EnterBehaviour(float dt, CharacterState fromState)
|
||||
{
|
||||
CharacterActor.alwaysNotGrounded = false;
|
||||
|
||||
targetLookingDirection = CharacterActor.Forward;
|
||||
|
||||
if (fromState == CharacterStateController.GetState<WallSlide>())
|
||||
{
|
||||
// "availableNotGroundedJumps + 1" because the update code will consume one jump!
|
||||
notGroundedJumpsLeft = verticalMovementParameters.availableNotGroundedJumps + 1;
|
||||
|
||||
// Reduce the amount of air control (acceleration and deceleration) for 0.5 seconds.
|
||||
ReduceAirControl(0.5f);
|
||||
}
|
||||
|
||||
currentPlanarSpeedLimit = Mathf.Max(CharacterActor.PlanarVelocity.magnitude, planarMovementParameters.baseSpeedLimit);
|
||||
|
||||
CharacterActor.UseRootMotion = false;
|
||||
}
|
||||
|
||||
protected virtual void HandleRotation(float dt)
|
||||
{
|
||||
HandleLookingDirection(dt);
|
||||
}
|
||||
|
||||
void HandleLookingDirection(float dt)
|
||||
{
|
||||
if (!lookingDirectionParameters.changeLookingDirection)
|
||||
return;
|
||||
|
||||
switch (lookingDirectionParameters.lookingDirectionMode)
|
||||
{
|
||||
case LookingDirectionParameters.LookingDirectionMode.Movement:
|
||||
|
||||
switch (CharacterActor.CurrentState)
|
||||
{
|
||||
case CharacterActorState.NotGrounded:
|
||||
|
||||
SetTargetLookingDirection(lookingDirectionParameters.notGroundedLookingDirectionMode);
|
||||
|
||||
break;
|
||||
case CharacterActorState.StableGrounded:
|
||||
|
||||
SetTargetLookingDirection(lookingDirectionParameters.stableGroundedLookingDirectionMode);
|
||||
|
||||
break;
|
||||
case CharacterActorState.UnstableGrounded:
|
||||
|
||||
SetTargetLookingDirection(lookingDirectionParameters.unstableGroundedLookingDirectionMode);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LookingDirectionParameters.LookingDirectionMode.ExternalReference:
|
||||
|
||||
if (!CharacterActor.CharacterBody.Is2D)
|
||||
targetLookingDirection = CharacterStateController.MovementReferenceForward;
|
||||
|
||||
break;
|
||||
|
||||
case LookingDirectionParameters.LookingDirectionMode.Target:
|
||||
|
||||
targetLookingDirection = (lookingDirectionParameters.target.position - CharacterActor.Position);
|
||||
targetLookingDirection.Normalize();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Quaternion targetDeltaRotation = Quaternion.FromToRotation(CharacterActor.Forward, targetLookingDirection);
|
||||
Quaternion currentDeltaRotation = Quaternion.Slerp(Quaternion.identity, targetDeltaRotation, lookingDirectionParameters.speed * dt);
|
||||
|
||||
if (CharacterActor.CharacterBody.Is2D)
|
||||
CharacterActor.SetYaw(targetLookingDirection);
|
||||
else
|
||||
CharacterActor.SetYaw(currentDeltaRotation * CharacterActor.Forward);
|
||||
}
|
||||
|
||||
void SetTargetLookingDirection(LookingDirectionParameters.LookingDirectionMovementSource lookingDirectionMode)
|
||||
{
|
||||
if (lookingDirectionMode == LookingDirectionParameters.LookingDirectionMovementSource.Input)
|
||||
{
|
||||
if (CharacterStateController.InputMovementReference != Vector3.zero)
|
||||
targetLookingDirection = CharacterStateController.InputMovementReference;
|
||||
else
|
||||
targetLookingDirection = CharacterActor.Forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CharacterActor.PlanarVelocity != Vector3.zero)
|
||||
targetLookingDirection = Vector3.ProjectOnPlane(CharacterActor.PlanarVelocity, CharacterActor.Up);
|
||||
else
|
||||
targetLookingDirection = CharacterActor.Forward;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateBehaviour(float dt)
|
||||
{
|
||||
HandleSize(dt);
|
||||
HandleVelocity(dt);
|
||||
HandleRotation(dt);
|
||||
}
|
||||
|
||||
|
||||
public override void PreCharacterSimulation(float dt)
|
||||
{
|
||||
// Pre/PostCharacterSimulation methods are useful to update all the Animator parameters.
|
||||
// Why? Because the CharacterActor component will end up modifying the velocity of the actor.
|
||||
if (!CharacterActor.IsAnimatorValid())
|
||||
return;
|
||||
|
||||
CharacterStateController.Animator.SetBool(groundedParameter, CharacterActor.IsGrounded);
|
||||
CharacterStateController.Animator.SetBool(stableParameter, CharacterActor.IsStable);
|
||||
CharacterStateController.Animator.SetFloat(horizontalAxisParameter, CharacterActions.movement.value.x);
|
||||
CharacterStateController.Animator.SetFloat(verticalAxisParameter, CharacterActions.movement.value.y);
|
||||
CharacterStateController.Animator.SetFloat(heightParameter, CharacterActor.BodySize.y);
|
||||
}
|
||||
|
||||
public override void PostCharacterSimulation(float dt)
|
||||
{
|
||||
// Pre/PostCharacterSimulation methods are useful to update all the Animator parameters.
|
||||
// Why? Because the CharacterActor component will end up modifying the velocity of the actor.
|
||||
if (!CharacterActor.IsAnimatorValid())
|
||||
return;
|
||||
|
||||
// Parameters associated with velocity are sent after the simulation.
|
||||
// The PostSimulationUpdate (CharacterActor) might update velocity once more (e.g. if a "bad step" has been detected).
|
||||
CharacterStateController.Animator.SetFloat(verticalSpeedParameter, CharacterActor.LocalVelocity.y);
|
||||
CharacterStateController.Animator.SetFloat(planarSpeedParameter, CharacterActor.PlanarVelocity.magnitude);
|
||||
}
|
||||
|
||||
protected virtual void HandleSize(float dt)
|
||||
{
|
||||
// Get the crouch input state
|
||||
if (crouchParameters.enableCrouch)
|
||||
{
|
||||
if (crouchParameters.inputMode == InputMode.Toggle)
|
||||
{
|
||||
if (CharacterActions.crouch.Started)
|
||||
wantToCrouch = !wantToCrouch;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantToCrouch = CharacterActions.crouch.value;
|
||||
}
|
||||
|
||||
if (!crouchParameters.notGroundedCrouch && !CharacterActor.IsGrounded)
|
||||
wantToCrouch = false;
|
||||
|
||||
if (CharacterActor.IsGrounded && wantToRun)
|
||||
wantToCrouch = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantToCrouch = false;
|
||||
}
|
||||
|
||||
if (wantToCrouch)
|
||||
Crouch(dt);
|
||||
else
|
||||
StandUp(dt);
|
||||
}
|
||||
|
||||
void Crouch(float dt)
|
||||
{
|
||||
CharacterActor.SizeReferenceType sizeReferenceType = CharacterActor.IsGrounded ?
|
||||
CharacterActor.SizeReferenceType.Bottom : crouchParameters.notGroundedReference;
|
||||
|
||||
bool validSize = CharacterActor.CheckAndInterpolateHeight(
|
||||
CharacterActor.DefaultBodySize.y * crouchParameters.heightRatio,
|
||||
crouchParameters.sizeLerpSpeed * dt, sizeReferenceType);
|
||||
|
||||
if (validSize)
|
||||
isCrouched = true;
|
||||
}
|
||||
|
||||
void StandUp(float dt)
|
||||
{
|
||||
CharacterActor.SizeReferenceType sizeReferenceType = CharacterActor.IsGrounded ?
|
||||
CharacterActor.SizeReferenceType.Bottom : crouchParameters.notGroundedReference;
|
||||
|
||||
bool validSize = CharacterActor.CheckAndInterpolateHeight(
|
||||
CharacterActor.DefaultBodySize.y,
|
||||
crouchParameters.sizeLerpSpeed * dt, sizeReferenceType);
|
||||
|
||||
if (validSize)
|
||||
isCrouched = false;
|
||||
}
|
||||
|
||||
|
||||
protected virtual void HandleVelocity(float dt)
|
||||
{
|
||||
ProcessVerticalMovement(dt);
|
||||
ProcessPlanarMovement(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user