溫馨提示×

溫馨提示×

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

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

怎么用Javascript實現(xiàn)俄羅斯方塊游戲

發(fā)布時間:2021-07-29 21:19:33 來源:億速云 閱讀:196 作者:chen 欄目:web開發(fā)

這篇文章主要介紹“怎么用Javascript實現(xiàn)俄羅斯方塊游戲”,在日常操作中,相信很多人在怎么用Javascript實現(xiàn)俄羅斯方塊游戲問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么用Javascript實現(xiàn)俄羅斯方塊游戲”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

本俄羅斯方塊代碼采用 JavaScript 腳本代碼寫成,簡單易懂;

全代碼采用靜態(tài)類及靜態(tài)變量成員組成;

全腳本通過實現(xiàn)代碼全局配置 OLSFK.Options = {...}

定義方塊起始坐標(biāo)及定義各自的旋轉(zhuǎn)點;

從初始化俄羅斯方塊界面開始,再監(jiān)聽鍵盤事件;以及左右,向下及旋轉(zhuǎn)動作判斷,重新渲染方塊位置;

判斷是否消行,以及相應(yīng)的加級判斷,執(zhí)行速度,加分操作來執(zhí)行;

***以判斷是否當(dāng)前級別大于所定義的***級別來判斷是否結(jié)束;

代碼說明講解

OLSFK.Options = { //相關(guān)參數(shù)      width:12,//界面橫向方塊數(shù)      height:20,//界面縱向方塊數(shù)      boxWidth : '16px',      curLevel:1,      speed : 1000, //setInterval,setTimeout      direct : { //可以設(shè)定是A S D W, 還是← ↓ →           Down: 40 , /*run speed*/         Left: 37,          Right: 39,          Rotate: 38      },      Move:true,//是否正在移動      Eventing:false,      Levels: {          1:1000,          2:900,          3:800,          4:700,          5:600,          6:500,          7:400,          8:300,          9:200,          10:100      },      curBlock:4, //當(dāng)前移動的圖形名稱      nextBlock:0,      GampMap:new Object(),      Timer:null,      deline:0,      Score:0,      Deling:false,      Start:false,      lineNum:10, //刪除幾行了,加級      ScoreNum:40 //消一行加分  }

direct 表示 使用鍵盤方位鍵來操作方塊的移動方向;

使用哪種方向鍵按自由喜歡配置,比如字母鍵的A, S, D, W; 或右邊小數(shù)字鍵盤的數(shù)字鍵各自的鍵盤編碼;

比如 上(旋轉(zhuǎn))、下、左、右 方向鍵的編碼分別為:38、40、37、39;

Levels:表示級別配置,本配置共分為10級,每個級別所對應(yīng)的下落速度,即定時執(zhí)行間隔;

curBlock:表示當(dāng)前活動的方塊;

nextBlock:表示接下來執(zhí)行的方塊索引,并顯示界面右上角的預(yù)覽框中;

GampMap:用于保存在根據(jù)定義行列數(shù)形成的游戲表格中保存每個格的數(shù)據(jù)信息;

OLSFK.Options.GampMap[x+'_'+y] = 0;

對象表格為: id: "box_"+x+"_"+y;

初始化數(shù)據(jù)為 ‘0’;  表示該表格還未占用;當(dāng)有占用時,設(shè)置值為 ‘1’;

Timer:為定時執(zhí)行器;setTimeout 定時執(zhí)行方塊下落的的頻率;定時時間越小,速度越快;

Deling:當(dāng)正在執(zhí)行消行操作時,下次暫不顯示并下落;

lineNum:表示消超過 10 行,加一級;

ScoreNum:表示每消一行所加的分?jǐn)?shù);

OLSFK.ReItems = function (cur){ //key旋轉(zhuǎn)點            switch (cur)      {          case 1:              OLSFK.Items[1] = {//長塊 LongBlock                                  1:{x:4,y:0},                                  2:{x:5,y:0},                                  3:{x:6,y:0},                                  4:{x:7,y:0},                                  5:{x:5,y:0} //旋轉(zhuǎn)點                              };              break;                          //....          }  }

該方法用于恢復(fù)方塊的初始設(shè)置;

OLSFK.Next = { //key旋轉(zhuǎn)點      //長塊 LongBlock      1: {          1:{x:0,y:1},          2:{x:1,y:1},          3:{x:2,y:1},          4:{x:3,y:1}      },          //...  }

為不了不與游戲方塊的設(shè)置沖突,獨立出來下次隨機方塊的對象配置;

OLSFK.Items = { //key旋轉(zhuǎn)點      //長塊 LongBlock      1: {          1:{x:4,y:0},          2:{x:5,y:0},          3:{x:6,y:0},          4:{x:7,y:0},          5:{x:5,y:0}      },      //方塊Box      2: {          1:{x:4,y:0},          2:{x:5,y:0},          3:{x:4,y:1},          4:{x:5,y:1},          5:{x:0,y:0}      },      //凸塊 TuBlock      3: {          1:{x:4,y:1},          2:{x:5,y:0},          3:{x:5,y:1},          4:{x:6,y:1},          5:{x:5,y:1}      },      //L塊 LBlock      4: {          1:{x:5,y:0},          2:{x:5,y:1},          3:{x:5,y:2},          4:{x:6,y:2},          5:{x:5,y:2}      },      5: { //反向L塊 FLBlock          1:{x:5,y:2},          2:{x:6,y:2},          3:{x:6,y:1},          4:{x:6,y:0},          5:{x:6,y:2}      },      //Z塊 ZBlock      6: {          1:{x:4,y:0},          2:{x:5,y:0},          3:{x:5,y:1},          4:{x:6,y:1},          5:{x:5,y:0}      },      7: {//反向Z塊 FZBlock          1:{x:4,y:1},          2:{x:5,y:1},          3:{x:5,y:0},          4:{x:6,y:0},          5:{x:5,y:1}      }  }

方塊共分為:長條塊,方塊,凸塊(T塊),L塊,反L塊,Z塊,反Z塊幾種;

共7種方塊,以1,2,3,4,5,6,7 索引鍵表示,方塊是四個小塊組成,每塊都有各自的坐標(biāo),1-4表示組成該塊的初始坐標(biāo)位置,5表示旋轉(zhuǎn)點;

OLSFK.Init = function() { //初始化界面      //...  }

俄羅斯方塊的界面初始化方法;將在 window.onload 中調(diào)用執(zhí)行;

var w = OLSFK.Options.width;      var h = OLSFK.Options.height;      var total = w * h;       var x=0,y=0;      for (var i=0; i<total; i++)      {                    OLSFK.Options.GampMap[x+'_'+y] = 0;           Lib.Tag('SPAN',{id:"box_"+x+"_"+y,name:"cbox",style:{              width:OLSFK.Options.boxWidth,              height:OLSFK.Options.boxWidth,              border:"2px outset #669",              background:"#ddd",              float:"left",              overflow:"hidden"         },innerHTML:"&nbsp;",className:"cssbox"},back);           var end = i + 1;          x++;          if (end >= w && end % w == 0)          {              x=0;              y++;              Lib.Tag('DIV',{style:{                  clear:"both"             }},back);          }       }

通過設(shè)置的 Options.width, Options.height 列數(shù)與行數(shù),以及設(shè)置的小方格寬度,初始化了一個寬:Options.width列,高為 Options.height 的表格界面出來;

Lib.Tag 用于創(chuàng)建標(biāo)簽對象;

Lib.Tag = function(TAG,json,pnode) {      //...  }

TAG為標(biāo)簽名,比如: div, span 等;

json為設(shè)置標(biāo)簽樣式 style;

pnode 是該創(chuàng)建所在的父容器;

OLSFK.Init = function() {} 還創(chuàng)建主游戲區(qū)域旁邊的下次隨機方塊預(yù)覽區(qū),當(dāng)前級別,及分?jǐn)?shù),以及操作“開始”,“暫停”按鈕等;

怎么用Javascript實現(xiàn)俄羅斯方塊游戲

游戲初始入口點

window.onload = function() {      if (window.isIE)      {          document.attachEvent("onkeydown",function(e) {              if (OLSFK.Options.Start)              {                  var E = OLSFK.KeyCode();                  OLSFK.EventFunc(E);              }           });           document.attachEvent("onkeyup",function(e) {              if (!OLSFK.Options.Move && OLSFK.Options.Start)              {                  OLSFK.Options.Move = true;                  OLSFK.Options.Eventing = false;                   OLSFK.Options.Timer = setTimeout(function() {                      OLSFK.play();                  }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);              }          });      } else {          document.addEventListener("keydown",function(e) {               if (OLSFK.Options.Start)              {                  var E = OLSFK.KeyCode();                  OLSFK.EventFunc(E);              }                        },false);           document.addEventListener("keyup",function(e) {              if (!OLSFK.Options.Move && OLSFK.Options.Start)              {                  OLSFK.Options.Move = true;                  OLSFK.Options.Eventing = false;                   OLSFK.Options.Timer = setTimeout(function() {                      OLSFK.play();                  }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);              }          },false);      }      OLSFK.Init();  }

主要是監(jiān)聽鍵盤事件,根據(jù) 鍵盤事件 返回的按鈕編碼與 OLSFK.Options.direct 設(shè)置方向鍵匹配來操作方塊的移動,旋轉(zhuǎn)等;

keydown 用于操作下落方塊的移動方向,旋轉(zhuǎn)等;并重新繪制方塊位置;

keyup 后繼續(xù)按本級速度向下落;

OLSFK.Options.Levels[OLSFK.Options.curLevel]

表示當(dāng)前級別對應(yīng)的速度,即定時器間隔執(zhí)行時間(毫秒);

OLSFK.EventFunc = function(code) {      switch (code)      {          case OLSFK.Options.direct.Left: //LEFT              if (!OLSFK.Options.Deling)              {                  clearTimeout(OLSFK.Options.Timer);                  OLSFK.Options.Eventing = true;                  OLSFK.Options.Move = false;                  OLSFK.Left();              }               break;              //...          }  }

該方法是 監(jiān)聽 keydown 事件執(zhí)行的動作;code 為按鍵 編碼;

當(dāng)判斷未在消行動作時,清除定時器,OLSFK.Options.Eventing 設(shè)置為事件中 true,OLSFK.Options.Move 為 false 表示停止移動;

進(jìn)入 向左移動方法 OLSFK.Left();

OLSFK.Left = function() {      var block = OLSFK.Items[OLSFK.Options.curBlock];       if (block)      {          var flag = true;          for (var i=1; i<=4; i++)          {              var x = block[i].x;              var y = block[i].y;               if (x-1 < 0)              {                  flag = false;                  break;              }                            if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))              {                  flag = false;                  break;              }          }           if (flag)          {              for (var i=1; i<=4; i++) //清除圖形              {                  var itm = block[i];                  var box = Lib.Getid('box_'+itm.x+'_'+itm.y);                   box.style.background = '#ddd';                  OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;              }               for (var i=1; i<=5; i++)              {                  var x = block[i].x;                  var y = block[i].y;                   OLSFK.Items[OLSFK.Options.curBlock][i] = {x:(x-1),y:y};              }                            OLSFK.draw();          }       }  }

var block = OLSFK.Items[OLSFK.Options.curBlock]; 表示獲取當(dāng)前移動方塊;

if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))  {      flag = false;      break;  }

判斷該方塊四個小方塊左邊是否有被占用的方塊,也即: OLSFK.Options.GampMap[(x-1)+'_'+y] 為 1; 并且該位置塊不屬于方塊自己的;

當(dāng)左邊方向無占用格時,清除當(dāng)前方塊四個小方塊位置,重新繪制方塊新坐標(biāo)位置;并重置 相應(yīng)的 OLSFK.Options.GameMap [x+y] 相應(yīng)格的值;

當(dāng)按鈕 keyup 時,繼承正常向下落;

OLSFK.isMe 代碼:

OLSFK.isMe = function(x,y) {      var block = OLSFK.Items[OLSFK.Options.curBlock];       if (block)      {          for (var i=1; i<=4; i++)          {              if (block[i].x == x && block[i].y == y)              {                  return true;              }          }      }       return false;  }

即指定的 x,y (參數(shù)值) 是否還在當(dāng)前方塊四個坐標(biāo)內(nèi);

OLSFK.Right () 與 Left() 一樣;

旋轉(zhuǎn)方塊代碼;

OLSFK.Rotate = function() {      var block = OLSFK.Items[OLSFK.Options.curBlock];       if (block)      {          var flag = true;           var R = block[5];          for (var i=1; i<=4; i++)          {              var x = block[i].x;              var y = block[i].y;               if (R.x == x && R.y == y)              {                                } else {                  var nson = new Object();                   nson.x = R.x + R.y - y;                  nson.y = R.y - R.x + x;                   if ( nson.x < 0 || nson.y < 0 || nson.x >= OLSFK.Options.width || nson.y >= OLSFK.Options.height )                  {                      flag = false;                      break;                  }                   if (OLSFK.Options.GampMap[nson.x+'_'+nson.y] == 1 && !OLSFK.isMe(nson.x,nson.y))                  {                      flag = false;                      break;                  }              }          }           if (flag)          {              for (var i=1; i<=4; i++) //清除圖形              {                  var itm = block[i];                  var box = Lib.Getid('box_'+itm.x+'_'+itm.y);                   box.style.background = '#ddd';                  OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;              }               var Pnt = 1;               for (var i=1; i<=4; i++)              {                  var x = block[i].x;                  var y = block[i].y;                                    if (R.x == x && R.y == y)                  {                      Pnt = i;                  } else {                      var nson = new Object();                       nson.x = R.x + R.y - y;                      nson.y = R.y - R.x + x;                      OLSFK.Items[OLSFK.Options.curBlock][i] = {x:nson.x,y:nson.y};                  }              }               OLSFK.Items[OLSFK.Options.curBlock][5] = OLSFK.Items[OLSFK.Options.curBlock][Pnt];                            OLSFK.draw();          }       }  }

var R = block[5]; 就是獲取旋轉(zhuǎn)點;

就開始對方塊四個小塊以旋轉(zhuǎn)點為中心,逆時針旋轉(zhuǎn)(并不全是 90 度);當(dāng)當(dāng)前塊不為旋轉(zhuǎn)點時,旋轉(zhuǎn)公式;

var nson = new Object();

nson.x = R.x + R.y - y;
nson.y = R.y - R.x + x;

這個公式要這樣看;

ResultX = RotateX + (RotateY - CurrentY);
ResultY = RotateY - (RotateX - CurrentX);//Y的偏移量,就是X的增加值;//反之同

當(dāng)旋轉(zhuǎn)四周都無占用物時;清除當(dāng)前圖形,重繪旋轉(zhuǎn)后的圖形位置;

重置 OLSFK.Options.GampMap[itm.x+'_'+itm.y] 各個方塊的占用值;

OLSFK.Random = function() {       if (OLSFK.Options.nextBlock != 0)      {          OLSFK.Options.curBlock = OLSFK.Options.nextBlock;           var block = OLSFK.Next[OLSFK.Options.nextBlock];          if (block)          {              for (var i=1; i<=4; i++)              {                  var itm = block[i];                  var box = Lib.Getid('cur_'+itm.x+'_'+itm.y);                   box.style.background = '#ddd';                  //OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;              }          }      } else {          OLSFK.Options.curBlock = Math.floor(Math.random() * 7 + 1);      }      OLSFK.Options.nextBlock = Math.floor(Math.random() * 7 + 1);       OLSFK.drawNext();  }

隨機生成下次預(yù)下落的方塊;并顯示到右上角的預(yù)覽表格里;

OLSFK.play = function(speed) {      var block = OLSFK.Items[OLSFK.Options.curBlock];       if (block && OLSFK.Options.Move)      {           var flag = true;          for (var i=1; i<=4; i++)          {              var x = block[i].x;              var y = block[i].y;               if (y+1 >= OLSFK.Options.height)              {                  flag = false;                  break;              }                            if (OLSFK.Options.GampMap[x+'_'+(y+1)] == 1 && !OLSFK.isMe(x,y+1))              {                  flag = false;                  break;              }          }                    if (flag)          {              for (var i=1; i<=4; i++) //清除圖形              {                  var itm = block[i];                  var box = Lib.Getid('box_'+itm.x+'_'+itm.y);                   box.style.background = '#ddd';                  OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;              }               for (var i=1; i<=5; i++)              {                  var x = block[i].x;                  var y = block[i].y;                   OLSFK.Items[OLSFK.Options.curBlock][i] = {x:x,y:(y+1)};              }              OLSFK.draw();                            var S = OLSFK.Options.Levels[OLSFK.Options.curLevel];              if (speed)              {                  S = 50;              }              OLSFK.Options.Timer = setTimeout(function() {                  OLSFK.play();              }, S);          } else {              OLSFK.ReItems(OLSFK.Options.curBlock);              OLSFK.newRun();          }      }  }

OLSFK.play 正常下落的方法,也得判斷下落一格是否有被占用的格,如果沒有,清除當(dāng)前方塊,繪制方塊新位置;

當(dāng)方塊不能再下落時(flag = false),重置當(dāng)前方塊坐標(biāo)配置; OLSFK.ReItems(OLSFK.Options.curBlock);

進(jìn)入 OLSFK.newRun(); 新下落方塊下落過程準(zhǔn)備;

OLSFK.newRun = function() {       clearTimeout(OLSFK.Options.Timer);      OLSFK.DelFunc();      if (OLSFK.Options.deline >= 10)      {          OLSFK.Options.deline = 0;          OLSFK.Options.curLevel ++;          OLSFK.Element.CurLevel.setHTML("級:"+OLSFK.Options.curLevel);      }      OLSFK.Element.Score.setHTML("分:"+OLSFK.Options.Score);       if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)      {          OLSFK.Random();          //判斷是否結(jié)束          OLSFK.ChkEnd();      } else {          OLSFK.Options.Move = false;          OLSFK.Options.Start = false;          OLSFK.Options.Eventing = false;          OLSFK.Options.Deling = false;          Lib.Getid('spn').innerHTML = 'Game Is Over! You Win the Game!';           Lib.Getid('dobtn').innerHTML = ' 開始 ';      }        }

當(dāng)下落結(jié)束時,清除定時器,暫停新方塊下落,檢測是否有可消除的行;減了多少行;

每減去一行 加分 OLSFK.Options.Score += OLSFK.Options.ScoreNum;

這個方法在 :

OLSFK.DelFunc = function() {      OLSFK.Options.Deling = true;      OLSFK.Options.Move = false;      OLSFK.Options.Eventing = false;      var Fn = 0;      for (var i=OLSFK.Options.height-1; i>=0; i--)      {          Fn = 0;          for (var j=0; j<OLSFK.Options.width; j++)          {              if (OLSFK.Options.GampMap[j+'_'+i] == 1)              {                  Fn++;              }          }           if (Fn == OLSFK.Options.width)          {              OLSFK.Options.deline ++;              OLSFK.Options.Score += OLSFK.Options.ScoreNum;              OLSFK.DelLine(i);              i++;          }      }      OLSFK.Options.Deling = false;      OLSFK.Options.Move = true;      OLSFK.Options.Eventing = true;  }

中執(zhí)行;

減完一行,就重置該行以上所有行往下降一行;并重置 :

OLSFK.Options.GampMap[x+'_'+y] = OLSFK.Options.GampMap[x+'_'+(y-1)];

該減行為上行的數(shù)據(jù);

if (Fn == OLSFK.Options.width)          {              OLSFK.Options.deline ++;              OLSFK.Options.Score += OLSFK.Options.ScoreNum;              OLSFK.DelLine(i);              i++;          }

該判斷表示該行上所有格都被占用到;

回到 newRun 上,當(dāng)判斷消行超過幾行時,即加級;

if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)
    {
        OLSFK.Random();//判斷是否結(jié)束        OLSFK.ChkEnd();
    }

如果級數(shù)小于配置的總級數(shù),則進(jìn)入 OLSFK.random();

設(shè)置當(dāng)前下落方塊,并隨機生成下次下落方塊并預(yù)覽右上角表格上;

OLSFK.ChkEnd = function() {      var block = OLSFK.Items[OLSFK.Options.curBlock];       if (block && OLSFK.Options.Move)      {           var flag = true;          for (var i=1; i<=4; i++)          {              var x = block[i].x;              var y = block[i].y;                            if (OLSFK.Options.GampMap[x+'_'+y] == 1)              {                  flag = false;                  break;              }          }      }       if (flag )      {          OLSFK.draw();           //定時往下掉          OLSFK.Options.Timer = setTimeout(function() {              OLSFK.play();          }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);      } else {          OLSFK.Options.Move = false;          OLSFK.Options.Start = false;          OLSFK.Options.Eventing = false;          OLSFK.Options.Deling = false;          Lib.Getid('spn').innerHTML = 'Game Is Over';           Lib.Getid('dobtn').innerHTML = ' 開始 ';      }  }

當(dāng)當(dāng)前下落的方塊進(jìn)入表格上有被占用的格子,即被卡住,游戲結(jié)束;

反之 則 setTimeout 開始新方塊的下落動作;

其他方法說明

OLSFK.Event = function() {      if (window.isIE)          return window.event;      func = OLSFK.Event.caller;        while(func!=null)       {          var arg0=func.arguments[0];           if(arg0)           {              return arg0;           }          func=func.caller;       }      return null;   }   OLSFK.KeyCode = function() {      return OLSFK.Event().keyCode || OLSFK.Event().which;  }

OLSFK.Event = function();

這是一種獲取當(dāng)前事件的方法,可以比較兼容獲取當(dāng)前的事件;

俄羅斯方塊 JavaScript 代碼

http://files.cnblogs.com/editor/OLSFK.rar

到此,關(guān)于“怎么用Javascript實現(xiàn)俄羅斯方塊游戲”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

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

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

AI