用 JavaScript 實現簡單拼圖遊戲

雷曼同學發表於2018-11-15
用 JavaScript 實現簡單拼圖遊戲

本篇主要講解,如何利用原生的 JavaScript 來實現一個簡單的拼圖小遊戲。

線上體驗地址:拼圖

一、遊戲的基礎邏輯

想用一門語言來開發遊戲,必須先了解如何使用這門語言來實現一些基礎邏輯,比如影像的繪製、互動的處理、定時器等。

1、圖形繪製

圖形繪製是一切的基礎,這裡使用 JavaScriptcanvas 上進行繪製。即先在 html 中建立 canvas 元素,然後在 JavaScript 中,通過 id 拿到這個元素,並且通過 canvas 拿到對應的上下文環境 context,為後續的繪圖做好準備。

<
canvas id="background" width="450px" height="450px">
<
/canvas>
複製程式碼
var background = document.getElementById("background");
var context = background.getContext('2d');
複製程式碼

通過 contextdrawImage 方法可以繪製圖片,這裡進行了相應的封裝:

**注:**這裡要等圖片載入完畢後再進行繪製,即在 onload 中去呼叫 drawImage 方法,否則會繪製失敗。

var drawImageItem = function(index, position) { 
var img = new Image();
img.src = './image/dog_0' + String(index+1) + '.jpg';
img.onload = () =>
{
var rect = rectForPosition(position);
context.drawImage(img, rect[0], rect[1], rect[2], rect[3]);

}
}複製程式碼

在繪製圖片之後,我們還需要去動態重新整理檢視,否則 canvas 就只是一張靜態的圖片。如果是簡單的圖形重新整理,只需在原來的位置重新繪製,進行覆蓋即可。但有時候我們只需要將原來已存在的圖形清除掉,而不需要繪製新圖案。比如在拼圖遊戲中,將一個方塊移動到另一個位置後,需要清空原來的位置。

通過 contextclearRect 方法可以達到清除的目的。以下是清除 canvas 的某個區域的程式碼:

var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
複製程式碼

2、事件處理

有了圖形的繪製後,我們還需要處理玩家的輸入事件,然後根據輸入事件,來決定什麼時候重新整理檢視。輸入事件可以分為 3 種:在手機上有觸屏事件;在 PC 上,有滑鼠和鍵盤事件。

JavaScript 中對觸屏和滑鼠點選的監聽是一樣的,都是通過 canvasonclick 事件進行回撥,具體如下:

// 螢幕點選background.onclick = function(e) {
};
複製程式碼

我們可以通過 e.offsetXe.offsetY 來獲取觸控點在 canvas 中的位置。

注: canvas 的座標原點在左上角,即左上角的座標是 (0, 0)

鍵盤的按鍵點選則是通過 documentonkeyuponkeydown 等事件進行回撥。onkeyup 是指按鍵的抬起事件,onkeydown 是指按鍵的按下事件。我們可以通過 keyCode 知道當前具體是哪一個按鍵,然後根據不同的按鍵去處理不同的邏輯,如下:

if (event.keyCode == '37') { 
// 左 // do something
} else if (event.keyCode == '38') {
// 上 // do something
} else if (event.keyCode == '39') {
// 右 // do something
} else if (event.keyCode == '40') {
// 下 // do something
}複製程式碼

3、定時器

有時候,除了在玩家輸入的時候需要去重新整理檢視,還需要每隔一段時間定時去重新整理檢視。比如在一個貪吃蛇遊戲中,就需要每隔一段時間就去重新整理蛇的位置。

這個時候我們就需要一個定時器,讓它每隔一段時間去執行一段重新整理檢視的程式碼。我們通過 setInterval 方法來實現定時器功能:

setInterval("run()", 100);
複製程式碼

上面這段程式碼表示每隔 100 毫秒,去執行一次 run 方法。

二、拼圖的基礎邏輯

有了遊戲的基礎邏輯,下面來看一下如何實現拼圖的邏輯。

1、生成隨機序列

因為不是任意序列都可以通過平移的方式來還原,所以我們不能簡單地生成一個隨機序列。比如 1、0、2、3、4、5、6、7、8 這個序列,無論怎麼平移,都不可能還原。

這裡採取的做法是:預先設定了 4 個可還原的序列,先從這 4 個序列中隨機選取一個,然後再對序列進行模擬平移若干步驟。以此來儘可能地保證初始序列的多樣性,也保證了序列的可還原性。具體程式碼如下:

var setupRandomPosition = function() { 
var list1 = [4, 3, 2, 8, 0, 7, 5, 6, 1];
var list2 = [2, 0, 5, 6, 8, 7, 3, 1, 4];
var list3 = [3, 7, 2, 4, 1, 6, 8, 0, 5];
var list4 = [3, 2, 4, 1, 7, 6, 5, 0, 8];
var lists = [list1, list2, list3, list4];
imageIndexForPosition = lists[parseInt(Math.random() * 4)];
// 獲取空位位置 var emptyPosition = 0;
for (var i = imageIndexForPosition.length - 1;
i >
= 0;
i--) {
if (imageIndexForPosition[i] == lastIndex()) {
emptyPosition = i;
break;

}
} background.emptyPosition = emptyPosition;
// 隨機移動次數 var times = 10;
while (times--) {
// 獲取隨機數,決定空位哪個位置進行移動 var direction = parseInt(Math.random() * 4);
var target = -1;
if (direction == 0) {
target = topOfPosition(emptyPosition);
// 上
} else if (direction == 1) {
target = leftOfPosition(emptyPosition);
// 左
} else if (direction == 2) {
target = rightOfPosition(emptyPosition);
// 右
} else if (direction == 3) {
target = bottomOfPosition(emptyPosition);
// 下
} if (target <
0 || target >
lastIndex()) {
// 位置不合法,繼續下一次迴圈 continue;

} var result = moveImageIfCanAtPosition(target);
if (result >
= 0) {
// 如果移動成功,更新空位的位置 emptyPosition = target;

}
}
}複製程式碼

2、判斷是否可以移動方塊

在儲存順序的時候,是用 0~8 這 9 個數字來儲存,而空白的方塊是數字 8 的位置。所以判斷可以移動的唯一條件是,目標位置的值是否為 8。程式碼如下:

var isPositionEmpty = function(position) { 
if (position <
0 || position >
lastIndex()) {
return false;

} if (imageIndexForPosition[position] == lastIndex()) {
return true;

} else {
return false;

}
}複製程式碼

上面 lastIndex() 的值為 8。

3、實現方塊移動

方塊移動的實現很簡單,先將舊位置的圖形清除,然後在新的位置繪製。

var refreshImagePositions = function(origin, target) { 
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
drawImageItem(imageIndexForPosition[target], target);

}複製程式碼

4、檢查是否完成

檢查圖案是否已經還原,只需要對陣列進行一次遍歷,看是否有序即可。

var checkIfFinish = function() { 
for (var index = 0;
index <
imageIndexForPosition.length;
index++) {
if (index != imageIndexForPosition[index]) {
return false;

}
} return true;

}複製程式碼

5、互動事件遮蔽

當圖案還原之後,我們不希望玩家還能通過鍵盤或滑鼠來移動方塊,這個時候就需要對互動事件進行遮蔽。

只需要一個標誌位就可以達到這個目的:

// 螢幕點選background.onclick = function(e) { 
if (isFinish) {
return;

} // do something
};
// 鍵盤按鈕事件document.onkeyup = function(event) {
if (isFinish) {
return;

} // do something
}複製程式碼

當圖案還原之後,標誌位 isFinish 會被置為 true,然後在螢幕點選和鍵盤按鈕響應事件的開始處新增判斷,如果已經結束,則不繼續走方塊移動的邏輯。

三、原始碼

請到 GitHub 上檢視完整程式碼。

參考

JavaScript 教程

獲取更佳的閱讀體驗,請訪問原文地址 【Lyman’s Blog】用 JavaScript 實現簡單拼圖遊戲

來源:https://juejin.im/post/5bed4265f265da61193b68af#comment

相關文章