6-15 游戏键盘输入机制
6-15 晴
一、键盘输入机制
关键字:消息处理 消息分发 消息注册 逻辑集中 解耦。
键盘输入起始总是从键盘事件开始的,这是一个源头。
在特定的UI元素上面(这个和你采取的具体平台相关,但一般情况下都是一个UIElement),注册键盘输入事件和处理函数。
这里的秘密就在于这个处理函数,当然,你可以在处理函数中直接调用很键盘输入相关的游戏逻辑处理,比如UpKey Down ,Y 坐标增加,这就是一个按向上箭头,物体向上移动的效果。但这么做是不够好的。有几点原因:
其一,这种做法会让游戏的动画受限于了键盘输入的频率,难以控制,会很卡。这个我们后面会详细讲解。
其二,这种做法属于一种“硬编码”,键盘按下,物体移动,直接把一个游戏逻辑和一个硬输入连接在了一起,它们之间其实没有什么联系,这很不科学,也不柔和。
解决这个问题,有很多做法,下面我来讲讲在LLGame的机制下,是怎么样处理的。LLGame本身是一种基于消息的处理机制。
看一下图:
其实键盘处理的消息机制和游戏中其他的消息处理本质上说一样的,这也是消息处理的好处,统一的机制,不会让你陷入到不同复杂逻辑中,不断变换思维而穷于应付。
Step1:
首先你要准备好一个实体,这个实体能够接收带有键盘信息的消息,至于这个实体是作为键盘输入管理器,还是作为场景管理器,并没有一定之规,视乎游戏具体逻辑和个人思路而定。总之,需要有个地方集中收集键盘消息。
Step2:
根据具体游戏平台进行键盘处理事件注册,一般都是选择一个UIElement进行注册,例如在Flash平台上面,选择了一个DisplayObject进行键盘事件注册。在事件处理函数中,向刚才已经做好准备的实体(这个实体已经能够处理键盘消息)发送带有键盘信息的消息。
这个键盘管理器(或者场景管理器),收到消息后,进一步和游戏逻辑联系起来。比如这时候你仍然喜欢让精灵坐标向上,那么也恭喜你,你把这个事情和一条消息联系了起来,而不是一个硬输入。更合理的做法,是在键盘管理器收到消息后,进行初步的处理,然后根据具体情况,再一次进行消息分发,在更具体的实体哪里处理逻辑。(这时候那个实体应该已经注册好了消息处理函数)。
1 private static function InitKeyMouse():void 2 { 3 IME.enabled = false; //中文输入控制 4 AcceptStage.addEventListener(KeyboardEvent.KEY_DOWN, function (e:KeyboardEvent):void 5 { 6 MsgManager.SendMessage(new MsgId("KeyDownMsg", 0, SceneID,DataSource.MsgMins["KeyDown"], e.keyCode)); 7 }); 8 AcceptStage.addEventListener(KeyboardEvent.KEY_UP, function (e:KeyboardEvent):void 9 { 10 MsgManager.SendMessage(new MsgId("KeyUpMsg", 0, SceneID,DataSource.MsgMins["KeyUp"], e.keyCode)); 11 }); 12 }
在下面,我们谈谈鼠标输入。
二、鼠标输入机制
对于鼠标输入和键盘输入非常类似,但也有不同点:键盘输入的全局性更强,鼠标输入会针对某一个精灵(或者其他具体的东西)。根据这个特点,可以采取不同的做法。我在使用GPU的情况下使用Silverlight技术做2D游戏,因为整个画面都是贴图渲染,所以仍然采取的是将鼠标输入作为了一个整体,只有根UIElement注册,然后根据位置算出来鼠标在哪个精灵上面,再向此精灵发送消息,这样做,性能更高,结构简单;但在Flash平台下面,采取的是向每个精灵注册鼠标事件,这样实现起来更方便,不过在删除精灵实体的时候,需要把注册的事件也要清除,否则不断累积,造成性能低下。
/** * 根据实体ID,为VisualEnt实体的ImgContainer添加事件处理函数 * 所以请注意,这个方法限制在VisualEnt实体上面 */ public static function AddHandler(_id:int, _event:String, _handler:Function):void { var data:VisualEntData = DataCenter.GetData(_id); data.ImgContainer.addEventListener(_event, _handler); data.AddHandler(_event, _handler); }