Unity3d New Input System(2.8), 无法在编辑器中引用 Input Action

Cur*_*984 5 c# unity-game-engine

我刚刚将新的输入系统从 2.7 更新到 2.8。

新输入系统的工作原理是您通过转到 Create-> Input Actions 创建输入操作资产

输入动作.

这将创建一个资产,其中的操作可以映射到键。然后从这个资产创建一个 C# 脚本并在他们的代码中使用它。这就是我所做的。我调用了资产MyInput.inputactions,C# 脚本是MyInput.cs

资产和生成的 C# 类

当您以这种方式使用生成的 C# 脚本时,您需要在脚本中引用资产。但是,更新后,似乎无法从编辑器中做到这一点。当我在类中定义一个公共 MyInput变量时,如下所示:

public class ShapeMover: MonoBehaviour
{
    public MyInput controls;

    private       float        _lastFallTime;
    private       float        _fallSpeed;
    private       ShapeSpawner _spawn;
    private       GameObject   _shapeToMove;
    private       Transform    _shapeToMoveTransform;
    private       bool         _isGameOver;
    private const float        _leftRotationAngle  = (float) -1.57079633;
    private const float        _rightRotationAngle = (float) 1.57079633;
}
Run Code Online (Sandbox Code Playgroud)

它没有在检查器中暴露:

在此处输入图片说明

NullReferenceException当我尝试访问controls变量时,我得到一个明显的错误。

难道我做错了什么?

如何从检查员处引用资产?我曾尝试添加 [SerializeField]到公共声明中,但没有帮助。

我一直在关注这个视频,它运行良好,直到我更新到更新的输入系统版本。

作为参考,这是完整的 ShapeMover 类:

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace _Scripts
{
    public class ShapeMover : MonoBehaviour
    {
        [SerializeField]
        public MyInput controls;

        private       float        _lastFallTime;
        private       float        _fallSpeed;
        private       ShapeSpawner _spawn;
        private       GameObject   _shapeToMove;
        private       Transform    _shapeToMoveTransform;
        private       bool         _isGameOver;
        private const float        _leftRotationAngle  = (float) -1.57079633;
        private const float        _rightRotationAngle = (float) 1.57079633;


        private void Awake()
        {
            _spawn        = FindObjectOfType<ShapeSpawner>();
            _lastFallTime = 0f;
            _fallSpeed    = GameGrid.Instance.GetFallSpeed();
            _isGameOver   = false;

            Debug.Log("Registering controls callbacks...");
            controls.Player.Movement.performed += ctx => Movement(ctx.ReadValue<Vector2>(), true);
            controls.Player.Drop.performed     += ctx => Drop();
            controls.Menu.Reset.performed      += ctx => Restart();
            controls.Menu.Pause.performed      += ctx => PauseToggle();
            SetShapeToMove();
        }

        private void Restart()
        {
            GameGrid.Instance.ResetGame();
            _isGameOver = false;
            SetShapeToMove();
        }


        private void PauseToggle()
        {
            Debug.Log("Got Pause input");
            var currentPauseState = GameGrid.Instance.IsPaused;
            //If not paused, will pause
            if (!currentPauseState)
            {
//                controls.Player.Movement.Disable();
//                controls.Player.Drop.Disable();
//                controls.Player.Menu.Disable();
//                controls.Player.Disable();
                GameGrid.Instance.IsPaused = true;
            }
            else
            {
//                controls.Player.Movement.Enable();
//                controls.Player.Drop.Enable();
//                controls.Player.Menu.Enable();
//                controls.Player.Enable();
                GameGrid.Instance.IsPaused = false;
            }
        }

        private void Drop()
        {
//            Debug.Log("Should Drop Shape!");
            bool didMove = true;
            while (didMove)
            {
                didMove = Movement(new Vector2(0, -1), false);
            }
        }

        private bool Movement(Vector2 direction, bool isFromInput)
        {
            if (isFromInput)
            {
                Debug.Log($"Got input {direction.ToString()}");
            }

            //Disable movement controls when game is over.
            if (_isGameOver)
            {
                return false;
            }

            var oldPosition = _shapeToMoveTransform.position;
            var oldRotation = _shapeToMoveTransform.rotation;
//            Transform[] children       = _shapeToMoveTransform.Cast<Transform>().ToArray();
            var didMove        = true;
            var didEndMovement = false;

            GameGrid.Instance.RemoveShapeFromGrid(_shapeToMoveTransform);

            if (direction.x < 0)
            {
                didMove = MoveLeft();
            }
            else if (direction.x > 0)
            {
                didMove = MoveRight();
            }
            else if (direction.y > 0)
            {
                didMove = RotateLeft();
            }
            else if (direction.y < 0)
            {
                didMove = MoveDown();

                if (!didMove)
                {
                    didEndMovement = true;
                }
            }

            //If Shape didn't move, restore previous position.
            if (!didMove)
            {
                _shapeToMoveTransform.position = oldPosition;
                _shapeToMoveTransform.rotation = oldRotation;
            }

            GameGrid.Instance.AddShapeToGrid(_shapeToMoveTransform);

//            Debug.Log($"Shape {_shapeToMove.name} Position after movement Did Move: {didMove.ToString()}");

//            Transform[] children = _shapeToMoveTransform.Cast<Transform>().ToArray();

//            var lowestChild = children.OrderBy(x => x.position.y).First();

//            Debug.Log($"{lowestChild.position.ToString()}");

            if (didEndMovement)
            {
                GameGrid.Instance.ClearRows(_shapeToMoveTransform);
                _isGameOver = GameGrid.Instance.IsGameOver(_shapeToMoveTransform);
                if (!_isGameOver)
                {
                    SetShapeToMove();
                }
            }

            return didMove;
        }

        private void SetShapeToMove()
        {
            _shapeToMove          = _spawn.SpawnShape();
            _shapeToMoveTransform = _shapeToMove.transform;
        }

        private void Update()
        {
            if (_isGameOver)
            {
                return;
            }

            if (GameGrid.Instance.IsPaused)
            {
                return;
            }


            var time = Time.time;
            if (!(time - (_lastFallTime + _fallSpeed) > 0))
            {
                return;
            }

            Movement(new Vector2(0, -1), false);
            _lastFallTime = time;
            _fallSpeed    = GameGrid.Instance.GetFallSpeed();
        }


        private bool MoveLeft()
        {
            _shapeToMoveTransform.position += Vector3.right;
            return GameGrid.Instance.CanMove(_shapeToMoveTransform);
        }

        private bool MoveRight()
        {
            _shapeToMoveTransform.position += Vector3.left;
            return GameGrid.Instance.CanMove(_shapeToMoveTransform);
        }

        private bool MoveDown()
        {
            _shapeToMoveTransform.position += Vector3.down;
            return GameGrid.Instance.CanMove(_shapeToMoveTransform);
        }


        private bool RotateLeft()
        {
            _shapeToMoveTransform.Rotate(0, 0, -90);
//            foreach (Transform child in _shapeToMoveTransform)
//            {
//                RotateTransform(child, _leftRotationAngle);
//            }

            return GameGrid.Instance.CanMove(_shapeToMoveTransform);
        }

        private void RotateTransform(Transform transformToRotate, float rotationAngleRadian)
        {
            var currentLocalPosition = transformToRotate.localPosition;
            var currentX             = currentLocalPosition.x;
            var currentY             = currentLocalPosition.y;

            var rotatedX = currentX * Mathf.Cos(rotationAngleRadian) - currentY * Mathf.Sin(rotationAngleRadian);
            var rotatedY = currentX * Mathf.Sin(rotationAngleRadian) + currentY * Mathf.Cos(rotationAngleRadian);

            transformToRotate.localPosition = new Vector2(rotatedX, rotatedY);
//            Debug.Log($"Position after rotation is: {transformToRotate.localPosition.ToString()}");
        }

        private bool RotateRight()
        {
            _shapeToMoveTransform.Rotate(0, 0, -90);
            return GameGrid.Instance.CanMove(_shapeToMoveTransform);
        }

        private void OnEnable()
        {
            Debug.Log("Controls Enabled...");
            controls.Enable();
        }

//        private void OnDisable()
//        {
//            Debug.Log("Controls Disabled...");
//            controls.Disable();
//        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Eya*_*yap 5

正如您所说,您无法再引用新生成的输入类。为了使其正常工作,我实例化了该类,并使用 SetCallbacks 方法,如下所示:

private MyInput _inputs;

public void Awake()
{
    _inputs = new MyInput();
}
Run Code Online (Sandbox Code Playgroud)

说实话,我不知道这是否是使用输入类的预期方式,但它确实有效。

编辑 :

从2.8预览版开始,自动生成界面。我只能推荐它,因为它非常容易使用,你只需要继承 IYourActionsSetNameActions 并添加回调即可。(此外,您必须启用/禁用操作集,但您应该能够在另一个脚本中执行此操作)

这是一个完整的基本示例,使用您的命名:

public class ShapeMover : MonoBehaviour, MyInput.IPlayerActions
{
    private MyInput _inputs;

    public void Awake()
    {
        _inputs = new MyInput();
        _inputs.Player.SetCallbacks(this);
    }

    public void OnEnable()
    {
        _inputs.Player.Enable();
    }

    public void OnDisable()
    {
        _inputs.Player.Disable();
    }

    public void OnMovement(InputAction.CallbackContext context)
    {
        Vector2 delta = context.ReadValue<Vector2>();
        transform.position += new Vector3(delta.x, 0, delta.y);
    }

    public void OnDrop(InputAction.CallbackContext context)
    {
        //TODO
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)