首页 > 【CSON原创】HTML5游戏框架cnGameJS开发实录(外部输入模块篇)

【CSON原创】HTML5游戏框架cnGameJS开发实录(外部输入模块篇)

返回目录

1.为什么我们需要外部输入模块?

  在游戏中我们常常用到类似这样的操作:鼠标点击某位置,玩家对象移动到该位置,或者按鼠标方向键,玩家向不同方向移动,等等。这些操作无一不用与外部输入设备打交道。作为游戏的设计者,我们很需要在任何时候知道鼠标目前的位置,键盘的点击状况等,从而方便我们对游戏元素加以控制。因此作为一个游戏框架,外部输入模块也是必不可少的。

2.提供哪些功能,怎样使用?

  外部输入模块主要实现的功能就是动态记录鼠标相对于canvas的位置,以及记录键盘上哪些键是按下的,哪些键刚刚松开,并触发相应的回调函数。

  我们可以通过框架保存的两个字段获取鼠标当前在canvas的位置:

 

var x=cnGame.input.mouseX;

var y=cnGame.input.mouseY;



  由于canvas下的游戏编程模式是通过一个游戏循环来实现的帧动画(关于游戏循环请看:HTML5游戏框架cnGameJS开发实录(游戏循环篇)),因此单纯对键盘keyup与keydown的绑定,往往并不能达到期望效果,举个例子,我们如果想在键盘按下左键时使元素一直向左移动:

 

cnGame.input.onKeyDown("left",function(){ 

player.move(-10);

})

  我们会发现这种方法并不能很好的运用在帧动画的编程模型。由于当我们按着键盘左方向键时,其回调函数会不断触发,因此触发频率并不能和你的帧动画的频率一致(要么太快要么太慢,取决于你的帧频率),所以更好的选择是每次帧更新时,判断左键是否按下,如果是按下游戏元素就向左移动一定位置,这样游戏元素就成为帧动画的一部分,随着每次帧的更新而更新:

 

/*每次帧更新调用的函数*/

var update=function(){

cnGame.input.isPressed("left",function(){player.move(-10);})

}



3.代码实现

  首先看如何保持鼠标在canvas的位置。鼠标相对于canvas的位置,其实就是鼠标相对于页面的位置和canvas的位置之差。在之前的HTML5游戏框架cnGameJS开发实录(核心函数模块篇)里已经介绍过,在框架的初始化函数里,我们已经通过getCanvasPos获取到canvas在页面的位置,因此鼠标相对于canvas的位置可以如此计算: 

 

    /**

*记录鼠标在canvas内的位置

*
*/

var recordMouseMove=function(eve){

var pageX,pageY,x,y;

eve=cg.core.getEventObj(eve);

pageX = eve.pageX || eve.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft;

pageY = eve.pageY || eve.clientY + document.documentElement.scrollTop - document.documentElement.clientTop;

cg.input.mouseX=pageX-cg.x;

cg.input.mouseY=pageY-cg.y;



}

  之后再看看键盘输入的记录如何实现,我们需要一个数组,保存每个键的名值对(键名和键编码),以及一些对象,保存每个键对应的按下和松开的回调函数,还有最后一个对象,保存那些需要禁止默认行为的键名。(禁止键盘默认行为在游戏开发中很必要,可以防止玩家在操控时游戏对象时触发不必要的浏览器默认行为,例如滚动条滚动等)。

 首先是建立键名和键编码的字典:

    /**

*键盘按键编码和键名

*
*/

var k=[];

k[8] = "backspace"

k[9] = "tab"

k[13] = "enter"

k[16] = "shift"

k[17] = "ctrl"

k[18] = "alt"

k[19] = "pause"

k[20] = "capslock"

k[27] = "esc"

k[32] = "space"

k[33] = "pageup"

k[34] = "pagedown"

k[35] = "end"

k[36] = "home"

k[37] = "left"

k[38] = "up"

k[39] = "right"

k[40] = "down"

k[45] = "insert"

k[46] = "delete"



k[91] = "leftwindowkey"

k[92] = "rightwindowkey"

k[93] = "selectkey"

k[106] = "multiply"

k[107] = "add"

k[109] = "subtract"

k[110] = "decimalpoint"

k[111] = "divide"



k[144] = "numlock"

k[145] = "scrollock"

k[186] = "semicolon"

k[187] = "equalsign"

k[188] = "comma"

k[189] = "dash"

k[190] = "period"

k[191] = "forwardslash"

k[192] = "graveaccent"

k[219] = "openbracket"

k[220] = "backslash"

k[221] = "closebracket"

k[222] = "singlequote"



var numpadkeys = ["numpad1","numpad2","numpad3","numpad4","numpad5","numpad6","numpad7","numpad8","numpad9"]

var fkeys = ["f1","f2","f3","f4","f5","f6","f7","f8","f9"]

var numbers = ["0","1","2","3","4","5","6","7","8","9"]

var letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]

for(var i = 0; numbers[i]; i++) { k[48+i] = numbers[i] }

for(var i = 0; letters[i]; i++) { k[65+i] = letters[i] }

for(var i = 0; numpadkeys[i]; i++) { k[96+i] = numpadkeys[i] }

for(var i = 0; fkeys[i]; i++) { k[112+i] = fkeys[i] }

  有点长,不过其实没啥技术含量,就是方便我们以后知道某个编码的键名是什么。例如我们按下左键,那么流程就是:获取到左键的键盘编码->在字典中得到键名->在对象中通过键名获取到之前同样通过键名保存的处理程序,并执行。

  为键盘绑定处理程序的代码如下:

    /**

*记录键盘按下的键

*
*/

var recordPress=function(eve){

eve=cg.core.getEventObj(eve);

var keyName=k[eve.keyCode];

pressed_keys[keyName]=true;

if(keydown_callbacks[keyName]){

for(var i=0,len=keydown_callbacks[keyName].length;i
keydown_callbacks[keyName][i]();



}



}

if(keydown_callbacks["allKeys"]){

for(var i=0,len=keydown_callbacks["allKeys"].length;i
keydown_callbacks["allKeys"][i]();



}

}

if(preventDefault_keys[keyName]){

cg.core.preventDefault(eve);

}

}



  每个键的处理程序可以有多个,所以这里保存处理程序的对象保存的是一个数组。另外需要注意通过pressed_keys数组保存了按下的键(pressed_keys[keyName]=true;),就是为了方便实现之前说过的在帧更新中进行一致的参数更新(可以在每次update时通过isPressed(keyName)判断某个键是否按下)。  

  最后附上该输入模块所有源代码:

/**

*

*输入记录模块

*

*
*/

cnGame.register("cnGame.input",function(cg){



this.mouseX=0;

this.mouseY=0;

/**

*记录鼠标在canvas内的位置

*
*/

var recordMouseMove=function(eve){

var pageX,pageY,x,y;

eve=cg.core.getEventObj(eve);

pageX = eve.pageX || eve.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft;

pageY = eve.pageY || eve.clientY + document.documentElement.scrollTop - document.documentElement.clientTop;

cg.input.mouseX=pageX-cg.x;

cg.input.mouseY=pageY-cg.y;



}



cg.core.bindHandler(window,"mousemove",recordMouseMove);



/**

*被按下的键的集合

*
*/

var pressed_keys={};

/**

*要求禁止默认行为的键的集合

*
*/

var preventDefault_keys={};

/**

*键盘按下触发的处理函数

*
*/

var keydown_callbacks={};

/**

*键盘弹起触发的处理函数

*
*/

var keyup_callbacks={};





/**

*键盘按键编码和键名

*
*/

var k=[];

k[8] = "backspace"

k[9] = "tab"

k[13] = "enter"

k[16] = "shift"

k[17] = "ctrl"

k[18] = "alt"

k[19] = "pause"

k[20] = "capslock"

k[27] = "esc"

k[32] = "space"

k[33] = "pageup"

k[34] = "pagedown"

k[35] = "end"

k[36] = "home"

k[37] = "left"

k[38] = "up"

k[39] = "right"

k[40] = "down"

k[45] = "insert"

k[46] = "delete"



k[91] = "leftwindowkey"

k[92] = "rightwindowkey"

k[93] = "selectkey"

k[106] = "multiply"

k[107] = "add"

k[109] = "subtract"

k[110] = "decimalpoint"

k[111] = "divide"



k[144] = "numlock"

k[145] = "scrollock"

k[186] = "semicolon"

k[187] = "equalsign"

k[188] = "comma"

k[189] = "dash"

k[190] = "period"

k[191] = "forwardslash"

k[192] = "graveaccent"

k[219] = "openbracket"

k[220] = "backslash"

k[221] = "closebracket"

k[222] = "singlequote"



var numpadkeys = ["numpad1","numpad2","numpad3","numpad4","numpad5","numpad6","numpad7","numpad8","numpad9"]

var fkeys = ["f1","f2","f3","f4","f5","f6","f7","f8","f9"]

var numbers = ["0","1","2","3","4","5","6","7","8","9"]

var letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]

for(var i = 0; numbers[i]; i++) { k[48+i] = numbers[i] }

for(var i = 0; letters[i]; i++) { k[65+i] = letters[i] }

for(var i = 0; numpadkeys[i]; i++) { k[96+i] = numpadkeys[i] }

for(var i = 0; fkeys[i]; i++) { k[112+i] = fkeys[i] }



/**

*记录键盘按下的键

*
*/

var recordPress=function(eve){

eve=cg.core.getEventObj(eve);

var keyName=k[eve.keyCode];

pressed_keys[keyName]=true;

if(keydown_callbacks[keyName]){

for(var i=0,len=keydown_callbacks[keyName].length;i
keydown_callbacks[keyName][i]();



}



}

if(keydown_callbacks["allKeys"]){

for(var i=0,len=keydown_callbacks["allKeys"].length;i
keydown_callbacks["allKeys"][i]();



}

}

if(preventDefault_keys[keyName]){

cg.core.preventDefault(eve);

}

}

/**

*记录键盘松开的键

*
*/

var recordUp=function(eve){

eve=cg.core.getEventObj(eve);

var keyName=k[eve.keyCode];

pressed_keys[keyName]=false;

if(keyup_callbacks[keyName]){

for(var i=0,len=keyup_callbacks[keyName].length;i
keyup_callbacks[keyName][i]();



}

}

if(keyup_callbacks["allKeys"]){

for(var i=0,len=keyup_callbacks["allKeys"].length;i
keyup_callbacks["allKeys"][i]();



}

}

if(preventDefault_keys[keyName]){

cg.core.preventDefault(eve);

}

}

cg.core.bindHandler(window,"keydown",recordPress);

cg.core.bindHandler(window,"keyup",recordUp);



/**

*判断某个键是否按下

*
*/

this.isPressed=function(keyName){

return !!pressed_keys[keyName];

};

/**

*禁止某个键按下的默认行为

*
*/

this.preventDefault=function(keyName){

if(cg.core.isArray(keyName)){

for(var i=0,len=keyName.length;i
arguments.callee.call(this,keyName[i]);

}

}

else{

preventDefault_keys[keyName]=true;

}

}

/**

*绑定键盘按下事件

*
*/

this.onKeyDown=function(keyName,handler){

keyName=keyName||"allKeys";

if(cg.core.isUndefined(keydown_callbacks[keyName])){

keydown_callbacks[keyName]=[];

}

keydown_callbacks[keyName].push(handler);



}

/**

*绑定键盘弹起事件

*
*/

this.onKeyUp=function(keyName,handler){

keyName=keyName||"allKeys";

if(cg.core.isUndefined(keyup_callbacks[keyName])){

keyup_callbacks[keyName]=[];

}

keyup_callbacks[keyName].push(handler);



}

/**

*清除键盘按下事件处理程序

*
*/

this.clearDownCallbacks=function(keyName){

if(keyName){

keydown_callbacks[keyName]=[];

}

else{

keydown_callbacks={};

}



}

/**

*清除键盘弹起事件处理程序

*
*/

this.clearUpCallbacks=function(keyName){

if(keyName){

keyup_callbacks[keyName]=[];

}

else{

keyup_callbacks={};

}



}

});

转载于:https://www.cnblogs.com/Cson/archive/2012/02/14/2348684.html

更多相关: