Files
2025TapTapGameJam/Assets/Script/Gameplay/Player/PlayerMoveController.cs

192 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<CharacterController>();
if (characterController == null)
Debug.LogError("PlayerMoveController 需要 CharacterController 组件!");
initSpeed = speed;
playerSound = playerSound != null ? playerSound : GetComponent<AudioSource>();
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<PlayerController>();
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;
}
}
}