【问题标题】:I have some serious problems with new Input System我对新的输入系统有一些严重的问题
【发布时间】:2021-03-04 08:52:20
【问题描述】:

我正在使用 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);
}
}

【问题讨论】:

  • 应该OnJump 设置跳跃速度吗?看起来你应该有一个布尔值设置为true,例如jumped。然后在您的计算中使用它而不是控件上的triggered 属性。在使用控件时,我遇到了很多期望与实际的问题。如果你能确认你的意图,我可以提供一个官方样本。
  • Input.GetAxisRaw("Horizontal"); 也应更改为 moveInput.X;。不应使用 GetAxisRaw,因为您已经从 OnMove 方法中获取了移动值。
  • 感谢您的回复。我想也许我应该在“OnJump”中使用“jumpInput”而不是“JumpVelocity”。这段代码中的所有内容都搞砸了。事实上,我从 Git Hub 下载了一个播放器控制器代码以将其用作指南,但问题是它使用的是旧输入系统。尽管如此,我还是复制了该代码并将其粘贴到该代码中。这就是为什么这里的一切都很复杂。我之前添加了“jumpInput”,但“JumpVelocity”是针对其他播放器控制器的。
  • 你能给我看一个布尔值的例子吗?我明白你的意思,但我想写正确,所以我问。
  • @ps2goat 另外,我更改了 Input.GetAxisRaw("Horizo​​ntal");移动Input.X;但我收到一条错误消息,提示“float”不包含“x”的定义。如何定义“x”?

标签: c# unity3d input 2d-games


【解决方案1】:

我想试试这个,因为我还没有在我自己的游戏中实现跳跃,我想看看新输入系统能有多么简单。我很喜欢这个,关于基于事件的输入最酷的部分之一是您不必将所有内容都放在一个方法中!

请注意,我是在 3D 中完成的——我还没有设置 2D 游戏。我假设您可能需要调整施加力的轴,以及使用 RigidBody2D 和 2D 对撞机。

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

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

首先,请注意,当您创建控件并自动生成 C# 类时,您需要让您的类继承它。您的控件类称为PlayerInputActions。我没有看到“Action Map”的名称,所以我将使用我的名称。在 GUI 中,我的称为“AvatarDefault”。该动作称为“跳跃”。如果您检查自动生成的 C# 类,您会发现命名空间、接口和方法。我的动作图在生成时变成了一个界面,命名为IAvatarDefaultActions。由于您没有列出您的 ActionMap 名称,因此我将使用我的名称。在您的代码中将其替换为您的。

如有必要,导入您的命名空间,并在您的播放器输入类上继承接口。

为简洁起见删除了一些代码!

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 以进行摇杆和方向键移动。所以通过的值将有movement.xmovement.y 分别获得水平和垂直输入。

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

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

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


    private Vector2 moveInput;

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

现在您只需在更新代码中使用moveInput.x 来获取水平值!

【讨论】:

  • 感谢您的帮助。我做了你说的一切,但我仍然有一些问题和疑问。首先,我有太多的跳跃变量,例如 jumpInput、jumpForce 和 JumpVelocity,它们让事情变得复杂。其次,我遇到了一些奇怪的错误,我不知道它们是干什么用的。例如,“controls.Player.SetCallbacks(this);”的错误或者这个 " else if (Mathf.Sign(moveInput.x)) != Mathf.Sign(Horizo​​ntalVelocity); Horizo​​ntalVelocity *= Mathf.Pow(1f - Horizo​​ntalDampingWhenTurning, Time.deltaTime * 10f);"
  • 错误提示无法将浮点类型隐式转换为 'bool 但 moveInput 是 Vector2。
  • 以及“controls.Player.SetCallbacks(this);”的错误说参数 1:无法从“PlayerController”转换为“PlayerInputActions”。
  • 对于跳转变量,除了我在示例中的内容外,请尝试取出所有内容。我不确定您是否需要速度,但您当然可以稍后再添加。 SetCallbacks 应该是自动生成的。如果您在“项目”窗口中选择播放器控件文件,是否在“检查器”窗口中选择了“生成 C# 类”?我的机器上安装了 1.0.0 版的新输入系统包。
  • 我解决了这个问题。我所做的只是删除“rb.velocity = new Vector2(moveInput.x * jumpForce, rb.velocity.y);”在固定更新中。它阻止了玩家在跳跃后移动。另外,我意识到当我在检查器中更改 JumpForce 的值时,它在游戏中不会改变,并且仍然会在低高度跳跃。也许代码有问题。对于 AddForce,我使用这个“rb.AddForce(Vector2.up * this.jumpForce, ForceMode2D.Force);”。如何更改值?
【解决方案2】:

从统一文档和我对统一的小知识来看,您似乎正确使用了它,但是在示例中他们运行 float speed = Input.GetAxisRaw("Horizontal") * Time.deltaTime; 所以如果您遇到问题,请尝试使用该行并查看有什么变化。如果您在键映射方面遇到困难,它还说您可以在 Edit->Settings->Input 中进行编辑。

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

【讨论】:

  • 那是旧的输入系统。新的输入系统非常不同。虽然我现在在 OP 的代码中看到了它。这也可能是问题的一部分。
  • time.deltatime 还在使用吗?我记得当我看 brackeys 教程时,它对速度等非常重要。
  • 是的,它仍然应该用于根据更新之间的时间进行缩放,但我认为这个算法的错误不止于此。
  • 就我个人而言,Brackeys 教程除了一次之外从未解决过我的问题。一般来说,我还没有找到关于新输入系统的有用教程,我想知道它们比旧系统教程少。
猜你喜欢
  • 2021-10-03
  • 2011-04-20
  • 2015-05-03
  • 2014-09-10
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多