基于上次的丢鱼雷小游戏的代码。这次删除了投弹相关的代码,并在原先代码的基础上制作了图片,让游戏更像是FC红白机时代的游戏。

因为有了图片,所以就要注意图片必须要加载完才能运行canvas绘制。这里就用到了读取相关的代码:


  1. var imgSrc = [
  2. "img/bg.png",
  3. "img/mycar.png",
  4. "img/emcar.png",
  5. "img/boom.png"
  6. ]
  7. var images = [];
  8.  
  9. function loading(){
  10. var imgLength = imgSrc.length;
  11. var loadingNum = 0;
  12. for(var i=0;i<imgLength;i++){
  13. images[i] = new Image();
  14. images[i].src = imgSrc[i];
  15. images[i].onload = function(){
  16. loadingNum++;
  17. if(loadingNum===imgLength){
  18. loadingOK();
  19. }
  20. }
  21. }
  22. }
  23.  
  24. function loadingOK(){
  25. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  26. ctx.font = String(14*devicePixelRatio)+"px Courier New";//设定字体
  27. ctx.fillStyle = "#333";//设定字颜色
  28. ctx.textAlign="center";//设定字居中
  29. ctx.fillText("点击开始游戏", Math.round(ctxW*blockSize/2), 50*devicePixelRatio);
  30. canvas.onclick=function(event){
  31. init();
  32. };
  33. }
另外,为了适应手机端,所以这次还加入了虚拟按键。以及在手机上运行后才发现还要注意PPI的问题。


众所周知,手机的PPI是比手机要高,也就是说精度要比电脑高,所以就会导致了一样是20px的图片,在手机上模糊,电脑上是正常的。所以在制图的时候需要制作2倍以上的精度,也就是说20x20的图片做成40x40来应付手机的高PPI,并通过如下代码实现。


  1. var devicePixelRatio = window.devicePixelRatio || 1;//获取屏幕的ppi
  2. var blockSize = 20*devicePixelRatio;//每格像素
  3. var ctxW = 12;//宽多少格
  4. var ctxH = 6;//高多少格
  5. canvas.width=ctxW*blockSize;//设定画布宽度,就是格子*每格像素
  6. canvas.height=ctxH*blockSize;//设定画布高度,就是格子*每格像素
  7. canvas.style.width = ctxW*blockSize/devicePixelRatio + "px";
  8. canvas.style.height = ctxH*blockSize/devicePixelRatio +"px";
注意点大概就这么多,下面直接丢全部的代码。


HTML:


  1. <div class="canvasbox">
  2. <canvas id="myCanvas" class="canvas"></canvas>
  3. <div>分数:<span id="score"></span></div>
  4. <div>HP:<span id="HP"></span></div>
  5. </div>
  6. <p style="margin-top:10px;">操作说明:方向键可以控制方向。或点击下方按钮。</p>
  7. <div class="btnbox">
  8. <button type="button" class="up btn" id="up"></button>
  9. <button type="button" class="down btn" id="down"></button>
  10. <button type="button" class="left btn" id="left"></button>
  11. <button type="button" class="right btn" id="right"></button>
  12. </div>


CSS:


  1. .canvas{
  2. border:1px solid #333;
  3. cursor:pointer;
  4. display:block;
  5. margin:0 auto;
  6. margin-bottom:10px;
  7. }
  8. .btnbox{
  9. position:relative;
  10. z-index:1;
  11. width:100%;
  12. height:160px;
  13. margin-top:10px;
  14. }
  15. .btn{
  16. width:75px;
  17. height:75px;
  18. border:1px solid #525252;
  19. background:none;
  20. position:absolute;
  21. z-index:1;
  22. }
  23. .btn.up{
  24. top:0;
  25. left:50%;
  26. margin-left:-37px;
  27. }
  28. .btn.down{
  29. top:85px;
  30. left:50%;
  31. margin-left:-37px;
  32. }
  33. .btn.left{
  34. top:42px;
  35. left:0;
  36. }
  37. .btn.right{
  38. top:42px;
  39. right:0;
  40. }


JS:


  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 devicePixelRatio = window.devicePixelRatio || 1;//获取屏幕的ppi
  6. var blockSize = 20*devicePixelRatio;//每格像素
  7. var ctxW = 12;//宽多少格
  8. var ctxH = 6;//高多少格
  9. canvas.width=ctxW*blockSize;//设定画布宽度,就是格子*每格像素
  10. canvas.height=ctxH*blockSize;//设定画布高度,就是格子*每格像素
  11. canvas.style.width = ctxW*blockSize/devicePixelRatio + "px";
  12. canvas.style.height = ctxH*blockSize/devicePixelRatio +"px";
  13.  
  14. var imgSrc = [
  15. "img/bg.png",
  16. "img/mycar.png",
  17. "img/emcar.png",
  18. "img/boom.png"
  19. ]
  20. var images = [];
  21.  
  22. ctx.font = String(14*devicePixelRatio)+"px Courier New";//设定字体
  23. ctx.fillStyle = "#333";//设定字颜色
  24. ctx.textAlign="center";//设定字居中
  25. ctx.fillText("读取中...", Math.round(ctxW*blockSize/2), 50*devicePixelRatio);
  26. var emt = null;//用于存放定时器,用于更新敌车坐标
  27. var creatEm = null;//用于存放定时器,用于增加敌车
  28. var flush = null;//用于存放定时器,用于刷新画布
  29. var addscoreT = null;
  30.  
  31. var myShipY=0;//我方的Y初始位置
  32. var myShipX=0;//我方X初始位置
  33. var emShip = [];//存放敌方数据
  34. var boom = [];//存放爆炸效果数据
  35. var hard = 0;//难度(刷新速度,越小刷新越快单位毫秒)
  36. var score = 0;//得分
  37. var HP = 0;//HP
  38.  
  39. var BGx = 0;
  40.  
  41. function loading(){
  42. var imgLength = imgSrc.length;
  43. var loadingNum = 0;
  44. for(var i=0;i<imgLength;i++){
  45. images[i] = new Image();
  46. images[i].src = imgSrc[i];
  47. images[i].onload = function(){
  48. loadingNum++;
  49. if(loadingNum===imgLength){
  50. loadingOK();
  51. }
  52. }
  53. }
  54. }
  55.  
  56. function loadingOK(){
  57. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  58. ctx.font = String(14*devicePixelRatio)+"px Courier New";//设定字体
  59. ctx.fillStyle = "#333";//设定字颜色
  60. ctx.textAlign="center";//设定字居中
  61. ctx.fillText("点击开始游戏", Math.round(ctxW*blockSize/2), 50*devicePixelRatio);
  62. canvas.onclick=function(event){
  63. init();
  64. };
  65. }
  66.  
  67. function init(){//初始化
  68.  
  69. myShipY=1;//设定我方的Y初始位置
  70. myShipX=1;//设定我方的X初始位置
  71. emShip = [];//清空敌车数据
  72. boom = [];//清空爆炸效果数据
  73. hard = 3000;//初始化难度
  74. score = 0;//初始化分数
  75. HP = 3;//初始化HP
  76. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  77. creatEmShip();//创建敌车
  78. paintMyShip();//绘制我方
  79. paintEmship();//绘制敌车
  80. scoreSpan.innerHTML = String(score);//初始化计分板
  81. HPSpan.innerHTML = String(HP);//初始化HP剩余量
  82. clearInterval(emt);//清除更新敌车坐标定时器器
  83. clearInterval(creatEm);//清除创建敌车定时器
  84. clearInterval(flush);//清除刷新画布定时器
  85. clearInterval(addscoreT);
  86. emt = setInterval(function(){//每400毫秒敌车向左移动一次
  87. emShipMove();
  88. },140);
  89. creatEm = setInterval(function(){//根据难度创建敌车
  90. creatEmShip();
  91. },hard);
  92. flush = setInterval(function(){//100毫秒刷新画布
  93. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  94. paintBG();
  95. paintEmship();//绘制敌车
  96. paintMyShip();//绘制我方
  97. boomEmship();//判断是否炸中敌车
  98. },20);
  99. addscoreT = setInterval(function(){
  100. addScore();
  101. },3000);
  102. }
  103. function paintBG(){
  104. ctx.drawImage(images[0],BGx,0,canvas.width*2,canvas.height);
  105. paintBGMove();
  106. }
  107. function paintBGMove(){
  108. BGx = BGx-5*devicePixelRatio;
  109. if(BGx <= -canvas.width){
  110. BGx = 0;
  111. }
  112. }
  113. function paintMyShip(){//绘制我方
  114. var shipX = (myShipX-1)*blockSize;//设定我方船只的X坐标,因为左边是从(0,0)开始,格子定为1开始所以-1
  115. var shipY = (myShipY-1)*blockSize;//设定我方船只的X坐标,因为左边是从(0,0)开始,格子定为1开始所以-1
  116. ctx.drawImage(images[1],shipX,shipY,blockSize,blockSize);
  117. }
  118. function creatEmShip(){//随机出现敌车
  119. var Y = Math.floor(Math.random()*(ctxH) + 1);//高度一共有6个格子,出去丢雷的格子和我方的格子就是6-2,然后就随机从1-4中生成随机数
  120. emShip.push([blockSize*ctxW,Y,false]);//给敌车数据添加敌车坐标
  121. }
  122. function paintEmship(){//绘制敌车
  123. for(var i=0;i<emShip.length;i++){//循环敌车数据
  124. var emShipX = emShip[i][0];//保存敌车X坐标
  125. var emShipY = (emShip[i][1]-1)*blockSize;//保存敌车Y坐标,因为Y是1-4的所在格子,所以要*每格像素来计算出像素坐标
  126. if(emShip[i][2]){
  127. ctx.drawImage(images[3],emShipX,emShipY,blockSize,blockSize);
  128. }else{
  129. ctx.drawImage(images[2],emShipX,emShipY,blockSize,blockSize);
  130. }
  131. }
  132. }
  133. function emShipMove(){//移动敌车
  134. for(var i=0;i<emShip.length;i++){//循环敌车数据
  135. var X = emShip[i][0]-blockSize;//敌车X坐标向左移动一个格子
  136. emShip[i][0] = X;//重新写入X坐标
  137. }
  138. removeEmShip();//清除多余的敌车(画布外)
  139. }
  140. function removeEmShip(){//超出范围删除敌车并且HP-1
  141. for(var i=0;i<emShip.length;i++){//循环敌车数据
  142. var X = emShip[i][0];//储存敌车X坐标
  143. if(X<0){//如果已经在画布外
  144. emShip.splice(i,1);//删除敌车
  145. }
  146. }
  147. }
  148. function boomEmship(){//判定炸了
  149. var boom_X = (myShipX-1)*blockSize;//保存X坐标
  150. var boom_Y = (myShipY-1)*blockSize;//保存Y坐标
  151. for(var j=0;j<emShip.length;j++){//循环敌车数据
  152. var emShip_X = emShip[j][0];//保存敌车X坐标
  153. var emShip_Y = emShip[j][1]-1;//保存敌车Y坐标
  154. var emShipIsBoom = emShip[j][2];
  155. if(boom_X===emShip_X){//判断是否X坐标相同
  156. if(boom_Y===emShip_Y*blockSize){//如果Y坐标也相同
  157. if(!emShipIsBoom){
  158. minusHP();//扣血
  159. emShip[j][2] = true;
  160. }
  161. }
  162. }
  163. }
  164. }
  165. function gameOver(){//游戏结束
  166. ctx.clearRect(0,0,canvas.width,canvas.height);//清空画布
  167. clearInterval(emt);
  168. clearInterval(creatEm);
  169. clearInterval(flush);//清空所有定时器
  170. clearInterval(addscoreT);
  171. ctx.font = String(14*devicePixelRatio)+"px Courier New";//设定字体
  172. ctx.fillStyle = "#333";//设定字颜色
  173. ctx.textAlign="center";//设定字居中
  174. ctx.fillText("游戏结束,你得了"+score+"分", Math.round(ctxW*blockSize/2), 50*devicePixelRatio);
  175. //显示游戏结束,你得了x分在画布中间
  176. }
  177. function addScore(){//加分
  178. score ++;//加分
  179. scoreSpan.innerHTML = String(score);//更新计分板
  180. hard = hard-100;//难度增加20
  181. if(hard<=300){
  182. hard=300;//如果难度已经是800了则保持800
  183. }
  184. creatEmShip();//立刻创建一个敌车
  185. clearInterval(creatEm);
  186. creatEm = setInterval(function(){//根据难度创建敌车
  187. creatEmShip();
  188. },hard);
  189. }
  190. function minusHP(){//减HP
  191. HP --;//减HP
  192. if(HP<=0){
  193. HPSpan.innerHTML = String(HP);//更新HP剩余量
  194. setTimeout("gameOver()",0);//如果HP为0则游戏结束
  195. }else{
  196. HPSpan.innerHTML = String(HP);//更新HP剩余量
  197. }
  198. }
  199.  
  200. document.onkeydown=function(event){//绑定键盘事件
  201. var e = event || window.event || arguments.callee.caller.arguments[0];
  202. if(e && e.keyCode==37){//左
  203. if(myShipX===1){//防止我方移动到画布外面
  204. return
  205. }
  206. myShipX= myShipX-1;
  207. }
  208. if(e && e.keyCode==39){//右
  209. if(myShipX===ctxW){//防止我方移动到画布外面
  210. return
  211. }
  212. myShipX= myShipX+1;
  213. }
  214. if(e && e.keyCode==38){//上
  215. if(myShipY===1){//防止我方移动到画布外面
  216. return
  217. }
  218. myShipY= myShipY-1;
  219. }
  220. if(e && e.keyCode==40){//下
  221. if(myShipY===ctxH){//防止我方移动到画布外面
  222. return
  223. }
  224. myShipY= myShipY+1;
  225. }
  226. }
  227. document.getElementById('up').onclick=function(event){
  228. if(myShipY===1){//防止我方移动到画布外面
  229. return
  230. }
  231. myShipY= myShipY-1;
  232. }
  233. document.getElementById('down').onclick=function(event){
  234. if(myShipY===ctxH){//防止我方移动到画布外面
  235. return
  236. }
  237. myShipY= myShipY+1;
  238. }
  239. document.getElementById('left').onclick=function(event){
  240. if(myShipX===1){//防止我方移动到画布外面
  241. return
  242. }
  243. myShipX= myShipX-1;
  244. }
  245. document.getElementById('right').onclick=function(event){
  246. if(myShipX===ctxW){//防止我方移动到画布外面
  247. return
  248. }
  249. myShipX= myShipX+1;
  250. }
  251.  
  252. loading();


手机可以点击:预览DEMO