2021SC@SDUSC
本次代码分析观察主要涉及InputDevice.h和VirtualInput.h两大文件,他们是输入设备和虚拟输入的头文件。
首先是VirtualInput.h:
可以看到主要是对“friendly name”这一行为名称的定义和操作,简而言之就是对一些自定义的操作进行绑定和设置,在之后的编辑行为中有所涉及。
/// <summary>
/// Maps keyboard, controller, or mouse inputs to a "friendly name" that will later be bound to continuous game behavior, such as movement. The inputs mapped in AxisMappings are continuously polled, even if they are just reporting that their input value.
/// </summary>
API_STRUCT() struct ActionConfig
{
DECLARE_SCRIPTING_TYPE_MINIMAL(ActionConfig);
/// <summary>
/// The action "friendly name" used to access it from code.
/// </summary>
API_FIELD(Attributes="EditorOrder(0)")
String Name;
/// <summary>
/// The trigger mode. Allows to specify when input event should be fired.
/// </summary>
API_FIELD(Attributes="EditorOrder(5)")
InputActionMode Mode;
/// <summary>
/// The keyboard key to map for this action. Use <see cref="KeyboardKeys.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(10)")
KeyboardKeys Key;
/// <summary>
/// The mouse button to map for this action. Use <see cref="MouseButton.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(20)")
MouseButton MouseButton;
/// <summary>
/// The gamepad button to map for this action. Use <see cref="GamepadButton.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(30)")
GamepadButton GamepadButton;
/// <summary>
/// Which gamepad should be used.
/// </summary>
API_FIELD(Attributes="EditorOrder(40)")
InputGamepadIndex Gamepad;
};
/// <summary>
/// Maps keyboard, controller, or mouse inputs to a "friendly name" that will later be bound to continuous game behavior, such as movement. The inputs mapped in AxisMappings are continuously polled, even if they are just reporting that their input value.
/// </summary>
API_STRUCT() struct AxisConfig
{
DECLARE_SCRIPTING_TYPE_MINIMAL(AxisConfig);
/// <summary>
/// The axis "friendly name" used to access it from code.
/// </summary>
API_FIELD(Attributes="EditorOrder(0)")
String Name;
/// <summary>
/// The axis type (mouse, gamepad, etc.).
/// </summary>
API_FIELD(Attributes="EditorOrder(10)")
InputAxisType Axis;
/// <summary>
/// Which gamepad should be used.
/// </summary>
API_FIELD(Attributes="EditorOrder(20)")
InputGamepadIndex Gamepad;
/// <summary>
/// The button to be pressed for movement in positive direction. Use <see cref="KeyboardKeys.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(30)")
KeyboardKeys PositiveButton;
/// <summary>
/// The button to be pressed for movement in negative direction. Use <see cref="KeyboardKeys.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(40)")
KeyboardKeys NegativeButton;
/// <summary>
/// Any positive or negative values that are less than this number will register as zero. Useful for gamepads to specify the deadzone.
/// </summary>
API_FIELD(Attributes="EditorOrder(50)")
float DeadZone;
/// <summary>
/// For keyboard input, a larger value will result in faster response time (in units/s). A lower value will be more smooth. For Mouse delta the value will scale the actual mouse delta.
/// </summary>
API_FIELD(Attributes="EditorOrder(60)")
float Sensitivity;
/// <summary>
/// For keyboard input describes how fast will the input recenter. Speed (in units/s) that output value will rest to neutral value if not when device at rest.
/// </summary>
API_FIELD(Attributes="EditorOrder(70)")
float Gravity;
/// <summary>
/// Additional scale parameter applied to the axis value. Allows to invert it or modify the range.
/// </summary>
API_FIELD(Attributes="EditorOrder(80)")
float Scale;
/// <summary>
/// If enabled, the axis value will be immediately reset to zero after it receives opposite inputs. For keyboard input only.
/// </summary>
API_FIELD(Attributes="EditorOrder(90)")
bool Snap;
};
接下来我们重点分析Input.cpp文件,它是对几乎所有input操作实际定义的代码类:
struct AxisEvaluation
{
float RawValue;
float Value;
float PrevKeyValue;
bool Used;
};
struct ActionData
{
bool Active;
uint64 FrameIndex;
ActionData()
{
Active = false;
FrameIndex = 0;
}
};
开始两个结构体分别代表了轴的值和动作的值,这两个值记录了游戏编辑时的一些定位。
class InputService : public EngineService
{
public:
InputService()
: EngineService(TEXT("Input"), -60)
{
}
void Update() override;
void Dispose() override;
};
InputService即输入服务实现类,是对之前分析过的引擎服务类中的输入服务的实现,包括update函数和dispose函数的重写。
void InputSettings::Apply()
{
Input::ActionMappings = ActionMappings;
Input::AxisMappings = AxisMappings;
}
将之前两个结构体的轴和行为信息传给变量,方便之后使用。
void InputSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
const auto actionMappings = stream.FindMember("ActionMappings");
if (actionMappings != stream.MemberEnd())
{
auto& actionMappingsArray = actionMappings->value;
if (actionMappingsArray.IsArray())
{
ActionMappings.Resize(actionMappingsArray.Size(), false);
for (uint32 i = 0; i < actionMappingsArray.Size(); i++)
{
auto& v = actionMappingsArray[i];
if (!v.IsObject())
continue;
ActionConfig& config = ActionMappings[i];
config.Name = JsonTools::GetString(v, "Name");
config.Mode = JsonTools::GetEnum(v, "Mode", InputActionMode::Pressing);
config.Key = JsonTools::GetEnum(v, "Key", KeyboardKeys::None);
config.MouseButton = JsonTools::GetEnum(v, "MouseButton", MouseButton::None);
config.GamepadButton = JsonTools::GetEnum(v, "GamepadButton", GamepadButton::None);
config.Gamepad = JsonTools::GetEnum(v, "Gamepad", InputGamepadIndex::All);
}
}
else
{
ActionMappings.Resize(0, false);
}
}
反串行化函数是十分重要的输入初始化设置函数,它包含对鼠标、gamepad、键盘按键等一些之前提到的预先设计好的标志位的输入信息进行以json格式的传入,代码逻辑简单,但是需要结合之前的代码才能比较清楚地理解这段代码作者的意图。
|