摘要
本文介绍Mover2.0中的输入处理机制,什么是输入命令上下文,如何通过上下文传递数据到Mover系统,以及如何自定义InputProducer以操控上下文。
介绍
不像CharacterMovementComponent(继承自PawnMovementComponent),你只需要调用AddInputVector即可驱动角色的移动。
在Mover中,移动输入的处理变得更加灵活,但其代价是用户代码会变得更加底层且复杂。
输入命令上下文
在Mover中,将用户输入传递到Mover系统的主要方式是通过InputCmdContext(输入命令上下文),后文简称为Context。
你可以将Context简单理解为是一个MoverData容器,可以通过蓝图/C++的API对其包含的数据进行增删改查。
这里的MoverData指的是:继承自FMoverDataStructBase的结构体,因此,必须通过C++新增MoverData类型。
Context可以容纳多个类型的输入参数结构体。
什么是InputProducer?
任意实现了MoverInputProducerInterface的UObject可以视为一个InputProducer。
MoverComponent内置一个ProduceInput函数,会在每帧调用。
同时还持有一个实现了MoverInputProducerInterface的对象的引用。上面的ProduceInput默认实现是通过下面的InputProducer对象来完成具体的输入处理逻辑。这样的设计,允许用户将输入逻辑从Mover系统中解耦。
默认情况下,MoverComponent会在Beginplay时,尝试从所属Actor或其组件树中查询实现了该接口的对象。
由于该对象是公开的,且蓝图可读写,你可以随时将任意实现了MoverInputProducerInterface的对象赋值给这个成员即可。
注意
尽管代码注释声称该对象是可选的,但当前Mover插件中的很多引擎代码并没有将其作为“
可选”对待。所以确保你始终提供InputProducer
用户只需要关心,如何将输入命令控制参数通过ProduceInput函数传递给InputCmdContext(输入命令上下文)。
实现MoverInputProducerInterface接口
蓝图和C++都可以实现MoverInputProducerInterface,
提示
ProduceInput会在每帧执行,但是你不一定需要每帧都往Context中添加数据。
官方案例
在MoverExample插件中,MoverExamplesCharacter这个Class实现了MoverInputProducerInterface,并演示了如何绑定InputAction,缓存Action的值,并在OnProduceInput中,根据配置,角色当前的状态,InputAction的值,构建了针对于CharacterDefaultInputs。你可以参考它以了解基本的用法,但请参考后文了解如何设计你的InputProducer。
设计你的InputProducer
我推荐通过Component来实现该接口,而不是通过Actor。基于组件开发能提升代码的可移植性。
使用单独的组件,实现业务的控制逻辑,通过组件的继承,从而实现不同的控制策略。
你可以通过你的组件衍生类,进行逻辑控制。
Loading Blueprint
Initializing BlueprintUE renderer...
构建输入控制系统
默认角色输入
Mover插件已经提供CharacterDefaultInputs,该结构体定义了用于控制MoverComponent的所需的基本输入参数。
简而言之,用户可以通过动态地构建FCharacterDefaultInputs结构体来提供输入参数,然后将其传入Context即可。
构建上层逻辑
这里就是你构建专属于项目的上层控制逻辑的地方。比如根据外部信息,决定是使用轴向运动还是靶向运动等。
桥接输入系统
无论InputProducer是通过Actor,还是Component实现,它都需要知道玩家实际的输入Action值,并根据这些Action值去构建最终的输入参数。
你可以在实现了MoverInputProducerInterface的组件(控制系统)上定义所需的InputAction值,并通过EnhancedAction事件回调,将这些值赋值到组件上,或者将其进一步封装。
Loading Blueprint
Initializing BlueprintUE renderer...
其他类型的输入
默认参数能够满足角色基本的控制需求,如移动方向,跳跃请求等。但具体的项目,一般还需要各种其他输入,如Dash,Crouch,等Ability输入。
这时候就需要新增继承自FMoverDataStructBase的结构体用于封装所需的输入参数,并将其加入Context。
在MoverExamples中,你就能看到一个示例Ability输入的案例。
处理输入
你有一些输入参数结构体,你也通过InputProducer将这些参数加入到了Context,接下来干什么?
接下来,你可以通过绑定MoverComponent上的OnPreSimulationTick事件,并在回调中去处理这些输入参数。并添加各种运动效果。
Loading Blueprint
Initializing BlueprintUE renderer...
底层细节
在引擎底层,MoverComponent上的ProduceInput由NetworkPrediction插件中的NetworkPredictionWorldManager进行调用。
它是一个世界子系统,随着世界的生命周期进行更新。我们会在以后的文章中更深入地去了解这一部分的内容。