Unity3d新输入系统(2.8),无法在编辑器中引用输入操作

时间:2019-05-05 13:45:48

标签: c# unity3d

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

新输入法的工作原理是,通过转到创建->输入操作

来创建输入操作资产

Input Actions

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

Asset and generated C# class

以这种方式使用生成的C#脚本时,您需要在脚本中引用资产。但是,更新后,似乎无法从编辑器中完成此操作。当我在课堂上定义 public 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;
}

它没有在检查器中显示:

enter image description here

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

我做错什么了吗?

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

我一直在跟踪this视频,直到我更新到更新的输入系统版本为止,它都工作正常。

作为参考,这是完整的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();
//        }
    }
}

1 个答案:

答案 0 :(得分:1)

就像您说的那样,您不能再引用新生成的输入类。 为了使其工作,我实例化了该类,并使用SetCallbacks方法,如下所示:

#include <map>
#include <set>
#include <vector>
#include <type_traits>

template <template <typename...> class C>
struct ttw
 { 
   template <typename ... Ts>
   constexpr ttw (C<Ts...> const &) 
    { }
 };

template <template <typename...> class... Templates>
struct template_pack
 {
   constexpr template_pack (ttw<Templates> const & ...)
    { }
 };

template <typename ... Ts>
constexpr auto make_template_pack (Ts && ... ts)
 { return template_pack{ttw{std::forward<Ts>(ts)}...}; }

int main ()
 { 
   template_pack tp1 {ttw{std::vector<int>{}},
                      ttw{std::set<long>{}},
                      ttw{std::map<char, short>{}}};

   auto tp2 { make_template_pack(std::vector<long>{},
                                 std::set<int>{},
                                 std::map<char, short>{}) };

   using t0 = template_pack<std::vector, std::set, std::map>;
   using t1 = decltype(tp1);
   using t2 = decltype(tp2);

   static_assert( std::is_same<t0, t1>::value );
   static_assert( std::is_same<t0, t2>::value );
 }

应该告诉我,我不知道这是否是使用输入类的预期方式,但是它有效。

编辑:

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

下面是使用您的命名的完整基本示例:

private MyInput _inputs;

public void Awake()
{
    _inputs = new MyInput();
}