JavaScript
來實現一個簡單的拼圖小遊戲。
線上體驗地址:拼圖javascript
想用一門語言來開發遊戲,必須先了解如何使用這門語言來實現一些基礎邏輯,好比圖像的繪製、交互的處理、定時器等。html
圖形繪製是一切的基礎,這裏使用 JavaScript
在 canvas
上進行繪製。即先在 html
中建立 canvas
元素,而後在 JavaScript
中,經過 id 拿到這個元素,而且經過 canvas
拿到對應的上下文環境 context
,爲後續的繪圖作好準備。java
<canvas id="background" width="450px" height="450px"></canvas>
複製代碼
var background = document.getElementById("background");
var context = background.getContext('2d');
複製代碼
經過 context
的 drawImage
方法能夠繪製圖片,這裏進行了相應的封裝:git
注: 這裏要等圖片加載完畢後再進行繪製,即在
onload
中去調用drawImage
方法,不然會繪製失敗。github
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
就只是一張靜態的圖片。若是是簡單的圖形刷新,只需在原來的位置從新繪製,進行覆蓋便可。但有時候咱們只須要將原來已存在的圖形清除掉,而不須要繪製新圖案。好比在拼圖遊戲中,將一個方塊移動到另外一個位置後,須要清空原來的位置。canvas
經過 context
的 clearRect
方法能夠達到清除的目的。如下是清除 canvas
的某個區域的代碼:數組
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
複製代碼
有了圖形的繪製後,咱們還須要處理玩家的輸入事件,而後根據輸入事件,來決定何時刷新視圖。輸入事件能夠分爲 3 種:在手機上有觸屏事件;在 PC 上,有鼠標和鍵盤事件。dom
JavaScript
中對觸屏和鼠標點擊的監聽是同樣的,都是經過 canvas
的 onclick
事件進行回調,具體以下:ui
// 屏幕點擊
background.onclick = function(e) {
};
複製代碼
咱們能夠經過 e.offsetX
、e.offsetY
來獲取觸控點在 canvas
中的位置。spa
注:
canvas
的座標原點在左上角,即左上角的座標是(0, 0)
。
鍵盤的按鍵點擊則是經過 document
的 onkeyup
、onkeydown
等事件進行回調。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
}
複製代碼
有時候,除了在玩家輸入的時候須要去刷新視圖,還須要每隔一段時間定時去刷新視圖。好比在一個貪吃蛇遊戲中,就須要每隔一段時間就去刷新蛇的位置。
這個時候咱們就須要一個定時器,讓它每隔一段時間去執行一段刷新視圖的代碼。咱們經過 setInterval
方法來實現定時器功能:
setInterval("run()", 100);
複製代碼
上面這段代碼表示每隔 100 毫秒,去執行一次 run
方法。
有了遊戲的基礎邏輯,下面來看一下如何實現拼圖的邏輯。
由於不是任意序列均可以經過平移的方式來還原,因此咱們不能簡單地生成一個隨機序列。好比 一、0、二、三、四、五、六、七、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;
}
}
}
複製代碼
在保存順序的時候,是用 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。
方塊移動的實現很簡單,先將舊位置的圖形清除,而後在新的位置繪製。
var refreshImagePositions = function(origin, target) {
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
drawImageItem(imageIndexForPosition[target], target);
}
複製代碼
檢查圖案是否已經還原,只須要對數組進行一次遍歷,看是否有序便可。
var checkIfFinish = function() {
for (var index = 0; index < imageIndexForPosition.length; index++) {
if (index != imageIndexForPosition[index]) {
return false;
}
}
return true;
}
複製代碼
當圖案還原以後,咱們不但願玩家還能經過鍵盤或鼠標來移動方塊,這個時候就須要對交互事件進行屏蔽。
只須要一個標誌位就能夠達到這個目的:
// 屏幕點擊
background.onclick = function(e) {
if (isFinish) {
return;
}
// do something
};
// 鍵盤按鈕事件
document.onkeyup = function(event) {
if (isFinish) {
return;
}
// do something
}
複製代碼
當圖案還原以後,標誌位 isFinish
會被置爲 true
,而後在屏幕點擊和鍵盤按鈕響應事件的開始處添加判斷,若是已經結束,則不繼續走方塊移動的邏輯。
請到 GitHub 上查看完整代碼。
獲取更佳的閱讀體驗,請訪問原文地址 【Lyman's Blog】用 JavaScript 實現簡單拼圖遊戲