Input.GetKey(sprintKey) 在每一帧之间切换?

问题描述 投票:0回答:1

我目前正在为我的第一人称控制器开发冲刺功能。

我的设置是一个“PlayerMovementController”、一个“PlayerStatusController”和一个可编写脚本的对象“PlayerStatusData”,StatusController 正在获取有关玩家耐力的信息。

玩家移动控制器:

    private void Update()
    {
        HandleMovementInput();
        ApplyMovement();
    }

    private void HandleMovementInput()
    {
        if (Input.GetKey(sprintKey) && !isSprinting)                 // SPRINTING
        {
            if (OnCheckStamina != null && OnCheckStamina())
            {
                StartSprint();
                OnStaminaDrain?.Invoke();
            }
        }
        else                                                         // NOT SPRINTING
        {
            StopSprint();
            OnStaminaRegen?.Invoke();
        }
        /*** SPRINTING ENDE ***/

        currentInput = new Vector2(movementSpeed * Input.GetAxis("Vertical"), movementSpeed * Input.GetAxis("Horizontal"));
        float moveDirectionY = moveDirection.y;
        moveDirection = (transform.TransformDirection(Vector3.forward) * currentInput.x) + (transform.TransformDirection(Vector3.right) * currentInput.y);
        moveDirection.y = moveDirectionY;
    }

    private void ApplyMovement()
    {
        if (!characterController.isGrounded)
            moveDirection.y -= gravity * Time.deltaTime;

        characterController.Move(moveDirection * Time.deltaTime);
    }


    private void StartSprint()
    {
        isSprinting = true;
        movementSpeed = sprintSpeed;
        
    }

    private void StopSprint()
    {
        isSprinting = false;
        movementSpeed = walkSpeed;
        
    }

Sprint 本身像这样工作得很好,但我在检查器上注意到 isSprinting 布尔值和运动速度在 true 和 false 以及 3f 到 1.8f 之间不断变化。 我不敢相信这是正常的,必须有一个适当的开关......对吧? 在游戏视图本身中,这似乎不是问题,但处理这些事件的耐力系统并没有真正发挥作用。他们不断地在“恢复体力”和“消耗体力”之间切换

玩家状态控制器:

public class PlayerStatusController : MonoBehaviour
{
    [Header("Scriptable Object")]
    public PlayerStatusData playerStatusData, pSD;

    private void OnEnable()
    {
        PlayerMovementController.OnCheckStamina += HasStamina;
        PlayerMovementController.OnStaminaDrain += DrainStamina;
        PlayerMovementController.OnStaminaRegen += RegenerateStamina;
    }

    private void OnDisable()
    {
        PlayerMovementController.OnCheckStamina -= HasStamina;
        PlayerMovementController.OnStaminaDrain -= DrainStamina;
        PlayerMovementController.OnStaminaRegen -= RegenerateStamina;

    }
    private bool HasStamina()
    {
        return playerStatusData.currentStamina > 0;
    }

    private void DrainStamina()
    {
        if (playerStatusData.currentStamina != playerStatusData.minStamina)
        {
            playerStatusData.currentStamina -= playerStatusData.staminaDrain * Time.deltaTime;
            playerStatusData.currentStamina = Mathf.Max(0, playerStatusData.currentStamina); // Ensure stamina doesn't go below 0
            Debug.Log("DRAINING STAMINA");
        }

    }

    private void RegenerateStamina()
    {
        if (playerStatusData.currentStamina < playerStatusData.maxStamina)
        {
            playerStatusData.currentStamina += playerStatusData.staminaRegen * Time.deltaTime;
            playerStatusData.currentStamina = Mathf.Min(100, playerStatusData.currentStamina); // Ensure stamina doesn't go above 100
            Debug.Log("REGENERATING STAMINA");
        }
    }
}

在我看来,事件系统应该工作得很好......但我认为冲刺脚本的开/关切换存在问题,这会导致耐力系统出现问题。有人能解决这个问题吗?

c# unity-game-engine events controller delegates
1个回答
0
投票

这是因为你的if语句逻辑:

if (Input.GetKey(sprintKey) && !isSprinting)
。一旦冲刺开始,
!isSprinting
变为假,这意味着即使仍然按住该键,StopSprinting()将始终在下一帧被调用。

示例帧序列:

  • 第 1 帧:
    (Input.GetKey = false & !isSprinting = false) == false
    ,调用 StopSprint()
  • 第 2 帧:
    (Input.GetKey = true & !isSprinting = false) == true
    ,调用 StartSprint()
  • 第 3 帧:
    Input.GetKey = true & !isSprinting = true, == false
    ,调用 StopSprint()(即使仍按住)
  • 第 4 帧:
    (Input.GetKey = true & !isSprinting = false) == true
    ,StartSprint() 再次被调用

!isSprinting
检查更改为第一个 if 语句的 inside 以解决此问题

        if (Input.GetKey(sprintKey)) // SPRINTING
        {
            if (!isSprinting && OnCheckStamina != null && OnCheckStamina())
            {
                StartSprint();
                OnStaminaDrain?.Invoke();
            }
        }
        else // NOT SPRINTING
        {
            StopSprint();
            OnStaminaRegen?.Invoke();
        }
© www.soinside.com 2019 - 2024. All rights reserved.