溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

js如何實(shí)現(xiàn)坦克大戰(zhàn)游戲

發(fā)布時(shí)間:2021-04-19 09:52:42 來(lái)源:億速云 閱讀:270 作者:小新 欄目:web開(kāi)發(fā)

小編給大家分享一下js如何實(shí)現(xiàn)坦克大戰(zhàn)游戲,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

具體內(nèi)容如下

<!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">
  <h2 id="ifo_title"></h2>
  <h4>按鍵說(shuō)明:</h4>
  T:開(kāi)始游戲(游戲開(kāi)始后無(wú)效)<br/>
  P:暫停游戲<br/>
  W、S、A、D:上、下、左、右<br/>
  ENTER:發(fā)射子彈<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;
 //當(dāng)前文件同目錄
 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;
 //坦克移動(dòng)不響應(yīng)時(shí)間
 const NORESPONSEFIRETIME = 200;
 const NORESPONSETANKMOVETIME = TANK_FREQ + 100;
 //我方坦克開(kāi)火、移動(dòng)狀態(tài)
 noresponseFire = false;
 noresponseTankMove = false;
 //游戲狀態(tài)
 state = "READY";
 //frequency頻率

 //對(duì)象id
 var tank_id = 0;
 var bullent_id = 0;
 var wall_id = 0;
 //敵方坦克總數(shù)
 var emTankNum = 20;
 var meTankNum = 3;
 //我方坦克對(duì)象
 var mytank = null;

 var tankArray = new Array();
 var bullentArray = new Array();
 //因?yàn)楣δ苄源u塊會(huì)與普通靜態(tài)磚塊重疊所以必須另外存儲(chǔ)
 var functionWallArray = new Array();
 //地圖width=390,地圖中最小的靜物wall寬度高度=15,所以數(shù)組的一維二維均為390/15=26
 //先聲明一維
 var noMoveArray = new Array(4);
 for (var i = 0; i < MAP_W / WALL_W; i++) {
  //一維長(zhǎng)度
  noMoveArray[i] = new Array();
  //再聲明二維
  for (var j = 0; j < MAP_H / WALL_H; j++) {
  //二維長(zhǎng)度
  noMoveArray[i][j] = null;
  }
 }
 //常量及全局變量完--------------------------------------------------------------------------------

 //對(duì)象的定義-------------------------------------------------------------------------------------

 //坦克對(duì)象
 tank = function(selfType, x, y, belongs, dir) {
  //共有屬性
  this.id = "tank_" + tank_id++;
  this.type = "tank";
  //selfType可取1、2、3表示一類(lèi)坦克,二類(lèi)坦克,三類(lèi)坦克
  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;
  //因?yàn)樘箍说膇mg與方向有關(guān),每一次改變dir都會(huì)影響img,所以設(shè)置一個(gè)對(duì)象函數(shù)用于獲取
  this.getImg = function() {
  return img = this.belongs + "Tank" + this.selfType + this.dir;
  }

  //敵方坦克的自移動(dòng)函數(shù)的setInterval的值t
  this.t;
  createDOM(this.id, this.width, this.height, this.x, this.y, this.getImg(), 2);
  //把生成的坦克對(duì)象存入移動(dòng)對(duì)象數(shù)組
  tankArray.push(this);

  if (belongs == "me") {
  mytank = this;
  meTankNum--;
  }
  //敵方坦克調(diào)用自移動(dòng)函數(shù)
  if (this.belongs == "em") {
  emTankNum--;
  //檢測(cè)是否需要生成功能磚塊
  createFunctionWall();
  autoMove(this);
  }
 }

 //子彈對(duì)象
 bullent = function(selfType, x, y, belongs, dir) {
  //播放發(fā)射子彈音樂(lè)
  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保持一致,同樣設(shè)置一個(gè)對(duì)象函數(shù)用于獲取
  this.getImg = function() {
  return img = this.type;
  }
  //子彈與敵方坦克特有屬性,自移動(dòng)的定時(shí)器
  this.t;
  createDOM(this.id, this.width, this.height, this.x, this.y, this.getImg(), 1);
  //把生成的子彈對(duì)象存入移動(dòng)對(duì)象數(shù)組
  bullentArray.push(this);
  autoMove(this);

 }

 //墻對(duì)象 
 wall = function(selfType, x, y, belongs) {
  //共有屬性
  this.id = "wall_" + wall_id++;
  this.type = "wall";
  //wall、steel、star、timer分別表示普通磚塊、子彈不可打破磚塊、我方老巢、定時(shí)器
  this.selfType = selfType;
  this.x = x;
  this.y = y;
  //belongs取值home、ordinary、function分別表示老巢的磚塊、一般磚塊、功能性磚塊
  this.belongs = belongs;
  this.width;
  this.height;

  if (this.selfType == "star") {
  //設(shè)置全局變量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保持一致,同樣設(shè)置一個(gè)對(duì)象函數(shù)用于獲取
  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類(lèi)型的,分為長(zhǎng)寬15的wall、steel和長(zhǎng)寬30的star;我們只需要存儲(chǔ)15規(guī)格的,star只有一個(gè)不需要存儲(chǔ)
  if (this.belongs != "function") {
  noMoveArray[x / 15][y / 15] = this;
  } else {
  functionWallArray.push(this);
  }
 }

 //對(duì)象的定義完------------------------------------------------------------------------------------

 //DOM對(duì)象創(chuàng)建與顯示-------------------------------------------------------------------------------
 //總體說(shuō)明:1、為了便于計(jì)算所有對(duì)象的width、height、x、y均不帶px單位
 // 創(chuàng)建DOM對(duì)象函數(shù)
 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對(duì)象函數(shù)
 function delDOM(id) {
  var it = document.getElementById(id);
  map.removeChild(it);
 }

 //展示函數(shù),根據(jù)obj的屬性刷新對(duì)應(yīng)的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對(duì)象創(chuàng)建與顯示完-------------------------------------------------------------------------------

 //對(duì)象的創(chuàng)建與銷(xiāo)毀函數(shù)群-----------------------------------------------------------------------------

 //創(chuàng)建坦克函數(shù)
 //因?yàn)樘箍顺霈F(xiàn)有一個(gè)動(dòng)畫(huà),不能直接new tank生成
 //new tank(3,15 * 8,15 * 24,"me","U")
 function createTank(selfType, belongs, x, y) {
  //先讓創(chuàng)建動(dòng)畫(huà)顯示
  var emTank_x1 = 0
  , emTank_x2 = 180;
  emTank_x3 = 360;
  var emTank_y = 0;
  var meTank_x = 15 * 8;
  var meTank_y = 15 * 24;

  //因?yàn)閯?chuàng)建動(dòng)畫(huà)顯示3s+銷(xiāo)毀1s,所以需要在4s后創(chuàng)建坦克
  //這里需要對(duì)出生的位置進(jìn)行檢測(cè),防止坦克重疊
  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;
  }
  }

 }

 //發(fā)射子彈函數(shù)
 //根據(jù)發(fā)射子彈坦克位置和方向,生成一個(gè)子彈
 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);

 }

 //刪除對(duì)象函數(shù)
 //在html中刪除元素,并將數(shù)組中的值賦值為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;
   }
   //調(diào)用銷(xiāo)毀坦克動(dòng)畫(huà)
   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;
  }

 }

 //對(duì)象的創(chuàng)建與銷(xiāo)毀函數(shù)群完---------------------------------------------------------------------------

 //碰撞檢測(cè)與處理------------------------------------------------------------------------------------

 //獲取可能碰撞的靜態(tài)物體函數(shù)
 //在存儲(chǔ)靜物的時(shí)候使用二維數(shù)組相當(dāng)于將地圖畫(huà)成間距15的小格子,所有的靜物均在小格子中,所以給定一個(gè)物體就可以得到包圍它一圈的小格子;
 //這比遍歷整個(gè)noMoveArray來(lái)的快的多
 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;
  //計(jì)算出的左側(cè)、右側(cè)、上下側(cè)均不能出地圖
  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;

 }

 //碰撞檢測(cè)及處理函數(shù)
 function collision(obj) {
  //collresult有三個(gè)值,MOVE、DELETE、NOMOVE;move表示檢測(cè)后的處理結(jié)果是繼續(xù)移動(dòng)(即使碰上了,有些也不需要處理),DELETE表示刪除自身
  //因?yàn)榕鲎矙z測(cè)只存在與移動(dòng)物體,而移動(dòng)函數(shù)需要碰撞檢測(cè)給出是否移動(dòng)的結(jié)果,所以不能在碰撞處理中直接刪除被檢測(cè)物體
  var collresult = "MOVE";
  //單獨(dú)檢測(cè)是否碰撞老巢
  //collresult = isCollision(obj, star) ? gameOver():"MOVE";
  //檢測(cè)功能性磚塊
  for (var i = 0; i < functionWallArray.length; i++) {
  if (functionWallArray[i] != null && isCollision(obj, functionWallArray[i])) {
   collresult = delColl(obj, functionWallArray[i]);
  }
  }

  //檢測(cè)所有的靜物;采用的是遍歷所有靜物
  // 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]);
  //  }
  // }
  // }

  //檢測(cè)所有的靜物;采用的是遍歷可能相撞的靜物
  var PossibleCollisionObjArray = getPossibleCollisionObj(obj);
  for (var i = 0; i < PossibleCollisionObjArray.length; i++) {
  if (isCollision(obj, PossibleCollisionObjArray[i])) {
   collresult = delColl(obj, PossibleCollisionObjArray[i]);
  }
  }

  //檢測(cè)坦克
  for (var i = 0; i < tankArray.length; i++) {
  //tankArray[i].id != obj.id 因?yàn)闄z測(cè)的時(shí)候的對(duì)象是通過(guò)拷貝得到的,它與真正的坦克的id一樣
  if (tankArray[i] != null && tankArray[i].id != obj.id && isCollision(obj, tankArray[i])) {
   collresult = delColl(obj, tankArray[i]);
  }
  }

  //檢測(cè)子彈
  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;
 }

 //碰撞檢測(cè)
 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;

  //分別不在被檢測(cè)物體的左右上下說(shuō)明發(fā)生碰撞,開(kāi)始處理(第一種檢測(cè)碰撞算法,考慮反面情況)
  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;

 }

 //碰撞處理函數(shù)
 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+"相撞了  "+"結(jié)果="+collresult);
  return collresult;
 }

 //碰撞檢測(cè)與處理完------------------------------------------------------------------------------------

 //坦克與子彈移動(dòng)函數(shù)-----------------------------------------------------------------------------------

 //移動(dòng)函數(shù)
 function move(obj, newDir) {
  var oldDir = obj.dir;
  obj.dir = newDir;
  if (state != "RUN") {
  // if(obj.type!="bullent"){
  // return;
  // }
  return;
  }
  //新的方向與坦克原來(lái)方向相同就前進(jìn),否則改變坦克方向
  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);
  //出界檢測(cè);
  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;
  }
  //調(diào)用碰撞檢測(cè)及處理函數(shù)給出移動(dòng)結(jié)果
  } else if (collresult == "MOVE") {
  // if(obj.type=="tank"){
  // movingFrame(obj,checkObj.x,checkObj.y) 
  movingFrame(obj, checkObj.x, checkObj.y);
  // }
  // console.log("目標(biāo)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());
  //如果是敵方坦克就給他一個(gè)相反的方向,防止它撞墻不回頭
  if (obj.belongs == "em" && obj.type == "tank") {}
  return;
  }

 }

 //反方向函數(shù)
 //返回一個(gè)與輸入方向相反的方向
 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;
  }
 }

 //自動(dòng)移動(dòng)函數(shù)
 //子彈坦克所特有
 function autoMove(obj) {
  // console.log("游戲狀態(tài)="+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);
 }

 //簡(jiǎn)化版移動(dòng)框架
 //為了使坦克的移動(dòng)更平滑;使用移動(dòng)框架的前提:必須在t時(shí)間內(nèi)屏蔽坦克的任何方向改變
 //因?yàn)閖s浮點(diǎn)數(shù)的處理很復(fù)雜,這里僅僅滿足x,y為7.5的倍數(shù),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);

  //浮點(diǎn)數(shù)的加減乘除

  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自動(dòng)移動(dòng)定時(shí)器的清除與重建函數(shù)
 //itState表示清除、建立定時(shí)器
 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]);
   }
  }
  }
 }

 //坦克隨機(jī)狀態(tài)函數(shù)
 //為自動(dòng)移動(dòng)的敵方坦克,返回一個(gè)方向LRUD或者Fire或者none,分別表示轉(zhuǎn)向、開(kāi)火和什么也不做(繼續(xù)前行)
 function randState() {
  var z;
  //敵方坦克隨機(jī)發(fā)射子彈的概率是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表示發(fā)射子彈
  case 5:
  return "Fire";
  break;
  default:
  //none表示按照原來(lái)方向前進(jìn)
  return "none";
  break;
  }
  function randomNum(scope) {
  return parseInt(Math.random() * scope);
  }

 }

 //坦克與子彈移動(dòng)函數(shù)完--------------------------------------------------------------------------

 //游戲狀態(tài)及提示函數(shù)群--------------------------------------------------------------------------

 //開(kāi)始游戲
 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);

 }
 //游戲暫停函數(shù)
 function stopGame() {

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

 }

 //游戲結(jié)束函數(shù)
 function gameOver() {
  state = "OVER";
  //暫停子彈的所有定時(shí)器
  objTimer("stop");
  //alert("GAME OVER");
  createDOM("over", 120, 67.5, (MAP_W - 120) / 2, (MAP_H - 67.5) / 2, "over");
  flickerObj("over");

 }

 //更改地圖
 //保留的第二關(guān)、第三關(guān)
 function changeMap() {
  //清除所有定時(shí)器及地圖
  objTimer("stop");
  var mapChildrenNodes = map.childNodes;
  document.body.removeChild(map);

  //執(zhí)行runGame
  //runGame(map2);

 }

 //提示信息函數(shù)
 //根據(jù)游戲狀態(tài)提示信息
 function ifo(state) {
  var ifo = document.getElementById("ifo");
  var ifo_title = document.getElementById("ifo_title");
  switch (state) {
  case "READY":
  ifo_title.innerHTML = "坦克大戰(zhàn)";
  break;
  case "RUN":
  ifo.style.display = "none";
  break;
  case "STOP":
  ifo.style.display = "block";
  ifo_title.innerHTML = "暫停";
  ifo.style.backgroundColor = "transparent";
  break;
  }
 }

 //游戲狀態(tài)及提示函數(shù)群完---------------------------------------------------------------------------------

 //功能磚塊函數(shù)-----------------------------------------------------------------------------------------
 //生成功能性磚塊
 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秒后刪除前閃爍功能磚,如果已經(jīng)被吃了就取消閃爍
  if (functionWallArray.indexOf(it) != -1) {
   flickerObj(it.id);
  }
  }, 10000);

  setTimeout(function() {
  //如果11秒刪除時(shí)發(fā)現(xiàn)功能磚已經(jīng)被吃了就取消刪除
  if (functionWallArray.indexOf(it) != -1) {
   delObj(it);
  }
  }, 11000);
 }

 //老巢steel磚塊函數(shù)
 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);
 }

 //爆炸磚塊函數(shù)
 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]);
  }
  }
 }

 //定時(shí)器磚塊函數(shù)
 function timer() {
  //暫停坦克的所有定時(shí)器
  objTimer("stop");
  setTimeout(function() {
  objTimer("run");
  }, 2000);
 }
 //功能磚塊函數(shù)完---------------------------------------------------------------------------------------

 //特效函數(shù)群------------------------------------------------------------------------------------------

 //音樂(lè)函數(shù)
 function playMusic(src) {
  var audio = document.createElement("audio");
  //var audio=document.createElement("<video controls muted autoplay >");
  audio.src = MUSIC_PATH + src + ".wav";
  //路徑
  audio.play();
 }

 //閃爍函數(shù)
 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);

  }
 }

 //創(chuàng)建坦克/坦克爆炸動(dòng)畫(huà)函數(shù)
 //animationType可取born、blast分別表示坦克出生以及子彈爆炸
 function animation(animationType, x, y) {
  //這里給動(dòng)畫(huà)所用原子設(shè)置一個(gè)隨機(jī)數(shù)id,防止兩幅動(dòng)畫(huà)使用id一樣造成只有一幅動(dòng)畫(huà)的情況
  //這樣仍可能使用一副動(dòng)畫(huà),不過(guò)可能為4/1000
  animationTypeid = Math.random() * 1000;
  var id = animationType + animationTypeid;
  //顯示次數(shù)
  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;
  //創(chuàng)建動(dòng)畫(huà)原子并閃爍
  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));

 }
 //特效函數(shù)群完--------------------------------------------------------------------------------------

 //坦克大戰(zhàn)主邏輯-----------------------------------------------------------------------------------

 ifo("READY");

 //坦克大戰(zhàn)主邏輯完---------------------------------------------------------------------------------

 //鍵盤(pán)監(jiān)聽(tīng)及觸發(fā)處理開(kāi)始------------------------------------------------------------------------------

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

  //如果游戲狀態(tài)為結(jié)束就屏蔽所有按鍵
  if (state == "OVER") {
  return;
  }
  var myTank = tankArray[0];
  var newDir;
  // 87=W;83=S;65=A;68=D
  code = event.keyCode;
  //可以通過(guò)在此輸出code檢測(cè)鍵盤(pán)的鍵值碼
  // 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 開(kāi)始游戲
  } else if (code == 84 && state == "READY") {
  runGame(map1);
  return;
  //發(fā)射子彈 Enter 13
  } else if (code == 13 && state == "RUN" && mytank != null && noresponseFire == false) {
  //按鍵屏蔽,一定時(shí)間內(nèi)發(fā)射子彈無(wú)效

  createBullent(myTank);
  noresponseFire = true;
  //屏蔽P鍵300ms
  setTimeout(function() {
   noresponseFire = false;
  }, NORESPONSEFIRETIME);
  return;
  //屏蔽其他無(wú)關(guān)按鍵
  //P 80表示暫停
  } else if (code == 80 && (state == "RUN" || state == "STOP")) {
  stopGame();
  return;
  //屏蔽其他無(wú)關(guān)按鍵
  } else {
  return;
  }
  move(myTank, newDir);

 }

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

 }

 //鍵盤(pán)監(jiān)聽(tīng)及觸發(fā)處理完------------------------------------------------------------------------------

 //地圖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如何實(shí)現(xiàn)坦克大戰(zhàn)游戲”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

js
AI