new dash implementation
This commit is contained in:
@@ -21,18 +21,19 @@ namespace Beyond
|
||||
|
||||
[Header("Beyond's Dash Settings")]
|
||||
public string dashBlendTreeState = "Dash_Directional";
|
||||
public string dashHorizontalParam = "DashHorizontal";
|
||||
public string dashVerticalParam = "DashVertical";
|
||||
|
||||
// Internal flag to lock animator parameters during dash
|
||||
private bool _lockAnimParamsForDash = false;
|
||||
[Tooltip("If your animation is slightly rotated (Red arrow offset), add an angle here to compensate (e.g. -45 or 45).")]
|
||||
public float dashAngleCorrection = 0f;
|
||||
|
||||
[Tooltip("Print debug info to Console when dashing")]
|
||||
public bool debugDash = true;
|
||||
|
||||
public bool GodMode
|
||||
{
|
||||
get => m_GodMode;
|
||||
set
|
||||
{
|
||||
m_GodMode = value;
|
||||
isImmortal = m_GodMode;
|
||||
}
|
||||
set { m_GodMode = value; isImmortal = m_GodMode; }
|
||||
}
|
||||
|
||||
protected override bool canRecoverHealth
|
||||
@@ -44,21 +45,13 @@ namespace Beyond
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDashingOrRolling()
|
||||
{
|
||||
return m_isDashing || isRolling;
|
||||
}
|
||||
public bool IsDashingOrRolling() => m_isDashing || isRolling;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
protected override void RollBehavior()
|
||||
{
|
||||
base.RollBehavior();
|
||||
}
|
||||
|
||||
public override void Roll()
|
||||
{
|
||||
Dash();
|
||||
@@ -71,71 +64,59 @@ namespace Beyond
|
||||
ReduceStamina(rollStamina, false);
|
||||
currentStaminaRecoveryDelay = 2f;
|
||||
|
||||
// 1. Handle Stationary (Backwards Dash)
|
||||
if (input.sqrMagnitude < 0.05f)
|
||||
// Setup Camera Vectors
|
||||
Transform camT = Camera.main != null ? Camera.main.transform : transform;
|
||||
// Flatten camera vectors so looking up/down doesn't affect dash length
|
||||
Vector3 camFwd = Vector3.Scale(camT.forward, new Vector3(1, 0, 1)).normalized;
|
||||
Vector3 camRight = Vector3.Scale(camT.right, new Vector3(1, 0, 1)).normalized;
|
||||
|
||||
Vector3 targetWorldDir = Vector3.zero;
|
||||
|
||||
// 1. Determine Target World Direction
|
||||
if (input.sqrMagnitude < 0.1f)
|
||||
{
|
||||
ApplyDashParams(0f, -1f);
|
||||
// NO INPUT -> Move strictly "Into the Screen" (Towards Camera)
|
||||
// This is the negative of the Camera Forward vector.
|
||||
targetWorldDir = -camFwd;
|
||||
if (debugDash) Debug.Log($"[Dash] No Input. Target: BACKWARD ({targetWorldDir})");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. Handle Directional Input (Camera Relative -> Character Relative)
|
||||
// DIRECTIONAL INPUT
|
||||
// FIX: Use input.z for Forward/Backward, NOT input.y
|
||||
targetWorldDir = (camFwd * input.z + camRight * input.x).normalized;
|
||||
|
||||
// A. Get the Input Direction relative to the Camera
|
||||
Vector3 inputDir = Vector3.zero;
|
||||
if (Camera.main != null)
|
||||
{
|
||||
// Convert joystick input (X,Y) into World Space based on Camera facing
|
||||
Vector3 camFwd = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
|
||||
Vector3 camRight = Vector3.Scale(Camera.main.transform.right, new Vector3(1, 0, 1)).normalized;
|
||||
inputDir = (camFwd * input.y + camRight * input.x).normalized;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback if no camera found
|
||||
inputDir = new Vector3(input.x, 0, input.y).normalized;
|
||||
}
|
||||
|
||||
// B. Convert that World Direction into the Character's Local Space
|
||||
// This tells us: "Is the input to the Left, Right, or Forward of ME?"
|
||||
Vector3 localDir = transform.InverseTransformDirection(inputDir);
|
||||
|
||||
// C. Send to Animator
|
||||
ApplyDashParams(localDir.x, localDir.z);
|
||||
if (debugDash) Debug.Log($"[Dash] Input: {input}. Target World Dir: {targetWorldDir}");
|
||||
}
|
||||
|
||||
// 3. Play Animation
|
||||
// 2. Convert World Direction to Character Local Space
|
||||
// "Where is the Target World Dir relative to ME?"
|
||||
Vector3 localDir = transform.InverseTransformDirection(targetWorldDir);
|
||||
|
||||
// 3. Apply Angle Correction (If animation is skewed 45 degrees)
|
||||
if (dashAngleCorrection != 0f)
|
||||
{
|
||||
localDir = Quaternion.Euler(0, dashAngleCorrection, 0) * localDir;
|
||||
}
|
||||
|
||||
// 4. Normalize (Ensure full blend magnitude)
|
||||
localDir.y = 0;
|
||||
localDir.Normalize();
|
||||
|
||||
// 5. Send to Animator (Dedicated Parameters)
|
||||
animator.SetFloat(dashHorizontalParam, localDir.x);
|
||||
animator.SetFloat(dashVerticalParam, localDir.z);
|
||||
|
||||
if (debugDash)
|
||||
{
|
||||
Debug.Log($"[Dash Final] Local X: {localDir.x} | Local Z: {localDir.z}");
|
||||
}
|
||||
|
||||
// 6. Play Animation
|
||||
animator.CrossFadeInFixedTime(dashBlendTreeState, rollTransition, baseLayer);
|
||||
|
||||
// 4. Lock parameters briefly so Invector doesn't overwrite them immediately
|
||||
StartCoroutine(LockDashParamsRoutine());
|
||||
}
|
||||
|
||||
// Helper to set params and lock the update loop
|
||||
private void ApplyDashParams(float x, float y)
|
||||
{
|
||||
_lockAnimParamsForDash = true;
|
||||
animator.SetFloat(vAnimatorParameters.InputHorizontal, x);
|
||||
animator.SetFloat(vAnimatorParameters.InputVertical, y);
|
||||
}
|
||||
|
||||
// Release the lock after a short delay (once the blend has firmly started)
|
||||
private IEnumerator LockDashParamsRoutine()
|
||||
{
|
||||
yield return new WaitForSeconds(0.2f); // Adjust this if the blend pops back too soon
|
||||
_lockAnimParamsForDash = false;
|
||||
}
|
||||
|
||||
// --- CRITICAL FIX: Override Invector's Parameter Update ---
|
||||
public override void UpdateAnimatorParameters()
|
||||
{
|
||||
// If we are locking parameters for the dash, DO NOT let the base class overwrite them.
|
||||
if (_lockAnimParamsForDash) return;
|
||||
|
||||
// Otherwise, run standard Invector logic
|
||||
base.UpdateAnimatorParameters();
|
||||
}
|
||||
|
||||
// Standard overrides below...
|
||||
// --- Standard Boilerplate Below ---
|
||||
public void OnEvadeStart() { if (!m_GodMode) isImmortal = true; }
|
||||
public void OnEvadeEnd() { if (!m_GodMode) isImmortal = false; }
|
||||
public override void ActionsControl() { base.ActionsControl(); m_isDashing = IsAnimatorTag("IsDashing"); }
|
||||
@@ -148,30 +129,18 @@ namespace Beyond
|
||||
{
|
||||
int deadLayer = 0;
|
||||
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
||||
if (info != null)
|
||||
{
|
||||
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f) RemoveComponents();
|
||||
}
|
||||
if (info != null && !animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f) RemoveComponents();
|
||||
}
|
||||
else if (deathBy == DeathBy.AnimationWithRagdoll)
|
||||
{
|
||||
int deadLayer = 0;
|
||||
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
||||
if (info != null)
|
||||
{
|
||||
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.8f) onActiveRagdoll.Invoke(null);
|
||||
}
|
||||
}
|
||||
else if (deathBy == DeathBy.Ragdoll)
|
||||
{
|
||||
onActiveRagdoll.Invoke(null);
|
||||
if (info != null && !animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.8f) onActiveRagdoll.Invoke(null);
|
||||
}
|
||||
else if (deathBy == DeathBy.Ragdoll) onActiveRagdoll.Invoke(null);
|
||||
}
|
||||
|
||||
public void RemoveAnimatorTags()
|
||||
{
|
||||
animatorStateInfos.stateInfos.vToList().ForEach(infos => infos.tags.Clear());
|
||||
}
|
||||
public void RemoveAnimatorTags() => animatorStateInfos.stateInfos.vToList().ForEach(infos => infos.tags.Clear());
|
||||
|
||||
public override void ControlAnimatorRootMotion()
|
||||
{
|
||||
@@ -191,24 +160,17 @@ namespace Beyond
|
||||
if (useRootMotion) MoveCharacter(moveDirection);
|
||||
}
|
||||
|
||||
protected override void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!m_ignoreTriggers) onActionEnter.Invoke(other);
|
||||
}
|
||||
|
||||
protected override void OnTriggerEnter(Collider other) { if (!m_ignoreTriggers) onActionEnter.Invoke(other); }
|
||||
protected override void OnTriggerStay(Collider other)
|
||||
{
|
||||
try { CheckForAutoCrouch(other); }
|
||||
catch (UnityException e) { Debug.LogWarning(e.Message); }
|
||||
try { CheckForAutoCrouch(other); } catch (UnityException e) { Debug.LogWarning(e.Message); }
|
||||
if (!m_ignoreTriggers) base.OnTriggerStay(other);
|
||||
}
|
||||
|
||||
protected override void OnTriggerExit(Collider other)
|
||||
{
|
||||
AutoCrouchExit(other);
|
||||
if (!m_ignoreTriggers) base.OnTriggerExit(other);
|
||||
}
|
||||
|
||||
void DrawWeaponLowLeft() { }
|
||||
|
||||
public override void ControlRotationType()
|
||||
@@ -217,10 +179,7 @@ namespace Beyond
|
||||
bool validInput = input != Vector3.zero || (isStrafing ? strafeSpeed.rotateWithCamera : freeSpeed.rotateWithCamera);
|
||||
if (validInput)
|
||||
{
|
||||
if (lockAnimMovement)
|
||||
{
|
||||
inputSmooth = Vector3.Lerp(inputSmooth, input, (isStrafing ? strafeSpeed.movementSmooth : freeSpeed.movementSmooth) * Time.deltaTime);
|
||||
}
|
||||
if (lockAnimMovement) inputSmooth = Vector3.Lerp(inputSmooth, input, (isStrafing ? strafeSpeed.movementSmooth : freeSpeed.movementSmooth) * Time.deltaTime);
|
||||
Vector3 dir = (isStrafing && isGrounded && (!isSprinting || sprintOnlyFree == false) || (freeSpeed.rotateWithCamera && input == Vector3.zero)) && rotateTarget ? rotateTarget.forward : moveDirection;
|
||||
if (isStrafing || !useAnimationBasedRotation) RotateToDirection(dir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user