1. 程式人生 > 程式設計 >js實現坦克大戰遊戲

js實現坦克大戰遊戲

本文例項為大家分享了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,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,1);
      //把生成的子彈物件存入移動物件陣列
      bullentArray.push(this);
      autoMove(this);

    }

    //牆物件  
    wall = function(selfType,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,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,img,zIndex) {
      var map = document.getElementById("map");
      var it = document.createElement("div");
      it.id = id;
      it.style.zIndex = zIndex;
      map.appendChild(it);
      showDOM(id,img);

    }
    //刪除DOM物件函式
    function delDOM(id) {
      var it = document.getElementById(id);
      map.removeChild(it);
    }

    //展示函式,根據obj的屬性重新整理對應的DOM
    function showDOM(id,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,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 * 24);
        //我方坦克顯示位置固定
        setTimeout(function() {
          var mytank = new tank(3,"U");
          flickerObj(mytank.id);
        },4500);

      }
      if (belongs == "em" && emTankNum != 0) {
        animation("born",y);
        //我方坦克顯示位置固定
        setTimeout(function() {
          var emtank = new tank(1,"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",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);
            ;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.y,obj.getImg());
        }
        ;break;
      case "wall":
        if (obj.selfType == "star") {
          img = "destory";
          showDOM(obj.id,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.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.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.y);
        // }
        // console.log("目標y="+checkTank.y)
        obj.x = checkObj.x;
        obj.y = checkObj.y;
        // if(obj.type=="bullent"){
        //   showDOM(obj.id,obj.getImg());
        // }
        // showDOM(obj.id,obj.getImg());

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

        delObj(obj);
      } else if (collresult == "NOMOVE") {
        showDOM(obj.id,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,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,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,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,0);
      createTank(1,180,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,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,"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.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,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,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,"home");
      new wall("wall",15 * 11,15 * 25,15 * 23,"home");

      new wall("wall",15 * 13,15 * 14,"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,"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,"ordinary");
        }

      }

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

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

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

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。