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<InputManager>
{
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了。
网友评论