使用Unity新输入系统实现玩家翻滚时遇报错及角色卡顿求助
Unity新输入系统实现翻滚功能遇到的问题:错误与角色持续移动无响应
尝试用Unity新输入系统实现玩家翻滚功能时,出现2个NullReferenceException错误,且角色陷入持续移动状态,无法响应任何输入。
错误信息
两个错误均为空引用异常:
NullReferenceException: Object reference not set to an instance of an object
抛出位置:MovementToPositionEvent.CallMovementToPositionEvent(第19行)NullReferenceException: Object reference not set to an instance of an object
抛出位置:MovementToPositionEvent+<>c.<CallMovementToPositionEvent>b__2_0(第19行)
相关代码
MovementToPositionEvent
public class MovementToPositionEvent : MonoBehaviour { public event Action<MovementToPositionEvent, MovementToPositionArgs> OnMovementToPosition; public void CallMovementToPositionEvent(Vector3 targetPosition, Vector3 currentPosition, float moveSpeed, Vector3 moveDirection, bool isRolling) { OnMovementToPosition?.Invoke(this, new MovementToPositionArgs() { targetPosition = targetPosition, currentPosition = currentPosition, moveSpeed = moveSpeed, moveDirection = moveDirection, isRolling = isRolling }); } }
MovementToPosition
public class MovementToPosition : MonoBehaviour { private Rigidbody2D _rigidbody; private Player _player; private void Awake() { _rigidbody = GetComponent<Rigidbody2D>(); _player = GetComponent<Player>(); } private void OnEnable() { _player.MovementToPositionEvents.OnMovementToPosition += MovementToPositionEvent_OnMovementToPosition; } private void OnDisable() { _player.MovementToPositionEvents.OnMovementToPosition -= MovementToPositionEvent_OnMovementToPosition; } private void MovementToPositionEvent_OnMovementToPosition(MovementToPositionEvent movementToPositionEvent, MovementToPositionArgs movementToPositionArgs) { MoveToPosition(movementToPositionArgs); } private void MoveToPosition(MovementToPositionArgs movementToPositionArgs) { Vector3 direction = (movementToPositionArgs.targetPosition - movementToPositionArgs.currentPosition).normalized; _rigidbody.MovePosition(_rigidbody.position + (Vector2)direction * movementToPositionArgs.moveSpeed * Time.fixedDeltaTime); } }
AnimatePlayer
private void OnEnable() { _player.IdleEvents.OnIdle += IdleEvent_OnIdle; _player.AimWeaponEvents.OnWeaponAim += AimWeaponEvent_OnWeaponAim; _player.MovementByVelocityEvents.OnMovementByVelocity += MovementByVelocityEvent_OnMovementByVelocity; _player.MovementToPositionEvents.OnMovementToPosition += MovementToPositionEvent_OnMovementToPosition; } private void OnDisable() { _player.IdleEvents.OnIdle -= IdleEvent_OnIdle; _player.AimWeaponEvents.OnWeaponAim -= AimWeaponEvent_OnWeaponAim; _player.MovementByVelocityEvents.OnMovementByVelocity -= MovementByVelocityEvent_OnMovementByVelocity; _player.MovementToPositionEvents.OnMovementToPosition -= MovementToPositionEvent_OnMovementToPosition; } private void MovementToPositionEvent_OnMovementToPosition(MovementToPositionEvent movementToPositionEvent, MovementToPositionArgs movementToPositionArgs) { InitializeAimAnimationParameters(); InitializeRollAnimationParameters(); SetMovementToPositionAnimationParameters(movementToPositionArgs); } private void InitializeRollAnimationParameters() { _player.Animators.SetBool(Settings.RollDown, false); _player.Animators.SetBool(Settings.RollLeft, false); _player.Animators.SetBool(Settings.RollRight, false); _player.Animators.SetBool(Settings.RollUp, false); } private void SetMovementToPositionAnimationParameters(MovementToPositionArgs movementToPositionArgs) { if (movementToPositionArgs.IsRolling) { if (movementToPositionArgs.MoveDirection.x > 0.0f) _player.Animators.SetBool(Settings.RollRight, true); else if (movementToPositionArgs.MoveDirection.x < 0.0f) _player.Animators.SetBool(Settings.RollLeft, true); else if (movementToPositionArgs.MoveDirection.y > 0.0f) _player.Animators.SetBool(Settings.RollUp, true); else if (movementToPositionArgs.MoveDirection.y < 0.0f) _player.Animators.SetBool(Settings.RollDown, true); } }
PlayerControl
private PlayerInput _playerInput; private Player _player; private float _moveSpeed; private WaitForFixedUpdate _waitForFixedUpdate; private bool _isPlayerRolling; private bool _playerRoll; private float _playerRollCooldownTimer; private MovementDetailsSO _movementDetails; private Coroutine _playerRollCoroutine; private void Awake() { _playerInput = new PlayerInput(); _player = GetComponent<Player>(); _moveSpeed = _movementDetails.GetMoveSpeed(); } private void Start() { _waitForFixedUpdate = new WaitForFixedUpdate(); } private void Update() { if (_isPlayerRolling) return; MovementInput(); WeaponInput(); PlayerRollCooldownTimer(); } private void OnEnable() { _playerInput.Enable(); } private void OnDisable() { _playerInput.Disable(); } private void MovementInput() { Vector2 inputVector = _playerInput.Player.Movement.ReadValue<Vector2>(); _playerRoll = _playerInput.Player.Rolling.ReadValue<float>() > 0.5f; Debug.Log(_playerRoll.ToString()); if (inputVector != Vector2.zero) { if (!_playerRoll) { _player.MovementByVelocityEvents.CallMovementByVelocityEvent(inputVector, _moveSpeed); } else if (_playerRollCooldownTimer <= 0.0f) { Debug.Log(_playerRollCooldownTimer.ToString()); PlayerRoll((Vector3)inputVector); } } else { _player.IdleEvents.CallIdleEvent(); } } private void PlayerRoll(Vector3 direction) { _playerRollCoroutine = StartCoroutine(PlayerRollRoutine(direction)); } private IEnumerator PlayerRollRoutine(Vector3 direction) { float minDistance = 0.2f; float rollTimer = 0f; float maxRollTime = 1f; _isPlayerRolling = true; Vector3 targetPosition = _player.transform.position + direction * _movementDetails.RollDistance; while (Vector2.Distance(_player.transform.position, targetPosition) > minDistance && rollTimer < maxRollTime) { _player.MovementToPositionEvents.CallMovementToPositionEvent(targetPosition, _player.transform.position, _movementDetails.RollSpeed, direction, _isPlayerRolling); rollTimer += Time.fixedDeltaTime; yield return _waitForFixedUpdate; } _isPlayerRolling = false; _playerRollCooldownTimer = _movementDetails.RollCooldownTime; _player.transform.position = targetPosition; } private void PlayerRollCooldownTimer() { if (_playerRollCooldownTimer > 0) { _playerRollCooldownTimer -= Time.deltaTime; } }
解决建议
1. 修复空引用异常
- 确保
Player组件中MovementToPositionEvents字段已正确挂载对应脚本,且不为null。 - 在
MovementToPosition脚本的Awake方法中,确认_player已正确获取组件引用(如添加_player = GetComponent<Player>();)。 - 在
MovementToPositionEvent.CallMovementToPositionEvent中,可添加显式空检查避免调用空委托:if (OnMovementToPosition != null) { OnMovementToPosition.Invoke(this, new MovementToPositionArgs(...)); }
2. 修复角色持续移动、无响应输入问题
- 将翻滚循环中的
Vector3.Distance改为Vector2.Distance,避免2D游戏中Z轴差异导致循环无法结束。 - 添加翻滚超时逻辑,防止因移动速度异常等原因导致循环无限执行。
- 调整
_playerRoll的判断逻辑为_playerInput.Player.Rolling.ReadValue<float>() > 0.5f,避免输入精度问题导致判断失误。 - 确认
PlayerRollCooldownTimer方法已实现冷却时间递减逻辑(如上述补充代码)。
内容的提问来源于stack exchange,提问作者ali mahdi
相关产品推荐
相关产品推荐

