InputSystem和UGUI写法

InputSystem是Unity新的输入系统,但在和UGUI结合使用的时候会出现问题。

说一下现在项目中的做法,GamePlay的输入来源是封装在InputManager中,InputManager从InputSystem中去获取感兴趣的InputDevice收集的事件(信号),然后派发给游戏逻辑,或者调用游戏逻辑。这种做法是把输入和GamePlay的解耦开了。

但是在UI这边,需要挂InputSystem组件(OnScreenContrl、OnScreenButton……),InputSystem组件相当于是游戏逻辑的输入源,不应该随着UI变化,换句话说无论UI怎么变化,游戏逻辑输入源都不该变化,输入源只会跟gameplay需求而变化。

现在是和Button挂在一起,当UI隐藏的时候,InputSystem组件就会进行销毁,再显示的时候就会初始化,而InputSystem本身设计上应该是一个偏底层的系统,不应该随着UI显示和隐藏,它的生命周期应该是游戏的生命周期(或者小一点的级别)。

InputSystem组件频繁的初始化和销毁,一方面性能会有问题,另一方面会出现事件被莫名打断的情况(OnEnable可能会重置数据)。

如下一种基于InputSystem的代码设计,我觉得比较合理。


InputManager设计.png
  • InputSystem:统一各种输入,包括不同硬件和UI。
  • InputManager:获取感兴趣的输入信号,派发或调用gameplay。
  • 硬件输入:InputSystem封装好了硬件输入,只需要配置就行。
  • UI:触摸或点击或拖拽屏幕按钮等输入。
  • 其它逻辑:有些逻辑可能需要模拟输入。

下面有个简单封装例子
InputSystem中按输入值类型分为三种:Button(Vector1),Vector2,Vector3
如下包装:

public class InputVector1Wrap:OnScreenControl
    {
        [InputControl( layout = "Button" )]
        [SerializeField]
        private string _controlPath;

        protected override string controlPathInternal
        {
            get => _controlPath;
            set => _controlPath = value;
        }

        public void SendValueToControl( float f )
        {
            base.SendValueToControl( f );
        }
    }
public class InputVector2Wrap:OnScreenControl
    {
        [InputControl( layout = "Vector2" )]
        [SerializeField]
        private string _controlPath;

        protected override string controlPathInternal
        {
            get => _controlPath;
            set => _controlPath = value;
        }

        public void SendValueToControl( Vector2 v )
        {
            base.SendValueToControl( v );
        }
    }
public class InputVector3Wrap:OnScreenControl
    {
        [InputControl( layout = "Vector3" )]
        [SerializeField]
        private string _controlPath;

        protected override string controlPathInternal
        {
            get => _controlPath;
            set => _controlPath = value;
        }

        public void SendValueToControl( Vector3 v )
        {
            base.SendValueToControl( v );
        }
    }
public class InputManager : ManagerBase
    {
        public InputVector2Wrap move;
        public InputVector1Wrap jump;
        public InputVector1Wrap skill0;
        public InputVector1Wrap skill1;
        public InputVector1Wrap skill2;
        
        public void InputMove(Vector2 v)
        {
            move.SendValueToControl(v);
        }

        public void InputJump(float i)
        {
            jump.SendValueToControl(i);
        }

        public void InputSkill0(float i)
        {
            skill0.SendValueToControl(i);
        }

        public void InputSkill1(float i)
        {
            skill1.SendValueToControl(i);
        }
        
        public void InputSkill2(float i)
        {
            skill2.SendValueToControl(i);
        }

        private void Update()
        {
            //从InputSystem中获取不同事件,分发到游戏逻辑中
        }
    }

UI这边的话,只需在点击技能按钮或者移动摇杆时调用

InputManager.Instance.InputMove(delta);
InputManager.Instance.InputJump(1);
InputManager.Instance.InputSkill0(1);
InputManager.Instance.InputSkill1(1);
InputManager.Instance.InputSkill2(1);

这样UI和GamePlay都不需要关心InputSystem了。

你可能感兴趣的:(InputSystem和UGUI写法)