Unity3d Новая система ввода (2.8), не может ссылаться на действие ввода в редакторе - PullRequest
1 голос
/ 05 мая 2019

Я только что обновил систему ввода с 2,7 до 2,8.

Как работает новая система ввода, вы создаете актив действий ввода, перейдя в Create-> Input Actions

Input Actions.

Это создает актив, где действия могут быть сопоставлены с ключами. Затем создайте сценарий C # из этого ресурса и используйте его в своем коде. Что я и сделал. Я назвал Актив MyInput.inputactions, а сценарий C # - MyInput.cs

Asset and generated C# class

Когда вы используете сгенерированный сценарий C # таким образом, вам нужно сослаться на asset в вашем сценарии. Однако после обновления кажется, что это невозможно сделать из редактора. Когда я определяю переменную 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] в публичную декларацию, это не помогло.

Я следил за этим видео, и оно работало нормально, пока я не обновился до более новой версии Системы ввода.

Для справки, это полный класс 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 Ответ

1 голос
/ 06 мая 2019

Как вы сказали, вы больше не можете ссылаться на новый сгенерированный входной класс. Чтобы заставить его работать, я создал экземпляр класса и использовал метод SetCallbacks, например:

private MyInput _inputs;

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

По правде говоря, я не знаю, является ли это предполагаемым способом использования входного класса, но он работает.

РЕДАКТИРОВАТЬ:

Начиная с предварительного просмотра 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
    }

    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...