前言
前段時間發現網上有很多收費或公開課都有教用 js 做 2048 小遊戲的,然後自己就也想動手做一個,做這個小遊戲主要是為了鍛鍊自己的邏輯能力,也算是對之前一些學習的總結吧
注:
- 實現方法完全是自己邊玩 2048 邊想的,所有些亂還請見諒
- 另外配色方案是在某個 2048 遊戲截圖,然後用 ps 吸取的,非本人原創
- 程式碼中有很多都可以使用陣列相關的方法來代替,這裡是為了自己理解陣列方法是什麼原理
- 由於時間關係本次不做詳解
遊戲邏輯
- 隨機位置生成數字 2 或 4
- 按方向鍵,有挨著的相同的數字就合併成新的數字
- 按方向鍵,數字會移動到對應方向的最邊上(按左,數字全部移動到左邊)
- 每次按方向鍵,合併完成後,會在沒有數字的隨機位置都會生成新的數字 2 或 4
- 當前分數等於當前所有數字相加
- 當有數字達到 2048 遊戲結束
專案相關
這個版本是用原生 ES6 寫的,只實現了遊戲邏輯中的 1,2,3,4;
第一版地址:https://github.com/yhtx1997/S…
之後是打算用 vue 重新寫一遍,並且完善下,因為長時間用原生,導致 vue 有些生疏,藉此機會重新溫習下
專案程式碼
採用二維陣列進行資料的管理,預設全部為零
let arr = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
];
隨機建立數字
let s = 0;
let create = () => {
let x = Math.floor(Math.random() * 4);
let y = Math.floor(Math.random() * 4);
// console.log(s)
if (s > 100) {
s = 0;
return;
}
if (arr[x][y] == 0) {
if (Math.floor(Math.random() * 10) % 2 == 0) {
arr[x][y] = 2;
} else {
arr[x][y] = 4;
}
s = 0;
return;
} else {
s++;
return create();
}
}
渲染頁面
let updateHtml = () => {
//獲取元素
let warp = document.getElementById(`warp`);
let html = ``;
//將資料轉換為 HTML
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
html += `<div class=`c c-${arr[i][j]}`>${arr[i][j]==0?``:arr[i][j]}</div>`;
}
}
//將 資料轉換的 HTML 渲染到頁面
warp.innerHTML = html;
}
事件監聽
window.onkeydown = (e) => {
switch (e.keyCode) {
case 37:
// ←
console.log(`←`);
arr = new move(arr).moveLeft();
create(); //隨機位置新建
updateHtml(); //更新資料到頁面
break;
case 38:
// ↑
console.log(`↑`);
arr = new move(arr).moveUp();
create(); //隨機位置新建
updateHtml(); //更新資料到頁面
break;
case 39:
// →
console.log(`→`);
arr = new move(arr).moveRight();
create(); //隨機位置新建
updateHtml(); //更新資料到頁面
break;
case 40:
// ↓
console.log(`↓`);
arr = new move(arr).moveDown();
create(); //隨機位置新建
updateHtml(); //更新資料到頁面
break;
}
}
具體處理函式
先提取非零數字
export default function ClearZero (arr){//去零
let clearZero = [[],[],[],[]];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (arr[i][j] != 0) {
clearZero[i].push(arr[i][j])
}
}
}
return clearZero;
}
將挨著的相等數字分組並相加
分組
import Deduplication from `./deduplication`;//將相鄰且相同的數字相加
export default class Grouping{//將相鄰的相同數字分組
constructor(clearZero){
this.clearZero = clearZero;
}
left(){
let newarr = [[],[],[],[]];
for (let j = 0; j < this.clearZero.length; j++) {
let grouping = [];
let i = 0;
//將重複的 分到一組
while (i < this.clearZero[j].length) {
if (this.clearZero[j][i] == this.clearZero[j][i + 1]) {
grouping.push([this.clearZero[j][i], this.clearZero[j][i + 1]]);
i += 2;
} else {
grouping.push(this.clearZero[j][i]);
i++;
}
}
//去重複
newarr[j] = Deduplication(grouping);
}
return newarr;
}
right(){
let newarr = [[],[],[],[]];
for (let i = 0; i < this.clearZero.length; i++) {
let grouping = [];
let j = this.clearZero[i].length - 1;
//將重複的 分到一組
while (j >= 0) {
if (this.clearZero[i][j] == this.clearZero[i][j - 1]) {
grouping.unshift([this.clearZero[i][j], this.clearZero[i][j - 1]]);
j -= 2;
} else {
grouping.unshift(this.clearZero[i][j]);
j--;
}
}
//將重複的進行計算
newarr[i] = Deduplication(grouping);
}
return newarr;
}
}
相加
export default function Deduplication (grouping){//將相鄰且相同的數字相加
for (let i = 0; i < grouping.length; i++) {
if (typeof grouping[i] == `object`) {
grouping[i] = grouping[i][0] + grouping[i][1];
}
}
return grouping;
}
新增佔位用的零
export default function AddZero (newarr,w){//加零
for (let i = 0; i < newarr.length; i++) {
while (newarr[i].length != 4) {
if(w == `l`){
newarr[i].push(0);
}else if(w == `r`){
newarr[i].unshift(0);
}
}
}
return newarr;
}
上下的處理
將 Y 軸的處理轉換成 X 軸的處理
export default function turn(arr) {//將陣列轉一下
let clearZero = [[],[],[],[]];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
clearZero[i][j] = arr[j][i]
}
}
return clearZero;
}
等處理完成後再呼叫上邊的函式,將 X 軸的處理結果轉換回 Y 軸的表現方式