|
|
|
|
@@ -0,0 +1,588 @@
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
#endif
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using TMPro;
|
|
|
|
|
|
|
|
|
|
public class CharacterMovement : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
//jump system variables
|
|
|
|
|
private bool jump;
|
|
|
|
|
GroundCheck groundCheck;
|
|
|
|
|
public FallCheck fallCheck;
|
|
|
|
|
[SerializeField] private float jumpForce = 20f;
|
|
|
|
|
[SerializeField] private float gravity = -9.81f;
|
|
|
|
|
[SerializeField] private float gravityScale = 5f;
|
|
|
|
|
private float floatSpeed;
|
|
|
|
|
private float gvelocity;
|
|
|
|
|
|
|
|
|
|
//camera direction variables
|
|
|
|
|
private bool useCharacterForward = false;
|
|
|
|
|
private bool lockToCameraForward = false;
|
|
|
|
|
|
|
|
|
|
[SerializeField] private float turnSpeed = 10f;
|
|
|
|
|
|
|
|
|
|
public GameObject player;
|
|
|
|
|
public GameObject enemy;
|
|
|
|
|
|
|
|
|
|
public float distance;
|
|
|
|
|
private AnimatorClipInfo[] m_CurrentClipInfo;
|
|
|
|
|
private float m_CurrentClipLength;
|
|
|
|
|
private string m_ClipName;
|
|
|
|
|
public float nextAnimationTime;
|
|
|
|
|
public float animationInterval;
|
|
|
|
|
|
|
|
|
|
private float turnSpeedMultiplier;
|
|
|
|
|
|
|
|
|
|
private float direction = 0f;
|
|
|
|
|
private bool isSprinting = false;
|
|
|
|
|
|
|
|
|
|
public Animator anim;
|
|
|
|
|
|
|
|
|
|
private Vector3 targetDirection;
|
|
|
|
|
|
|
|
|
|
private Quaternion freeRotation;
|
|
|
|
|
private Camera mainCamera;
|
|
|
|
|
private float velocity;
|
|
|
|
|
|
|
|
|
|
// Cached reference: avoids FindFirstObjectByType every FixedUpdate (was 300 calls/sec)
|
|
|
|
|
private PlayerManagerNew _cachedPlayerManager;
|
|
|
|
|
private bool _playerManagerCached;
|
|
|
|
|
|
|
|
|
|
public bool block;
|
|
|
|
|
|
|
|
|
|
Vector2 input;
|
|
|
|
|
|
|
|
|
|
public PlayerScript playerScript;
|
|
|
|
|
|
|
|
|
|
// New modular input handler (used if PlayerScript is not present)
|
|
|
|
|
private CharacterInputHandler inputHandler;
|
|
|
|
|
|
|
|
|
|
private AnimatorClipInfo[] playerclipinfo;
|
|
|
|
|
|
|
|
|
|
private Vector3 playerDirection;
|
|
|
|
|
private float rotationSpeed;
|
|
|
|
|
|
|
|
|
|
[SerializeField] private float joystickSensitivity = 1f;
|
|
|
|
|
private Vector2 joystickInput;
|
|
|
|
|
float inputThreshold;
|
|
|
|
|
|
|
|
|
|
// Scale protection: some animation clips contain baked scale curves from FBX import
|
|
|
|
|
// that can shrink the character model. We save the original scale and restore it every frame.
|
|
|
|
|
private Vector3 originalScale;
|
|
|
|
|
|
|
|
|
|
[Header("Grounding")]
|
|
|
|
|
[Tooltip("Layers to raycast against for ground detection. Must exclude character layers to prevent floating.")]
|
|
|
|
|
[SerializeField] private LayerMask groundLayerMask = 0;
|
|
|
|
|
|
|
|
|
|
// Animation transition parameters
|
|
|
|
|
private float animationBlendTime = 0.15f; // Time to blend between animations
|
|
|
|
|
private float movementSmoothTime = 0.1f; // Time to smooth movement speed change
|
|
|
|
|
private float rotationSmoothTime = 0.1f; // Time to smooth rotation
|
|
|
|
|
private float currentMoveSpeed = 0f; // Current movement speed for smooth transitions
|
|
|
|
|
private float currentTurnSpeed = 0f; // Current turn speed for smooth transitions
|
|
|
|
|
|
|
|
|
|
[SerializeField] private float smoothTurnSpeed = 5f; // Lower = smoother, for realistic turning
|
|
|
|
|
|
|
|
|
|
// Walk/Run sound effects
|
|
|
|
|
[Header("Footstep Sound Effects")]
|
|
|
|
|
public AudioClip walkSoundEffect;
|
|
|
|
|
public AudioClip runSoundEffect;
|
|
|
|
|
private AudioSource footstepAudioSource;
|
|
|
|
|
private bool isFootstepPlaying = false;
|
|
|
|
|
private float lastSpeedParam = 0f;
|
|
|
|
|
|
|
|
|
|
//Link to Mission Handler Script
|
|
|
|
|
//Initialize the scripts
|
|
|
|
|
MissionHandler mission_handler;
|
|
|
|
|
GameStatsManager game_statsManager;
|
|
|
|
|
TextMeshProUGUI txt;
|
|
|
|
|
|
|
|
|
|
// Add reference to AnimationManager
|
|
|
|
|
private AnimationManager animationManager;
|
|
|
|
|
|
|
|
|
|
void OnEnable(){
|
|
|
|
|
GameObject gamestatsmanager_go = GameObject.Find("GameStatsManager");
|
|
|
|
|
if (gamestatsmanager_go != null) {
|
|
|
|
|
game_statsManager = gamestatsmanager_go.GetComponent<GameStatsManager>();
|
|
|
|
|
mission_handler = gamestatsmanager_go.GetComponent<MissionHandler>();
|
|
|
|
|
} else {
|
|
|
|
|
DevLog.LogWarning("GameStatsManager not found - mission tracking will be disabled");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//txt = gamestatsmanager_go.transform.Find("Canvas/move_txt").GetComponent<TextMeshProUGUI>();
|
|
|
|
|
|
|
|
|
|
if (mission_handler != null){
|
|
|
|
|
//DevLog.LogWarning("Character Movement Found");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start is called before the first frame update
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
|
|
|
|
// Save original scale before anything can modify it
|
|
|
|
|
originalScale = transform.localScale;
|
|
|
|
|
|
|
|
|
|
jumpForce = 40;
|
|
|
|
|
gravity = -9.81f;
|
|
|
|
|
gravityScale = 5;
|
|
|
|
|
rotationSpeed = 2;
|
|
|
|
|
input = Vector2.zero;
|
|
|
|
|
anim = GetComponent<Animator>();
|
|
|
|
|
|
|
|
|
|
// Set animator transition parameters
|
|
|
|
|
if (anim != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var layer in new int[] { 0, 1, 2 }) // Check multiple layers if needed
|
|
|
|
|
{
|
|
|
|
|
if (layer < anim.layerCount)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < anim.parameters.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
// Adjust transition times in the Animator
|
|
|
|
|
AnimatorControllerParameter param = anim.parameters[i];
|
|
|
|
|
if (param.type == AnimatorControllerParameterType.Float && param.name == "TransitionTime")
|
|
|
|
|
{
|
|
|
|
|
anim.SetFloat(param.name, animationBlendTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mainCamera = Camera.main;
|
|
|
|
|
player = GameObject.FindGameObjectWithTag("Player");
|
|
|
|
|
enemy = GameObject.FindGameObjectWithTag("Enemy");
|
|
|
|
|
animationInterval = 3.0f;
|
|
|
|
|
block = false;
|
|
|
|
|
|
|
|
|
|
// Get PlayerScript from this character - this is essential for movement
|
|
|
|
|
// Try new modular CharacterInputHandler first, fall back to PlayerScript
|
|
|
|
|
inputHandler = GetComponent<CharacterInputHandler>();
|
|
|
|
|
playerScript = GetComponent<PlayerScript>();
|
|
|
|
|
|
|
|
|
|
if (inputHandler == null && playerScript == null)
|
|
|
|
|
{
|
|
|
|
|
DevLog.LogWarning($"[CharacterMovement] No CharacterInputHandler or PlayerScript found on {gameObject.name}. Movement will not work for player-controlled characters.");
|
|
|
|
|
}
|
|
|
|
|
else if (inputHandler != null)
|
|
|
|
|
{
|
|
|
|
|
DevLog.Log($"[CharacterMovement] Using new modular CharacterInputHandler on {gameObject.name}");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DevLog.Log($"[CharacterMovement] Using legacy PlayerScript on {gameObject.name}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get or add required components with null checks
|
|
|
|
|
groundCheck = GetComponent<GroundCheck>();
|
|
|
|
|
if (groundCheck == null) {
|
|
|
|
|
groundCheck = gameObject.AddComponent<GroundCheck>();
|
|
|
|
|
DevLog.LogWarning("GroundCheck component not found, adding one automatically.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fallCheck = GetComponent<FallCheck>();
|
|
|
|
|
if (fallCheck == null) {
|
|
|
|
|
fallCheck = gameObject.AddComponent<FallCheck>();
|
|
|
|
|
DevLog.LogWarning("FallCheck component not found, adding one automatically.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inputThreshold = 0.3f;
|
|
|
|
|
|
|
|
|
|
// Get or add AnimationManager component
|
|
|
|
|
animationManager = GetComponent<AnimationManager>();
|
|
|
|
|
if (animationManager == null)
|
|
|
|
|
{
|
|
|
|
|
animationManager = gameObject.AddComponent<AnimationManager>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Setup footstep audio source
|
|
|
|
|
footstepAudioSource = GetComponent<AudioSource>();
|
|
|
|
|
if (footstepAudioSource == null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource = gameObject.AddComponent<AudioSource>();
|
|
|
|
|
}
|
|
|
|
|
footstepAudioSource.spatialBlend = 1f; // 3D sound
|
|
|
|
|
footstepAudioSource.loop = true;
|
|
|
|
|
footstepAudioSource.playOnAwake = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FixedUpdate()
|
|
|
|
|
{
|
|
|
|
|
// Cached PlayerManagerNew lookup — avoids FindFirstObjectByType every FixedUpdate
|
|
|
|
|
if (!_playerManagerCached)
|
|
|
|
|
{
|
|
|
|
|
_cachedPlayerManager = GameObject.FindFirstObjectByType<PlayerManagerNew>();
|
|
|
|
|
_playerManagerCached = true;
|
|
|
|
|
}
|
|
|
|
|
if (_cachedPlayerManager != null && _cachedPlayerManager.pause)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Determine if movement should be blocked based on available input source
|
|
|
|
|
bool isBlocking = false;
|
|
|
|
|
bool isDodging = false;
|
|
|
|
|
bool hasInputSource = false;
|
|
|
|
|
|
|
|
|
|
if (inputHandler != null)
|
|
|
|
|
{
|
|
|
|
|
isBlocking = inputHandler.block;
|
|
|
|
|
isDodging = inputHandler.dodge;
|
|
|
|
|
hasInputSource = true;
|
|
|
|
|
}
|
|
|
|
|
else if (playerScript != null)
|
|
|
|
|
{
|
|
|
|
|
isBlocking = playerScript.block;
|
|
|
|
|
isDodging = playerScript.dodge;
|
|
|
|
|
hasInputSource = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Always update footstep sounds based on animator state (for AI and all characters)
|
|
|
|
|
UpdateFootstepSoundsFromAnimator();
|
|
|
|
|
|
|
|
|
|
// No input source - don't process player movement
|
|
|
|
|
// This is fine for AI characters which use NavMeshAgent
|
|
|
|
|
if (!hasInputSource)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Block movement only during blocking or dodging
|
|
|
|
|
if (isBlocking || isDodging)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gvelocity += gravity * gravityScale * Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
if (groundCheck != null && groundCheck.isGrounded && gvelocity < 0)
|
|
|
|
|
{
|
|
|
|
|
//print("jump reset");
|
|
|
|
|
gvelocity = 0;
|
|
|
|
|
jump = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get input from available source (prefer new modular handler)
|
|
|
|
|
if (inputHandler != null) {
|
|
|
|
|
input = inputHandler.input;
|
|
|
|
|
} else if (playerScript != null) {
|
|
|
|
|
input = playerScript.input;
|
|
|
|
|
}
|
|
|
|
|
inputThreshold = 0.3f; // Adjust this value as needed
|
|
|
|
|
|
|
|
|
|
//ensure the character always stays upright
|
|
|
|
|
if (transform.rotation.z > 0.5 || transform.rotation.x > 0.5 || transform.rotation.z < -0.5 || transform.rotation.x < -0.5)
|
|
|
|
|
{
|
|
|
|
|
print("make player upright");
|
|
|
|
|
Quaternion rotation = Quaternion.Euler(0, transform.rotation.y, 0);
|
|
|
|
|
//transform.rotation = rotation;
|
|
|
|
|
|
|
|
|
|
// Dampen towards the target rotation
|
|
|
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime);
|
|
|
|
|
}
|
|
|
|
|
//ensure that the character is always grounded if they are not jumping
|
|
|
|
|
if (jump == false)
|
|
|
|
|
{
|
|
|
|
|
// Auto-configure ground layer mask if not set (exclude character layers)
|
|
|
|
|
if (groundLayerMask.value == 0)
|
|
|
|
|
{
|
|
|
|
|
groundLayerMask = ~0; // Start with everything
|
|
|
|
|
int playerLayer = LayerMask.NameToLayer("Player");
|
|
|
|
|
int enemyLayer = LayerMask.NameToLayer("Enemy");
|
|
|
|
|
int characterLayer = LayerMask.NameToLayer("Character");
|
|
|
|
|
int ignoreRaycast = LayerMask.NameToLayer("Ignore Raycast");
|
|
|
|
|
if (playerLayer >= 0) groundLayerMask &= ~(1 << playerLayer);
|
|
|
|
|
if (enemyLayer >= 0) groundLayerMask &= ~(1 << enemyLayer);
|
|
|
|
|
if (characterLayer >= 0) groundLayerMask &= ~(1 << characterLayer);
|
|
|
|
|
if (ignoreRaycast >= 0) groundLayerMask &= ~(1 << ignoreRaycast);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RaycastHit hit;
|
|
|
|
|
// CRITICAL: Use groundLayerMask to ignore character body colliders
|
|
|
|
|
// Without this, raycast hits character chest/head colliders and thinks "ground" is at chest height
|
|
|
|
|
if (Physics.Raycast(transform.position + Vector3.up * 0.5f, Vector3.down, out hit, 50f, groundLayerMask))
|
|
|
|
|
{
|
|
|
|
|
float groundY = hit.point.y;
|
|
|
|
|
if (transform.position.y > groundY + 0.15f)
|
|
|
|
|
{
|
|
|
|
|
// Instant snap to ground instead of slow 1f/frame drift
|
|
|
|
|
transform.position = new Vector3(transform.position.x, groundY + 0.05f, transform.position.z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Protect against animation clips overwriting scale
|
|
|
|
|
if (transform.localScale != originalScale)
|
|
|
|
|
{
|
|
|
|
|
transform.localScale = originalScale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Move();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void UpdateTargetDirection()
|
|
|
|
|
{
|
|
|
|
|
if (playerScript != null) {
|
|
|
|
|
input = playerScript.input;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mainCamera == null)
|
|
|
|
|
mainCamera = Camera.main;
|
|
|
|
|
|
|
|
|
|
Vector3 forward = mainCamera.transform.forward;
|
|
|
|
|
Vector3 right = mainCamera.transform.right;
|
|
|
|
|
|
|
|
|
|
// Project onto XZ plane
|
|
|
|
|
forward.y = 0f;
|
|
|
|
|
right.y = 0f;
|
|
|
|
|
forward.Normalize();
|
|
|
|
|
right.Normalize();
|
|
|
|
|
|
|
|
|
|
// input.x = horizontal (A/D or left/right), input.y = vertical (W/S or up/down)
|
|
|
|
|
targetDirection = right * input.x + forward * input.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Move()
|
|
|
|
|
{
|
|
|
|
|
if (IsInHitReactionAnimation())//
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
UpdateTargetDirection();
|
|
|
|
|
|
|
|
|
|
// Calculate raw input magnitude for animation
|
|
|
|
|
float inputMagnitude = input.magnitude;
|
|
|
|
|
|
|
|
|
|
// Define thresholds
|
|
|
|
|
float walkThreshold = 0.1f; // Minimum input to start walking
|
|
|
|
|
float runThreshold = 0.7f; // Input magnitude to start running
|
|
|
|
|
|
|
|
|
|
float speedParam = 0f;
|
|
|
|
|
|
|
|
|
|
if (inputMagnitude > walkThreshold && inputMagnitude < runThreshold)
|
|
|
|
|
{
|
|
|
|
|
// Walking
|
|
|
|
|
speedParam = 0.2f; // Match your blend tree's walk value
|
|
|
|
|
}
|
|
|
|
|
else if (inputMagnitude >= runThreshold)
|
|
|
|
|
{
|
|
|
|
|
// Running
|
|
|
|
|
speedParam = 1f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Idle
|
|
|
|
|
speedParam = 0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debug logging for movement diagnosis
|
|
|
|
|
if (inputMagnitude > 0.01f)
|
|
|
|
|
{
|
|
|
|
|
DevLog.Log($"[CharacterMovement] Input: ({input.x:F2}, {input.y:F2}), Magnitude: {inputMagnitude:F2}, Speed: {speedParam}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
anim.SetFloat("Speed", speedParam);
|
|
|
|
|
|
|
|
|
|
// --- Footstep Sound Logic ---
|
|
|
|
|
if (speedParam == 0f)
|
|
|
|
|
{
|
|
|
|
|
if (footstepAudioSource.isPlaying)
|
|
|
|
|
footstepAudioSource.Stop();
|
|
|
|
|
isFootstepPlaying = false;
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam > 0f && !isFootstepPlaying)
|
|
|
|
|
{
|
|
|
|
|
if (speedParam < 0.7f && walkSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = walkSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
isFootstepPlaying = true;
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam >= 0.7f && runSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = runSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1.1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
isFootstepPlaying = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isFootstepPlaying)
|
|
|
|
|
{
|
|
|
|
|
// Switch between walk/run sound if needed
|
|
|
|
|
if (speedParam < 0.7f && footstepAudioSource.clip != walkSoundEffect && walkSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = walkSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam >= 0.7f && footstepAudioSource.clip != runSoundEffect && runSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = runSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1.1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lastSpeedParam = speedParam;
|
|
|
|
|
// --- End Footstep Sound Logic ---
|
|
|
|
|
|
|
|
|
|
// Only move and rotate if there's actual input
|
|
|
|
|
if (inputMagnitude > walkThreshold)
|
|
|
|
|
{
|
|
|
|
|
Vector3 moveAmount = targetDirection * 4f * Time.deltaTime;
|
|
|
|
|
transform.Translate(moveAmount, Space.World);
|
|
|
|
|
|
|
|
|
|
if (targetDirection != Vector3.zero)
|
|
|
|
|
{
|
|
|
|
|
Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
|
|
|
|
|
// Use a lower turn speed for smoother, more realistic turning
|
|
|
|
|
transform.rotation = Quaternion.Slerp(
|
|
|
|
|
transform.rotation,
|
|
|
|
|
targetRotation,
|
|
|
|
|
smoothTurnSpeed * Time.deltaTime
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (inputMagnitude <= walkThreshold && speedParam == 0f)
|
|
|
|
|
{
|
|
|
|
|
anim.SetFloat("Speed", 0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsInHitReactionAnimation()
|
|
|
|
|
{
|
|
|
|
|
// Use AnimationManager to check if playing hit reaction animations
|
|
|
|
|
if (animationManager != null)
|
|
|
|
|
{
|
|
|
|
|
return animationManager.IsPlayingAnimation(
|
|
|
|
|
// Active animation reactions only
|
|
|
|
|
AnimationNames.JabReaction,
|
|
|
|
|
AnimationNames.HaymakerReaction,
|
|
|
|
|
AnimationNames.SpinningBackfistReaction,
|
|
|
|
|
AnimationNames.ElbowSmashReaction,
|
|
|
|
|
AnimationNames.ChargedPunchReaction,
|
|
|
|
|
AnimationNames.AirPunchReaction,
|
|
|
|
|
AnimationNames.DropKickReaction,
|
|
|
|
|
AnimationNames.LowKickReaction
|
|
|
|
|
|
|
|
|
|
/* Commented out other reactions for future use
|
|
|
|
|
// Original hit reactions
|
|
|
|
|
AnimationNames.RightHookHitReaction,
|
|
|
|
|
AnimationNames.BodyKickHitReaction,
|
|
|
|
|
AnimationNames.HookHitReaction,
|
|
|
|
|
AnimationNames.JabHitReaction,
|
|
|
|
|
AnimationNames.LegKickHitReaction,
|
|
|
|
|
AnimationNames.UppercutPowerHitReaction,
|
|
|
|
|
AnimationNames.OverhandHitReaction,
|
|
|
|
|
|
|
|
|
|
// Other new hit reactions
|
|
|
|
|
AnimationNames.ChopReaction,
|
|
|
|
|
AnimationNames.GroundPoundReaction,
|
|
|
|
|
AnimationNames.AirKickReaction,
|
|
|
|
|
AnimationNames.SignSwingReaction,
|
|
|
|
|
AnimationNames.SignOverheadSlamReaction,
|
|
|
|
|
AnimationNames.SignChargeAttackReaction
|
|
|
|
|
*/
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fall back to original implementation if AnimationManager is not available
|
|
|
|
|
AnimatorClipInfo[] m_CurrentClipInfo;
|
|
|
|
|
m_CurrentClipInfo = gameObject.GetComponent<Animator>().GetCurrentAnimatorClipInfo(0);
|
|
|
|
|
|
|
|
|
|
if (m_CurrentClipInfo.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
// No clips are currently playing
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_ClipName = m_CurrentClipInfo[0].clip.name;
|
|
|
|
|
|
|
|
|
|
// Check for active animation reactions only
|
|
|
|
|
return m_ClipName == AnimationNames.JabReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.HaymakerReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.SpinningBackfistReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.ElbowSmashReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.ChargedPunchReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.AirPunchReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.DropKickReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.LowKickReaction;
|
|
|
|
|
|
|
|
|
|
/* Commented out other reactions for future use
|
|
|
|
|
m_ClipName == AnimationNames.RightHookHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.BodyKickHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.HookHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.JabHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.LegKickHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.UppercutPowerHitReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.OverhandHitReaction ||
|
|
|
|
|
|
|
|
|
|
// Other new hit reactions
|
|
|
|
|
m_ClipName == AnimationNames.ChopReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.GroundPoundReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.AirKickReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.SignSwingReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.SignOverheadSlamReaction ||
|
|
|
|
|
m_ClipName == AnimationNames.SignChargeAttackReaction;
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates footstep sounds based on animator Speed parameter.
|
|
|
|
|
/// Called for all characters (including AI) to ensure footstep sounds play.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateFootstepSoundsFromAnimator()
|
|
|
|
|
{
|
|
|
|
|
if (anim == null || footstepAudioSource == null) return;
|
|
|
|
|
|
|
|
|
|
// Read current speed from animator
|
|
|
|
|
float speedParam = anim.GetFloat("Speed");
|
|
|
|
|
|
|
|
|
|
// Use a slight threshold to avoid noise
|
|
|
|
|
if (speedParam < 0.05f)
|
|
|
|
|
{
|
|
|
|
|
if (footstepAudioSource.isPlaying)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.Stop();
|
|
|
|
|
}
|
|
|
|
|
isFootstepPlaying = false;
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam > 0.05f && !isFootstepPlaying)
|
|
|
|
|
{
|
|
|
|
|
// Start playing appropriate sound
|
|
|
|
|
if (speedParam < 0.7f && walkSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = walkSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
isFootstepPlaying = true;
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam >= 0.7f && runSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = runSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1.1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
isFootstepPlaying = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isFootstepPlaying)
|
|
|
|
|
{
|
|
|
|
|
// Switch between walk/run sound if needed
|
|
|
|
|
if (speedParam < 0.7f && footstepAudioSource.clip != walkSoundEffect && walkSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = walkSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
}
|
|
|
|
|
else if (speedParam >= 0.7f && footstepAudioSource.clip != runSoundEffect && runSoundEffect != null)
|
|
|
|
|
{
|
|
|
|
|
footstepAudioSource.clip = runSoundEffect;
|
|
|
|
|
footstepAudioSource.pitch = 1.1f;
|
|
|
|
|
footstepAudioSource.Play();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastSpeedParam = speedParam;
|
|
|
|
|
}
|
|
|
|
|
}
|