lot's of fixes, fixed animation retargetting, fixed FSM

This commit is contained in:
2025-07-24 17:19:42 +02:00
parent 802eb5ac1d
commit d4d01dfb69
27 changed files with 4381 additions and 2990 deletions

View File

@@ -9,12 +9,29 @@ namespace Beyond
{
public class bThirdPersonController : vThirdPersonController
{
//public bool triggerDieBehaviour = false;
protected bool m_isDashing;
protected bool m_GodMode = false;
public bool m_ignoreTriggers = true;
[Header("Beyond's Custom Settings")]
[Tooltip("When 'Use RootMotion' is checked, and this is true, the animation's root motion will control character rotation (for 8-way directional movement). If false, the script will rotate the character to face the input direction.")]
public bool useAnimationBasedRotation = false;
[Header("Beyond's Strafe Combat Settings")]
[Tooltip("The minimum horizontal input value to trigger a side roll instead of a forward/backward one.")]
[Range(0.1f, 1.0f)]
public float strafeRollInputThreshold = 0.3f;
[Tooltip("The name of the animation state to play when rolling forward while strafing. (This is now disabled)")]
public string strafeRollForwardAnim = "Roll_Forward"; // Kept for reference, but won't be used
[Tooltip("The name of the animation state to play when rolling backward while strafing.")]
public string strafeRollBackwardAnim = "Roll_Backward";
[Tooltip("The name of the animation state to play when rolling left while strafing.")]
public string strafeRollLeftAnim = "Roll_Left";
[Tooltip("The name of the animation state to play when rolling right while strafing.")]
public string strafeRollRightAnim = "Roll_Right";
public bool GodMode
{
get => m_GodMode;
@@ -33,92 +50,121 @@ namespace Beyond
protected override void Start()
{
base.Start();
//var receiver = GetComponent<vAnimatorEventReceiver>();
//var ev = new vAnimatorEvent();
// ev.
}
public void OnEvadeStart()
protected override void RollBehavior()
{
if (m_GodMode)
// If we are not strafing, use the default Invector roll behavior.
if (!isStrafing)
{
base.RollBehavior();
return;
isImmortal = true;
}
}
public void OnEvadeEnd()
{
if (m_GodMode)
// --- Custom Strafe Roll with Root Motion ---
if (!isRolling)
{
return;
isImmortal = false;
}
}
public override void ActionsControl()
{
base.ActionsControl();
m_isDashing = IsAnimatorTag("IsDashing");
// We apply the root motion position change directly.
Vector3 deltaPosition = new Vector3(animator.deltaPosition.x, 0f, animator.deltaPosition.z);
Vector3 v = (deltaPosition / Time.deltaTime) * (1f - stopMoveWeight);
// Apply gravity to the roll if enabled
if (rollUseGravity && animator.GetNormalizedTime(baseLayer) >= rollUseGravityTime)
{
v.y = _rigidbody.linearVelocity.y;
}
_rigidbody.linearVelocity = v;
}
public override void Roll()
{
OnRoll.Invoke();
isRolling = true;
animator.CrossFadeInFixedTime("Roll", rollTransition, baseLayer);
ReduceStamina(rollStamina, false);
currentStaminaRecoveryDelay = 2f;
// If we are strafing, use our custom directional logic.
if (isStrafing)
{
TriggerStrafeRoll(strafeRollForwardAnim, strafeRollBackwardAnim, strafeRollLeftAnim, strafeRollRightAnim);
}
else // Otherwise, use the default free-locomotion roll.
{
OnRoll.Invoke();
isRolling = true;
animator.CrossFadeInFixedTime("Roll", rollTransition, baseLayer);
ReduceStamina(rollStamina, false);
currentStaminaRecoveryDelay = 2f;
}
}
public virtual void Dash()
{
// The Dash logic now mirrors the Roll logic.
if (isStrafing)
{
TriggerStrafeRoll(strafeRollForwardAnim, strafeRollBackwardAnim, strafeRollLeftAnim, strafeRollRightAnim);
}
else
{
OnRoll.Invoke();
isRolling = true;
animator.CrossFadeInFixedTime("Dash", rollTransition, baseLayer);
ReduceStamina(rollStamina, false);
currentStaminaRecoveryDelay = 2f;
}
}
// This is the private helper method that contains the core logic for this feature.
private void TriggerStrafeRoll(string forwardAnim, string backwardAnim, string leftAnim, string rightAnim)
{
OnRoll.Invoke();
isRolling = true;
animator.CrossFadeInFixedTime("Dash", rollTransition, baseLayer);
ReduceStamina(rollStamina, false);
currentStaminaRecoveryDelay = 2f;
string animToPlay;
// Prioritize side rolls based on horizontal input.
if (Mathf.Abs(horizontalSpeed) > strafeRollInputThreshold)
{
animToPlay = horizontalSpeed > 0 ? rightAnim : leftAnim;
}
// If horizontal input is not met, always default to the backward roll.
// This effectively blocks the forward roll.
else
{
animToPlay = backwardAnim;
}
animator.CrossFadeInFixedTime(animToPlay, rollTransition, baseLayer);
}
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"); }
protected override void DeadAnimation()
{
if (!isDead)
{
return;
}
if (!triggerDieBehaviour)
{
triggerDieBehaviour = true;
DeathBehaviour();
}
// death by animation
if (!isDead) return;
if (!triggerDieBehaviour) { triggerDieBehaviour = true; DeathBehaviour(); }
if (deathBy == DeathBy.Animation)
{
int deadLayer = 0;
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
if (info != null)
{
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f)
{
RemoveComponents();
}
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f) RemoveComponents();
}
}
// death by animation & ragdoll after a time
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);
}
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.8f) onActiveRagdoll.Invoke(null);
}
}
// death by ragdoll
else if (deathBy == DeathBy.Ragdoll)
{
onActiveRagdoll.Invoke(null);
@@ -132,17 +178,8 @@ namespace Beyond
public override void ControlAnimatorRootMotion()
{
if (!this.enabled)
{
return;
}
if (isRolling)
{
RollBehavior();
return;
}
if (!this.enabled) return;
if (isRolling) { RollBehavior(); return; }
if (customAction || lockAnimMovement)
{
StopCharacterWithLerp();
@@ -151,65 +188,80 @@ namespace Beyond
}
else if (IsAnimatorTag("Attack"))
{
StopCharacterWithLerp();
if (lockRotation) StopCharacterWithLerp();
transform.position = animator.rootPosition;
}
// commented for test
//else if (inputSmooth.magnitude == 0 && isGrounded && !isSliding)
//{
// if (!ignoreAnimatorMovement)
// {
// animator.ApplyBuiltinRootMotion();
// transform.position = animator.rootPosition;
// transform.rotation = animator.rootRotation;
// }
//}
if (useRootMotion)
{
MoveCharacter(moveDirection);
}
if (useRootMotion) MoveCharacter(moveDirection);
}
protected override void OnTriggerEnter(Collider other)
{
if (!m_ignoreTriggers)
onActionEnter.Invoke(other);
if (!m_ignoreTriggers) onActionEnter.Invoke(other);
}
/// <summary>
/// Call this in OnTriggerEnter or OnTriggerStay to check if enter in triggerActions
/// </summary>
/// <param name="other">collider trigger</param>
protected override void OnTriggerStay(Collider other)
{
try
{
CheckForAutoCrouch(other);
}
catch (UnityException e)
{
Debug.LogWarning(e.Message);
}
if (!m_ignoreTriggers)
base.OnTriggerStay(other);
try { CheckForAutoCrouch(other); }
catch (UnityException e) { Debug.LogWarning(e.Message); }
if (!m_ignoreTriggers) base.OnTriggerStay(other);
}
/// <summary>
/// Call this in OnTriggerExit to check if exit of triggerActions
/// </summary>
/// <param name="other"></param>
protected override void OnTriggerExit(Collider other)
{
AutoCrouchExit(other);
if (!m_ignoreTriggers)
base.OnTriggerExit(other);
if (!m_ignoreTriggers) base.OnTriggerExit(other);
}
//animation event handling
void DrawWeaponLowLeft() { }
public override void ControlRotationType()
{
if (lockAnimRotation || lockRotation || customAction || isRolling) return;
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);
}
Vector3 dir = (isStrafing && isGrounded && (!isSprinting || sprintOnlyFree == false) || (freeSpeed.rotateWithCamera && input == Vector3.zero)) && rotateTarget ? rotateTarget.forward : moveDirection;
if (isStrafing || !useAnimationBasedRotation) RotateToDirection(dir);
}
}
public override void UpdateAnimatorParameters()
{
if (disableAnimations) return;
animator.SetBool(vAnimatorParameters.IsStrafing, isStrafing);
animator.SetBool(vAnimatorParameters.IsSprinting, isSprinting);
animator.SetBool(vAnimatorParameters.IsSliding, isSliding && !isRolling);
animator.SetBool(vAnimatorParameters.IsCrouching, isCrouching);
animator.SetBool(vAnimatorParameters.IsGrounded, isGrounded);
animator.SetBool(vAnimatorParameters.IsDead, isDead);
animator.SetFloat(vAnimatorParameters.GroundDistance, groundDistance);
animator.SetFloat(vAnimatorParameters.GroundAngle, GroundAngleFromDirection());
if (!isGrounded) animator.SetFloat(vAnimatorParameters.VerticalVelocity, verticalVelocity);
{
if (isStrafing)
{
animator.SetFloat(vAnimatorParameters.InputHorizontal, horizontalSpeed, strafeSpeed.animationSmooth, Time.fixedDeltaTime);
animator.SetFloat(vAnimatorParameters.InputVertical, verticalSpeed, strafeSpeed.animationSmooth, Time.fixedDeltaTime);
}
else
{
animator.SetFloat(vAnimatorParameters.InputVertical, verticalSpeed, freeSpeed.animationSmooth, Time.fixedDeltaTime);
animator.SetFloat(vAnimatorParameters.InputHorizontal, useAnimationBasedRotation ? horizontalSpeed : 0, freeSpeed.animationSmooth, Time.fixedDeltaTime);
}
animator.SetFloat(vAnimatorParameters.InputMagnitude, Mathf.LerpUnclamped(inputMagnitude, 0f, stopMoveWeight), isStrafing ? strafeSpeed.animationSmooth : freeSpeed.animationSmooth, Time.fixedDeltaTime);
if (useLeanMovementAnim && inputMagnitude >= 0.1f)
{
animator.SetFloat(vAnimatorParameters.RotationMagnitude, rotationMagnitude, leanSmooth, Time.fixedDeltaTime);
}
else if (useTurnOnSpotAnim && inputMagnitude < 0.1f)
{
animator.SetFloat(vAnimatorParameters.RotationMagnitude, (float)System.Math.Round(rotationMagnitude, 2), rotationMagnitude == 0 ? 0.1f : 0.01f, Time.fixedDeltaTime);
}
}
}
}
}