手把手教你使用CanvasAPI打造一款拼圖游戲
一、canvas簡介
canvas是HTML5提供的一種新標簽,雙標簽;
HTML5 canvas標簽元素用于圖形的繪制,通過腳本 (通常是JavaScript)來完成;
canvas標簽只是圖形容器,必須使用腳本來繪制圖形;
Canvas是一個矩形區(qū)域的畫布,可以用JavaScript在上面繪畫;
二、案例目標
我們今天的目標是使用HTML5畫布技術制作一款拼圖小游戲,要求將圖像劃分為3*3的9塊方塊并打亂排序,用戶可以移動方塊拼成完整圖片。
效果如下所示:
三、程序流程
3.1 HTML靜態(tài)頁面布局
- <div id="container">
 - <!--頁面標題-->
 - <h3>HTML5畫布綜合項目之拼圖游戲</h3>
 - <!--水平線-->
 - <hr />
 - <!--游戲內(nèi)容-->
 - <!--游戲時間-->
 - <div id="timeBox">
 - 共計時間:<span id="time">00:00:00</span>
 - </div>
 - <!--游戲畫布-->
 - <canvas id="myCanvas" width="300" height="300" style="border:1px solid">
 - 對不起,您的瀏覽器不支持HTML5畫布API。
 - </canvas>
 - <!--游戲按鈕-->
 - <div>
 - <button onclick="restartGame()">
 - 重新開始
 - </button>
 - </div>
 - </div>
 
效果如下所示:
我們可以看到頁面的大致結(jié)構是已經(jīng)顯現(xiàn)出來了,就是骨架已經(jīng)搭建好了,現(xiàn)在我們要使用css強化樣式;
3.2 CSS打造頁面樣式
整體背景設置
- body {
 - background-color: silver;/*設置頁面背景顏色為銀色*/
 - }
 
游戲界面樣式設置
- #container {
 - background-color: white;
 - width: 600px;
 - margin: auto;
 - padding: 20px;
 - text-align: center;
 - box-shadow: 10px 10px 15px black;
 - }
 
游戲時間面板樣式設置
- #timeBox {
 - margin: 10px 0;
 - font-size: 18px;
 - }
 
游戲按鈕樣式設置
- button {
 - width: 200px;
 - height: 50px;
 - margin: 10px 0;
 - border: 0;
 - outline: none;
 - font-size: 25px;
 - font-weight: bold;
 - color: white;
 - background-color: lightcoral;
 - }
 
鼠標懸浮時的按鈕樣式設置
- button:hover {
 - background-color: coral;
 - }
 
設置好界面整體樣式之后我們得到完整的界面,如下所示:
可以看到整體的靜態(tài)界面已經(jīng)搭建出來了
3.3 js構建交互效果
3.3.1 對象的獲取以及圖片的設置
目標對象的獲取
- var c = document.getElementById('myCanvas'); //獲取畫布對象
 - var ctx = c.getContext('2d'); //獲取2D的context對象
 
聲明拼圖的圖片素材來源
- var img = new Image();
 - img.src = "image/pintu.jpg";
 - img.onload = function() { //當圖片加載完畢時
 - generateNum(); //打亂拼圖的位置
 - drawCanvas(); //在畫布上繪制拼圖
 - }
 
3.3.2 初始化拼圖
需要將素材圖片分割成3行3列的9個小方塊,并打亂順序放置在畫布上;
為了在游戲過程中便于查找當前的區(qū)域該顯示圖片中的哪一個方塊,首先為原圖片上的9個小方塊區(qū)域進行編號;
定義初始方塊位置
- var num = [[00, 01, 02], [10, 11, 12], [20, 21, 22]];
 
打亂拼圖的位置
- function generateNum() { //循環(huán)50次進行拼圖打亂
 - for (var i = 0; i < 50; i++) {
 - //隨機抽取其中一個數(shù)據(jù)
 - var i1 = Math.round(Math.random() * 2);
 - var j1 = Math.round(Math.random() * 2);
 - //再隨機抽取其中一個數(shù)據(jù)
 - var i2 = Math.round(Math.random() * 2);
 - var j2 = Math.round(Math.random() * 2);
 - //對調(diào)它們的位置
 - var temp = num[i1][j1];
 - num[i1][j1] = num[i2][j2];
 - num[i2][j2] = temp;
 - }
 - }
 
繪制拼圖
自定義名稱的drawCanvas()方法用于在畫布上繪制亂序后的圖片;
- function drawCanvas() {
 - //清空畫布
 - ctx.clearRect(0, 0, 300, 300);
 - //使用雙重for循環(huán)繪制3x3的拼圖
 - for (var i = 0; i < 3; i++) {
 - for (var j = 0; j < 3; j++) {
 - if (num[i][j] != 22) {
 - //獲取數(shù)值的十位數(shù),即第幾行
 - var row = parseInt(num[i][j] / 10);
 - //獲取數(shù)組的個位數(shù),即第幾列
 - var col = num[i][j] % 10;
 - //在畫布的相關位置上繪圖
 - ctx.drawImage(img, col * w, row * w, w, w, j * w, i * w, w, w); // w:300 / 3 = 100(小圖寬度)
 - }
 - }
 - }
 - }
 
如下所示:
3.3.3 事件綁定
監(jiān)聽鼠標監(jiān)聽事件
- c.onmousedown = function(e) {
 - var bound = c.getBoundingClientRect(); //獲取畫布邊界
 - var x = e.pageX - bound.left; //獲取鼠標在畫布上的坐標位置(x,y)
 - var y = e.pageY - bound.top;
 - var row = parseInt(y / w); //將x和y換算成幾行幾列
 - var col = parseInt(x / w);
 - if (num[row][col] != 22) { //如果當前點擊的不是空白區(qū)域
 - detectBox(row, col); //移動點擊的方塊
 - drawCanvas(); //重新繪制畫布
 - var isWin = checkWin(); //檢查游戲是否成功
 - if (isWin) { //如果游戲成功
 - clearInterval(timer); //清除計時器
 - ctx.drawImage(img, 0, 0); //繪制完整圖片
 - ctx.font = "bold 68px serif"; //設置字體為加粗、68號字,serif
 - ctx.fillStyle = "red"; //設置填充色為紅色
 - ctx.fillText("游戲成功!", 20, 150); //顯示提示語句
 - }
 - }
 - }
 
點擊方塊移動
- function detectBox(i, j) {
 - //如果點擊的方塊不在最上面一行
 - if (i > 0) {
 - //檢測空白區(qū)域是否在當前方塊的正上方
 - if (num[i-1][j] == 22) {
 - //交換空白區(qū)域與當前方塊的位置
 - num[i-1][j] = num[i][j];
 - num[i][j] = 22;
 - return;
 - }
 - }
 - //如果點擊的方塊不在最下面一行
 - if (i < 2) {
 - //檢測空白區(qū)域是否在當前方塊的正下方
 - if (num[i+1][j] == 22) {
 - //交換空白區(qū)域與當前方塊的位置
 - num[i+1][j] = num[i][j];
 - num[i][j] = 22;
 - return;
 - }
 - }
 - //如果點擊的方塊不在最左邊一列
 - if (j > 0) {
 - //檢測空白區(qū)域是否在當前方塊的左邊
 - if (num[i][j - 1] == 22) {
 - //交換空白區(qū)域與當前方塊的位置
 - num[i][j - 1] = num[i][j];
 - num[i][j] = 22;
 - return;
 - }
 - }
 - //如果點擊的方塊不在最右邊一列
 - if (j < 2) {
 - //檢測空白區(qū)域是否在當前方塊的右邊
 - if (num[i][j + 1] == 22) {
 - //交換空白區(qū)域與當前方塊的位置
 - num[i][j + 1] = num[i][j];
 - num[i][j] = 22;
 - return;
 - }
 - }
 - }
 
3.3.4 游戲計時
自定義函數(shù)getCurrentTime()用于進行游戲計時;
- function getCurrentTime() {
 - s = parseInt(s); //將時分秒轉(zhuǎn)換為整數(shù)以便進行自增或賦值
 - m = parseInt(m);
 - h = parseInt(h);
 - s++; //每秒變量s先自增1
 - if (s == 60) {
 - s = 0; //如果秒已經(jīng)達到60,則歸0
 - m++; //分鐘自增1
 - }
 - if (m == 60) {
 - m = 0; //如果分鐘也達到60,則歸0
 - h++; //小時自增1
 - }
 - //修改時分秒的顯示效果,使其保持兩位數(shù)
 - if (s < 10)
 - s = "0" + s;
 - if (m < 10)
 - m = "0" + m;
 - if (h < 10)
 - h = "0" + h;
 - time.innerHTML = h + ":" + m + ":" + s; //將當前計時的時間顯示在頁面上
 - }
 
在JavaScript中使用setInterval()方法每隔1秒鐘調(diào)用getCurrentTime()方法一次,以實現(xiàn)更新效果;
- var timer = setInterval("getCurrentTime()", 1000)
 
3.3.5 游戲成功與重新開始
游戲成功判定與顯示效果的實現(xiàn)
自定義函數(shù)checkWin()用于進行游戲成功判斷;
- function restartGame() {
 - clearInterval(timer); //清除計時器
 - s = 0; //時間清零
 - m = 0;
 - h = 0;
 - getCurrentTime(); //重新顯示時間
 - timer = setInterval("getCurrentTime()", 1000);
 - generateNum(); //重新打亂拼圖順序
 - drawCanvas(); //繪制拼圖
 - }
 
如果成功則使用clearInterval()方法清除計時器。然后在畫布上繪制完整圖片,并使用fillText()方法繪制出“游戲成功”的文字圖樣;
- if (isWin) { //如果游戲成功
 - clearInterval(timer); //清除計時器
 - ctx.drawImage(img, 0, 0); //繪制完整圖片
 - ctx.font = "bold 68px serif"; //設置字體為加粗、68號字,serif
 - ctx.fillStyle = "red"; //設置填充色為紅色
 - ctx.fillText("游戲成功!", 20, 150); //顯示提示語句
 - }
 
3.4 最終效果演示
靜態(tài)效果如上所示,至于游戲成功這里伙計們可以自行操作;
四、總結(jié)
本次案例我們使用HTML5的新特性canvas畫布標簽打造了簡單的9宮格拼圖游戲,總體來說沒有特別的復雜,主要是圖片的分割方塊移動事件的綁定,以及重新游戲的初始化操作,明確了游戲邏輯之后其實代碼的編寫其實不難。感興趣的小伙伴可以去嘗試一下。




















 
 
 








 
 
 
 