拼图游戏相信大家都不陌生,将一幅图片分割成若干拼块并将它们随机打乱顺序。当将所有拼块都放回原位置时,就完成了拼图,然后游戏结束。
在“游戏”中,单击滑块选择游戏难易,“容易”为3行3列拼图游戏,中间为一个4行4列拼图游戏,“难”为5行5列拼图游戏。拼块以随机顺序排列,玩家用鼠标单击空白块四周的来交换它们位置,直到所有拼块都回到原位置。
拼图游戏运行结果如下图所示。
HTML5可以把图片整合到网页中。使用canvas元素可以在这个空白的画布上填充线条,载入图片文件,甚至动画效果。这里制作拼图游戏用来展示HTML5 canvas的图片处理能力。
游戏程序首先显示以正确顺序排列的图片缩略图,根据玩家设置的分割数,将图片分割成相应 tileCount 行列数的拼块,并按顺序编号。动态生成一个大小 tileCount*tileCount 的数组 boardParts ,存放用 0 , 1 , 2 到 tileCount*tileCount-1 的数,每个数字代表一个拼块(例如 4*4 的游戏拼块编号如图 7-2 所示)。
游戏开始时,随机打乱这个数组 boardParts ,假如 boardParts[0] 是 5 则在左上角显示编号是 5 的拼块。根据玩家用鼠标点击的拼块和空白块所在位置,来交换该 boardParts 数组对应元素,最后判断元素排列顺序来判断是否已经完成游戏。
程序设计的步骤1. 游戏页面
<!doctype html>
<html>
<head>
<title>拼图游戏</title>
<style>
.picture {
border:1px solid black;
}
</style>
</head>
<body>
<div id="title">
<h2>拼图游戏</h2>
</div>
<div id="slider">
<form>
<label>容易</label>
<input type="range"id="scale" value="4" min="3" max="5"step="1">
<label>难</label>
<img id="source"width="120px" height="120px" src="//img.17u1u.com/defa.jpg" >
</form>
<br>
</div>
<div id="main"class="main">
<canvas id="puzzle"width="480px" height="480px"></canvas>
</div>
<scriptsrc="//img.17u1u.com/sliding.js"></script>
</body>
</html>
在网页中使用 canvas 标记用来创建画板。
<canvas width="480px"height="480px"></canvas>
canvas 的宽和高使用像素为单位。如果这两个属于没有被指定,它们的默认的宽度为: 300px ,高度为: 150px 。
网页中 <div id="slider"> 包括了另一个 HTML5 标记: range input ,这个标记 <inputtype="range"> 可以让用户拖放滑块选择一个数值。这里设置滑块最小值为 3 ,最大值为 5 。滑块值为 3 表明拼图游戏是 3 行 3 列的,滑块值为 4 表明拼图游戏是 4 行 4 列的,滑块值为 5 表明拼图游戏是 5 行 5 列的。
<img id="source" width="120px"height="120px" src="//img.17u1u.com/defa.jpg" > 显示原图 defa.jpg 的缩小图供玩家参照移动拼块。
2. sliding.js文件
在页面上画图需要使用 canvas 的上下文环境,通过调用 getContext() 方法获取上下文环境。
var context =document.getElementById('puzzle').getContext('2d');
我们还需要一个和 canvas 相同大小的图片 'defa.jpg' 。
var img = new Image();
img.src = 'defa.jpg';
img.addEventListener('load', drawTiles, false);
//load事件侦听,即图片加载完成事件
加入这个 'load' 事件是确保图片完成加载后,再把图片放入 canvas 中。 drawTiles() 函数绘制打乱的图块。
var boardSize =document.getElementById('puzzle').width;
//获取画板(画布)的宽度
var tileCount =document.getElementById('scale').value;
//获取滑块的值
boardSize 是 canvas 的宽度,通过 rangeinput 设置拼图的数量 tileCount ,数据范围从 3 到 5( 几行几列 ) 。
var tileSize = boardSize / tileCount;
//计算出拼块的大小宽度
最后定义 3 变量,其中 2 个 Object 对象变量, emptyLoc 保存空白拼图的位置( emptyLoc.x , emptyLoc.y ), clickLoc 记录用户单击的位置( clickLoc.x , clickLoc.y )。而 1 个 bool 变量 solved 是指拼图是否完成,所有的拼图都找到正确的位置后,设置它为 true 。
var context =document.getElementById('puzzle').getContext('2d');
var img = new Image();
img.src = 'dimetrodon.jpg';
img.addEventListener('load', drawTiles, false);
//load事件侦听,即图片加载完成事件
var boardSize = document.getElementById('puzzle').width;
//获取画板(画布)的宽度
var tileCount =document.getElementById('scale').value;
//获取滑块的值
var tileSize = boardSize / tileCount;
var clickLoc = new Object();
clickLoc.x = 0;
clickLoc.y = 0;
var emptyLoc = new Object();
emptyLoc.x = 0;
emptyLoc.y = 0;
var solved = false;
//拼图是否完成,false为未完成
下面实现拼块的随机排列。
我们使用一个一维数组存储每个拼块的编号。每一个元素代表一个拼块,初始时元素的数组下标与拼块的编号相同,说明位置正确。所以需要打乱数组的元素顺序,实现拼块的随机排列。而数组的元素顺序打乱使用带有排序函数的 Array.sort() 方法实现。
var boardParts = new Object();
initBoard();
//初始化拼块,并随机排列
function initBoard() {
boardParts = new Array(tileCount * tileCount);
for (vari = 0; i < tileCount * tileCount; i ) {
boardParts[i] = i;
}
shift(); //拼块的随机排列
}
function sortNumber(a,b) {//随机排序函数
returnMath.random() > 0.5 ? -1 : 1;
}
function shift() { //拼块的随机排列
boardParts.sort(sortNumber);
emptyLoc.x = 0;
emptyLoc.y = 0;
solved =false;
}
以上就实现拼块的随机放置。但是真正显示拼块在屏幕上是 drawTiles() 函数。 drawTiles() 函数显示各个拼块。这个函数判断是否是空白拼图的位置(emptyLoc.x , emptyLoc.y ),不是则调用 drawImage() 绘制相应图块。
drawImage() 最常用的是传入三个参数: image 对象,以及图片相对于画布的 x,y 坐标。 drawImage(image, x, y);
还可以加入两个参数用于设置图片的宽和高:
drawImage(image, x, y, width, height);
最复杂的 drawImage 函数有 9 个参数,按顺序分别为:图片对象,图片 x 坐标,图片 y 坐标,图片宽,图片高,目标 x 坐标,目标 y 坐标,目标宽和目标高。后四个参数主要是为了截取原图部分用来显示。这里把 boardParts 记录的拼块显示在(i*tileSize,j*tileSize )处。
//绘制所有拼块
function drawTiles() {
context.clearRect(0, 0, boardSize, boardSize);
for (vari = 0; i < tileCount; i ) {
for(var j = 0; j < tileCount; j ) {
var n = boardParts[i * tileCount j];
//计算出编号为n的拼块在原图的位置坐标(行列号)
var x = parseInt(n / tileCount);
//丢弃小数部分, 保留整数部分
var y = n % tileCount;
console.log(x ":" Math.floor(n / tileCount) ":" y);
if (i!= emptyLoc.x||j!= emptyLoc.y||solved==true) {
//不是空白拼图的位置且游戏未结束
//或者if( !(i==emptyLoc.x&&j== emptyLoc.y&&solved==false))可能更容易明白
//将编号为n的拼块显示在(i * tileSize, j * tileSize)处
context.drawImage(img, x * tileSize, y * tileSize, tileSize, tileSize,
i * tileSize, j * tileSize, tileSize, tileSize);
}
}
}
}
以下是事件定义。
首先为滑块定义触发事件,当它改变了,我们要重新计算拼块的数量和大小。滑块被移动时触发 onchange 事件,事件中计算拼块宽度大小,重新初始化画布,显示各个拼块。
document.getElementById('scale').onchange =function() {
tileCount =this.value;
tileSize =boardSize / tileCount;//计算拼块宽度大小
initBoard();//重新初始化拼块,并随机排列
drawTiles();//显示各个拼块
};
还要追踪鼠标经过的拼块以及哪个拼块被单击。画板中移动鼠标的 onmousemove 事件中,计算出鼠标所在网格坐标 clickLoc.x , clickLoc.y 。
document.getElementById('puzzle').onmousemove =function(e) {
clickLoc.x= Math.floor((e.pageX - this.offsetLeft) / tileSize);
clickLoc.y= Math.floor((e.pageY - this.offsetTop) / tileSize);
};
画布中单击鼠标的 onmousemove 事件中,计算出鼠标所在网格坐标 clickLoc.x , clickLoc.y 与空块位置间隔,如果间距为 1 则移动被单击的拼块。
document.getElementById('puzzle').onclick =function() {
if(distance(clickLoc.x, clickLoc.y, emptyLoc.x, emptyLoc.y) == 1) {
slideTile(emptyLoc, clickLoc);//交换被单击的拼块与空块位置
drawTiles();//显示各个拼块
}
if (solved){//如果成功
setTimeout(function() {alert("你成功了!");}, 500);
}
};
function distance(x1, y1, x2, y2) {
returnMath.abs(x1 - x2) Math.abs(y1 - y2);
}
注意有一些浏览器会在重画画布之前弹出对话框,为了防止它的发生,一定要用延迟。
setTimeout(function() {alert(" 你成功了 !");}, 500);
这句就是延迟 0.5 秒后,再弹出提示框 " 你成功了 !" 。
slideTile(emptyLoc, clickLoc) 是移动被单击的拼块 clickLoc 到空块位置 emptyLoc 。移动拼图的做法是:交换对应的 boardParts 元素,然后把单击位置设置成空块位置。
function slideTile(emptyLoc, clickLoc) {
if(!solved) {
vart;
t=boardParts[emptyLoc.x * tileCount emptyLoc.y];
boardParts[emptyLoc.x*tileCount emptyLoc.y]=boardParts[clickLoc.x*tileCount clickLoc.y];
boardParts[clickLoc.x * tileCount clickLoc.y] = t;
emptyLoc.x = clickLoc.x; //emptyLoc重新记录空白块位置
emptyLoc.y = clickLoc.y;
checkSolved();//检查是否成功
}
}
一旦拼图移动了,我们还要检查一下拼图是否全部在正确的位置。 checkSolved() 检查是否成功。如果有一个拼块不正确函数就会返回 false ,否则返回 true 。
function checkSolved() {
var flag= true;
for (vari = 0; i < tileCount * tileCount; i ) {
if(boardParts[i] != i) //判断元素排列顺序
flag = false;
}
solved =flag;
}
至此我们完成拼图游戏的设计。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved