Curtwagner1984
Curtwagner1984

Reputation: 2088

Unity3d New Input System(2.8), can't reference Input Action in the editor

I've just updated to the new Input System from 2.7 to 2.8.

How the new Input System works is you create an input actions asset by going to Create-> Input Actions

Input Actions.

This creates an asset where actions can be mapped to keys. One then create a C# script from this asset and use it in their code. Which is what I did. I called the Asset MyInput.inputactions and the C# script is MyInput.cs

Asset and generated C# class

When you use the generated C# script this way you need to reference the asset in your script. However, after the update, it seems this is impossible to do from the editor. When I define a public MyInput variable in my class, like so:

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;
}

It isn't exposed in the inspector:

enter image description here

And I get an obvious NullReferenceExceptionerror when I try to access the controls variable.

Am I doing something wrong?

How can I reference the asset from the inspector? I have tried adding [SerializeField] to the public declaration, it didn't help.

I was following this video and it worked fine until I updated to a newer Input System version.

For reference, this is the full ShapeMover class:

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();
//        }
    }
}

Upvotes: 4

Views: 11978

Answers (1)

Eyap
Eyap

Reputation: 694

Just as you said, you can't reference the new generated input class anymore. To make it works, i instantiated the class, and use the SetCallbacks method, like this :

private MyInput _inputs;

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

Truth be told, i don't know if it's the intended way of using the input class, but it works.

EDIT :

Starting from the 2.8 preview, an interface is automatically generated. I can only recommend it, cause it's very easy to use, you just need to inherits from IYourActionsSetNameActions and add the callbacks. (Also, you have to enable / disable the actions set, but you should be able to do it in another script)

Here is a complete base example, using your naming :

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
    }

    // ...
}

Upvotes: 5

Related Questions