这是非常简单的一个小游戏,js脚本甚至就只用200多行。

首先,确定下游戏规则。

1、我方战舰通过按空格丢出一枚鱼雷,鱼雷会以一定速度移动。
2、我方战舰可以通过左右按键来移动,但是不能上下移动。
3、敌方战舰不定时刷新,并按照一定速度向左移动。
4、一艘敌方战舰移出了画面外,判断为敌舰逃脱,HP-1 。
5、当HP归零游戏结束。
6、打中一艘敌方战舰获得1分。
7、每打中一艘敌方战舰就立刻刷新出新的战舰并且战舰刷新速度加快。
8、每逃脱一艘则刷新速度减慢。

大致先制定这么一套游戏规则。

先把html部分写出来。

  1. <canvas id="myCanvas" class="canvas" onClick="init()"></canvas>
  2. <div>分数:<span id="score"></span></div>
  3. <div>HP:<span id="HP"></span></div>

为了方便识别canvas 可以描个边。

  1. .canvas{
  2. border:1px solid #333;
  3. cursor:pointer;
  4. }

好了,接下来开始构思游戏。
因为是个简单的小游戏,可以用一些上个世纪的游戏布局。就是先将游戏画面拆分成一个一个小格子,这次制作的小游戏是12*6格子, 每格20*20像素。
图示:
sample.png

这样子只要通过比对鱼雷和敌方战舰的坐标就可以得出是否被炸到。

接下来脚本部分:

  1. var canvas=document.getElementById('myCanvas');//获取画布
  2. var scoreSpan = document.getElementById('score');//获取得分span
  3. var HPSpan = document.getElementById('HP');//获取HP的span
  4. var ctx=canvas.getContext('2d');//用于在画布上绘图的环境
  5. var blockSize = 20;//每格像素
  6. var ctxW = 12;//宽多少格
  7. var ctxH = 6;//高多少格
  8. canvas.width=ctxW*blockSize;//设定画布宽度,就是格子*每格像素
  9. canvas.height=ctxH*blockSize;//设定画布高度,就是格子*每格像素
  10. var emt = null;//用于存放定时器,用于更新敌舰坐标
  11. var boomT =null;//用于存放定时器,用于更新鱼雷坐标和状态
  12. var creatEm = null;//用于存放定时器,用于增加敌舰
  13. var flush = null;//用于存放定时器,用于刷新画布
  14.  
  15. var myShipX=0;//我方初始位置
  16. var emShip = [];//存放敌方数据
  17. var boom = [];//存放鱼雷数据
  18. var hard = 0;//难度(刷新速度,越小刷新越快单位毫秒)
  19. var score = 0;//得分
  20. var HP = 0;//HP
  21. var boomReload = true;//装弹是否完毕
  22.  
  23. function init(){//初始化
  24.  
  25. myShipX=3;//设定我方的初始位置
  26. emShip = [];//清空敌舰数据
  27. boom = [];//清空鱼雷数据
  28. hard = 3000;//初始化难度
  29. score = 0;//初始化分数
  30. HP = 50;//初始化HP
  31. boomReload = true;//装载鱼雷初始化
  32. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  33. creatEmShip();//创建敌舰
  34. paintMyShip();//绘制我方
  35. paintEmship();//绘制敌舰
  36. scoreSpan.innerHTML = String(score);//初始化计分板
  37. HPSpan.innerHTML = String(HP);//初始化HP剩余量
  38. clearInterval(emt);//清除更新敌舰坐标定时器
  39. clearInterval(boomT);//清除更新鱼雷坐标定时器
  40. clearInterval(creatEm);//清除创建敌舰定时器
  41. clearInterval(flush);//清除刷新画布定时器
  42. emt = setInterval(function(){//每400毫秒敌舰向左移动一次
  43. emShipMove();
  44. },400);
  45. boomT = setInterval(function(){//每200毫秒鱼雷向下移动一次
  46. boomMove();
  47. },200);
  48. creatEm = setInterval(function(){//根据难度创建敌舰
  49. creatEmShip();
  50. },hard);
  51. flush = setInterval(function(){//100毫秒刷新画布
  52. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  53. paintBoom();//绘制鱼雷
  54. paintEmship();//绘制敌舰
  55. paintMyShip();//绘制我方
  56. boomEmship();//判断是否炸中敌舰
  57. },100);
  58. }
  59. function paintMyShip(){//绘制我方
  60. var shipX = (myShipX-1)*blockSize;//设定我方船只的X坐标,因为左边是从(0,0)开始,格子定为1开始所以-1
  61. ctx.fillStyle="#0075a9";//设定我方颜色
  62. ctx.fillRect(shipX+2,blockSize-10,blockSize-4,blockSize-10);//填充方块,因为不想团一起并没有画正方形。
  63. }
  64. function creatEmShip(){//随机出现敌舰
  65. var Y = Math.floor(Math.random()*(ctxH-2) + 1);//高度一共有6个格子,出去丢雷的格子和我方的格子就是6-2,然后就随机从1-4中生成随机数
  66. emShip.push([blockSize*ctxW,Y]);//给敌舰数据添加敌舰坐标
  67. }
  68. function paintEmship(){//绘制敌舰
  69. for(var i=0;i<emShip.length;i++){//循环敌舰数据
  70. var emShipX = emShip[i][0];//保存敌舰X坐标
  71. var emShipY = (emShip[i][1]+1)*blockSize;//保存敌舰Y坐标,因为Y是1-4的所在格子,所以要*每格像素来计算出像素坐标
  72. ctx.fillStyle="#e60012";//设定敌舰颜色
  73. ctx.fillRect(emShipX+2,emShipY,blockSize-4,blockSize-10);//填充敌舰方块
  74. }
  75. }
  76. function emShipMove(){//移动敌舰
  77. for(let i=0;i<emShip.length;i++){//循环敌舰数据
  78. var X = emShip[i][0]-blockSize;//敌舰X坐标向左移动一个格子
  79. emShip[i][0] = X;//重新写入X坐标
  80. }
  81. removeEmShip();//清除多余的敌舰(画布外)
  82. }
  83. function addBoom(){//增加鱼雷
  84. if(boomReload){//判断是否还在装弹
  85. var boomX = (myShipX-1)*blockSize;//计算出鱼雷的初始位置,根据我方所在的X坐标
  86. boom.push([boomX,blockSize,true]);//设定鱼雷的X坐标,Y坐标因为是第二格直接就是格子的高度,true为正在投雷
  87. boomReload = false;//开始装弹
  88. var boomT = setTimeout(function(){
  89. boomReload = true;//800毫秒后装弹完毕
  90. },800);
  91. }
  92. }
  93. function paintBoom(){//绘制鱼雷
  94. for(let i=0;i<boom.length;i++){//循环鱼雷数据
  95. var boomX = boom[i][0];//保存鱼雷X坐标
  96. var boomY = boom[i][1];//保存鱼雷Y坐标
  97. ctx.fillStyle="#6b6b6b";//设定鱼雷颜色
  98. ctx.fillRect(boomX+7,boomY,blockSize-14,blockSize-10);//填充鱼雷方块
  99. }
  100. }
  101. function boomMove(){//鱼雷移动
  102. for(let i=0;i<boom.length;i++){//循环鱼雷数据
  103. if(boom[i][2]){
  104. boom[i][2] = false;//判断是否正在投雷,如果正在投弹则将其改变为投雷完毕状态
  105. }else{
  106. var Y = boom[i][1]+blockSize;//如果不是正在透雷,则Y坐标增加1格
  107. boom[i][1] = Y//重新写入Y坐标
  108. }
  109. }
  110. removeBoom();//清除多余的鱼雷(画布外)
  111. }
  112. function removeBoom(){//移除鱼雷
  113. for(let i=0;i<boom.length;i++){//循环鱼雷数据
  114. var Y = boom[i][1];//保存鱼雷Y坐标
  115. if(Y>ctxH*blockSize){
  116. boom.splice(i,1);//如果已经超过画布就删除
  117. }
  118. }
  119. }
  120. function removeEmShip(){//超出范围删除敌舰并且HP-1
  121. for(let i=0;i<emShip.length;i++){//循环敌舰数据
  122. var X = emShip[i][0];//储存敌舰X坐标
  123. if(X<0){//如果已经在画布外
  124. minusHP();//减HP
  125. emShip.splice(i,1);//删除敌舰
  126. hard = hard+50;//难度降低50
  127. if(hard>=3000){
  128. hard=3000;//如果难度已经是3000了则保持3000
  129. }
  130. }
  131. }
  132. }
  133. function boomEmship(){//判定炸了
  134. for(let i=0;i<boom.length;i++){//循环鱼雷数据
  135. var boom_X = boom[i][0];//保存鱼雷X坐标
  136. var boom_Y = boom[i][1];//保存鱼雷Y坐标
  137. for(let j=0;j<emShip.length;j++){//循环敌舰数据
  138. var emShip_X = emShip[j][0];//保存敌舰X坐标
  139. var emShip_Y = emShip[j][1];//保存敌舰Y坐标
  140. if(boom_X===emShip_X){//判断是否X坐标相同
  141. if(boom_Y===(emShip_Y+1)*blockSize){//如果Y坐标也相同
  142. boom.splice(i,1);//删除这个鱼雷
  143. emShip.splice(j,1);//删除这个敌舰
  144. hard = hard-50;//难度增加50
  145. addScore();//加分
  146. if(hard<=1200){
  147. hard=1200;//如果难度已经是1200则保持1200
  148. }
  149. clearInterval(creatEm);//清除创建敌舰定时器
  150. creatEmShip();//立刻创建一个敌舰
  151. creatEm = setInterval(function(){
  152. creatEmShip();//用新的难度(速度)创建敌舰
  153. },hard);
  154. }
  155. }
  156. }
  157. }
  158. }
  159. function gameOver(){//游戏结束
  160. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  161. clearInterval(emt);
  162. clearInterval(boomT);
  163. clearInterval(creatEm);
  164. clearInterval(flush);//清空所有定时器
  165. ctx.font = "14px Courier New";//设定字体
  166. ctx.fillStyle = "#333";//设定字颜色
  167. ctx.textAlign="center";//设定字居中
  168. ctx.fillText("游戏结束,你得了"+score+"分", Math.round(ctxW*blockSize/2), 50);
  169. //显示游戏结束,你得了x分在画布中间
  170. }
  171. function addScore(){//加分
  172. score ++;//加分
  173. scoreSpan.innerHTML = String(score);//更新计分板
  174. }
  175. function minusHP(){//减HP
  176. HP --;//减HP
  177. if(HP<=0){
  178. HPSpan.innerHTML = String(HP);//更新HP剩余量
  179. setTimeout("gameOver()",0);//如果HP为0则游戏结束
  180. }else{
  181. HPSpan.innerHTML = String(HP);//更新HP剩余量
  182. }
  183. }
  184.  
  185. document.onkeydown=function(event){//绑定键盘事件
  186. var e = event || window.event || arguments.callee.caller.arguments[0];
  187. if(e && e.keyCode==37){//左
  188. if(myShipX===1){//防止我方移动到画布外面
  189. return
  190. }
  191. myShipX= myShipX-1;
  192. }
  193. if(e && e.keyCode==39){//右
  194. if(myShipX===ctxW){//防止我方移动到画布外面
  195. return
  196. }
  197. myShipX= myShipX+1;
  198. }
  199. if(e && e.keyCode==32){//空格
  200. addBoom();//创建鱼雷
  201. }
  202. }
预览DEMO

---------------------

PS.怎么感觉这游戏像是个拉屎丢人的游戏……