<font size="3">HTML5有许多功能特性可以把多媒体整合到网页中。使用canvas元素可以在这个空白的画板上填充线条,载入图片文件,甚至动画效果。<br> <br> 在这篇文章中,我将做一个滑动拼图的游戏用来展示HTML5 canvas的图片处理能力。<br> 在网页中使用canvas标签用来创建画板。<br> <br> </font><div class="blockcode"> <div id="code_4qD"><ol><li><font size="3"><canvas width="480px" height="480px"></canvas></font></li></ol></div> <em onclick="copycode($('code_4qD'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> <br> canvas的宽和高使用像素为单位。如果这两个属于没有被指定,他们的默认的宽度为:300px,高度为:150px。在图板画图需要使用canvas的上下文环境,通过脚本调用getContext()方法获取上下文环境。W3C定义它为二维,更确切的说是2d。所以初始化上下文环境如果如下方法:<br> </font><div class="blockcode"> <div id="code_7kW"><ol><li><font size="3">document.getElementById("vanvas").getContext("2d");</font></li></ol></div> <em onclick="copycode($('code_7kW'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 下一步要做的是在画板上显示图片,API只提供drawImage()一种方法。但是有三种调用方式。最常用的是传入三个参数:image对象,以及图片相对于画板的x,y坐标。<br> </font><div class="blockcode"> <div id="code_mEx"><ol><li><font size="3">drawImage(image, x, y);</font></li></ol></div> <em onclick="copycode($('code_mEx'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 还可以加入两个参数用于设置图片的宽和高<br> </font><div class="blockcode"> <div id="code_87T"><ol><li><font size="3">drawImage(image, x, y, width, height);</font></li></ol></div> <em onclick="copycode($('code_87T'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 最复杂的drawImage函数有9个参数,按顺序分别为:图片对象,图片x坐标,图片y坐标,图片宽,图片高,目标x坐标,目标y坐标,目标宽和目标高。后四个参数主要是为了截取原图部分用来显示,比如局部放大、剪切等。以上就是图像处理的方法,让我们做一个练习。<br> </font><div class="blockcode"> <div id="code_zQR"><ol> <li><div id="slider"><font size="3"><br> </font></div></li> <li> <font size="3"> </font><form><font size="3"> <br> </font></form> </li> <li><font size="3"> <label>Easy</label><br> </font></li> <li><font size="3"> <input type="range" id="scale" value="4" min="3" max="5" step="1"><br> </font></li> <li><font size="3"> <label>Hard</label><br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3"><br><br> </font></li> <li> </ol></div> <font size="3"><br> </font><li><div id="main" class="main"><font size="3"><br> </font></div></li> <li><font size="3"><canvas id="puzzle" width="480px" height="480px"></canvas><br> </font></li> <li> </div> <font size="3"><em onclick="copycode($('code_zQR'));">复制代码</em><br> 上面的DIV包括了另一个HTML5标签:range input,这个标签可以让用户拖放滑块选择一个数值。回头我们再说在拼图中如何与range input交互。到目前为止ie和firefox并不支持这个标签。<br> 现在就像我上面说过,想要在canvas上绘图,我们需要context。<br> </font><div class="blockcode"> <div id="code_PXQ"><ol><li><font size="3">var context = document.getElementById("puzzle").getContext("2d");</font></li></ol></div> <em onclick="copycode($('code_PXQ'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 对了我们还需要一个图片,使用例子里自带的,或者找一个和canvas相同大小的图片都行。<br> </font><div class="blockcode"> <div id="code_Nw1"><ol> <li><font size="3">var img = new Image();<br> </font></li> <li><font size="3">img.src = 'http://www.brucealderman.info/Images/dimetrodon.jpg';<br> </font></li> <li><font size="3">img.addEventListener('load', drawTiles, false);</font></li> </ol></div> <em onclick="copycode($('code_Nw1'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 加入这个事件是确保图片完成加载后,再把图片放入canvas中。下面我们通过range input设置拼图的数量,数据范围从3到5(几行几列)。<br> </font><div class="blockcode"> <div id="code_TA3"><ol> <li><font size="3">var boardSize = document.getElementById('puzzle').width;<br> </font></li> <li><font size="3">var tileCount = document.getElementById('scale').value;</font></li> </ol></div> <em onclick="copycode($('code_TA3'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 有了上面两个数值就可以计算一个拼图的大小了<br> </font><div class="blockcode"> <div id="code_xe5"><ol><li><font size="3">var tileSize = boardSize / tileCount;</font></li></ol></div> <em onclick="copycode($('code_xe5'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> OK我们开始创建画板<br> </font><div class="blockcode"> <div id="code_OFM"><ol> <li><font size="3">var boardParts = new Object;<br> </font></li> <li><font size="3">setBoard();</font></li> </ol></div> <em onclick="copycode($('code_OFM'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> setBoard()的作用是初始化看板,要模拟显示这个画板,我们使用一个二维数组。不过用JavaScript创建这样数组的过程不是很优雅,我们先定义一个平面数组,每个数组再定义一个数组。这个拼图游戏,每一个元素都是一个对象,它带有x和y坐标记录所在的网格位置。因此每个对象有两个坐标,第一个坐标是数组坐标,表示它在画板的位置,另外的坐标是对象的x,y属性,它记录着拼图图片的位置。当这两个坐标相同了就说明位置正确。<br> 为了达到目的,我们在初始化的时候把它们的位置互换。这样拼图就不在正确的位置了。<br> </font><div class="blockcode"> <div id="code_b1P"><ol> <li><font size="3">function setBoard() {<br> </font></li> <li><font size="3"> boardParts = new Array(tileCount);<br> </font></li> <li><font size="3"> for (var i = 0; i </font></li> <li><font size="3"> boardParts[i] = new Array(tileCount);<br> </font></li> <li><font size="3"> for (var j = 0; j </font></li> <li><font size="3"> boardParts[i][j] = new Object;<br> </font></li> <li><font size="3"> boardParts[i][j].x = (tileCount - 1) - i;<br> </font></li> <li><font size="3"> boardParts[i][j].y = (tileCount - 1) - j;<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> emptyLoc.x = boardParts[tileCount - 1][tileCount - 1].x;<br> </font></li> <li><font size="3"> emptyLoc.y = boardParts[tileCount - 1][tileCount - 1].y;<br> </font></li> <li><font size="3"> solved = false;<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_b1P'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 最后三个变量我们还没有定义<br> 我们必须追踪空白拼图的位置还要记录用户点击的位置<br> </font><div class="blockcode"> <div id="code_HlC"><ol> <li><font size="3">var clickLoc = new Object;<br> </font></li> <li><font size="3">clickLoc.x = 0;<br> </font></li> <li><font size="3">clickLoc.y = 0;<br> </font></li> <li><font size="3">var <br> </font></li> <li><font size="3">emptyLoc = new Object;<br> </font></li> <li><font size="3">emptyLoc.x = 0;<br> </font></li> <li><font size="3">emptyLoc.y = 0;</font></li> </ol></div> <em onclick="copycode($('code_HlC'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 最后这个变量是指拼图是否完成<br> </font><div class="blockcode"> <div id="code_fYx"><ol><li><font size="3">var solved = false;</font></li></ol></div> <em onclick="copycode($('code_fYx'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 所有的拼图都找到正确的位置后,设置它为true。<br> 现在我们需要一些和解决拼图相关的方法<br> 首先为rang input定义触发事件,当它改变了,我们要重新计算拼图的数量和大小<br> </font><div class="blockcode"> <div id="code_U2m"><ol> <li><font size="3">document.getElementById('scale').onchange = function() {<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">tileCount = this.value;<br> </font></li> <li><font size="3"> tileSize = boardSize / <br> </font></li> <li><font size="3">tileCount;<br> </font></li> <li><font size="3"> setBoard();<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">drawTiles();<br> </font></li> <li><font size="3">};</font></li> </ol></div> <em onclick="copycode($('code_U2m'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 还要追踪鼠标经过的拼图以及哪个拼图被点击<br> </font><div class="blockcode"> <div id="code_DH2"><ol> <li><font size="3">document.getElementById('puzzle').onmousemove = function(e) <br> </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> clickLoc.x = Math.floor((e.pageX - this.offsetLeft) / <br> </font></li> <li><font size="3">tileSize);<br> </font></li> <li><font size="3"> clickLoc.y = Math.floor((e.pageY - <br> </font></li> <li><font size="3">this.offsetTop) / tileSize);<br> </font></li> <li><font size="3">};<br> </font></li> <li><font size="3">document.getElementById('puzzle').onclick <br> </font></li> <li><font size="3">= function() {<br> </font></li> <li><font size="3"> if (distance(clickLoc.x, clickLoc.y, <br> </font></li> <li><font size="3">emptyLoc.x, emptyLoc.y) == 1) {<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">slideTile(emptyLoc, clickLoc);<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">drawTiles();<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> if (solved) <br> </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> alert("You solved <br> </font></li> <li><font size="3">it!");<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3">};</font></li> </ol></div> <em onclick="copycode($('code_DH2'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 有一些浏览器会在重画画板之前弹出对话框,为了防止它的发生,一定要用延迟。<br> </font><div class="blockcode"> <div id="code_bsG"><ol> <li><font size="3">if (solved) {<br> </font></li> <li><font size="3"> setTimeout(function() {alert("You solved <br> </font></li> <li><font size="3">it!");}, 500);<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_bsG'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 当一个拼图被点击时,我们要知道它的四周是否可以移动。判断的方法是当前位置到空白位置的总距离为1时就可以移动。<br> 简单点说就是x相同要判断y的距离是否为1,y相同要判断x的距离是否为1。<br> </font><div class="blockcode"> <div id="code_W2H"><ol> <li><font size="3">function distance(x1, y1, x2, y2) {<br> </font></li> <li><font size="3"> return Math.abs(x1 - <br> </font></li> <li><font size="3">x2) + Math.abs(y1 - y2);<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_W2H'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 移动拼图的做法是,我们复制被点击拼图的坐标到空位置。然后把点击位置设置成空白坐标。<br> </font><div class="blockcode"> <div id="code_0SX"><ol> <li><font size="3">function slideTile(toLoc, fromLoc) {<br> </font></li> <li><font size="3"> if (!solved) <br> </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> boardParts[toLoc.x][toLoc.y].x = <br> </font></li> <li><font size="3">boardParts[fromLoc.x][fromLoc.y].x;<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">boardParts[toLoc.x][toLoc.y].y = <br> </font></li> <li><font size="3">boardParts[fromLoc.x][fromLoc.y].y;<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">boardParts[fromLoc.x][fromLoc.y].x = tileCount - <br> </font></li> <li><font size="3">1;<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">boardParts[fromLoc.x][fromLoc.y].y = tileCount - <br> </font></li> <li><font size="3">1;<br> </font></li> <li><font size="3"> toLoc.x = <br> </font></li> <li><font size="3">fromLoc.x;<br> </font></li> <li><font size="3"> toLoc.y = <br> </font></li> <li><font size="3">fromLoc.y;<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">checkSolved();<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_0SX'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 一旦拼图移动了,我们还要检查一下拼图是否全部在正确的位置。<br> </font><div class="blockcode"> <div id="code_QMq"><ol> <li><font size="3">function checkSolved() {<br> </font></li> <li><font size="3"> var flag = <br> </font></li> <li><font size="3">true;<br> </font></li> <li><font size="3"> for (var i = 0; i </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> for (var j = 0; j </font></li> <li><font size="3">tileCount; ++j) <br> </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> if <br> </font></li> <li><font size="3">(boardParts[i][j].x != i || boardParts[i][j].y != j) <br> </font></li> <li><font size="3">{<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">flag = <br> </font></li> <li><font size="3">false;<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">}<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> <br> </font></li> <li><font size="3">}<br> </font></li> <li><font size="3"> solved = flag;<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_QMq'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 如果有一个拼图不正确函数就会返回false,否则返回true。<br> 最后,重绘被点击的拼图到新的位置。<br> </font><div class="blockcode"> <div id="code_xkz"><ol> <li><font size="3">function drawTiles() {<br> </font></li> <li><font size="3"> context.clearRect ( 0 , 0 , boardSize , boardSize );<br> </font></li> <li><font size="3"> for (var i = 0; i </font></li> <li><font size="3"> for (var j = 0; j </font></li> <li><font size="3"> var x = boardParts[i][j].x;<br> </font></li> <li><font size="3"> var y = boardParts[i][j].y;<br> </font></li> <li><font size="3"> if(i != emptyLoc.x || j != emptyLoc.y || solved == true) {<br> </font></li> <li><font size="3"> context.drawImage(img, x * tileSize, y * tileSize, tileSize, tileSize,<br> </font></li> <li><font size="3"> i * tileSize, j * tileSize, tileSize, tileSize);<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3"> }<br> </font></li> <li><font size="3">}</font></li> </ol></div> <em onclick="copycode($('code_xkz'));"><font size="3">复制代码</font></em> </div> <font size="3"><br> 当画拼图时,这个函数可以防止填充画板时匹配空的位置,因为在游戏中用户可以选择不同的难度。<br> <br><br><br><br> 转自<a href="http://bbs.9ria.com/thread-112666-1-1.html">天地会</a><br></font> <br>