是一个奥特曼拼图小游戏戏

503 Service Temporarily Unavailable
503 Service Temporarily Unavailable
openresty/1.11.2.4魔仙拼拼看
非玩不可的拼图游戏
登录7k7k发现更多乐趣
7K7K网页游戏
7K7K儿童游戏
法律顾问:北京市诺恒律师事务所
京公网安备37
游戏作品版权归原作者享有,如无意之中侵犯了您的版权,请您按照来信告知,本网站将应您的要求删除。
7k7k小游戏温馨提示:适度游戏娱乐,沉迷游戏伤身,合理安排时间,享受快乐生活……速度挑战 - 2小时完成HTML5拼图小游戏 - CSDN博客
速度挑战 - 2小时完成HTML5拼图小游戏
初学lufylegend.js之日,我用lufylegend.js开发了第一个HTML5小游戏——拼图游戏,还写了篇博文来炫耀一下:。不过当时初学游戏开发,经验浅薄,所以没有好好专研游戏里的算法和代码的缺陷,导致游戏出现了很多bug,甚至拼图打乱后很可能无法复原。最近经常有朋友问起这个游戏,希望我能把代码里的bug改一下方便初学者学习,顺便我也打算测试一下自己写这种小游戏的速度,所以就抽出了一些时间将这个游戏从头到尾重新写了一遍,计算了一下用时,从准备、修改素材到最后完成游戏,一共用了大约2h的时间。
以下是游戏地址:
这是我的游戏记录,欢迎各位挑战:
接下来就来讲讲如何开发完成这款游戏的。(按“编年体”)
准备lufylegend游戏引擎,大家可以去官方网站下载:
引擎文档地址:
可以说,如果没有强大的lufylegend引擎,这种html5小游戏用原生canvas制作,少说要一天呢。
准备素材(10min) + 修改素材(20min)。由于在下实在手残,不善于P图,修改图片用了大约20min,囧……
开发开始界面。游戏不能没有开始界面所以我们首先实现这部分代码。在此之前是index.html里的代码,代码如下:
&!DOCTYPE html&
charset="utf-8"&
name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"&
type="text/javascript" src="./lib/lufylegend-1.10.1.simple.min.js"&&
type="text/javascript" src="./js/Main.js"&&
style="margin: 0 font-size: 0 background: #F2F2F2;"&
id="mygame"&&
主要是引入一些js文件,不多说。然后准备一个Main.js文件,在这个文件里添加初始化界面和加载资源的代码:
LInit(60, "mygame", 390, 580, main);
var stageLayer, gameLayer, overL
var blockL
var isGameO
var startTime, time, timeT
var steps, stepsT
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"}
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();
到此,运行代码,得到我们的开始界面:
看到这个画面,其实我自己都想吐槽一下实在是太“朴素”了,囧……
不过我这次图个制作速度,所以还望各位看官海量。
这40分钟的时间,是最关键时期,期间我们要完成整个游戏的主体部分。首先,我们需要用代码来实现以下过程:
初始化游戏界面数据(如游戏时间、所用步数)和显示一些UI部件(如图样)
-& 获取随机的拼图块位置
-& 显示打乱后的拼图块
我们将这些步骤做成一个个的函数方便我们统一调用:
function startGame () {
isGameOver = false;
startTime = (new Date()).getTime();
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 =
this.addEventListener(LMouseEvent.MOUSE_UP, this.onClick);
Block类继承自LSprite,属于一个显示对象,所以我们在这个类中添加了一个位图对象用于显示拼图块对应的图片。除此之外,我们还为拼图块添加了一个边框,在显示时用于隔开周围的拼图块。Block类有一个index属性,代表拼图块在拼图块列表blockList中的正确位置。最后,我们为此类添加了一个鼠标按下事件,用于处理鼠标按下后移动图块操作。
接下来我们还要介绍这个类的一个方法setLocation:
Block.prototype.setLocation = function (x, y) {
this.locationX =
this.locationY =
this.x = x * 130;
this.y = y * 130;
这个方法用于设置拼图块对象的显示位置以及保存拼图块的“数组位置”。什么是“数组位置”呢?各位看官可以通过下面的图片加以了解:
可以看到,“数组位置”就类似于二维数组中的元素下标。储存这个位置的作用在于可以很方便地从blockList中获取到附近的其他拼图块。这个方法在我们显示拼图时有调用到,在显示拼图之前,我们得先打乱拼图,见如下代码:
function getRandomBlockList () {
blockList.sort(function () {
return 0.5 - Math.random();
var reverseAmount = 0;
for (var i = 0, l = blockList. i & i++) {
var currentBlock = blockList[i];
for (var j = i + 1; j & j++) {
var comparedBlock = blockList[j];
if (comparedBlock.index & currentBlock.index) {
reverseAmount++;
if (reverseAmount % 2 != 0) {
getRandomBlockList();
打乱拼图部分直接用数组的sort方法进行随机打乱:
blockList.sort(function () {
return 0.5 - Math.random();
其实打乱算法有很多种,我这里采用最粗暴的方法,也就是随机打乱。这种算法简单是简单,坏在可能出现无法复原的现象。针对这个问题,就有配套的检测打乱后是否可还原的算法,具体的算法理论我借用的评论:
此类游戏能否还原关键是看它打乱后的逆序次数之和是否为偶数
假设你打乱后的数组中的每一个小图块为obj0,obj1,obj2,…它们打乱之前的序号分别为obj0.num,obj1.num…
接下来循环数组,如果前面元素的序号比此元素后某个元素的序号大,如obj0.num & obj1.num或者obj2.num & obj4.num就表示一个逆序
当全部的逆序之和为奇数时表示不可还原,重新打乱即可,打乱后重新检测,直到逆序之和为偶数为止
举个例子,如果有一个数组为[3, 4, 2, 1],那么里面3 2, 3 1, 2 4, 4 1, 2 1是逆序的,所以逆序数是5。
上面我给出的getRandomBlockList里的代码就是在实现打乱算法和检测是否可还原算法。
还有一种打乱方式,大家可以尝试尝试:和复原拼图一样,将空白块一步一步地与周围的拼图随机交换顺序。这个打乱算法较上一种而言,不会出现无法复原的现象,而且可以根据打乱的步数设定游戏难度。
在完成打乱拼图块后,如期而至的是显示拼图块:
function showBlock() {
for (var i = 0, l = blockList. i & i++) {
var b = blockList[i];
var y = (i / 3) &&& 0, x = i % 3;
b.setLocation(x, y);
gameLayer.addChild(b);
显示了拼图块后,我们要做的就是添加操作拼图块的功能。于是需要拓展Block类,为其添加事件监听器onClick方法:
Block.prototype.onClick = function (e) {
var self = e.currentT
if (isGameOver) {
var checkList = new Array();
if (self.locationX & 0) {
checkList.push(Block.getBlock(self.locationX - 1, self.locationY));
if (self.locationX & 2) {
checkList.push(Block.getBlock(self.locationX + 1, self.locationY));
if (self.locationY & 0) {
checkList.push(Block.getBlock(self.locationX, self.locationY - 1));
if (self.locationY & 2) {
checkList.push(Block.getBlock(self.locationX, self.locationY + 1));
for (var i = 0, l = checkList. i & i++) {
var checkO = checkList[i];
if (checkO.index == 8) {
updateStepsTxt();
Block.exchangePosition(self, checkO);
首先,我们在这里看到了isGameOver全局变量的作用,即在游戏结束后,阻断点击拼图块后的操作。
在点击了拼图块后,我们先获取该拼图块周围的拼图块,并将它们装入checkList,再遍历checkList,当判断到周围有空白拼图块后,即周围有index属性等于8的拼图块后,先更新操作步数,然后将这两个拼图块交换位置。具体交换拼图块位置的方法详见如下代码:
Block.exchangePosition = function (b1, b2) {
var b1x = b1.locationX, b1y = b1.locationY,
b2x = b2.locationX, b2y = b2.locationY,
b1Index = b1y * 3 + b1x,
b2Index = b2y * 3 + b2x;
blockList.splice(b1Index, 1, b2);
blockList.splice(b2Index, 1, b1);
b1.setLocation(b2x, b2y);
b2.setLocation(b1x, b1y);
Block.isGameOver();
还有就是Block.getBlock静态方法,用于获取给定的“数组位置”下的拼图块:
Block.getBlock = function (x, y) {
return blockList[y * 3 + x];
在Block.exchangePosition中,我们通过Block.isGameOver判断玩家是否已将拼图复原:
Block.isGameOver = function () {
var reductionAmount = 0, l = blockList.
for (var i = 0; i & i++) {
var b = blockList[i];
if (b.index == i) {
reductionAmount++;
if (reductionAmount == l) {
gameOver();
到这里,我们就实现了打乱和操作拼图块部分。
90~120min
最后30min用于细枝末节上的处理,如显示拼图缩略图、显示&更新时间和步数,以及添加游戏结束画面,这些就交给如下冗长而简单的代码来完成吧:
function showThumbnail() {
var thumbnail = new LBitmap(imgBmpd);
thumbnail.scaleX = 130 / imgBmpd.
thumbnail.scaleY = 130 / imgBmpd.
thumbnail.x = (LGlobal.width - 100) /2;
thumbnail.y = 410;
overLayer.addChild(thumbnail);
function addTimeTxt () {
timeTxt = new LTextField();
timeTxt.stroke = true;
timeTxt.lineWidth = 3;
timeTxt.lineColor = "#54D9EF";
timeTxt.color = "#FFFFFF";
timeTxt.size = 18;
timeTxt.x = 20;
timeTxt.y = 450;
overLayer.addChild(timeTxt);
updateTimeTxt();
function updateTimeTxt () {
timeTxt.text = "时间:" + getTimeTxt(time);
function getTimeTxt () {
var d = new Date(time);
return d.getMinutes() + " : " + d.getSeconds();
function addStepsTxt () {
stepsTxt = new LTextField();
stepsTxt.stroke = true;
stepsTxt.lineWidth = 3;
stepsTxt.lineColor = "#54D9EF";
stepsTxt.color = "#FFFFFF";
stepsTxt.size = 18;
stepsTxt.y = 450;
overLayer.addChild(stepsTxt);
updateStepsTxt();
function updateStepsTxt () {
stepsTxt.text = "步数:" +
stepsTxt.x = LGlobal.width - stepsTxt.getWidth() - 20;
function onFrame () {
if (isGameOver) {
var currentTime = (new Date()).getTime();
time = currentTime - startT
updateTimeTxt();
function gameOver () {
isGameOver = true;
var resultLayer = new LSprite();
resultLayer.filters = [new LDropShadowFilter()];
resultLayer.graphics.drawRoundRect(3, "#BBBBBB", [0, 0, 350, 350, 5], true,"#DDDDDD");
resultLayer.x = (LGlobal.width - resultLayer.getWidth()) / 2;
resultLayer.y = LGlobal.height / 2;
resultLayer.alpha = 0;
overLayer.addChild(resultLayer);
var title = new LTextField();
title.text = "游戏通关"
title.weight = "bold";
title.stroke = true;
title.lineWidth = 3;
title.lineColor = "#555555";
title.size = 30;
title.color = "#FFFFFF";
title.x = (resultLayer.getWidth() - title.getWidth()) / 2;
title.y = 30;
resultLayer.addChild(title);
var usedTimeTxt = new LTextField();
usedTimeTxt.text = "游戏用时:" + getTimeTxt(time);
usedTimeTxt.size = 20;
usedTimeTxt.stroke = true;
usedTimeTxt.lineWidth = 2;
usedTimeTxt.lineColor = "#555555";
usedTimeTxt.color = "#FFFFFF";
usedTimeTxt.x = (resultLayer.getWidth() - usedTimeTxt.getWidth()) / 2;
usedTimeTxt.y = 130;
resultLayer.addChild(usedTimeTxt);
var usedStepsTxt = new LTextField();
usedStepsTxt.text = "所用步数:" +
usedStepsTxt.size = 20;
usedStepsTxt.stroke = true;
usedStepsTxt.lineWidth = 2;
usedStepsTxt.lineColor = "#555555";
usedStepsTxt.color = "#FFFFFF";
usedStepsTxt.x = usedTimeTxt.x;
usedStepsTxt.y = 180;
resultLayer.addChild(usedStepsTxt);
var hintTxt = new LTextField();
hintTxt.text = "- 点击屏幕重新开始 -";
hintTxt.size = 23;
hintTxt.stroke = true;
hintTxt.lineWidth = 2;
hintTxt.lineColor = "#888888";
hintTxt.color = "#FFFFFF";
hintTxt.x = (resultLayer.getWidth() - hintTxt.getWidth()) / 2;
hintTxt.y = 260;
resultLayer.addChild(hintTxt);
LTweenLite.to(resultLayer, 0.5, {
alpha : 0.7,
y : (LGlobal.height - resultLayer.getHeight()) / 2,
onComplete : function () {
stageLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {
gameLayer.removeAllChild();
overLayer.removeAllChild();
stageLayer.removeAllEventListener();
startGame();
Ok,2h下来,整个游戏就搞定咯~不得不表扬一下lufylegend这个游戏引擎,实在是可以大幅提升开发效率。
源代码下载
最后奉上源代码:
致谢与反思
这篇博文在最初写成的时候,我没有对逆序算法进行深入研究,再加上我的测试不仔细,我没有发现算法的错误之处。因此,在博文发布后,不少读者发现游戏无解现象并将此问题反馈给了我,经过网友热心帮助,我才找到了问题所在,并更正了算法。在此对这些热心的网友表示真心的感谢,也为我学习不深入,以及误导了不少读者而感到十分内疚自责。
如果大家对本文有任何意见或不解,欢迎留言~
欢迎大家继续关注我的博客
转载请注明出处:Yorhom’s Game Box
本文已收录于以下专栏:
相关文章推荐
HTML5技术之图像处理:一个滑动的拼图游戏
HTML5有许多功能特性可以把多媒体整合到网页中。使用canvas元素可以在这个空白的画板上填充线条,载入图片文件,甚至动画效果。
在这篇文章中,我将做一...
现在越来越多的人开始尝试使用HTML5开发,HTML5的引擎也逐渐增多,开发者到底应该选择一款什么样的引擎呢?这一次我来对比一下几个我个人认为还不错的引擎的效率。
本次参加对比的引擎:
1. crea...
愤怒的小鸟是一款人气火爆的益智游戏,现在我试着用lufylegend库件和Box2dWeb物理引擎来看看在html5中如何制作此类经典的物理游戏。准备工作一首先,你需要下载lufylegend库件1....
最近开始研究Box2dweb,Box2dweb是一款物理引擎,主要是对物理刚体和关节连接进行了封装,box2dweb很强大当然也有些复杂,不过幸好lufylegend.js做了这方面的封装,在制作时如...
第七篇,自定义按钮
这次弄个简单点的,自定义按钮。
其实,有了前面所定义的LSprite,LBitmap等类,定义按钮就很方便了。
下面是添加按钮的代码,
function gameI...
上一篇,我已经模仿as,加入了LBitmap和LBitmapData类,并且用它们实现了静态图片的显示。
这次用Sprite来动态显示图片。
依然遵循上一篇对显示对象的处理的思路,添加LSprit...
第八篇,图片处理+粒子效果用仿ActionScript的语法来编写html5系列开发到现在,应该可以做出一些东西了,下面先来研究下图片的各种效果预览各种效果看下图效果和代码看这里,看不到效果的请下载支...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)6款好玩的手机拼图游戏推荐
6款好玩的手机拼图游戏推荐
  最近,岳云鹏送给雷佳音女儿一副拼图,但是。这一副拼图长达5米,让雷佳音感觉女儿一辈子都拼不完。不过,对于喜欢玩拼图游戏的网友来说:拼图游戏非常有趣。今天的软件推荐里,小编就准备给喜欢拼图游戏的网友推荐6款好玩的手机拼图游戏,希望大家喜欢!
猫和老鼠拼图
  6款好玩的手机拼图游戏推荐
  一、猫和老鼠拼图
  《猫和老鼠拼图》是一款休闲的拼图小游戏。汤姆又来抓杰瑞了,杰瑞是否会被抓到呢?此游戏精选多张猫和老鼠动画图片,用手指移动各种混乱的拼图碎片,让他们合并成一个完整的图案。
  游戏特色
  玩法简单,操作易上手,
  精美的游戏画面
  不同难度的玩法模式,为你的游戏增添趣味和挑战
  下载地址:
  二、幼儿拼图游戏
幼儿拼图游戏
  狐涂涂系列手机app是面向全球2~7岁宝宝的育儿早教国际知名系列产品,是全世界上亿家长的选择。 本系列囊括涂色画画,涂鸦绘画,折纸动手,休闲益智,认物识字,启蒙教育等各方面的儿童益智应用,宝宝喜欢的应有尽有。 儿童拼图游戏应用适合各个年龄段宝宝玩,是不错的儿童学习好助手!关爱宝宝的爸爸妈妈们,可以寓教于乐通过玩游戏方式,让宝宝轻松学习各种知识,开发宝宝的智力!
  1、拼图片数从4块到36块递进,适合2岁至7岁的宝宝开发智力;
  2、2-3岁幼儿适合4片拼图,4到5岁宝宝适合9片或16片拼图,6-7岁儿童适合25或36片拼图;
  3、无需联网即可使用;
  4、拍照自动生成拼图,宝宝喜欢的小动物、玩具、人物、数字、游戏、动画、景色,一键生成拼图,带给宝宝想要的拼图画面!
  5、寓教于乐,通过拼图学习各种知识;
  6、目标导向,认识各种小动物和交通工具;
  7、注重细节更多互动,让宝宝乐此不疲;
  8、友好的语音伴读,助宝宝轻松学习。
  下载地址:
  三、水果滑块拼图
水果滑块拼图
  采用精美水果图片的经典15块滑块拼图游戏。 点击空位四周的图块就可以将其移动到空位上,直至把整幅图片复原。
  下载地址:
大家都在下
还没关注下载之家微信 的亲们赶紧扫一扫左侧的二维码吧!或搜账号:
还没关注下载之家微信 的亲们赶紧扫一扫左侧的二维码吧!或搜账号:
微信公众号
Copyright &
下载之家().All Rights Reserved
备案号:闽ICP备号-8
京公网安备 19号您的网站尚未进行备案}

我要回帖

更多关于 熊出没拼图小游戏大全 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信