1. 程式人生 > >HTML5技術之影象處理:一個滑動的拼圖遊戲(轉)

HTML5技術之影象處理:一個滑動的拼圖遊戲(轉)

HTML5技術之影象處理:一個滑動的拼圖遊戲
HTML5有許多功能特性可以把多媒體整合到網頁中。使用canvas元素可以在這個空白的畫板上填充線條,載入圖片檔案,甚至動畫效果。
在這篇文章中,我將做一個滑動拼圖的遊戲用來展示HTML5 canvas的圖片處理能力。
在網頁中使用canvas標籤用來建立畫板

<canvas width="480px" height="480px"></canvas>

canvas的寬和高使用畫素為單位。如果這兩個屬於沒有被指定,他們的預設的寬度為:300px,高度為:150px。

在圖板畫圖需要使用canvas的上下文環境,通過指令碼呼叫getContext()方法獲取上下文環境。W3C定義它為二維,更確切的說是2d。所以初始化上下文環境如果如下方法:
document.getElementById("vanvas").getContext("2d");

下一步要做的是在畫板上顯示圖片,API只提供drawImage()一種方法。但是有三種呼叫方式。最常用的是傳入三個引數:image物件,以及圖片相對於畫板的x,y座標。

drawImage(image, x, y);

還可以加入兩個引數用於設定圖片的寬和高

drawImage(image, x, y, width, height);

最複雜的drawImage函式有9個引數,按順序分別為:圖片物件,圖片x座標,圖片y座標,圖片寬,圖片高,目標x座標,目標y座標,目標寬和目標高。後四個引數主要是為了擷取原圖部分用來顯示,比如區域性放大、剪下等。
以上就是影象處理的方法,讓我們做一個練習。
<div id="slider">
  <form>    
    <label>Easy</label>
    <input type="range" id="scale" value="4" min="3" max="5" step="1">
    <label>Hard</label>
  </form>
<br>
</div>
<div id="main" class="main">
<canvas id="puzzle" width="480px" height="480px"></canvas>
</div>

上面的DIV包括了另一個HTML5標籤:range input,這個標籤可以讓使用者拖放滑塊選擇一個數值。回頭我們再說在拼圖中如何與range input互動。到目前為止ie和firefox並不支援這個標籤。

現在就像我上面說過,想要在canvas上繪圖,我們需要context。
var context = document.getElementById("puzzle").getContext("2d");

對了我們還需要一個圖片,使用例子裡自帶的,或者找一個和canvas相同大小的圖片都行。

var img = new Image();
img.src = 'http://www.brucealderman.info/Images/dimetrodon.jpg';
img.addEventListener('load', drawTiles, false);

加入這個事件是確保圖片完成載入後,再把圖片放入canvas中。

下面我們通過range input設定拼圖的數量,資料範圍從3到5(幾行幾列)。
var boardSize = document.getElementById('puzzle').width;
var tileCount = document.getElementById('scale').value;

有了上面兩個數值就可以計算一個拼圖的大小了

var tileSize = boardSize / tileCount;

OK我們開始建立畫板

var boardParts = new Object;
setBoard();

setBoard()的作用是初始化看板,要模擬顯示這個畫板,我們使用一個二維陣列。
不過用JavaScript建立這樣陣列的過程不是很優雅,我們先定義一個平面陣列,每個陣列再定義一個數組。這個拼圖遊戲,每一個元素都是一個物件,它帶有x和y座標記錄所在的網格位置。因此每個物件有兩個座標,
第一個座標是陣列座標,表示它在畫板的位置,另外的座標是物件的x,y屬性,它記錄著拼圖圖片的位置。當這兩個座標相同了就說明位置正確。
為了達到目的,我們在初始化的時候把它們的位置互換。這樣拼圖就不在正確的位置了。
function setBoard() {
    boardParts = new Array(tileCount);
    for (var i = 0; i < tileCount; ++i) {
     boardParts[i] = new Array(tileCount);
     for (var j = 0; j < tileCount; ++j) {
      boardParts[i][j] = new Object;
      boardParts[i][j].x = (tileCount - 1) - i;
      boardParts[i][j].y = (tileCount - 1) - j;
     }
 }
    emptyLoc.x = boardParts[tileCount - 1][tileCount - 1].x;
    emptyLoc.y = boardParts[tileCount - 1][tileCount - 1].y;
    solved = false;
}

最後三個變數我們還沒有定義

我們必須追蹤空白拼圖的位置還要記錄使用者點選的位置

var clickLoc = new Object;
clickLoc.x = 0;
clickLoc.y = 0;
var 
emptyLoc = new Object;
emptyLoc.x = 0;
emptyLoc.y = 0;

最後這個變數是指拼圖是否完成
var solved = false;

所有的拼圖都找到正確的位置後,設定它為true。
現在我們需要一些和解決拼圖相關的方法
首先為rang input定義觸發事件,當它改變了,我們要重新計算拼圖的數量和大小
document.getElementById('scale').onchange = function() {
    
tileCount = this.value;
    tileSize = boardSize / 
tileCount;
    setBoard();
    
drawTiles();
};

還要追蹤滑鼠經過的拼圖以及哪個拼圖被點選

document.getElementById('puzzle').onmousemove = function(e) 
{
    clickLoc.x = Math.floor((e.pageX - this.offsetLeft) / 
tileSize);
    clickLoc.y = Math.floor((e.pageY - 
this.offsetTop) / tileSize);
};
document.getElementById('puzzle').onclick 
= function() {
    if (distance(clickLoc.x, clickLoc.y, 
emptyLoc.x, emptyLoc.y) == 1) {
        
slideTile(emptyLoc, clickLoc);
        
drawTiles();
    }
    if (solved) 
{
        alert("You solved it!");
    }
};

有一些瀏覽器會在重畫畫板之前彈出對話方塊,為了防止它的發生,一定要用延遲。
if (solved) {
    setTimeout(function() {alert("You solved it!");}, 500);
}

當一個拼圖被點選時,我們要知道它的四周是否可以移動。判斷的方法是當前位置到空白位置的總距離為1時就可以移動。
簡單點說就是x相同要判斷y的距離是否為1,y相同要判斷x的距離是否為1。
function distance(x1, y1, x2, y2) {
    return Math.abs(x1 - 
x2) + Math.abs(y1 - y2);
}

移動拼圖的做法是,我們複製被點選拼圖的座標到空位置。然後把點選位置設定成空白座標。
function slideTile(toLoc, fromLoc) {
    if (!solved) 
{
        boardParts[toLoc.x][toLoc.y].x = 
boardParts[fromLoc.x][fromLoc.y].x;
        
boardParts[toLoc.x][toLoc.y].y = 
boardParts[fromLoc.x][fromLoc.y].y;
        
boardParts[fromLoc.x][fromLoc.y].x = tileCount - 
1;
        
boardParts[fromLoc.x][fromLoc.y].y = tileCount - 
1;
        toLoc.x = 
fromLoc.x;
        toLoc.y = 
fromLoc.y;
        
checkSolved();
    }
}

一旦拼圖移動了,我們還要檢查一下拼圖是否全部在正確的位置。
function checkSolved() {
    var flag = 
true;
    for (var i = 0; i < tileCount; ++i) 
{
        for (var j = 0; j < 
tileCount; ++j) 
{
            if 
(boardParts[i][j].x != i || boardParts[i][j].y != j) 
{
                
flag = 
false;
            
}
        }
    
}
    solved = flag;
}

如果有一個拼圖不正確函式就會返回false,否則返回true。
最後,重繪被點選的拼圖到新的位置。
function drawTiles() {
    context.clearRect ( 0 , 0 , boardSize , boardSize );
    for (var i = 0; i < tileCount; ++i) {
        for (var j = 0; j < tileCount; ++j) {
            var x = boardParts[i][j].x;
     var y = boardParts[i][j].y;
            if(i != emptyLoc.x || j != emptyLoc.y || solved == true) {
                context.drawImage(img, x * tileSize, y * tileSize, tileSize, tileSize,
                     i * tileSize, j * tileSize, tileSize, tileSize);
            }
        }
    }
}

當畫拼圖時,這個函式可以防止填充畫板時匹配空的位置,因為在遊戲中使用者可以選擇不同的難度。

時間有限難免有翻譯不正確的地方,請諒解。下面是原始碼(使用Chrome開啟呦)

下載地址:http://download.csdn.net/detail/dragoo1/8859295

轉自:http://bbs.9ria.com/thread-112666-1-1.html