裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

夕水發表於2019-05-11

有些奇淫技巧玩好的話,就能提升自己的逼格,這不,一行js程式碼實現一個貪吃蛇小遊戲就成了裝逼到了最高境界嘛!程式碼如下:

(function(){var s = [41,40],d = 1,f = 43,x,c = document.createElement('canvas');c.width=400;c.height=400;c.style.background="#535353";c.textContent="當前瀏覽器不支援canvas標籤";b=c.getContext('2d');function w(s,c){b.fillStyle = c;b.fillRect(s % 20 * 20, ~~(s / 20) * 20 , 18 , 18);};document.onkeydown=function(e){d = s[1] - s[0] == (x = [-1,-20,1,20][(e || event).keyCode - 37] || d ) ? d : x;};!(function(){s.unshift(x = s[0] + d);if(s.indexOf(x,1) > 0 || x < 0 || x > 399 || d == 1 && x % 20 == 0 || d == -1 && x % 20 == 19)return alert('遊戲結束!');w(x,'#2396ef');x === f ? (()=>{while (s.indexOf(f = ~~(Math.random() * 399)) > 0);w(f,'#35e3dc');})() : w(s.pop(),'#535353');setTimeout(arguments.callee,300);})();document.body.appendChild(c);})();
複製程式碼

ps:我不是來裝逼的。!

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

好了,讓我們來執行一下這行程式碼,看一下效果:

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

看動圖看著不過癮?,好,你自己去線上看看demo可以撒,具體示例

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

裝逼完成,

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

好了,言歸正傳,我怎麼可能是來裝逼的,我要來分析一下,這個是怎麼玩的,這才是我的目的。

讓我們拆分程式碼來看:

首先,最外層包裹了一個自呼叫函式,如下:

(function(){
    //具體內容
})();
//自呼叫函式當然不止這樣的寫法
複製程式碼

然後第二步,要畫一個場景,那很明顯,要用HTML5canvas標籤,我們可以採用document.createElement()這個方法來建立一個元素,繼續:

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
})();
複製程式碼

蛇運動的場景肯定是固定大小的,也就是說,我們要給canvas設定寬和高,在這裡,我就是設定的400X400,然後給場景加一個背景。就這樣:

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
})();
複製程式碼

建立了canvas元素,我們要新增到DOM網頁中去,所以用appendChild()來新增。如下:

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
    document.body.appendChild(c);
})();
複製程式碼

哦,有些瀏覽器可能不支援canvas標籤,所以我們不能忘了給一個優雅的提示:

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
    c.textContent="當前瀏覽器不支援canvas標籤";
    document.body.appendChild(c);
})();
複製程式碼

場景畫好了,接下來,我們要在場景上畫蛇,所以canvas.getContext('2d')這個方法是必不可少的。

 (function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   document.body.appendChild(c);
})();
複製程式碼

接下來分析蛇的構成,實際上這裡的場景,我們可以看成是40020*20的塊組成,那麼蛇也就可以看成一個塊一個塊的組成,用技術術語來說就是一個佇列,也就是一個陣列,[20]。在這裡初始化蛇為2個塊,也就是[20,20],那麼蛇初始化位置還是稍微調整一下嘛,所以也就改成[40,40],其實在這裡第一次出現的時候,是隱藏了一個食物的,預設就在蛇初始化位置的下一格,然後蛇會立即吃掉,然後就隨機出現下一個食物的位置了,因此預設食物的位置是40。為了一個方便細小的微差,就稍微調大一點,為43。好了,現在我們要知道蛇執行的方向,蛇可以上下左右活動,那麼,我們定義為s[1] - s[0],這是根據位置來計算的。我們們先定義蛇再說:

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的
       d = 1,//定義蛇活動方向,預設向右
       f = 42;//預設食物的位置
   document.body.appendChild(c);
})();
複製程式碼

接下來,開始繪製蛇,蛇活動的軌跡與食物。定義一個函式,利用canvas.fillStyle()填充背景,在這裡蛇與食物還有蛇活動的軌跡都是一個小方塊矩形,這樣我們就使用canvas.fillRect()來繪製一個矩形,這個方法有四個引數,如下圖所示:

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

蛇活動的軌跡座標,也就是定義的蛇陣列的座標,因此第一個引數就是s % 20 * 20,第二個引數就是~~(s / 20 * 20)。關於~~這個操作符,如果不理解的話,可以看我的文章淺談JavaScript位操作符。這裡感覺有些抽象,實際上,需要靠自己的想象力來想象理解。

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42;//預設食物的位置
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   document.body.appendChild(c);
})();
複製程式碼

蛇每吃掉一個食物,也就是往陣列中新增一個20*20的小塊,當然為了區分方向,這裡的小塊寬高應該與繪製的矩形寬高有關。因此,我們還要定義一個變數來代表蛇吃掉食物後,隨機出現的下一個食物出現的位置。

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   document.body.appendChild(c);
})();
複製程式碼

接下來就是使用者按鍵盤的方向鍵,當然也可以是wsad字母鍵來控制蛇活動的方向。不過我們需要知道鍵盤鍵的keyCode,方向鍵的keyCode分別是:向左:37,向上:38,,向右:39,向下:40。鍵盤事件為onkeydown

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   //按方向鍵控制蛇運動方向,這裡根據食物的位置來控制方向,防止使用者隨便更改方向,然後遊戲崩潰
   document.onkeydown = function(e){
       d = s[1] - s[0] === (x = [-1,-20,1,20][e || event].keyCode - 37 ] || d) ? d : x;
   }
   document.body.appendChild(c);
})();
複製程式碼

然後蛇吃掉一個食物就應該新增下一個食物,在這裡用unshift()方法來新增陣列。

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   //按方向鍵控制蛇運動方向,這裡根據食物的位置來控制方向,防止使用者隨便更改方向,然後遊戲崩潰
   document.onkeydown = function(e){
       //方向由蛇頭來確定,初始化蛇只有2個小方塊組成,因此蛇的方向就是s[1] - s[0]
       d = s[1] - s[0] === (x = [-1,-20,1,20][e || event].keyCode - 37 ] || d) ? d : x;
   }
   !(function(){
       s.unshift(x = s[0] + d);
   })();//這也是一種自呼叫函式寫法
   document.body.appendChild(c);
})();
複製程式碼

接下來判斷蛇如果撞牆或者撞到了自身,則遊戲結束。

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   //按方向鍵控制蛇運動方向,這裡根據食物的位置來控制方向,防止使用者隨便更改方向,然後遊戲崩潰
   document.onkeydown = function(e){
       //方向由蛇頭來確定,初始化蛇只有2個小方塊組成,因此蛇的方向就是s[1] - s[0]
       d = s[1] - s[0] === (x = [-1,-20,1,20][e || event].keyCode - 37 ] || d) ? d : x;
   }
   !(function(){
       s.unshift(x = s[0] + d);
       //判斷蛇如果撞牆或者撞到了自身,則遊戲結束
       if(s.indexOf(x,1) > 0 || x < 0 || x > 399 || d == 1 && x % 20 == 0 || d == -1 && x % 20 == 19)return alert('遊戲結束');
   })();//這也是一種自呼叫函式寫法
   document.body.appendChild(c);
})();
複製程式碼

然後開始畫食物,以及判斷食物是否被蛇吃掉,如果吃掉了,則隨機生成下一個食物。

(function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   //按方向鍵控制蛇運動方向,這裡根據食物的位置來控制方向,防止使用者隨便更改方向,然後遊戲崩潰
   document.onkeydown = function(e){
       //方向由蛇頭來確定,初始化蛇只有2個小方塊組成,因此蛇的方向就是s[1] - s[0]
       d = s[1] - s[0] === (x = [-1,-20,1,20][e || event].keyCode - 37 ] || d) ? d : x;
   }
   !(function(){
       s.unshift(x = s[0] + d);
       //判斷蛇如果撞牆或者撞到了自身,則遊戲結束
       if(s.indexOf(x,1) > 0 || x < 0 || x > 399 || d == 1 && x % 20 == 0 || d == -1 && x % 20 == 19)return alert('遊戲結束');
       //然後開始畫蛇節點的顏色
		w(x,'#e641d3');
		//判斷蛇是不是吃到食物,如果吃到則重新隨機生成一個節點也就是新食物的座標,Math.random()方法表示取隨機數,因為方向有可能是負的,所以用到了~~符號表示取絕對值到正數.~就是先取反再減一的意思.
		if(x == f){
			while (s.indexOf(f = ~~(Math.random() * 399)) > 0);
			//重新畫食物顏色
			w(f,'#35e3dc');
		}else{
			//蛇吃到食物,蛇身會變長,所以不會改變蛇的運動軌跡
			w(s.pop(),'#535353');
		}
   })();//這也是一種自呼叫函式寫法
   document.body.appendChild(c);
})();
複製程式碼

最後,讓蛇按一定的時間執行,如下:

  (function(){
    //建立canvas標籤
    var c = document.createElement('canvas');
    c.width = 400;
    c.height = 400;
    c.style.background = '#535353';
   var b = c.getContext('2d');
   var s = [41,40],//這裡41也是有講究的,代表預設向右方向
       d = 1,//定義蛇活動方向,預設向右,蛇運動方向為s[1] - s[0]
       f = 42,//預設食物的位置
       x;
   //這個函式既是繪製蛇方塊,也是繪製食物與蛇活動軌跡的定義
   function w(s,c){
       b.fillStyle = c;
       b.fillRect(s % 20 * 20,~~(s / 20 * 20),18,18);
   }
   //按方向鍵控制蛇運動方向,這裡根據食物的位置來控制方向,防止使用者隨便更改方向,然後遊戲崩潰
   document.onkeydown = function(e){
       //方向由蛇頭來確定,初始化蛇只有2個小方塊組成,因此蛇的方向就是s[1] - s[0]
       d = s[1] - s[0] === (x = [-1,-20,1,20][e || event].keyCode - 37 ] || d) ? d : x;
   }
   !(function(){
       s.unshift(x = s[0] + d);
       //判斷蛇如果撞牆或者撞到了自身,則遊戲結束
       if(s.indexOf(x,1) > 0 || x < 0 || x > 399 || d == 1 && x % 20 == 0 || d == -1 && x % 20 == 19)return alert('遊戲結束');
       //然後開始畫蛇節點的顏色
		w(x,'#e641d3');
		//判斷蛇是不是吃到食物,如果吃到則重新隨機生成一個節點也就是新食物的座標,Math.random()方法表示取隨機數,因為方向有可能是負的,所以用到了~~符號表示取絕對值到正數.~就是先取反再減一的意思.
		if(x == f){
			while (s.indexOf(f = ~~(Math.random() * 399)) > 0);
			//重新畫食物顏色
			w(f,'#35e3dc');
		}else{
			//蛇吃到食物,蛇身會變長,所以不會改變蛇的運動軌跡
			w(s.pop(),'#535353');
		}
        //這是一種遞迴的寫法
        setTimeout(arguments.callee,300);
   })();//這也是一種自呼叫函式寫法
   document.body.appendChild(c);
})();
複製程式碼

到此為止,就拆分完了,其實這裡的邏輯不算難,難的是計算蛇與蛇運動軌跡還有食物的座標。能夠理解透,就看個人的數學知識了,哈哈。最後,將這麼多程式碼整合成一行程式碼,就可以好好的裝逼了!

ps:本文程式碼借鑑國外某大神20多行js程式碼實現貪吃蛇,在原始碼基礎上進行分析並加以修改封裝而成,不喜勿噴。

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

鄙人建立了一個QQ群,供大家學習交流,希望和大家合作愉快,互相幫助,交流學習,以下為群二維碼:

裝逼的最高境界---一行js程式碼完成一個簡易版的貪吃蛇遊戲

相關文章