返回目录

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<len;i++){                keydown_callbacks[keyName][i]();

            }

        }if(keydown_callbacks["allKeys"]){for(var i=0,len=keydown_callbacks["allKeys"].length;i<len;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<len;i++){                keydown_callbacks[keyName][i]();

            }

        }if(keydown_callbacks["allKeys"]){for(var i=0,len=keydown_callbacks["allKeys"].length;i<len;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<len;i++){                keyup_callbacks[keyName][i]();

            }            }if(keyup_callbacks["allKeys"]){for(var i=0,len=keyup_callbacks["allKeys"].length;i<len;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<len;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

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

  1. html 游戏 精灵,HTML5游戏框架cnGameJS开发实录-精灵对象篇

    返回目录 1.什么是精灵对象(sprite)? 所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象.在cnGameJS框架中,精灵对象如下几个特点: 1.添加 ...

  2. 【CSON原创】HTML5游戏框架cnGameJS开发实录(精灵对象篇)

    返回目录 1.什么是精灵对象(sprite)? 所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象.在cnGameJS框架中,精灵对象如下几个特点: 1.添加 ...

  3. 【CSON原创】HTML5游戏框架cnGameJS开发实录

    cnGameJS是本人开发的一个基于HTML5的游戏框架,包括资源加载,碰撞检测,动画等模块.本系列文章主要介绍各个模块的开发流程,以及附上两个使用该框架进行开发的游戏demo. 目录: 1.核心函数 ...

  4. javascript+HTMl5游戏下载,开发一个都能月薪上万!舅服你

    HTML5时代已经到来许久了,你是否已经掌握了那么一点呢?今天小编给大家讲讲h5的折叠多设备.跨平台特性, 即用HTML5制作游戏.相比flash,HTML5更加灵活方便,随着浏览器技术的不断升级,H ...

  5. 推荐25款很棒的 HTML5 前端框架和开发工具【下篇】

    快速,安全,响应式,互动和美丽,这些优点吸引更多的 Web 开发人员使用 HTML5.HTML5 有许多新的特性功能,允许开发人员和设计师创建应用程序和网站,带给用户桌面应用程序的速度,性能和体验. ...

  6. Phaser开源2d引擎 javascript/html5游戏框架

    功能特点(Features) 易维护代码(Easy Asset Loading) Phaser可以加载图片,音频文件,数据文件,文本文件和自动解析精灵图和纹理地图集数据(出口纹理封隔器或Flash C ...

  7. HTML5游戏开发经验及开发工具分享

    当你开发基于HTML5的游戏时,你有很多选择.使用什么样的编辑器?是否用到Canvas 2d.WebGL?采用什么样的呈现框架和游戏引擎?这些选择大部分由开发者的个人经验和游戏将要发布的平台决定. 幸 ...

  8. Html5游戏框架createJS组件--EaselJS

    CreateJS库是一款HTML5游戏开发的引擎,是一套可以构建丰富交互体验的HTML5游戏的开源工具包,旨在降低HTML5项目的开发难度和成本,让开发者以熟悉的方式打造更具现代感的网络交互体验. 掌 ...

  9. Phaser开源2d引擎 html5游戏框架中文简介

    功能特点(Features) 易维护代码(Easy Asset Loading) Phaser可以加载图片,音频文件,数据文件,文本文件和自动解析精灵图和纹理地图集数据(出口纹理封隔器或Flash C ...

最新文章

  1. slice(),substring()和substr()的异同
  2. docker 限制cpu使用率
  3. android登录窗口——基础编
  4. 牛客 - umi和弓道(几何+贪心)
  5. git reset 回退以前某个版本_远程仓库版本回退方法--Git(二)
  6. 【原】Spark中Master源码分析(一)
  7. JMeter学习笔记——数据库压力测试(JDBC Request)
  8. python多线程刷网站流量(含ip代理池文档,可制作成exe文件挂服务器代刷)
  9. 【编程算法】跳跃游戏ⅠⅡⅢ(Python解法)
  10. 中国书法与传统文化的关系
  11. 【视频编码】【Vue】【明星开源项目】| Chat · 预告
  12. 什么是DNS缓存投毒?有哪些危害?
  13. ROS学习笔记9 —— launch文件
  14. 计算机二级wps知识点,计算机二级MS office和WPS office如何备考?
  15. HiveSql常用的时间维度计算方法(月初、月末、周几)及时间维度 表生成
  16. C语言中abs和fabs的区别
  17. 用c语言实现字母排列组合,C语言字母排列组合的实现.doc
  18. 树立正确的金钱观---《富爸爸,穷爸爸》
  19. 在日本,虚拟人都能赚百万美元了
  20. 设置浏览器的下载模式

热门文章

  1. mysql cert_Mysql使用SSL连接
  2. 计算机接口与通信技术考试题,全国2010年10月自学考试计算机通信接口技术试题...
  3. python3程序下载安装_程序猿的语言,Python 3.7.0下载安装
  4. Python,OpenCV中的K近邻(knn K-Nearest Neighbor)及改进版的K近邻
  5. 使用OpenCV和Python高效计算视频的总帧数
  6. GitHub开源的AI下五子棋(基于博弈树极大极小值alpha-beta剪枝搜索)
  7. kset_register
  8. 数据结构与算法(6-4)线索二叉树
  9. gitlab如何克隆项目到本地进行开发,如何让webstorm项目右键菜单出现Git子菜单,右下角出现Matser分支
  10. eclipse保存自动组织导入、删除不必要的导入、格式化代码