using System; using Core; using Script.Gameplay.Input; using UnityEngine; namespace Script.Gameplay.Player { public class PlayerMoveController : MonoBehaviour { [Header("Movement Settings")] [Tooltip("移动速度(米/秒)")] public float speed = 5f; [Tooltip("跳跃高度(米)")] public float jumpHeight = 2f; [Tooltip("重力加速度(米/秒²)")] public float gravity = -9.81f; [Header("Ground Check")] [Tooltip("检测地面的位置(通常为角色脚下)")] public Transform groundCheck; [Tooltip("地面检测半径")] public float groundDistance = 0.4f; [Tooltip("地面层(LayerMask)")] public LayerMask groundMask; [Header("Sound Effects")] [SerializeField] private AudioSource playerSound; [SerializeField] private AudioClip jumpSound; [SerializeField] private AudioClip walkSound; private float initSpeed; private CharacterController characterController; private Vector3 velocity; private bool isGrounded; private InputManager inputManager; private float lastGroundY; private bool wasGroundedLastFrame; [Tooltip("从高处落下时的伤害阈值(米)")] [SerializeField] private float fallDamageThreshold = 3f; //伤害阈值 [Tooltip("推动物体的力量")] [SerializeField] private float pushPower = 2f; [Header("Footstep Settings")] [Tooltip("判定为走路的最小输入强度")] [SerializeField] private float walkThreshold = 0.1f; private void Awake() { characterController = GetComponent(); if (characterController == null) Debug.LogError("PlayerMoveController 需要 CharacterController 组件!"); initSpeed = speed; playerSound = playerSound != null ? playerSound : GetComponent(); if (playerSound == null) Debug.LogWarning("PlayerMoveController: AudioSource 未设置,音效将不会播放。"); } private void Start() { inputManager = InputManager.Instance; } private void Update() { // 地面检测 bool isCurrentlyGrounded = groundCheck != null ? Physics.CheckSphere(groundCheck.position, groundDistance, groundMask) : characterController.isGrounded; // 记录离开地面时的高度 if (wasGroundedLastFrame && !isCurrentlyGrounded) { lastGroundY = transform.position.y; } // 落地检测 if (!wasGroundedLastFrame && isCurrentlyGrounded) { float fallHeight = lastGroundY - transform.position.y; if (fallHeight > fallDamageThreshold) // 3米为伤害阈值,可调整 { int damage = Mathf.RoundToInt((fallHeight - 3f) * 10); // 每超出1米伤害10点 var playerController = GetComponent(); if (playerController != null) playerController.TakeDamage(damage); } } wasGroundedLastFrame = isCurrentlyGrounded; // 地面检测 if (groundCheck != null) isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); else isGrounded = characterController.isGrounded; if (isGrounded && velocity.y < 0) velocity.y = -2f; // 保持贴地 Vector2 inputMove = inputManager.Move; // 获取输入 float x = inputMove.x; float z = inputMove.y; // 按玩家朝向移动 Vector3 move = transform.right * x + transform.forward * z; characterController.Move(move * speed * Time.deltaTime); // 走路音效逻辑:在地面且移动输入较大时播放循环走路音效 HandleFootstepAudio(x, z); // 跳跃 if (isGrounded && inputManager.JumpPressed) { // 跳跃时停止走路循环声并播放跳跃音效(一次性) StopWalkAudioIfPlaying(); if (playerSound != null && jumpSound != null) playerSound.PlayOneShot(jumpSound); velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); } // 重力 velocity.y += gravity * Time.deltaTime; characterController.Move(velocity * Time.deltaTime); } private void HandleFootstepAudio(float x, float z) { if (playerSound == null || walkSound == null) return; float inputMag = new Vector2(x, z).magnitude; bool shouldPlayWalk = isGrounded && inputMag > walkThreshold; if (shouldPlayWalk) { if (playerSound.clip != walkSound || !playerSound.isPlaying) { playerSound.clip = walkSound; playerSound.loop = true; playerSound.Play(); } } else { // 如果当前正在播放走路音效则停止 if (playerSound.clip == walkSound && playerSound.isPlaying) { playerSound.Stop(); playerSound.loop = false; playerSound.clip = null; } } } private void StopWalkAudioIfPlaying() { if (playerSound == null) return; if (playerSound.clip == walkSound && playerSound.isPlaying) { playerSound.Stop(); playerSound.loop = false; playerSound.clip = null; } } private void OnControllerColliderHit(ControllerColliderHit hit) { Rigidbody body = hit.collider.attachedRigidbody; // 只推动带有刚体且非静态的物体 if (body != null && !body.isKinematic) { // 忽略从下方碰撞 if (hit.moveDirection.y < -0.3f) return; Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z); body.AddForce(pushDir * pushPower, ForceMode.Impulse); } } public void SetSpeed(float newSpeed) { speed = newSpeed; } public void ResetSpeed() { speed = initSpeed; } } }