Unity角色水平轴输入检测失效,松开按键无法停止滑动如何解决
问题根因
- isMoving判断逻辑被覆盖:先判断水平轴输入修改isMoving后,紧接着的垂直轴输入判断会直接覆盖isMoving的值。这就是垂直轴逻辑正常、水平轴完全无效的核心原因:当你只按水平方向按键时,垂直轴为0,判断完水平轴把isMoving设为true后,马上被垂直轴的判断改成false。
- 输入获取和判断的时机错误:
horizontal和vertical变量是在FixedUpdate的MovePlayer方法里才更新的,但是你在Update的CheckInput方法里提前判断这两个变量的值,拿到的都是上一轮的旧值,判断结果自然不准确。 - Input.GetAxis有平滑过渡:Unity默认的
Input.GetAxis会对输入做平滑插值,松开按键后值不会立刻归零,会有渐变过程,就算逻辑修复也会残留一点滑行效果。
修复方案
- 修正isMoving的判断逻辑,合并水平、垂直轴的判断条件,避免分开判断互相覆盖值
- 把
horizontal和vertical的输入获取移到CheckInput里,保证判断的是当前最新的输入值 - 把
Input.GetAxis替换成Input.GetAxisRaw,松开按键输入值立刻归零 - 无关优化:把缩放值的初始化放到
Start里,不要每帧重复赋值
修正后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { [Header("Player Values")] [SerializeField] private float playerSpeed = 50f; [SerializeField] private float jumpHeight = 7f; [Header("Ground Check")] [SerializeField] private Transform groundCheck; [SerializeField] private LayerMask ground; private float checkLenght = 0.1f; private Rigidbody rb; private float horizontal; private float vertical; // Crouch Scales private Vector3 initialScale; private Vector3 crouchScale; // Counter Movement private bool isMoving; private bool isOnGround; private float counterDrag = 10f; private void Start() { rb = GetComponent<Rigidbody>(); // 缩放只需要初始化一次即可 initialScale = new Vector3(1f, 1f, 1f); crouchScale = new Vector3(1f, 0.5f, 1f); } void FixedUpdate() { // Player Movement MovePlayer(); // Counter Movement ApplyCounterMovement(); // Check Ground isOnGround = Physics.CheckSphere(groundCheck.position, checkLenght, ground); } private void Update() { CheckInput(); } private void MovePlayer() { Vector3 movement = transform.forward * vertical * playerSpeed + transform.right * horizontal * playerSpeed; rb.AddForce(movement, ForceMode.Acceleration); } private void CheckInput() { if(Input.GetKeyDown(KeyCode.LeftShift)) { getDown(); } if(Input.GetKeyUp(KeyCode.LeftShift)) { getUp(); } // 直接获取最新输入,用GetAxisRaw无平滑过渡,松开立刻归零 horizontal = Input.GetAxisRaw("Horizontal"); vertical = Input.GetAxisRaw("Vertical"); // 合并判断逻辑,只要水平或垂直有输入就设为正在移动,不会互相覆盖 isMoving = Mathf.Abs(horizontal) > 0f || Mathf.Abs(vertical) > 0f; // Check Jump if(Input.GetKeyDown(KeyCode.Space)) { Jump(); } } // Crouch private void getDown() { transform.localScale = crouchScale; transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z); } // Get Up From Crouching private void getUp() { transform.localScale = initialScale; transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z); } // Apply Counter Movement private void ApplyCounterMovement() { rb.drag = isMoving ? 0f : counterDrag; } private void Jump() { if(isOnGround) { rb.AddForce(Vector3.up * jumpHeight, ForceMode.VelocityChange); } } }
额外优化建议
如果还是觉得停止不够快,可以在isMoving为false的时候,直接把Rigidbody的水平速度归零,停止效果更干脆:
private void ApplyCounterMovement() { if(isMoving) { rb.drag = 0f; return; } rb.drag = counterDrag; // 直接清空水平方向速度,立刻停止 Vector3 horizontalVelocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z); rb.velocity -= horizontalVelocity; }
内容的提问来源于stack exchange,提问作者Meriegg
相关产品推荐
相关产品推荐

