接着上一篇(http://www.cnblogs.com/zhouhuan/p/H5_tankgame2.html),这篇主要修复两个bug,第一,玩家按下方向键时,坦克的炮筒应该指向相应的方向,并向该方向移动,第二,坦克不能开出边界,上一节的代码坦克是可以开出边界的,这样显然是不行的。
 
  1. 修复第一个bug
  我们的思路是,给造坦克的函数里再传一个方向的参数,我们让"u", "d", "l", "r"分别表示上下左右,封装这样一个可以传方向的函数之后,我们在用户按下不同的键时传不同的参数进去,由于整个地板每隔100毫秒会刷新一次,那么这个函数就能以肉眼分辨不出来的速度,在用户按下键的一瞬间相应地生产出不同方向的坦克了。

  如下:
  1. //封装一个画坦克的函数,传两个参数x,y,分别代表左上角的横纵坐标
  2. //再增加一个参数dir来表示方向 上下左右分别传"u" "d" "l" "r"
  3. function drawTank(x,y,dir){
  4. var cxt = getCxt();
  5. switch(dir){
  6. case "u": //此时造一个向上的坦克
  7. cxt.fillStyle = "#542174";
  8. cxt.fillRect(x,y,20,65);
  9. cxt.fillRect(x+70,y,20,65);
  10. cxt.fillRect(x+23,y+10,44,50);
  11. cxt.fillStyle = "#FCB827";
  12. cxt.beginPath();
  13. cxt.arc(x+45,y+35,16,0,2*Math.PI,false);
  14. cxt.closePath();
  15. cxt.fill();
  16. cxt.strokeStyle = "#FCB827";
  17. cxt.lineWidth = "8.0";
  18. cxt.moveTo(x+45,y+35);
  19. cxt.lineTo(x+45,y-25);
  20. cxt.stroke();
  21. break;
  22. case "d": //此时造向下的坦克
  23. cxt.fillStyle = "#542174";
  24. cxt.fillRect(x,y,20,65);
  25. cxt.fillRect(x+70,y,20,65);
  26. cxt.fillRect(x+23,y+10,44,50);
  27. cxt.fillStyle = "#FCB827";
  28. cxt.beginPath();
  29. cxt.arc(x+45,y+35,16,0,2*Math.PI,false);
  30. cxt.closePath();
  31. cxt.fill();
  32. cxt.strokeStyle = "#FCB827";
  33. cxt.lineWidth = "8.0";
  34. cxt.moveTo(x+45,y+35);
  35. cxt.lineTo(x+45,y+95); //和向上造相比,只有炮筒需要改变
  36. cxt.stroke();
  37. break;
  38. case "l": //此时造向左的坦克
  39. cxt.fillStyle = "#542174";
  40. cxt.fillRect(x,y,65,20); //和向上造坦克相比,画第一个矩形时长宽互换即可
  41. cxt.fillRect(x,y+70,65,20); //向左的坦克,注意坐标之间的转换即可,以下类似不再一一解释
  42. cxt.fillRect(x+10,y+23,50,44);
  43. cxt.fillStyle = "#FCB827";
  44. cxt.beginPath();
  45. cxt.arc(x+35,y+45,16,0,2*Math.PI,false);
  46. cxt.closePath();
  47. cxt.fill();
  48. cxt.strokeStyle = "#FCB827";
  49. cxt.lineWidth = "8.0";
  50. cxt.moveTo(x+35,y+45);
  51. cxt.lineTo(x-25,y+45);
  52. cxt.stroke();
  53. break;
  54. case "r":
  55. cxt.fillStyle = "#542174";
  56. cxt.fillRect(x,y,65,20); //和造向左的坦克类似,只要改动炮筒即可向右
  57. cxt.fillRect(x,y+70,65,20);
  58. cxt.fillRect(x+10,y+23,50,44);
  59. cxt.fillStyle = "#FCB827";
  60. cxt.beginPath();
  61. cxt.arc(x+35,y+45,16,0,2*Math.PI,false);
  62. cxt.closePath();
  63. cxt.fill();
  64. cxt.strokeStyle = "#FCB827";
  65. cxt.lineWidth = "8.0";
  66. cxt.moveTo(x+35,y+45);
  67. cxt.lineTo(x+95,y+45);
  68. cxt.stroke();
  69. }
  70. }
  和之前不同的是,我们增加了一个switch语句,用来判断传进来的方向,然后将不同的画坦克的动作放进不同的case分支里。看起来代码量很大,但其实都是从向上画的代码改过来的,难度不大,具体一些的说明都写在了注释里。
  接下来我们给myTank这个对象增加一个属性direction,用来确定坦克的方向,初始的时候我们让它等于"u",画一个向上的坦克。
  相应地,造坦克的时候多传一个参数进去就可以了:
  1. drawTank(myTank.x,myTank.y,myTank.direction);
  再接着我们要做的就是在玩家按下不同的键时响应的改变方向就可以了:
  1. window.onkeydown = function(eve){
  2. switch(eve.keyCode){
  3. case 38:
  4. case 87:
  5. myTank.y -= myTank.step; //Y坐标减小向上移动
  6. myTank.direction = "u"; //改变成向上的方向
  7. break;
  8. case 40:
  9. case 83:
  10. myTank.y += myTank.step; //Y坐标增加向下移动
  11. myTank.direction = "d"; //改变为向下的方向
  12. break;
  13. case 37:
  14. case 65:
  15. myTank.x -= myTank.step; //X坐标减小向左移动
  16. myTank.direction = "l"; //改变为向左的方向
  17. break;
  18. case 39:
  19. case 68:
  20. myTank.x += myTank.step; //X坐标增加向右移动
  21. myTank.direction = "r"; //改变为向右的方向
  22. }
  23. };
  不过,我们最好再做进一步的封装,首先给myTank对象增加一些方法:
  1. myTank.turnUp = function(){
  2. myTank.y -= myTank.step;
  3. myTank.direction = "u";
  4. };
  5. myTank.turnDown = function(){
  6. myTank.y += myTank.step;
  7. myTank.direction = "d";
  8. };
  9. myTank.turnLeft = function(){
  10. myTank.x -= myTank.step;
  11. myTank.direction = "l";
  12. };
  13. myTank.turnRight = function(){
  14. myTank.x += myTank.step;
  15. myTank.direction = "r";
  16. };
  再根据玩家的操作进行相应地调用:
  1. window.onkeydown = function(eve){
  2. switch(eve.keyCode){
  3. case 38:
  4. case 87:
  5. myTank.turnUp();
  6. break;
  7. case 40:
  8. case 83:
  9. myTank.turnDown();
  10. break;
  11. case 37:
  12. case 65:
  13. myTank.turnLeft();
  14. break;
  15. case 39:
  16. case 68:
  17. myTank.turnRight();
  18. }
  19. };
  给myTank对象添加的属性和方法多了之后这样看着很烦,可读性也比较差,我们有必要对它进行改动:
  1. var myTank = {
  2. x : 350,
  3. y : 400,
  4. step : 3,
  5. direction : "u",
  6. turnUp : function(){
  7. myTank.y -= myTank.step;
  8. myTank.direction = "u";
  9. },
  10. turnDown : function(){
  11. myTank.y += myTank.step;
  12. myTank.direction = "d";
  13. },
  14. turnLeft : function(){
  15. myTank.x -= myTank.step;
  16. myTank.direction = "l";
  17. },
  18. turnRight : function(){
  19. myTank.x += myTank.step;
  20. myTank.direction = "r";
  21. }
  22. };
  嗯,这样看着舒服多了。
 
  2.解决第二个bug
  我们的思路是,重新封装一下turnUp turnDown turnLeft turnRight这几个方法,给里面加上判断条件,如果判断为将要出界,那么不再执行改变坐标的代码,这样,坦克就只能在可视区内运动了。具体判断方法如下:
  坦克如果将要开出上面的边界,那么开出去之前它一定是向上的,此时(myTank.x, myTank.y)点是坦克左边履带左上角的点,我们暂且将这个点称为原点,再回头看一下向上画坦克时的代码:cxt.arc(x+45,y+35,16,0,2*Math.PI,false); 可知圆盖中心点(也就是炮筒的起点)和原点之间的纵向距离为35,又易知炮筒的总长度为60(cxt.moveTo(x+45,y+35); cxt.lineTo(x+45,y-25);),那么显然炮筒的起点与原点的纵向距离就是25,所以我们就可以这样判断,坦克的y坐标减去25大于等于0的时候我们再让坦克向上动起来,转化成代码就是:
  1. var myTank = {
  2. turnUp : function(){
  3. if((myTank.y-25) >= 0){
  4. myTank.y -= myTank.step;
  5. myTank.direction = "u";
  6. }
  7. }
  8. };
  这时候,坦克就不会再超出上面的边界了。
  坦克向下移动的时候,我们把坦克履带的长度考虑进去就可以了,如下:
  1. var myTank = {
  2. turnDown : function(){
  3. if((myTank.y+90) <= 500){
  4. myTank.y += myTank.step;
  5. myTank.direction = "d";
  6. }
  7. }
  8. };
  同理坦克向左和向右移动时如下:
  1. var myTank = {
  2. turnLeft : function(){
  3. if((myTank.x-25) >= 0){
  4. myTank.x -= myTank.step;
  5. myTank.direction = "l";
  6. }
  7. },
  8. turnRight : function(){
  9. if((myTank.x+90) <= 800){
  10. myTank.x += myTank.step;
  11. myTank.direction = "r";
  12. }
  13. }
  14. };
  3. 补充说明
  上一节的代码其实存在一定的问题,就是每一次更新战场的时候都会去getCxt()一下,清理了战场之后后面又会drawTank(), drawTank()里面又有getCxt(),这样就会重复不断地获取同一个节点,而且更新战场的函数每100毫秒执行一次,虽然不会影响功能,但是会影响到游戏的性能,我们可以定义一个变量专门用来存放获取到的绘图环境,后面需要的时候直接用就好了。
 
  4. 最终代码
  1. //封装一个获取绘图环境的函数
  2. function getCxt(){
  3. var myCanvas = document.getElementById('floor'),
  4. myContext = myCanvas.getContext('2d');
  5. return myContext;
  6. }
  7. //为了防止重复地获取节点影响性能,我们将获取到的绘图环境(也就是画笔对象)存起来
  8. var oCxt = getCxt();
  9.  
  10. //封装一个画坦克的函数,传两个参数x,y,分别代表左上角的横纵坐标
  11. //再增加一个参数dir来表示方向 上下左右分别传"u" "d" "l" "r"
  12. function drawTank(x,y,dir){
  13. switch(dir){
  14. case "u": //此时造一个向上的坦克
  15. oCxt.fillStyle = "#542174";
  16. oCxt.fillRect(x,y,20,65);
  17. oCxt.fillRect(x+70,y,20,65);
  18. oCxt.fillRect(x+23,y+10,44,50);
  19. oCxt.fillStyle = "#FCB827";
  20. oCxt.beginPath();
  21. oCxt.arc(x+45,y+35,16,0,2*Math.PI,false);
  22. oCxt.closePath();
  23. oCxt.fill();
  24. oCxt.strokeStyle = "#FCB827";
  25. oCxt.lineWidth = "8.0";
  26. oCxt.moveTo(x+45,y+35);
  27. oCxt.lineTo(x+45,y-25);
  28. oCxt.stroke();
  29. break;
  30. case "d": //此时造向下的坦克
  31. oCxt.fillStyle = "#542174";
  32. oCxt.fillRect(x,y,20,65);
  33. oCxt.fillRect(x+70,y,20,65);
  34. oCxt.fillRect(x+23,y+10,44,50);
  35. oCxt.fillStyle = "#FCB827";
  36. oCxt.beginPath();
  37. oCxt.arc(x+45,y+35,16,0,2*Math.PI,false);
  38. oCxt.closePath();
  39. oCxt.fill();
  40. oCxt.strokeStyle = "#FCB827";
  41. oCxt.lineWidth = "8.0";
  42. oCxt.moveTo(x+45,y+35);
  43. oCxt.lineTo(x+45,y+95); //和向上造相比,只有炮筒需要改变
  44. oCxt.stroke();
  45. break;
  46. case "l": //此时造向左的坦克
  47. oCxt.fillStyle = "#542174";
  48. oCxt.fillRect(x,y,65,20); //和向上造坦克相比,画第一个矩形时长宽互换即可
  49. oCxt.fillRect(x,y+70,65,20); //向左的坦克,注意坐标之间的转换即可,以下类似不再一一解释
  50. oCxt.fillRect(x+10,y+23,50,44);
  51. oCxt.fillStyle = "#FCB827";
  52. oCxt.beginPath();
  53. oCxt.arc(x+35,y+45,16,0,2*Math.PI,false);
  54. oCxt.closePath();
  55. oCxt.fill();
  56. oCxt.strokeStyle = "#FCB827";
  57. oCxt.lineWidth = "8.0";
  58. oCxt.moveTo(x+35,y+45);
  59. oCxt.lineTo(x-25,y+45);
  60. oCxt.stroke();
  61. break;
  62. case "r":
  63. oCxt.fillStyle = "#542174";
  64. oCxt.fillRect(x,y,65,20); //和造向左的坦克类似,只要改动炮筒即可向右
  65. oCxt.fillRect(x,y+70,65,20);
  66. oCxt.fillRect(x+10,y+23,50,44);
  67. oCxt.fillStyle = "#FCB827";
  68. oCxt.beginPath();
  69. oCxt.arc(x+35,y+45,16,0,2*Math.PI,false);
  70. oCxt.closePath();
  71. oCxt.fill();
  72. oCxt.strokeStyle = "#FCB827";
  73. oCxt.lineWidth = "8.0";
  74. oCxt.moveTo(x+35,y+45);
  75. oCxt.lineTo(x+95,y+45);
  76. oCxt.stroke();
  77. }
  78. }
  79.  
  80. //初始化一个对象myTank,用来存储一些属性和方法
  81. var myTank = {
  82. x : 350,
  83. y : 400,
  84. step : 3,
  85. direction : "u",
  86. turnUp : function(){
  87. if((myTank.y-25) >= 0){ //加判断条件防止开出边界
  88. myTank.y -= myTank.step;
  89. myTank.direction = "u";
  90. }
  91. },
  92. turnDown : function(){
  93. if((myTank.y+90) <= 500){
  94. myTank.y += myTank.step;
  95. myTank.direction = "d";
  96. }
  97. },
  98. turnLeft : function(){
  99. if((myTank.x-25) >= 0){
  100. myTank.x -= myTank.step;
  101. myTank.direction = "l";
  102. }
  103. },
  104. turnRight : function(){
  105. if((myTank.x+90) <= 800){
  106. myTank.x += myTank.step;
  107. myTank.direction = "r";
  108. }
  109. }
  110. };
  111.  
  112. //先画一个坦克出来
  113. drawTank(myTank.x,myTank.y,myTank.direction); //一开始先造一个向上的出来
  114.  
  115. //封装一个更新战场的函数
  116. function updateFloor(){
  117. oCxt.clearRect(0,0,800,500); //更新之前先清除画布
  118. drawTank(myTank.x,myTank.y,myTank.direction); //清除完之后重新造坦克,坦克要移动就必须实时地根据坐标重新来造
  119. }
  120.  
  121. //设置一个间歇调用的函数,每隔100ms更新一下战场
  122. setInterval(function(){
  123. updateFloor();
  124. },100);
  125.  
  126. //响应玩家的操作指令
  127. window.onkeydown = function(eve){
  128. switch(eve.keyCode){
  129. case 38:
  130. case 87:
  131. myTank.turnUp();
  132. break;
  133. case 40:
  134. case 83:
  135. myTank.turnDown();
  136. break;
  137. case 37:
  138. case 65:
  139. myTank.turnLeft();
  140. break;
  141. case 39:
  142. case 68:
  143. myTank.turnRight();
  144. }
  145. };

H5 canvas控制坦克移动2的更多相关文章

  1. H5 canvas控制坦克移动

    接着上一篇(http://www.cnblogs.com/zhouhuan/p/H5_tankgame.html),这一篇研究一下怎么响应玩家的操作让坦克进行相应的移动.   1. 了解keydown ...

  2. H5 canvas绘制出现模糊的问题

    在之前做移动端小游戏幸运转盘.九宫格转盘,使用到了 canvas ,也是第一次在项目中使用 canvas 来实现. 近期测试人员反应 canvas 绘制的内容太模糊,心想着用 canvas 绘制出来的 ...

  3. h5 canvas 小球移动

    h5 canvas 小球移动 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  4. h5 canvas 画图

    h5 canvas 画图 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  5. H5 canvas建造敌人坦克

      接着上一篇(http://www.cnblogs.com/zhouhuan/p/H5_tankgame3.html),这一篇建造敌人的坦克. 思路是,基于可扩展性和性能等方面的考虑,用构造函数改造 ...

  6. 使用H5 canvas画一个坦克

      具体步骤如下:   1. 首先做出绘图区,作为坦克的战场   <canvas id="floor" width="800px" height=&quo ...

  7. H5坦克大战之【玩家控制坦克移动2】

    周一没有看圣诞大战,这几天比较忙也没有看赛后的报道,今天就先不扯NBA,随便扯扯自己.昨天在电脑里找东西的时候翻到以前兼职健身教练时的照片,思绪一下子回到学生时代,脑子久久换不过来.现在深深觉得健身和 ...

  8. H5坦克大战之【玩家控制坦克移动】

    自从威少砍下45+11+11的大号三双之后,网上出现了各种各样的神级段子,有一条是这样的: 威少:Hey,哥们,最近过得咋样! 浓眉:对方开启了好友验证,请先添加对方为好友 威少:...... JRS ...

  9. H5 canvas 绘图

    H5的canvas绘图技术   canvas元素是HTML5中新添加的一个元素,该元素是HTML5中的一个亮点.Canvas元素就像一块画布,通过该元素自带的API结合JavaScript代码可以绘制 ...

随机推荐

  1. mysql常见的错误码

    Mysql错误代码 Mysql错误代码分为两部分,老版本一部分,4.1版本为新的部分 第一部分: mysql的出错代码表,根据mysql的头文件mysql/include/mysqld_error.h ...

  2. MacBook Pro Retina 安装WIN7 - 对抗模糊及其它

    最近对虚拟机里的WIN7受够了,把整个虚拟机都删了,准备装双系统. 安装过程还是很简单的,网上教程一大堆,就是通过MAC OS X自带的BootCamp工具来管理整个安装过程,我是用外置光驱安装的,没 ...

  3. pta习题集5-16 地下迷宫探索

    地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式.地道网是房连房.街连街.村连村的地下工事,如下图所示. 我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智. ...

  4. Code Forces 149DColoring Brackets(区间DP)

     Coloring Brackets time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  5. CH1301 邻值查找【set应用】

    1301 邻值查找 0x10「基本数据结构」例题 描述 给定一个长度为 n 的序列 A,A 中的数各不相同.对于 A 中的每一个数 A_i,求:min(1≤j<i) ⁡|A_i-A_j|以及令上 ...

  6. 如何在chrome上开启WebGL功能和判断目前浏览器是否支持

        1.开启方式: 第一种:打开cmd,切换到Chorme的安装目录,敲入chrome.exe --enable -webgl,回车就会打开一个chrome浏览器窗口: 第二种:找到Chrome浏 ...

  7. redis cluster 集群畅谈(三) 之 水平扩容、slave自动化迁移

    上一篇http://www.cnblogs.com/qinyujie/p/9029522.html, 主要讲解 实验多master写入.读写分离.实验自动故障切换(高可用性),那么本篇我们就来聊了聊r ...

  8. django如何防止csrf(跨站请求伪造)

    什么是CSRF 下面这张图片说明了CSRF的攻击原理: Django中如何防范CSRF Django使用专门的中间件(CsrfMiddleware)来进行CSRF防护.具体的原理如下: 1.它修改当前 ...

  9. 大话https演化过程(对称加密、非对称加密、公钥、私钥、数字签名、数字证书)

    大话https演化过程(包括概念:对称加密.非对称加密.公钥.私钥.数字签名.数字证书.https访问全过程)   在网络上发送数据是非常不安全的,非常容易被劫持或是被篡改,所以每次定向发送数据你都可 ...

  10. 设置XShell快捷键 复制粘贴 并禁用智能选择

    设置XShell快捷键 复制粘贴 并禁用智能选择 1打开选项 2键盘和鼠标->打开编辑 3新建 组合键 Ctrl+C 类型:菜单 ->操作 [编辑]复制  [编辑]粘贴 4选中 ctrl+ ...