当前位置:首页 >> 编程开发 >> HTML+CSS >> 内容

HTML5技术之图像处理:一个滑动的拼图游戏

时间:2013/11/24 15:02:00 作者:平凡之路 来源:xuhantao.com 浏览:

HTML5有许多功能特性可以把多媒体整合到网页中。使用canvas元素可以在这个空白的画板上填充线条,载入图片文件,甚至动画效果。

在这篇文章中,我将做一个滑动拼图的游戏用来展示HTML5 canvas的图片处理能力。
在网页中使用canvas标签用来创建画板。

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

复制代码



canvas的宽和高使用像素为单位。如果这两个属于没有被指定,他们的默认的宽度为:300px,高度为:150px。在图板画图需要使用canvas的上下文环境,通过脚本调用getContext()方法获取上下文环境。W3C定义它为二维,更确切的说是2d。所以初始化上下文环境如果如下方法:

  1. document.getElementById("vanvas").getContext("2d");

复制代码


下一步要做的是在画板上显示图片,API只提供drawImage()一种方法。但是有三种调用方式。最常用的是传入三个参数:image对象,以及图片相对于画板的x,y坐标。

  1. drawImage(image, x, y);

复制代码


还可以加入两个参数用于设置图片的宽和高

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

复制代码


最复杂的drawImage函数有9个参数,按顺序分别为:图片对象,图片x坐标,图片y坐标,图片宽,图片高,目标x坐标,目标y坐标,目标宽和目标高。后四个参数主要是为了截取原图部分用来显示,比如局部放大、剪切等。以上就是图像处理的方法,让我们做一个练习。

  1. <div id="slider">
  2. <form>
  3. <label>Easy</label>
  4. <input type="range" id="scale" value="4" min="3" max="5" step="1">
  5. <label>Hard</label>
  6. </form>
  7. <br>
  8. </div>
  9. <div id="main" class="main">
  10. <canvas id="puzzle" width="480px" height="480px"></canvas>
  11. </div>

复制代码


上面的DIV包括了另一个HTML5标签:range input,这个标签可以让用户拖放滑块选择一个数值。回头我们再说在拼图中如何与range input交互。到目前为止ie和firefox并不支持这个标签。
现在就像我上面说过,想要在canvas上绘图,我们需要context。

  1. var context = document.getElementById("puzzle").getContext("2d");

复制代码


对了我们还需要一个图片,使用例子里自带的,或者找一个和canvas相同大小的图片都行。

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

复制代码


加入这个事件是确保图片完成加载后,再把图片放入canvas中。下面我们通过range input设置拼图的数量,数据范围从3到5(几行几列)。

  1. var boardSize = document.getElementById('puzzle').width;
  2. var tileCount = document.getElementById('scale').value;

复制代码


有了上面两个数值就可以计算一个拼图的大小了

  1. var tileSize = boardSize / tileCount;

复制代码


OK我们开始创建画板

  1. var boardParts = new Object;
  2. setBoard();

复制代码


setBoard()的作用是初始化看板,要模拟显示这个画板,我们使用一个二维数组。不过用javascript创建这样数组的过程不是很优雅,我们先定义一个平面数组,每个数组再定义一个数组。这个拼图游戏,每一个元素都是一个对象,它带有x和y坐标记录所在的网格位置。因此每个对象有两个坐标,第一个坐标是数组坐标,表示它在画板的位置,另外的坐标是对象的x,y属性,它记录着拼图图片的位置。当这两个坐标相同了就说明位置正确。
为了达到目的,我们在初始化的时候把它们的位置互换。这样拼图就不在正确的位置了。

  1. function setBoard() {
  2. boardParts = new Array(tileCount);
  3. for (var i = 0; i < tileCount; ++i) {
  4. boardParts[i] = new Array(tileCount);
  5. for (var j = 0; j < tileCount; ++j) {
  6. boardParts[i][j] = new Object;
  7. boardParts[i][j].x = (tileCount - 1) - i;
  8. boardParts[i][j].y = (tileCount - 1) - j;
  9. }
  10. }
  11. emptyLoc.x = boardParts[tileCount - 1][tileCount - 1].x;
  12. emptyLoc.y = boardParts[tileCount - 1][tileCount - 1].y;
  13. solved = false;
  14. }

复制代码


最后三个变量我们还没有定义
我们必须追踪空白拼图的位置还要记录用户点击的位置

  1. var clickLoc = new Object;
  2. clickLoc.x = 0;
  3. clickLoc.y = 0;
  4. var
  5. emptyLoc = new Object;
  6. emptyLoc.x = 0;
  7. emptyLoc.y = 0;

复制代码


最后这个变量是指拼图是否完成

  1. var solved = false;

复制代码


所有的拼图都找到正确的位置后,设置它为true。
现在我们需要一些和解决拼图相关的方法
首先为rang input定义触发事件,当它改变了,我们要重新计算拼图的数量和大小

  1. document.getElementById('scale').onchange = function() {

  2. tileCount = this.value;
  3. tileSize = boardSize /
  4. tileCount;
  5. setBoard();

  6. drawTiles();
  7. };

复制代码


还要追踪鼠标经过的拼图以及哪个拼图被点击

  1. document.getElementById('puzzle').onmousemove = function(e)
  2. {
  3. clickLoc.x = Math.floor((e.pageX - this.offsetLeft) /
  4. tileSize);
  5. clickLoc.y = Math.floor((e.pageY -
  6. this.offsetTop) / tileSize);
  7. };
  8. document.getElementById('puzzle').onclick
  9. = function() {
  10. if (distance(clickLoc.x, clickLoc.y,
  11. emptyLoc.x, emptyLoc.y) == 1) {

  12. slideTile(emptyLoc, clickLoc);

  13. drawTiles();
  14. }
  15. if (solved)
  16. {
  17. alert("You solved
  18. it!");
  19. }
  20. };

复制代码


有一些浏览器会在重画画板之前弹出对话框,为了防止它的发生,一定要用延迟。

  1. if (solved) {
  2. setTimeout(function() {alert("You solved
  3. it!");}, 500);
  4. }

复制代码


当一个拼图被点击时,我们要知道它的四周是否可以移动。判断的方法是当前位置到空白位置的总距离为1时就可以移动。
简单点说就是x相同要判断y的距离是否为1,y相同要判断x的距离是否为1。

  1. function distance(x1, y1, x2, y2) {
  2. return Math.abs(x1 -
  3. x2) + Math.abs(y1 - y2);
  4. }

复制代码


移动拼图的做法是,我们复制被点击拼图的坐标到空位置。然后把点击位置设置成空白坐标。

  1. function slideTile(toLoc, fromLoc) {
  2. if (!solved)
  3. {
  4. boardParts[toLoc.x][toLoc.y].x =
  5. boardParts[fromLoc.x][fromLoc.y].x;

  6. boardParts[toLoc.x][toLoc.y].y =
  7. boardParts[fromLoc.x][fromLoc.y].y;

  8. boardParts[fromLoc.x][fromLoc.y].x = tileCount -
  9. 1;

  10. boardParts[fromLoc.x][fromLoc.y].y = tileCount -
  11. 1;
  12. toLoc.x =
  13. fromLoc.x;
  14. toLoc.y =
  15. fromLoc.y;

  16. checkSolved();
  17. }
  18. }

复制代码


一旦拼图移动了,我们还要检查一下拼图是否全部在正确的位置。

  1. function checkSolved() {
  2. var flag =
  3. true;
  4. for (var i = 0; i < tileCount; ++i)
  5. {
  6. for (var j = 0; j <
  7. tileCount; ++j)
  8. {
  9. if
  10. (boardParts[i][j].x != i || boardParts[i][j].y != j)
  11. {

  12. flag =
  13. false;

  14. }
  15. }

  16. }
  17. solved = flag;
  18. }

复制代码


如果有一个拼图不正确函数就会返回false,否则返回true。
最后,重绘被点击的拼图到新的位置。

  1. function drawTiles() {
  2. context.clearRect ( 0 , 0 , boardSize , boardSize );
  3. for (var i = 0; i < tileCount; ++i) {
  4. for (var j = 0; j < tileCount; ++j) {
  5. var x = boardParts[i][j].x;
  6. var y = boardParts[i][j].y;
  7. if(i != emptyLoc.x || j != emptyLoc.y || solved == true) {
  8. context.drawImage(img, x * tileSize, y * tileSize, tileSize, tileSize,
  9. i * tileSize, j * tileSize, tileSize, tileSize);
  10. }
  11. }
  12. }
  13. }

复制代码


当画拼图时,这个函数可以防止填充画板时匹配空的位置,因为在游戏中用户可以选择不同的难度。




转自天地会

共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 徐汉涛(www.xuhantao.com) © 2024 版权所有 All Rights Reserved.
  • 部分内容来自网络,如有侵权请联系站长尽快处理 站长QQ:965898558(广告及站内业务受理) 网站备案号:蒙ICP备15000590号-1