js实现坦克大战游戏


Posted in Javascript onFebruary 24, 2020

本文实例为大家分享了js实现坦克大战游戏的具体代码,供大家参考,具体内容如下

<!DOCTYPE html>
<html>
 <head>
 <title>tank</title>
 <style type="text/css">
  body {
  margin: 0px;
  padding: 0px;
  border: 0px;
  }

  .map {
  position: absolute;
  top: 30px;
  width: 390px;
  height: 390px;
  left: 50%;
  margin-left: -200px;
  border: 9px solid orange;
  background-color: #8B8989;
  }

  .mapchild {
  position: absolute;
  background-size: cover;
  }

  #ifo {
  position: absolute;
  top: 30px;
  width: 418px;
  height: 418px;
  left: 50%;
  margin-left: -200px;
  color: green;
  text-align: center;
  background-color: #FAEBD7;
  z-index: 10;
  }
 </style>
 </head>
 <body>
 <div id="ifo">
  <h1 id="ifo_title"></h1>
  <h3>按键说明:</h3>
  T:开始游戏(游戏开始后无效)<br/>
  P:暂停游戏<br/>
  W、S、A、D:上、下、左、右<br/>
  ENTER:发射子弹<br/>
 </div>
 </body>
 <script type="text/javascript">
 //常量及全局变量的定义--------------------------------------------
 const TANK_W = 30;
 const TANK_H = 30;
 const MAP_W = TANK_W * 13;
 const MAP_H = TANK_H * 13;
 const BULLENT_W = 7.5;
 const BULLENT_H = 7.5;
 const WALL_W = 15;
 const WALL_H = 15;
 const BULLENT_FREQ = 30;
 const TANK_FREQ = 200;
 const TANK_STEP = 7.5;
 //当前文件同目录
 const IMG_PATH = "tankImage/";
 const MUSIC_PATH = "tankMusic/";
 // 87=W;83=S;65=A;68=D
 const KEYCODE_U = 87;
 const KEYCODE_D = 83;
 const KEYCODE_L = 65;
 const KEYCODE_R = 68;
 //坦克移动不响应时间
 const NORESPONSEFIRETIME = 200;
 const NORESPONSETANKMOVETIME = TANK_FREQ + 100;
 //我方坦克开火、移动状态
 noresponseFire = false;
 noresponseTankMove = false;
 //游戏状态
 state = "READY";
 //frequency频率

 //对象id
 var tank_id = 0;
 var bullent_id = 0;
 var wall_id = 0;
 //敌方坦克总数
 var emTankNum = 20;
 var meTankNum = 3;
 //我方坦克对象
 var mytank = null;

 var tankArray = new Array();
 var bullentArray = new Array();
 //因为功能性砖块会与普通静态砖块重叠所以必须另外存储
 var functionWallArray = new Array();
 //地图width=390,地图中最小的静物wall宽度高度=15,所以数组的一维二维均为390/15=26
 //先声明一维
 var noMoveArray = new Array(4);
 for (var i = 0; i < MAP_W / WALL_W; i++) {
  //一维长度
  noMoveArray[i] = new Array();
  //再声明二维
  for (var j = 0; j < MAP_H / WALL_H; j++) {
  //二维长度
  noMoveArray[i][j] = null;
  }
 }
 //常量及全局变量完--------------------------------------------------------------------------------

 //对象的定义-------------------------------------------------------------------------------------

 //坦克对象
 tank = function(selfType, x, y, belongs, dir) {
  //共有属性
  this.id = "tank_" + tank_id++;
  this.type = "tank";
  //selfType可取1、2、3表示一类坦克,二类坦克,三类坦克
  this.selfType = selfType;
  this.x = x;
  this.y = y;
  this.belongs = belongs;
  this.dir = dir;
  this.width = TANK_W;
  this.height = TANK_H;
  this.life = this.selfType;
  //因为坦克的img与方向有关,每一次改变dir都会影响img,所以设置一个对象函数用于获取
  this.getImg = function() {
  return img = this.belongs + "Tank" + this.selfType + this.dir;
  }

  //敌方坦克的自移动函数的setInterval的值t
  this.t;
  createDOM(this.id, this.width, this.height, this.x, this.y, this.getImg(), 2);
  //把生成的坦克对象存入移动对象数组
  tankArray.push(this);

  if (belongs == "me") {
  mytank = this;
  meTankNum--;
  }
  //敌方坦克调用自移动函数
  if (this.belongs == "em") {
  emTankNum--;
  //检测是否需要生成功能砖块
  createFunctionWall();
  autoMove(this);
  }
 }

 //子弹对象
 bullent = function(selfType, x, y, belongs, dir) {
  //播放发射子弹音乐
  playMusic("fire");
  //共有属性
  this.id = "bullent_" + bullent_id++;
  this.type = "bullent";

  this.selfType = selfType;
  this.x = x;
  this.y = y;
  this.belongs = belongs;
  this.dir = dir;
  this.width = BULLENT_W;
  this.height = BULLENT_H;
  //为了与坦克的img保持一致,同样设置一个对象函数用于获取
  this.getImg = function() {
  return img = this.type;
  }
  //子弹与敌方坦克特有属性,自移动的定时器
  this.t;
  createDOM(this.id, this.width, this.height, this.x, this.y, this.getImg(), 1);
  //把生成的子弹对象存入移动对象数组
  bullentArray.push(this);
  autoMove(this);

 }

 //墙对象 
 wall = function(selfType, x, y, belongs) {
  //共有属性
  this.id = "wall_" + wall_id++;
  this.type = "wall";
  //wall、steel、star、timer分别表示普通砖块、子弹不可打破砖块、我方老巢、定时器
  this.selfType = selfType;
  this.x = x;
  this.y = y;
  //belongs取值home、ordinary、function分别表示老巢的砖块、一般砖块、功能性砖块
  this.belongs = belongs;
  this.width;
  this.height;

  if (this.selfType == "star") {
  //设置全局变量star
  star = this;
  this.width = TANK_W;
  this.height = TANK_H;
  } else if (this.selfType != "star") {
  this.width = WALL_W;
  this.height = WALL_H;
  }
  //为了与坦克的img保持一致,同样设置一个对象函数用于获取
  this.getImg = function() {
  return img = this.selfType;
  }
  var zIndex = belongs == "function" ? 3 : 2;
  createDOM(this.id, this.width, this.height, this.x, this.y, this.getImg(), zIndex);
  // if(n==13)console.log(this)
  //地图中所有的静物都是wall类型的,分为长宽15的wall、steel和长宽30的star;我们只需要存储15规格的,star只有一个不需要存储
  if (this.belongs != "function") {
  noMoveArray[x / 15][y / 15] = this;
  } else {
  functionWallArray.push(this);
  }
 }

 //对象的定义完------------------------------------------------------------------------------------

 //DOM对象创建与显示-------------------------------------------------------------------------------
 //总体说明:1、为了便于计算所有对象的width、height、x、y均不带px单位
 // 创建DOM对象函数
 function createDOM(id, width, height, x, y, img, zIndex) {
  var map = document.getElementById("map");
  var it = document.createElement("div");
  it.id = id;
  it.style.zIndex = zIndex;
  map.appendChild(it);
  showDOM(id, width, height, x, y, img);

 }
 //删除DOM对象函数
 function delDOM(id) {
  var it = document.getElementById(id);
  map.removeChild(it);
 }

 //展示函数,根据obj的属性刷新对应的DOM
 function showDOM(id, width, height, x, y, img) {
  var it = document.getElementById(id);
  it.className = "mapchild";
  it.style.cssText = "width:" + width + "px;height:" + height + "px;left:" + x + "px;top:" + y + "px;background-image:url('" + IMG_PATH + img + ".gif');";
 }
 //DOM对象创建与显示完-------------------------------------------------------------------------------

 //对象的创建与销毁函数群-----------------------------------------------------------------------------

 //创建坦克函数
 //因为坦克出现有一个动画,不能直接new tank生成
 //new tank(3,15 * 8,15 * 24,"me","U")
 function createTank(selfType, belongs, x, y) {
  //先让创建动画显示
  var emTank_x1 = 0
  , emTank_x2 = 180;
  emTank_x3 = 360;
  var emTank_y = 0;
  var meTank_x = 15 * 8;
  var meTank_y = 15 * 24;

  //因为创建动画显示3s+销毁1s,所以需要在4s后创建坦克
  //这里需要对出生的位置进行检测,防止坦克重叠
  if (belongs == "me" && meTankNum != 0) {
  animation("born", 15 * 8, 15 * 24);
  //我方坦克显示位置固定
  setTimeout(function() {
   var mytank = new tank(3,15 * 8,15 * 24,"me","U");
   flickerObj(mytank.id);
  }, 4500);

  }
  if (belongs == "em" && emTankNum != 0) {
  animation("born", x, y);
  //我方坦克显示位置固定
  setTimeout(function() {
   var emtank = new tank(1,x,y,"em","U");
   flickerObj(emtank.id);
  }, 4500);
  }

  //判断指定位置是否有坦克
  function isThereHaveTank(x, y) {
  if (tankArray.length == 0) {
   return false;
  }
  for (var i = 0; i < tankArray.length; i++) {
   return tankArray[i].x == x && tankArray[i].y == y;
  }
  }

 }

 //发射子弹函数
 //根据发射子弹坦克位置和方向,生成一个子弹
 function createBullent(obj) {
  var x, y;
  switch (obj.dir) {
  case "U":
  x = obj.x + 0.5 * obj.width - 0.5 * BULLENT_W;
  y = obj.y;
  break;
  case "D":
  x = obj.x + 0.5 * obj.width - 0.5 * BULLENT_W;
  y = obj.y + obj.height - BULLENT_H;
  break;
  case "L":
  x = obj.x;
  y = obj.y + 0.5 * obj.height - 0.5 * BULLENT_H;
  break;
  case "R":
  x = obj.x + obj.width - BULLENT_W;
  y = obj.y + 0.5 * obj.height - 0.5 * BULLENT_H;
  break;
  }
  new bullent("speed",x,y,obj.belongs,obj.dir);

 }

 //删除对象函数
 //在html中删除元素,并将数组中的值赋值为null
 function delObj(obj) {

  if (obj.t != undefined) {
  clearInterval(obj.t);
  }

  switch (obj.type) {
  case "bullent":
  delDOM(obj.id);
  bullentArray.splice(bullentArray.indexOf(obj), 1);
  break;
  case "tank":
  if (--obj.life == 0) {
   switch (obj.belongs) {
   case "me":
   meTankNum == 0 ? gameOver() : createTank(3, null, null, "me", null);
   ;break;

   case "em":
   console.log("敌方坦克=" + emTankNum)
   if (emTankNum == 0) {
    console.log("victory");
   }
   ;break;
   }
   //调用销毁坦克动画
   animation("blast", obj.x, obj.y);
   delDOM(obj.id);
   delete tankArray[tankArray.indexOf(obj)];
   if (obj.belongs == "me") {
   mytank = null;
   gameOver();
   }

   //obj.life!=0
  } else {
   obj.selfType = obj.life;
   showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
  }
  ;break;
  case "wall":
  if (obj.selfType == "star") {
   img = "destory";
   showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, img);
   gameOver();
  } else if (obj.belongs == "function") {
   delDOM(obj.id);
   functionWallArray.splice(bullentArray.indexOf(obj), 1);

  } else {
   delDOM(obj.id);
   noMoveArray[obj.x / 15][obj.y / 15] = null;
  }
  ;break;
  }

 }

 //对象的创建与销毁函数群完---------------------------------------------------------------------------

 //碰撞检测与处理------------------------------------------------------------------------------------

 //获取可能碰撞的静态物体函数
 //在存储静物的时候使用二维数组相当于将地图画成间距15的小格子,所有的静物均在小格子中,所以给定一个物体就可以得到包围它一圈的小格子;
 //这比遍历整个noMoveArray来的快的多
 function getPossibleCollisionObj(obj) {
  var PossibleCollisionObjArray = new Array();
  var largeWidth = WALL_W;
  var largeHeight = WALL_H;
  var x_l = obj.x - largeWidth;
  var x_r = obj.x + largeWidth + obj.width;
  var y_u = obj.y - largeHeight;
  var y_d = obj.y + largeHeight + obj.height;
  //计算出的左侧、右侧、上下侧均不能出地图
  if (x_l < 0)
  x_l = 0;
  if (x_r > MAP_W)
  x_r = MAP_W;
  if (y_u < 0)
  y_u = 0;
  if (y_d > MAP_H)
  y_d = MAP_H;

  for (var i = Math.floor(x_l / largeWidth); i < Math.floor(x_r / largeWidth); i++) {
  for (var j = Math.floor(y_u / largeHeight); j < Math.floor(y_d / largeHeight); j++) {
   if (noMoveArray[i][j] != null) {
   PossibleCollisionObjArray.push(noMoveArray[i][j]);
   }
  }
  }
  //console.log(PossibleCollisionObjArray);
  return PossibleCollisionObjArray;

 }

 //碰撞检测及处理函数
 function collision(obj) {
  //collresult有三个值,MOVE、DELETE、NOMOVE;move表示检测后的处理结果是继续移动(即使碰上了,有些也不需要处理),DELETE表示删除自身
  //因为碰撞检测只存在与移动物体,而移动函数需要碰撞检测给出是否移动的结果,所以不能在碰撞处理中直接删除被检测物体
  var collresult = "MOVE";
  //单独检测是否碰撞老巢
  //collresult = isCollision(obj, star) ? gameOver():"MOVE";
  //检测功能性砖块
  for (var i = 0; i < functionWallArray.length; i++) {
  if (functionWallArray[i] != null && isCollision(obj, functionWallArray[i])) {
   collresult = delColl(obj, functionWallArray[i]);
  }
  }

  //检测所有的静物;采用的是遍历所有静物
  // for (var i = 0; i < noMoveArray.length; i++) {
  // for (var j = 0; j < noMoveArray[i].length; j++) {
  //  if (noMoveArray[i][j] != null && isCollision(obj, noMoveArray[i][j])) {
  //  collresult = delColl(obj, noMoveArray[i][j]);
  //  }
  // }
  // }

  //检测所有的静物;采用的是遍历可能相撞的静物
  var PossibleCollisionObjArray = getPossibleCollisionObj(obj);
  for (var i = 0; i < PossibleCollisionObjArray.length; i++) {
  if (isCollision(obj, PossibleCollisionObjArray[i])) {
   collresult = delColl(obj, PossibleCollisionObjArray[i]);
  }
  }

  //检测坦克
  for (var i = 0; i < tankArray.length; i++) {
  //tankArray[i].id != obj.id 因为检测的时候的对象是通过拷贝得到的,它与真正的坦克的id一样
  if (tankArray[i] != null && tankArray[i].id != obj.id && isCollision(obj, tankArray[i])) {
   collresult = delColl(obj, tankArray[i]);
  }
  }

  //检测子弹
  for (var i = 0; i < bullentArray.length; i++) {
  if (bullentArray[i].id != obj.id && isCollision(obj, bullentArray[i])) {
   collresult = delColl(obj, bullentArray[i]);
  }
  }
  return collresult;
 }

 //碰撞检测
 function isCollision(obj, obji) {
  var iscoll;
  //用x_l、x_r、y_u、y_d分别表示左右上下的值
  var x_l = obj.x;
  var x_r = x_l + obj.width;
  var y_u = obj.y;
  var y_d = y_u + obj.height;
  var x_li = obji.x;
  var x_ri = x_li + obji.width;
  var y_ui = obji.y;
  var y_di = y_ui + obji.height;

  //分别不在被检测物体的左右上下说明发生碰撞,开始处理(第一种检测碰撞算法,考虑反面情况)
  if (!(x_r <= x_li | x_l >= x_ri | y_d <= y_ui | y_u >= y_di)) {
  //console.log(obj.id+"与"+obji.id+"相撞了")
  iscoll = true;
  } else {
  iscoll = false;
  }
  return iscoll;

 }

 //碰撞处理函数
 function delColl(obj, obji) {
  var collresult;
  switch (obj.type) {
  case "bullent":
  switch (obji.type) {
  case "tank":
   switch (obj.belongs) {
   case "me":
   switch (obji.belongs) {
   case "me":
    collresult = "MOVE";
    break;
   case "em":
    collresult = "DELETE";
    playMusic("hit");
    animation("blast", obji.x, obji.y);
    delObj(obji);
    break;
   }
   ;break;
   case "em":
   switch (obji.belongs) {
   case "me":
    collresult = "DELETE";
    playMusic("hit");
    delObj(obji);
    break;
   case "em":
    collresult = "MOVE";
    break;
   }
   ;break;
   }
   break;
  case "wall":
   switch (obji.selfType) {
   case "steel":
   collresult = "DELETE";
   playMusic("hit");
   break;
   case "wall":
   collresult = "DELETE";
   playMusic("hit");

   delObj(obji);

   break;
   case "star":
   collresult = "DELETE";
   playMusic("hit");
   delObj(obji);
   break;
   }
   ;break;
  case "bullent":
   switch (obji.belongs) {
   default:
   collresult = "MOVE";
   break;
   }
   ;break;

  }
  ;break;

  case "tank":
  switch (obji.type) {
  case "tank":
   collresult = "NOMOVE";
   break;

  case "wall":
   switch (obji.selfType) {
   case "wall":
   case "steel":
   collresult = "NOMOVE";
   break;
   case "timer":
   collresult = "MOVE";
   timer();
   delObj(obji);
   break;
   case "bomb":
   collresult = "MOVE";
   bomb();
   delObj(obji);
   break;
   case "stronghome":
   collresult = "MOVE";
   delObj(obji);
   StrongHome();
   break;
   }
   ;break;
  case "bullent":
   switch (obj.belongs) {
   case "me":
   switch (obji.belongs) {
   case "me":
    collresult = "MOVE";
    break;
   case "em":
    collresult = "DELETE";
    break;
   }
   ;break;

   case "em":
   switch (obji.belongs) {
   case "me":
    collresult = "DELETE";
    delObj(obji);
    break;
   case "em":
    collresult = "MOVE";
    break;
   }
   ;break;

   }
   ;break;

  }
  ;break;

  }
  //console.log(obj.id+"与"+obji.id+"相撞了  "+"结果="+collresult);
  return collresult;
 }

 //碰撞检测与处理完------------------------------------------------------------------------------------

 //坦克与子弹移动函数-----------------------------------------------------------------------------------

 //移动函数
 function move(obj, newDir) {
  var oldDir = obj.dir;
  obj.dir = newDir;
  if (state != "RUN") {
  // if(obj.type!="bullent"){
  // return;
  // }
  return;
  }
  //新的方向与坦克原来方向相同就前进,否则改变坦克方向
  if (obj.dir != oldDir && obj.type == "tank") {
  showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
  return;

  }
  var x = 0
  , y = 0;
  var step = TANK_STEP;

  switch (obj.dir) {
  case "L":
  x = -step;
  break;
  case "R":
  x = step;
  break;
  case "U":
  y = -step;
  break;
  case "D":
  y = step;
  break;
  }
  //粗糙的深拷贝
  var objString = JSON.stringify(obj);
  var checkObj = JSON.parse(objString);
  checkObj.x += x;
  checkObj.y += y;
  var collresult = collision(checkObj);
  //出界检测;
  if (checkObj.x < 0 || (checkObj.x + checkObj.width) > MAP_W || checkObj.y < 0 || (checkObj.y + checkObj.height) > MAP_H) {
  if (checkObj.type == "tank") {
   showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
   return;
  }
  if (checkObj.type == "bullent") {
   delObj(obj);
   return;
  }
  //调用碰撞检测及处理函数给出移动结果
  } else if (collresult == "MOVE") {
  // if(obj.type=="tank"){
  // movingFrame(obj,checkObj.x,checkObj.y) 
  movingFrame(obj, checkObj.x, checkObj.y);
  // }
  // console.log("目标y="+checkTank.y)
  obj.x = checkObj.x;
  obj.y = checkObj.y;
  // if(obj.type=="bullent"){
  // showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
  // }
  // showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());

  } else if (collresult == "DELETE") {

  delObj(obj);
  } else if (collresult == "NOMOVE") {
  showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
  //如果是敌方坦克就给他一个相反的方向,防止它撞墙不回头
  if (obj.belongs == "em" && obj.type == "tank") {}
  return;
  }

 }

 //反方向函数
 //返回一个与输入方向相反的方向
 function negativeDir(dir) {
  switch (dir) {
  case "L":
  return "R";
  break;
  case "R":
  return "L";
  break;
  case "U":
  return "D";
  break;
  case "D":
  return "U";
  break;
  }
 }

 //自动移动函数
 //子弹坦克所特有
 function autoMove(obj) {
  // console.log("游戏状态="+state)
  var itFreq = BULLENT_FREQ;
  var itType = obj.type;
  var itId = obj.id;
  var itDir = obj.dir;
  if (obj.type == "tank") {
  itFreq = TANK_FREQ;
  }
  obj.t = setInterval(function() {
  if (itType == "tank") {
   var itObj = obj;
   var turn = randState();
   if (turn == "Fire") {
   //console.log(obj.id+" "+obj.t)
   createBullent(itObj);
   return;
   } else if (turn == "none") {
   itDir = itObj.dir;

   } else {
   itDir = turn;
   }
  }
  move(obj, itDir);
  }, itFreq);
 }

 //简化版移动框架
 //为了使坦克的移动更平滑;使用移动框架的前提:必须在t时间内屏蔽坦克的任何方向改变
 //因为js浮点数的处理很复杂,这里仅仅满足x,y为7.5的倍数,step为7.5
 function movingFrame(obj, x, y) {
  var objDom = document.getElementById(obj.id);
  var t = TANK_FREQ;
  var x1 = obj.x;
  var y1 = obj.y;
  var step_x = div(sub(x, x1), t / 10);
  var step_y = div(sub(y, y1), t / 10);
  var aaa = 1;
  var times = 1;
  var tank_t = setInterval(function() {
  if (times == t / 10) {
   clearInterval(tank_t);
  }
  times++;
  x1 = add(x1, step_x);
  y1 = add(y1, step_y);
  objDom.style.left = x1 + "px";
  objDom.style.top = y1 + "px";

  }, 10);

  //浮点数的加减乘除

  function add(a, b) {
  var c, d, e;
  try {
   c = a.toString().split(".")[1].length;
  } catch (f) {
   c = 0;
  }
  try {
   d = b.toString().split(".")[1].length;
  } catch (f) {
   d = 0;
  }
  return e = Math.pow(10, Math.max(c, d)),
  (mul(a, e) + mul(b, e)) / e;
  }

  function sub(a, b) {
  var c, d, e;
  try {
   c = a.toString().split(".")[1].length;
  } catch (f) {
   c = 0;
  }
  try {
   d = b.toString().split(".")[1].length;
  } catch (f) {
   d = 0;
  }
  return e = Math.pow(10, Math.max(c, d)),
  (mul(a, e) - mul(b, e)) / e;
  }

  function mul(a, b) {
  var c = 0
   , d = a.toString()
   , e = b.toString();
  try {
   c += d.split(".")[1].length;
  } catch (f) {}
  try {
   c += e.split(".")[1].length;
  } catch (f) {}
  return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
  }

  function div(a, b) {
  var c, d, e = 0, f = 0;
  try {
   e = a.toString().split(".")[1].length;
  } catch (g) {}
  try {
   f = b.toString().split(".")[1].length;
  } catch (g) {}
  return c = Number(a.toString().replace(".", "")),
  d = Number(b.toString().replace(".", "")),
  mul(c / d, Math.pow(10, f - e));
  }
 }

 //tank自动移动定时器的清除与重建函数
 //itState表示清除、建立定时器
 function objTimer(itState) {
  for (var i = 0; i < tankArray.length; i++) {
  if (tankArray[i] != null && tankArray[i].type == "tank") {
   if (itState == "stop" && tankArray[i].t != undefined) {
   clearInterval(tankArray[i].t);
   }
   if (itState == "run" && tankArray[i].belongs == "em") {
   autoMove(tankArray[i]);
   }
  }
  }
 }

 //坦克随机状态函数
 //为自动移动的敌方坦克,返回一个方向LRUD或者Fire或者none,分别表示转向、开火和什么也不做(继续前行)
 function randState() {
  var z;
  //敌方坦克随机发射子弹的概率是1/7
  z = randomNum(10);

  switch (z) {
  case 1:
  return "L";
  break;
  case 2:
  return "R";
  break;
  case 3:
  return "D";
  break;
  case 4:
  return "L";
  break;
  //5表示发射子弹
  case 5:
  return "Fire";
  break;
  default:
  //none表示按照原来方向前进
  return "none";
  break;
  }
  function randomNum(scope) {
  return parseInt(Math.random() * scope);
  }

 }

 //坦克与子弹移动函数完--------------------------------------------------------------------------

 //游戏状态及提示函数群--------------------------------------------------------------------------

 //开始游戏
 function runGame(mapName) {
  //生成地图
  var map = document.createElement("div");
  map.id = "map";
  map.className = "map";
  document.body.appendChild(map);
  state = "RUN";
  ifo(state);
  mapName();
  playMusic("start");
  createTank(3, "me");
  createTank(1, "em", 0, 0);
  createTank(1, "em", 180, 0);
  createTank(1, "em", 330, 0);

 }
 //游戏暂停函数
 function stopGame() {

  if (state == "RUN") {
  state = "STOP";
  ifo("STOP");
  objTimer("stop");
  } else if (state == "STOP") {
  state = "RUN";
  ifo(state);
  objTimer("run");
  }

 }

 //游戏结束函数
 function gameOver() {
  state = "OVER";
  //暂停子弹的所有定时器
  objTimer("stop");
  //alert("GAME OVER");
  createDOM("over", 120, 67.5, (MAP_W - 120) / 2, (MAP_H - 67.5) / 2, "over");
  flickerObj("over");

 }

 //更改地图
 //保留的第二关、第三关
 function changeMap() {
  //清除所有定时器及地图
  objTimer("stop");
  var mapChildrenNodes = map.childNodes;
  document.body.removeChild(map);

  //执行runGame
  //runGame(map2);

 }

 //提示信息函数
 //根据游戏状态提示信息
 function ifo(state) {
  var ifo = document.getElementById("ifo");
  var ifo_title = document.getElementById("ifo_title");
  switch (state) {
  case "READY":
  ifo_title.innerHTML = "坦克大战";
  break;
  case "RUN":
  ifo.style.display = "none";
  break;
  case "STOP":
  ifo.style.display = "block";
  ifo_title.innerHTML = "暂停";
  ifo.style.backgroundColor = "transparent";
  break;
  }
 }

 //游戏状态及提示函数群完---------------------------------------------------------------------------------

 //功能砖块函数-----------------------------------------------------------------------------------------
 //生成功能性砖块
 function createFunctionWall() {
  if (emTankNum != 9 || emTankNum != 13 || emTankNum != 17) {
  return;
  }

  var selfType, x, y;
  switch (emTankNum) {
  case 9:
  selfType == "timer";
  x = 15 * 18;
  y = 15 * 6;
  break;
  case 13:
  selfType == "stronghome";
  x = 15 * 2;
  y = 15 * 18;
  break;
  case 17:
  selfType == "bomb";
  x = 15 * 22;
  y = 15 * 17;
  break;
  }
  var it = new wall(selfType,x,y,"function");
  flickerObj(it.id);
  //11秒后删除它
  setTimeout(function() {
  //10秒后删除前闪烁功能砖,如果已经被吃了就取消闪烁
  if (functionWallArray.indexOf(it) != -1) {
   flickerObj(it.id);
  }
  }, 10000);

  setTimeout(function() {
  //如果11秒删除时发现功能砖已经被吃了就取消删除
  if (functionWallArray.indexOf(it) != -1) {
   delObj(it);
  }
  }, 11000);
 }

 //老巢steel砖块函数
 function StrongHome() {

  function changeHome(selfType) {
  for (var i = 0; i < noMoveArray.length; i++) {
   for (var j = 0; j < noMoveArray[i].length; j++) {
   if (noMoveArray[i][j] != null && noMoveArray[i][j].belongs == "home" && noMoveArray[i][j].selfType != "star") {
    noMoveArray[i][j].selfType = selfType;
    noMoveArray[i][j].img = noMoveArray[i][j].selfType;
    var obj = noMoveArray[i][j];
    showDOM(obj.id, obj.width, obj.height, obj.x, obj.y, obj.getImg());
   }
   }
  }
  }
  changeHome("steel");
  setTimeout(function() {
  changeHome("wall");
  }, 5000);
 }

 //爆炸砖块函数
 function bomb() {
  for (var i = 0; i < tankArray.length; i++) {
  objTimer("stop");
  if (tankArray[i] != null && tankArray[i].belongs == "em") {
   //console.log(moveArray[i])
   delObj(tankArray[i]);
  }
  }
 }

 //定时器砖块函数
 function timer() {
  //暂停坦克的所有定时器
  objTimer("stop");
  setTimeout(function() {
  objTimer("run");
  }, 2000);
 }
 //功能砖块函数完---------------------------------------------------------------------------------------

 //特效函数群------------------------------------------------------------------------------------------

 //音乐函数
 function playMusic(src) {
  var audio = document.createElement("audio");
  //var audio=document.createElement("<video controls muted autoplay >");
  audio.src = MUSIC_PATH + src + ".wav";
  //路径
  audio.play();
 }

 //闪烁函数
 function flickerObj(id, interval) {
  var it = document.getElementById(id);
  for (let i = 1; i <= 3; i++) {
  setTimeout(function() {
   var display = i % 2 == 0 ? "none" : "block";
   it.style.display = display;
   //it.style.display="none";
  }, (interval / 3) * i);

  }
 }

 //创建坦克/坦克爆炸动画函数
 //animationType可取born、blast分别表示坦克出生以及子弹爆炸
 function animation(animationType, x, y) {
  //这里给动画所用原子设置一个随机数id,防止两幅动画使用id一样造成只有一幅动画的情况
  //这样仍可能使用一副动画,不过可能为4/1000
  animationTypeid = Math.random() * 1000;
  var id = animationType + animationTypeid;
  //显示次数
  var times = animationType == "born" ? 3 : 1;
  //显示频率
  var fre = animationType == "born" ? 1000 : 300;
  // var width = animationType == "born" ? TANK_W : BULLENT_W;
  // var height = animationType == "born" ? TANK_H : BULLENT_H;
  var width = TANK_W;
  var height = TANK_H;
  //创建动画原子并闪烁
  for (let i = 1; i <= times; i++) {
  setTimeout(function() {
   createDOM(id + i, width, height, x, y, animationType + i);
   flickerObj(id + i, fre / times);
  }, fre * i);

  }
  //闪烁完毕删除闪烁原子
  setTimeout(function() {
  for (let i = 1; i <= times; i++) {
   delDOM(id + i);
  }
  }, fre * (times + 1));

 }
 //特效函数群完--------------------------------------------------------------------------------------

 //坦克大战主逻辑-----------------------------------------------------------------------------------

 ifo("READY");

 //坦克大战主逻辑完---------------------------------------------------------------------------------

 //键盘监听及触发处理开始------------------------------------------------------------------------------

 noresponseFire = false;
 noresponseTankMove = false;
 document.onkeydown = function(event) {

  //如果游戏状态为结束就屏蔽所有按键
  if (state == "OVER") {
  return;
  }
  var myTank = tankArray[0];
  var newDir;
  // 87=W;83=S;65=A;68=D
  code = event.keyCode;
  //可以通过在此输出code检测键盘的键值码
  // console.log(code)
  if (code == 65 && state == "RUN" && mytank != null && noresponseTankMove == false) {
  setNOresponse("TankMove", NORESPONSEFIRETIME);
  newDir = "L";
  } else if (code == 87 && state == "RUN" && mytank != null && noresponseTankMove == false) {
  console.log(noresponseTankMove)
  setNOresponse("TankMove", NORESPONSEFIRETIME);
  newDir = "U";
  } else if (code == 68 && state == "RUN" && mytank != null && noresponseTankMove == false) {
  setNOresponse("TankMove", NORESPONSEFIRETIME);
  newDir = "R";
  } else if (code == 83 && state == "RUN" && mytank != null && noresponseTankMove == false) {
  setNOresponse("TankMove", NORESPONSEFIRETIME);
  newDir = "D";
  //T 84 开始游戏
  } else if (code == 84 && state == "READY") {
  runGame(map1);
  return;
  //发射子弹 Enter 13
  } else if (code == 13 && state == "RUN" && mytank != null && noresponseFire == false) {
  //按键屏蔽,一定时间内发射子弹无效

  createBullent(myTank);
  noresponseFire = true;
  //屏蔽P键300ms
  setTimeout(function() {
   noresponseFire = false;
  }, NORESPONSEFIRETIME);
  return;
  //屏蔽其他无关按键
  //P 80表示暂停
  } else if (code == 80 && (state == "RUN" || state == "STOP")) {
  stopGame();
  return;
  //屏蔽其他无关按键
  } else {
  return;
  }
  move(myTank, newDir);

 }

 function setNOresponse(noresponseState, t) {
  if (noresponseState == "TankMove") {
  noresponseTankMove = true;
  //屏蔽P键300ms
  setTimeout(function() {
   noresponseTankMove = false;
  }, t);
  }

 }

 //键盘监听及触发处理完------------------------------------------------------------------------------

 //地图1------------------------------------------------------------------------------------------

 var map1 = function() {

  //老巢
  new wall("star",15 * 12,15 * 24,"home");
  new wall("wall",15 * 11,15 * 25,"home");
  new wall("wall",15 * 11,15 * 24,"home");
  new wall("wall",15 * 11,15 * 23,"home");

  new wall("wall",15 * 12,15 * 23,"home");
  new wall("wall",15 * 13,15 * 23,"home");

  new wall("wall",15 * 14,15 * 25,"home");
  new wall("wall",15 * 14,15 * 24,"home");
  new wall("wall",15 * 14,15 * 23,"home");
  // 老巢完毕

  //所有普通wall
  for (var i = 1; i <= 11; i += 2) {
  for (var j = 2; j < 24; j++) {
   if (j >= 10 && j < 14) {
   continue;
   }
   if (i == 5 || i == 7) {
   if (j > 8 && j <= 11)
    continue;
   if (j > 20)
    continue;
   } else {
   if (j >= 14 && j < 16) {
    continue;
   }
   }

   new wall("wall",15 * 2 * i,15 * j,"ordinary");
   new wall("wall",15 * 2 * i + 15,15 * j,"ordinary");
  }
  }

  for (var i = 0; i < 6; i++) {
  for (var j = 0; j < 2; j++) {
   new wall("wall",15 * i + 15 * 10,15 * 11 + 15 * j,"ordinary");
   if (i > 3)
   continue;
   new wall("wall",15 * i + 15 * 4,15 * 12 + 15 * j,"ordinary");

   new wall("wall",15 * i + 15 * 18,15 * 12 + 15 * j,"ordinary");
  }

  }

  new wall("wall",15 * 12,15 * 15,"ordinary");
  new wall("wall",15 * 12,15 * 16,"ordinary");
  new wall("wall",15 * 13,15 * 15,"ordinary");
  new wall("wall",15 * 13,15 * 16,"ordinary");

  //steel 
  new wall("steel",15 * 0,15 * 13,"ordinary");
  new wall("steel",15 * 1,15 * 13,"ordinary");

  new wall("steel",15 * 24,15 * 13,"ordinary");
  new wall("steel",15 * 25,15 * 13,"ordinary");

  new wall("steel",15 * 12,15 * 6,"ordinary");
  new wall("steel",15 * 12,15 * 7,"ordinary");
  new wall("steel",15 * 13,15 * 6,"ordinary");
  new wall("steel",15 * 13,15 * 7,"ordinary");

 }
 //地图1完---------------------------------------------------------
 </script>
</html>

更多关于Js游戏的精彩文章,请查看专题: 《JavaScript经典游戏 玩不停》

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 面向对象继承
Nov 26 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
Nov 11 Javascript
jQuery 翻牌或百叶窗效果(内容三秒自动切换)
Jun 14 Javascript
node.js中的fs.closeSync方法使用说明
Dec 17 Javascript
JavaScript实现iframe自动高度调整和不同主域名跨域
Feb 27 Javascript
JS表单数据验证的正则表达式(常用)
Feb 18 Javascript
基于vue的fullpage.js单页滚动插件
Mar 20 Javascript
Vue+axios+WebApi+NPOI导出Excel文件实例方法
Jun 05 Javascript
vue element自定义表单验证请求后端接口验证
Dec 11 Javascript
微信小程序实现多选框全选与反全选及购物车中删除选中的商品功能
Dec 17 Javascript
js原生map实现的方法总结
Jan 19 Javascript
Vue中 axios delete请求参数操作
Aug 25 Javascript
Vue中点击active并第一个默认选中功能的实现
Feb 24 #Javascript
如何在JavaScript中创建具有多个空格的字符串?
Feb 23 #Javascript
浅谈TypeScript的类型保护机制
Feb 23 #Javascript
原生javascript制作的拼图游戏实现方法详解
Feb 23 #Javascript
原生javascript运动函数的封装示例【匀速、抛物线、多属性的运动等】
Feb 23 #Javascript
es6中Promise 对象基本功能与用法实例分析
Feb 23 #Javascript
原生JavaScript之es6中Class的用法分析
Feb 23 #Javascript
You might like
Zend Framework动作助手FlashMessenger用法详解
2016/03/05 PHP
setTimeout和setInterval的浏览器兼容性分析
2007/02/27 Javascript
解析javascript 数组以及json元素的添加删除
2013/06/26 Javascript
JavaScript中反正弦函数Math.asin()的使用简介
2015/06/14 Javascript
js中利用tagname和id获取元素的方法
2016/01/03 Javascript
javascript实现图片左右滚动效果【可自动滚动,有左右按钮】
2016/09/19 Javascript
走进AngularJs之过滤器(filter)详解
2017/02/17 Javascript
javascript中的面向对象
2017/03/30 Javascript
微信小程序 支付功能实现PHP实例详解
2017/05/12 Javascript
vue实现页面加载动画效果
2017/09/19 Javascript
vue2.0模拟锚点的实例
2018/03/14 Javascript
vue-cli3脚手架的配置及使用教程
2018/08/28 Javascript
Vue中使用ElementUI使用第三方图标库iconfont的示例
2018/10/11 Javascript
vue2.0 路由模式mode=&quot;history&quot;的作用
2018/10/18 Javascript
Vue 框架之键盘事件、健值修饰符、双向数据绑定
2018/11/14 Javascript
VUE接入腾讯验证码功能(滑块验证)备忘
2019/05/07 Javascript
vue中axios防止多次触发终止多次请求的示例代码(防抖)
2020/02/16 Javascript
Python中使用Boolean操作符做真值测试实例
2015/01/30 Python
解析Python中的异常处理
2015/04/28 Python
Python中断言Assertion的一些改进方案
2016/10/27 Python
Python yield与实现方法代码分析
2018/02/06 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
Python中itertools的用法详解
2020/02/07 Python
Python实现链表反转的方法分析【迭代法与递归法】
2020/02/22 Python
html5简单示例_动力节点Java学院整理
2017/07/07 HTML / CSS
美国指甲油品牌:Deco Miami
2017/01/30 全球购物
客房主管岗位职责
2013/12/09 职场文书
预备党员思想汇报范文
2014/01/11 职场文书
护理不良事件检讨书
2014/02/06 职场文书
学校搬迁方案
2014/06/15 职场文书
师范生免费教育协议书范本
2014/10/09 职场文书
单身申明具结书
2015/02/26 职场文书
幼儿教师师德培训心得体会
2016/01/09 职场文书
小学一年级语文教学反思
2016/03/03 职场文书
朋友圈早安励志语录!
2019/07/08 职场文书
PostgreSQL并行计算算法及参数强制并行度设置方法
2022/04/06 PostgreSQL