我建议将 UI 输入映射到特定操作的逻辑分离到专用对象中。我们称它们为 Sensor 对象。不知道你的实现语言,我会对此很笼统,但你应该明白。
OperationSensor
+ OnKeyDown
+ OnKeyPress
+ OnKeyUp
+ OnLeftMouseDown
+ OnLeftMouseUp
+ OnNodeSelect
+ OnNodeDeselect
+ OnDragStart
+ OnDragStop
假设您有一个集中所有各种 UI 输入的中心类 UiInputManager。它使用特定于语言的机制来侦听键盘和鼠标输入。它还检测基本操作,例如检测鼠标是否被按下,然后移动,即逻辑“拖动”。
UiInputManager
// event listeners
+ keyboard_keydownHandler
+ keyboard_keyupHandler
+ mouse_leftdownHandler
+ mouse_rightdownHandler
// active sensor list, can be added to or removed from
+ Sensors
UiInputManager 不负责了解这些输入导致的操作。它只是以特定语言的方式通知其传感器。
foreach sensor in Sensors
sensor.OnDragStarted
或者,如果传感器侦听 UiInputManager 发出的逻辑事件
RaiseEvent DragStarted
您现在拥有的是将输入路由到 OperationSensor 子类的管道。每个 OperationSensor 都具有仅与单个操作相关的逻辑。如果它检测到操作的条件已经满足,那么它会创建适当的 Command 对象并将其传递回去。
// Ctrl + zooms in, Ctrl - zooms out
ZoomSensor : OperationSensor
override OnKeyDown
{
if keyDown.Char = '+' && keyDown.IsCtrlDepressed
base.IssueCommand(new ZoomCommand(changeZoomBy:=10)
elseif keyDown.Char = '-' && keyDown.IsCtrlDepressed
base.IssueCommand(new ZoomCommand(changeZoomBy:=-10)
}
我建议将命令对象从传感器传递到 UiInputManager。然后,管理器可以将它们传递给您的命令处理子系统。这使管理器有机会通知传感器操作已完成,允许它们在需要时重置其内部状态。
可以通过两种不同的方式处理多步操作。您可以在 SensorOperation 中实现内部状态机,也可以让“第 1 步”传感器创建“第 2 步”传感器并将其添加到活动传感器列表中,甚至可能将其从列表中删除。当“第 2 步”完成后,它可以重新添加“第 1 步”传感器并自行移除。