using UnityEngine; /// /// 用 UI 虚拟摇杆(移动轮盘)驱动角色移动,替代原来的点击地面移动。 /// /// 用法:挂在带 CharacterController 的角色上,把场景里的 /// 拖到 joystick 字段(在 Inspector / 预制体里接线,代码里不查找节点)。 /// 摇杆方向默认按摄像机朝向换算成世界方向,推杆越满速度越快;只做水平移动,y 不变。 /// [RequireComponent(typeof(CharacterController))] public class PlayerMoveController : MonoBehaviour { [Header("输入")] [Tooltip("移动轮盘;必须在 Inspector / 预制体里指定,留空角色不会移动")] [SerializeField] private VirtualJoystick joystick; [Tooltip("是否按摄像机朝向移动(关掉则按世界坐标轴移动)")] [SerializeField] private bool cameraRelative = true; [Tooltip("朝向参考的摄像机,留空用 Camera.main")] [SerializeField] private Transform cameraTransform; [Header("移动")] [Tooltip("满杆时的移动速度(单位/秒)")] [SerializeField] private float speed = 5f; [Tooltip("转向平滑速度,越大转得越快")] [SerializeField] private float turnSpeed = 12f; [Tooltip("输入平滑时间(0 = 立刻响应)")] [SerializeField] private float inputSmoothing = 0.05f; private CharacterController _controller; private Vector2 _smoothedInput; private Vector2 _smoothingVelocity; private void Awake() { _controller = GetComponent(); if (joystick == null) Debug.LogError("[PlayerMoveController] 没有指定移动轮盘(joystick),请在 Inspector / 预制体里拖入。", this); } private void Update() { Vector2 input = joystick != null ? joystick.Value : Vector2.zero; if (inputSmoothing > 0f) input = Vector2.SmoothDamp(_smoothedInput, input, ref _smoothingVelocity, inputSmoothing); _smoothedInput = input; if (input.sqrMagnitude <= 0.0001f) return; Vector3 direction = ToWorldDirection(input); if (direction.sqrMagnitude <= 0.0001f) return; _controller.Move(direction * (speed * input.magnitude * Time.deltaTime)); transform.rotation = Quaternion.Slerp( transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime * turnSpeed); } /// 把摇杆的二维输入换算成世界方向(水平面内,已归一化)。 private Vector3 ToWorldDirection(Vector2 input) { Vector3 forward = Vector3.forward; Vector3 right = Vector3.right; if (cameraRelative) { Transform cam = cameraTransform != null ? cameraTransform : (Camera.main != null ? Camera.main.transform : null); if (cam != null) { forward = cam.forward; forward.y = 0f; right = cam.right; right.y = 0f; if (forward.sqrMagnitude > 0.0001f) forward.Normalize(); else forward = Vector3.forward; if (right.sqrMagnitude > 0.0001f) right.Normalize(); else right = Vector3.right; } } Vector3 dir = right * input.x + forward * input.y; if (dir.sqrMagnitude > 1f) dir.Normalize(); return dir; } }