You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Unity新输入系统实现玩家翻滚时遇报错及角色卡顿求助

Unity新输入系统实现翻滚功能遇到的问题:错误与角色持续移动无响应

尝试用Unity新输入系统实现玩家翻滚功能时,出现2个NullReferenceException错误,且角色陷入持续移动状态,无法响应任何输入。

错误信息

两个错误均为空引用异常:

  1. NullReferenceException: Object reference not set to an instance of an object
    抛出位置:MovementToPositionEvent.CallMovementToPositionEvent(第19行)
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:03:19