以下是游戏地址:
http://yuehaowang.github.io/games/puzzle/
这是我的游戏记录,欢迎各位挑战:

接下来就来讲讲如何开发完成这款游戏的。(按“编年体”)
准备阶段
准备lufylegend游戏引擎,大家可以去官方网站下载:
lufylegend.com/lufylegend
引擎文档地址:
lufylegend.com/lufylegend/api
可以说,如果没有强大的lufylegend引擎,这种html5小游戏用原生canvas制作,少说要一天呢。
0~30min
准备素材(10min) + 修改素材(20min)。由于在下实在手残,不善于P图,修改图片用了大约20min,囧……
30~50min
开发开始界面。游戏不能没有开始界面所以我们首先实现这部分代码。在此之前是index.html里的代码,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>Puzzle</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<script type="text/javascript" src="./lib/lufylegend-1.10.1.simple.min.js"></script>
<script type="text/javascript" src="./js/Main.js"></script>
</head>
<body style="margin: 0px; font-size: 0px; background: #F2F2F2;">
<p id="mygame"></p>
</body>
</html>主要是引入一些js文件,不多说。然后准备一个Main.js文件,在这个文件里添加初始化界面和加载资源的代码:
/** 初始化游戏 */
LInit(60, "mygame", 390, 580, main);
var imgBmpd;
/** 游戏层 */
var stageLayer, gameLayer, overLayer;
/** 拼图块列表 */
var blockList;
/** 是否游戏结束 */
var isGameOver;
/** 用时 */
var startTime, time, timeTxt;
/** 步数 */
var steps, stepsTxt;
function main () {
/** 全屏设置 */
if (LGlobal.mobile) {
LGlobal.stageScale = LStageScaleMode.SHOW_ALL;
}
LGlobal.screen(LGlobal.FULL_SCREEN);
/** 添加加载提示 */
var loadingHint = new LTextField();
loadingHint.text = "资源加载中……";
loadingHint.size = 20;
loadingHint.x = (LGlobal.width - loadingHint.getWidth()) / 2;
loadingHint.y = (LGlobal.height - loadingHint.getHeight()) / 2;
addChild(loadingHint);
/** 加载图片 */
LLoadManage.load(
[
{path : "./js/Block.js"},
{name : "img", path : "./images/img.jpg"}
],
null,
function (result) {
/** 移除加载提示 */
loadingHint.remove();
/** 保存位图数据,方便后续使用 */
imgBmpd = new LBitmapData(result["img"]);
gameInit();
}
);
}
function gameInit (e) {
/** 初始化舞台层 */
stageLayer = new LSprite();
stageLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EFEFEF");
addChild(stageLayer);
/** 初始化游戏层 */
gameLayer = new LSprite();
stageLayer.addChild(gameLayer);
/** 初始化最上层 */
overLayer = new LSprite();
stageLayer.addChild(overLayer);
/** 添加开始界面 */
addBeginningUI();
}以上代码有详细注释,大家可以对照引擎文档和注释进行阅读。有些全局变量会在以后的代码中使用,大家可以先忽略。接下来是addBeginningUI函数里的代码,用于实现开始界面:
function addBeginningUI () {
var beginningLayer = new LSprite();
beginningLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EDEDED");
stageLayer.addChild(beginningLayer);
/** 游戏标题 */
var title = new LTextField();
title.text = "拼图游戏";
title.size = 50;
title.weight = "bold";
title.x = (LGlobal.width - title.getWidth()) / 2;
title.y = 160;
title.color = "#FFFFFF";
title.lineWidth = 5;
title.lineColor = "#000000";
title.stroke = true;
beginningLayer.addChild(title);
/** 开始游戏提示 */
var hint = new LTextField();
hint.text = "- 点击屏幕开始游戏 -";
hint.size = 25;
hint.x = (LGlobal.width - hint.getWidth()) / 2;
hint.y = 370;
beginningLayer.addChild(hint);
/** 开始游戏 */
beginningLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {
beginningLayer.remove();
startGame();
});
}到此,运行代码,得到我们的开始界面:

看到这个画面,其实我自己都想吐槽一下实在是太“朴素”了,囧……
不过我这次图个制作速度,所以还望各位看官海量。
50~90min
这40分钟的时间,是最关键时期,期间我们要完成整个游戏的主体部分。首先,我们需要用代码来实现以下过程:
初始化游戏界面数据(如游戏时间、所用步数)和显示一些UI部件(如图样) | -> 获取随机的拼图块位置 | -> 显示打乱后的拼图块
我们将这些步骤做成一个个的函数方便我们统一调用:
function startGame () {
isGameOver = false;
/** 初始化时间和步数 */
startTime = (new Date()).getTime();
time = 0;
steps = 0;
/** 初始化拼图块列表 */
initBlockList();
/** 打乱拼图 */
getRandomBlockList();
/** 显示拼图 */
showBlock();
/** 显示缩略图 */
showThumbnail();
/** 显示时间 */
addTimeTxt();
/** 显示步数 */
addStepsTxt();
stageLayer.addEventListener(LEvent.ENTER_FRAME, onFrame);
}函数一开始,我们把isGameOver变量设定为false代表游戏未结束,在后期的代码里,我们会看到这个变量的作用。接着我们初始化了用于表示时间和步数的time和steps这两个全局变量,另外初始化变量startTime的值用于后面计算游戏时间。
接下来,我们就要开始初始化拼图块了。见initBlockList里的代码:
function initBlockList () {
blockList = new Array();
for (var i = 0; i < 9; i++) {
/** 根据序号计算拼图块图片显示位置 */
var y = (i / 3) >>> 0, x = i % 3;
blockList.push(new Block(i, x, y));
}
}这里我们使用了一个Block类,这个类用于显示拼图块和储存拼图块的数据,并提供了一些方法来操控拼图块,下面是其构造器的代码:
function Block (index, x, y) {
LExtends(this, LSprite, []);
var bmpd = imgBmpd.clone();
bmpd.setProperties(x * 130, y * 130, 130, 130);
this.bmp = new LBitmap(bmpd);
this.addChild(this.bmp);
var border = new LShape();
border.graphics.drawRect(3, "#CCCCCC", [0, 0, 130, 130]);
this.addChild(border);
this.index = index;
this.addEventListener(LMouseEvent.MOUSE_UP, this.onClick);
}Block类继承自LSprite,属于一个显示对象,所以我们在这个类中添加了一个位图对象用于显示拼图块对应的图片。除此之外,我们还为拼图块添加了一个边框,在显示时用于隔开周围的拼图块。Block类有一个index属性,代表拼图块在拼图块列表blockList中的正确位置。最后,我

