我在使用新的输入系统时遇到了一些严重的问题

I have some serious problems with new Input System

我正在使用 Unity 制作一款 2D 平台游戏,自从我决定使用新的输入系统来支持游戏手柄和键盘以来已经 3 周了,但我仍在为此苦苦挣扎。此外,我正在使用 Player Input 组件并调用统一事件行为。事实上,我从 GitHub 下载了一个播放器控制器代码以将其用作指南,并将其复制并粘贴到我的实际播放器控制器中,但问题是它使用的是旧的输入系统。所以我需要稍微更改一下代码,但我不知道如何在 void update 而不是 (Input.GetAxisRaw("Horizontal")) 中编写等效代码。我一直在努力解决这个问题,如果你能指导我,我将不胜感激。

这是我的播放器控制器代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    private PlayerInputActions controls;

    private Rigidbody2D rb;
    private Animator anim;
    private bool facingRight = true;
    private float moveInput;
    public Transform feetPos;
    public float jumpInput;
    public float speed;

    [SerializeField] float JumpVelocity = 5;
    float JumpPressedRemember = 0;
    [SerializeField] float JumpPressedRememberTime = 0.2f;

    float GroundedRemember = 0;

    [SerializeField] float GroundedRememberTime = 0.25f;
    [SerializeField] float HorizontalAcceleration = 1;
    [SerializeField] [Range(0, 1)] float HorizontalDampingBasic = 0.5f;
    [SerializeField] [Range(0, 1)] float HorizontalDampingWhenStopping = 0.5f;
    [SerializeField] [Range(0, 1)] float HorizontalDampingWhenTurning = 0.5f;
    [SerializeField] [Range(0, 1)] float JumpHeight = 0.5f;

    private void Awake()
    {
        controls = new PlayerInputActions();
    }

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    public void OnMove(InputAction.CallbackContext context)
    {
        moveInput = context.ReadValue<float>();
    }

    public void OnJump(InputAction.CallbackContext context)
    {
        JumpVelocity = context.ReadValue<float>();
    }

    void FixedUpdate()
    {
        rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
      
        if (facingRight == false && moveInput > 0)
        {
            Flip();
        }
        else if (facingRight == true && moveInput < 0)
        {

            Flip();
        }
    }

    void Flip()
    {
        facingRight = !facingRight;
        Vector3 Scaler = transform.localScale;
        Scaler.x *= -1;
        transform.localScale = Scaler;
    }

    void Update()
    {
        Vector2 GroundedBoxCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
        Vector2 GroundedBoxCheckScale = (Vector2)transform.localScale + new Vector2(-0.02f, 0);
        bool Grounded = Physics2D.OverlapBox(GroundedBoxCheckPosition, transform.localScale, 0);

        GroundedRemember -= Time.deltaTime;

        if (Grounded)
        {
            GroundedRemember = GroundedRememberTime;
        }

        JumpPressedRemember -= Time.deltaTime;

        if (controls.Player.Jump.triggered)
        {
            JumpPressedRemember = JumpPressedRememberTime;
        }

        if (controls.Player.Jump.triggered)
        {
            if (rb.velocity.y > 0)
            {
                rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * JumpHeight);
            }
        }

        if ((JumpPressedRemember > 0) && (GroundedRemember > 0))
        {
            JumpPressedRemember = 0;
            GroundedRemember = 0;
            rb.velocity = new Vector2(rb.velocity.x, JumpVelocity);
        }

        float HorizontalVelocity = rb.velocity.x;
        HorizontalVelocity += Input.GetAxisRaw("Horizontal");

        if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) < 0.01f)
            HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenStopping, Time.deltaTime * 10f);
        else if (Mathf.Sign(Input.GetAxisRaw("Horizontal")) != Mathf.Sign(HorizontalVelocity))
            HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenTurning, Time.deltaTime * 10f);
        else
            HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingBasic, Time.deltaTime * 10f);

        rb.velocity = new Vector2(HorizontalVelocity, rb.velocity.y);
    }
}

这是我从 GitHub 下载的代码。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
[SerializeField]
LayerMask lmWalls;

[SerializeField]
float fJumpVelocity = 5;

Rigidbody2D rigid;

float fJumpPressedRemember = 0;
[SerializeField]
float fJumpPressedRememberTime = 0.2f;

float fGroundedRemember = 0;
[SerializeField]
float fGroundedRememberTime = 0.25f;

[SerializeField]
float fHorizontalAcceleration = 1;
[SerializeField]
[Range(0, 1)]
float fHorizontalDampingBasic = 0.5f;
[SerializeField]
[Range(0, 1)]
float fHorizontalDampingWhenStopping = 0.5f;
[SerializeField]
[Range(0, 1)]
float fHorizontalDampingWhenTurning = 0.5f;

[SerializeField]
[Range(0, 1)]
float fCutJumpHeight = 0.5f;

void Start ()
{
    rigid = GetComponent<Rigidbody2D>();
}

void Update ()
{
    Vector2 v2GroundedBoxCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
    Vector2 v2GroundedBoxCheckScale = (Vector2)transform.localScale + new Vector2(-0.02f, 0);
    bool bGrounded = Physics2D.OverlapBox(v2GroundedBoxCheckPosition, v2GroundedBoxCheckScale, 0, lmWalls);

    fGroundedRemember -= Time.deltaTime;
    if (bGrounded)
    {
        fGroundedRemember = fGroundedRememberTime;
    }

    fJumpPressedRemember -= Time.deltaTime;
    if (Input.GetButtonDown("Jump"))
    {
        fJumpPressedRemember = fJumpPressedRememberTime;
    }

    if (Input.GetButtonUp("Jump"))
    {
        if (rigid.velocity.y > 0)
        {
            rigid.velocity = new Vector2(rigid.velocity.x, rigid.velocity.y * fCutJumpHeight);
        }
    }

    if ((fJumpPressedRemember > 0) && (fGroundedRemember > 0))
    {
        fJumpPressedRemember = 0;
        fGroundedRemember = 0;
        rigid.velocity = new Vector2(rigid.velocity.x, fJumpVelocity);
    }

    float fHorizontalVelocity = rigid.velocity.x;
    fHorizontalVelocity += Input.GetAxisRaw("Horizontal");

    if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) < 0.01f)
        fHorizontalVelocity *= Mathf.Pow(1f - fHorizontalDampingWhenStopping, Time.deltaTime * 10f);
    else if (Mathf.Sign(Input.GetAxisRaw("Horizontal")) != Mathf.Sign(fHorizontalVelocity))
        fHorizontalVelocity *= Mathf.Pow(1f - fHorizontalDampingWhenTurning, Time.deltaTime * 10f);
    else
        fHorizontalVelocity *= Mathf.Pow(1f - fHorizontalDampingBasic, Time.deltaTime * 10f);

    rigid.velocity = new Vector2(fHorizontalVelocity, rigid.velocity.y);
}
}

从 unity 文档和我对 unity 的小知识来看,您似乎在正确使用它,但是在示例中 运行 float speed = Input.GetAxisRaw("Horizontal") * Time.deltaTime; 所以如果您遇到问题,请尝试使用它线,看看有什么变化。如果您在键盘映射方面遇到困难,它还会说您可以在“编辑”->“设置”->“输入”中进行编辑。

文档:https://docs.unity3d.com/ScriptReference/Input.GetAxisRaw.html

我想试试这个,因为我还没有在我自己的游戏中实现跳跃,我想看看使用新输入系统它能有多简单。我很喜欢这个,关于 event-based 输入最酷的部分之一是你不必将所有东西都放在一个方法中!

请注意,我是在 3D 模式下进行的 -- 我还没有设置 2D 游戏。我假设您可能需要调整施加力的轴,以及使用 RigidBody2D 和 2D 碰撞器。

对于设置,您需要在地形上安装碰撞器,在角色上安装碰撞器和刚体。 (我假设您已经设置好了,但这是为找到答案的其他人准备的。)地形上的碰撞器是必需的,这样玩家就不会从地形中掉落。播放器上的对撞机也是出于同样的原因。 RigidBody 允许围绕重力和质量等进行物理和计算(您必须为此示例启用重力!)

所以这个例子将允许我们向玩家施加一个向上的力,然后重力将角色带回地形。

首先,请注意,当您创建控件并拥有 C# class auto-generated 时,您需要让 class 继承它。您的控件 class 称为 PlayerInputActions。我没有看到“动作地图”名称,所以我将使用我的名称。在 GUI 中,我的名称为“AvatarDefault”。该动作称为“跳跃”。如果您检查 auto-generated C# class,您将找到命名空间、接口和方法。我的action map在生成的时候就变成了一个界面,取名为IAvatarDefaultActions。由于您没有列出您的 ActionMap 名称,我将使用我的名称。在您的代码中将其替换为您的代码。

如有必要,导入您的命名空间,并继承您的播放器输入界面 class。

Some code removed for brevity!

public class PlayerController : MonoBehaviour, PlayerInputActions.IAvatarDefaultActions {
    
    // allow changing the force applied when jumping in the editor.
    // note that for a mass of 1 on my character, I had to use a value of about 300
    [SerializeField]
    private float jumpForce;

    // track our instance of controls
    private PlayerInputActions controls;

    // in awake, we need to create a new instance of controls
    // and bind the action events.

    private void Awake()
    {
        controls = new PlayerInputActions();
        // the auto-generated class takes care of all the event registration we need to do!
        // without this, we won't get event notifications.
        controls.AvatarDefault.SetCallbacks(this);
    }

    // I chose to explicitly implement the interface for clarity (since I'm still newish)
    void PlayerInputActions.IAvatarDefaultActions.OnJump(InputAction.CallbackContext context)
    {
        // there are several phases, but the only one we should care about is whether
        // the action was performed or not. (You can use an if statement, if you want)
        switch (context.phase)
        {
            case InputActionPhase.Performed:
                // to separate event handlers from actual code, I've been putting the
                // actual logic in a separate method
                this.Jump();
                break;
        }
    }

    public void Jump()
    {
        // you can play around with the ForceMode here, and probably need
        // to use a Vector2 since you're working with 2D.
        // in this example, though, it's applying the jump force on the y axis.
        // a positive value will make the character thrust upward.
        rb.AddForce(transform.up * this.jumpForce, ForceMode.Force);
    }

    // You should also have these two methods
    public void OnEnable()
    {
        controls.Enable();
    }

    public void OnDisable()
    {
        controls.Disable();
    }
}

如果这有帮助,请告诉我。如果没有,我可以尝试设置 2D 环境。看起来 2D 唯一会改变的是使用 ForceMode2D.Force.

作为参考,这是我的输入设置的样子。我将“跳转”设置为“按钮”动作类型,因为我只关心它是否被按下。

运动修正更新

至于 movement 的问题,输入系统旨在轻松传递 Vector2 以进行摇杆和 D-pad 移动。因此通过的值将 movement.xmovement.y 分别获得水平和垂直输入。

这就是我设置移动动作的方式:

这就是我将 Up 控件映射到 W 键的方式。 (其他类似,但映射到适当的键。)

这是我设置移动变量的代码。


    private Vector2 moveInput;

    void PlayerInputActions.IAvatarDefaultActions.OnMove(InputAction.CallbackContext context)
    {
        moveInput= context.ReadValue<Vector2>();
    }

现在您只需在水平值的更新代码中使用 moveInput.x