推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例;
推箱子游戏的在线DEMO : 打开
如下是效果图:
这个拖箱子游戏做了移动端的适配, 我使用了zepto的touch模块, 通过手指滑动屏幕就可以控制乌龟走不同的方向;
因为推箱子这个游戏比较简单, 直接用了过程式的方式写代码, 模块也就是两个View 和 Model, 剩下就是用户的事件Controller, 用户每一次按下键盘的方向键都会改变数据模型的数据,然后重新生成游戏的静态html, 然后用innerHTML方式插入到界面, 自动生成DOM节点;
游戏的关卡模型就是数据, 我把每一关的数据分为三块:
-
地图数据,二维数组(地图数据包括板砖, 箱子要去的目标位置, 空白的位置)
-
箱子数据,一维数组(箱子的初始位置)
-
小乌龟的数据,json对象
每一个关卡都有对应的游戏关卡数据, 模拟的数据如下:
level: [ { //0是空的地图
//1是板砖
//3是目标点
state:[ [0,0,1,1,1,0,0,0,0], [0,1,1,3,3,1,0,0,0], [0,1,0,0,0,0,1,0,0], [0,1,0,0,0,0,1,0,0], [0,1,1,1,1,1,1,0,0] ], person: {x : 2, y : 2}, box: [{x:3, y : 2},{x:4,y:2}] }, //第二关
{ //0是空的地图
//1是板砖
//3是目标点
state:[ [0,1,1,1,1,1,0,0], [0,1,0,0,1,1,1,0], [0,1,0,0,0,0,1,0], [1,1,1,0,1,0,1,1], [1,3,1,0,1,0,0,1], [1,3,0,0,0,1,0,1], [1,3,0,0,0,0,0,1], [1,1,1,1,1,1,1,1] ], person: {x : 2, y : 2}, box: [{x:3, y : 2}, {x:2,y:5} ,{x:5, y:6}] /* box : [ {x:3, y : 1}, {x:4, y : 1}, {x:4, y : 2}, {x:5, y : 5} ] */ }, //第三关
{ //0是空的地图
//1是板砖
//3是目标点
state:[ [0,0,0,1,1,1,1,1,1,0], [0,1,1,1,0,0,0,0,1,0], [1,1,3,0,0,1,1,0,1,1], [1,3,3,0,0,0,0,0,0,1], [1,3,3,0,0,0,0,0,1,1], [1,1,1,1,1,1,0,0,1,0], [0,0,0,0,0,1,1,1,1,0] ], person: {x : 8, y : 3}, box: [{x:4, y : 2}, {x:3,y:3} ,{x:4, y:4},{x:5, y:3},{x:6, y:4}] }, //第四关
{ //0是空的地图
//1是板砖
//3是目标点
state:[ [0,1,1,1,1,1,1,1,0,0], [0,1,0,0,0,0,0,1,1,1], [1,1,0,1,1,1,0,0,0,1], [1,0,0,0,0,0,0,0,0,1], [1,0,3,3,1,0,0,0,1,1], [1,1,3,3,1,0,0,0,1,0], [0,1,1,1,1,1,1,1,1,0] ], person: {x : 2, y : 3}, box: [{x:2, y : 2}, {x:4,y:3} ,{x:6, y:4},{x:7, y:3},{x:6, y:4}] }, //第五关
{ //0是空的地图
//1是板砖
//3是目标点
state:[ [0,0,1,1,1,1,0,0], [0,0,1,3,3,1,0,0], [0,1,1,0,3,1,1,0], [0,1,0,0,0,3,1,0], [1,1,0,0,0,0,1,1], [1,0,0,1,0,0,0,1], [1,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1] ], person: {x : 4, y : 6}, box: [{x:4, y : 3}, {x:3,y:4} ,{x:4, y:5}, {x:5,y:5}] /* box : [ {x:3, y : 1}, {x:4, y : 1}, {x:4, y : 2}, {x:5, y : 5} ] */ }, //第六关
{ //0是空的地图
//1是板砖
//3是目标点
state:[ [0,0,0,0,1,1,1,1,1,1,1,0], [0,0,0,0,1,0,0,1,0,0,1,0], [0,0,0,0,1,0,0,0,0,0,1,0], [1,1,1,1,1,0,0,1,0,0,1,0], [3,3,3,1,1,0,0,0,0,0,1,1], [3,0,0,1,0,0,0,0,1,0,0,1], [3,0,0,0,0,0,0,0,0,0,0,1], [3,0,0,1,0,0,0,0,1,0,0,1], [3,3,3,1,1,1,0,1,0,0,1,1], [1,1,1,1,1,0,0,0,0,0,1,0], [0,0,0,0,1,0,0,1,0,0,1,0], [0,0,0,0,1,1,1,1,1,1,1,0] ], person: {x : 5, y : 10}, box: [ {x:5, y:6}, {x:6, y:3}, {x:6, y:5}, {x:6, y:7}, {x:6, y:9}, {x:7, y:2}, {x:8, y:2}, {x:9, y:6} ] } ]
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
有一个很重要的东西就是推箱子游戏的主要逻辑:因为小乌龟走的地方只能是空白的区域,而且乌龟前面有墙就不能走, 或者乌龟前面是箱子,就再判断箱子前面是否有墙, 如果没有墙乌龟和箱子都可以走往前走一步,如果有墙就不能走。每一次小乌龟走了都改变地图数据,然后重新生成界面,如此循环, 每一小乌龟走完都要检测地图数据中的箱子数据是否全对上了,对上了就给用户提示, 并进入下一关;
游戏的模板引擎用了handlebarsJS, 可以去官网看API 。 这个是写过的一篇博客,Handlebars的使用方法文档整理(Handlebars.js):打开, 模板内容:
<script id="tpl" type="text/x-handlebars-template">
{{#initY}}{{/initY}}
{{#each this}}
{{#each this}}
<div class="{{#getClass this}}{{/getClass}}" data-x="{{@index}}" data-y="{{#getY}}{{/getY}}" style="left:{{#calc @index}}{{/calc}};top:{{#calc 1111}}{{/calc}}">
<!--{{@index}}
{{#getY}}{{/getY}}
-->
</div>
{{/each}}
{{#addY}}{{/addY}}
{{/each}}
</script>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
为Handlebars定了几个helper,包括initY, getClass, getY,calc 、、、、,模板引擎主要是辅助的作用, 这边用Handlebars不是很明智啊, 代码的可读性变差了点, 这里面也利用了闭包保存变量, 避免全局变量的污染:
(function() {
var y = 0;
Handlebars.registerHelper("initY", function() {
y = 0;
});
Handlebars.registerHelper("addY", function() {
y++;
});
Handlebars.registerHelper("getY", function() {
return y;
});
Handlebars.registerHelper("calc", function(arg) {
//console.log(arg)
if(arg!==1111) {
return 50*arg + "px";
}else{
return 50*y + "px";
};
});
Handlebars.registerHelper("getClass", function(arg) {
switch( arg ) {
case 0 :
return "bg"
case 1 :
return "block"
case 2 :
return "box"
case 3 :
return "target"
};
});
window.util = {
isMobile : function() {
return navigator.userAgent.toLowerCase().indexOf("mobile") !== -1 || navigator.userAgent.toLowerCase().indexOf("android") !== -1 || navigator.userAgent.toLowerCase().indexOf("pad") !== -1;
}
}
})();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
因为要兼容移动端, 我们要检查是否是手机或者平板,如果是的话,我就添加对应的DOM元素(方向键DOM元素),然后绑定对应的事件, zeptoJS提供了touch模块,我们要去官网去找,然后额外引用进来,打开地址 , 然后就可以使用swipeLeft,swipeUp,swipeDown, swipeRight 这几个事件:
if( window.util.isMobile() ) {
$(window).on("swipeLeft",function() {
_this.step("left");
}).on("swipeRight",function() {
_this.step("right");
}).on("swipeUp",function() {
_this.step("top");
}).on("swipeDown",function() {
_this.step("bottom");
});
mobileDOM();
$(".arrow-up").tap(function() {
_this.step("top");
});
$(".arrow-down").tap(function() {
_this.step("bottom");
});
$(".arrow-left").tap(function() {
_this.step("left");
});
$(".arrow-right").tap(function() {
_this.step("right");
});
}else{
$(window).on("keydown", function(ev) {
var state = "";
switch( ev.keyCode ) {
case 37 :
state = "left";
break;
case 39 :
state = "right";
break;
case 38 :
state = "top";
break;
case 40 :
state = "bottom";
break;
};
_this.step(state)
});
};
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
因为要保存用户的当前关卡, 也额外引用了jQuery-cookies插件, 每一次闯关成功,我们就保存一次当前的闯关记录, 当用户不想玩或者别的原因关闭了浏览器, 过几天想重新玩的时候可以继续玩;
if( G.now+1 > G.level.length-1 ) {
alert("闯关成功");
return ;
}else{
//如果可用的等级大于当前的等级,就把level设置进去;
if( G.now+1 > parseInt( $.cookie('level') || 0 )) {
$.cookie('level' , G.now+1 , { expires: 7 });
};
start( G.now+1 );
return ;
};
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
所有的代码在这里:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="http://sqqihao.github.io/games/rusBlock/libs/Tiny-Alert/css/zepto.alert.css"/>
<script src="libs/jquery-1.9.1.min.js"></script>
<script src="libs/handlebars.js"></script>
<script src="libs/jquery-cookie.js"></script>
<script src="http://sqqihao.github.io/games/rusBlock/libs/Tiny-Alert/js/zepto.alert.js"></script>
<script id="tpl" type="text/x-handlebars-template">
{{#initY}}{{/initY}}
{{#each this}}
{{#each this}}
<div class="{{#getClass this}}{{/getClass}}" data-x="{{@index}}" data-y="{{#getY}}{{/getY}}" style="left:{{#calc @index}}{{/calc}};top:{{#calc 1111}}{{/calc}}">
<!--{{@index}}
{{#getY}}{{/getY}}
-->
</div>
{{/each}}
{{#addY}}{{/addY}}
{{/each}}
</script>
<script>
(function() {
var y = 0;
Handlebars.registerHelper("initY", function() {
y = 0;
});
Handlebars.registerHelper("addY", function() {
y++;
});
Handlebars.registerHelper("getY", function() {
return y;
});
Handlebars.registerHelper("calc", function(arg) {
//console.log(arg)
if(arg!==1111) {
return 50*arg + "px";
}else{
return 50*y + "px";
};
});
Handlebars.registerHelper("getClass", function(arg) {
switch( arg ) {
case 0 :
return "bg"
case 1 :
return "block"
case 2 :
return "box"
case 3 :
return "target"
};
});
window.util = {
isMobile : function() {
return navigator.userAgent.toLowerCase().indexOf("mobile") !== -1 || navigator.userAgent.toLowerCase().indexOf("android") !== -1 || navigator.userAgent.toLowerCase().indexOf("pad") !== -1;
}
}
})();
</script>
</head>
<style>
#game{
display: none;
}
#house{
position: relative;
}
.bg{
position: absolute;
width:50px;
height:50px;
box-sizing: border-box;
}
.block{
position: absolute;
background-image: url(imgs/wall.png);
width:50px;
height:50px;
box-sizing: border-box;
}
.box{
position: absolute;
background: #fbd500;
width:50px;
height:50px;
background-image: url(imgs/box.png);
}
.target{
position: absolute;
background: url(imgs/target.jpg);
background-size: 50px 50px;;
width:50px;
height:50px;
box-sizing: border-box;
}
#person{
background-image: url(imgs/person.png);
width:50px;
height:50px;
position: absolute;
}
#person.up{
background-position: 0 0;
}
#person.right{
background-position:-50px 0 ;
}
#person.bottom{
background-position:-100px 0 ;
}
#person.left{
background-position:-150px 0 ;
}
/*移动端的DOM*/
.operate-bar{
font-size:30px;
}
.height20percent{
height:30%;
}
.height30percent{
height:30%;
}
.height40percent{
height:40%;
}
.height100percent{
height:100%;
}
.font30{
font-size:30px;
color:#34495e;
}
</style>
<body>
<div id="select">
<div class="container">
<div class="row">
<p class="text-info">
已经解锁的关卡:
<p id="level">
</p>
</p>
<button id="start" class="btn btn-default">
开始游戏
</button>
</div>
</div>
</div>
<div id="game" class="container">
<div class="row">
<button onclick="location.reload()" class="btn btn-info" >
返回选择关卡重新
</button>
<div id="house">
</div>
</div>
</div>
<script>
G = {
level: [
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,0,1,1,1,0,0,0,0],
[0,1,1,3,3,1,0,0,0],
[0,1,0,0,0,0,1,0,0],
[0,1,0,0,0,0,1,0,0],
[0,1,1,1,1,1,1,0,0]
],
person: {x : 2, y : 2},
box: [{x:3, y : 2},{x:4,y:2}]
},
//第二关
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,1,1,1,1,1,0,0],
[0,1,0,0,1,1,1,0],
[0,1,0,0,0,0,1,0],
[1,1,1,0,1,0,1,1],
[1,3,1,0,1,0,0,1],
[1,3,0,0,0,1,0,1],
[1,3,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1]
],
person: {x : 2, y : 2},
box: [{x:3, y : 2}, {x:2,y:5} ,{x:5, y:6}]
/*
box : [
{x:3, y : 1},
{x:4, y : 1},
{x:4, y : 2},
{x:5, y : 5}
]
*/
},
//第三关
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,0,0,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,1,0],
[1,1,3,0,0,1,1,0,1,1],
[1,3,3,0,0,0,0,0,0,1],
[1,3,3,0,0,0,0,0,1,1],
[1,1,1,1,1,1,0,0,1,0],
[0,0,0,0,0,1,1,1,1,0]
],
person: {x : 8, y : 3},
box: [{x:4, y : 2}, {x:3,y:3} ,{x:4, y:4},{x:5, y:3},{x:6, y:4}]
},
//第四关
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,1,1,1,1,1,1,1,0,0],
[0,1,0,0,0,0,0,1,1,1],
[1,1,0,1,1,1,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,3,3,1,0,0,0,1,1],
[1,1,3,3,1,0,0,0,1,0],
[0,1,1,1,1,1,1,1,1,0]
],
person: {x : 2, y : 3},
box: [{x:2, y : 2}, {x:4,y:3} ,{x:6, y:4},{x:7, y:3},{x:6, y:4}]
},
//第五关
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,0,1,1,1,1,0,0],
[0,0,1,3,3,1,0,0],
[0,1,1,0,3,1,1,0],
[0,1,0,0,0,3,1,0],
[1,1,0,0,0,0,1,1],
[1,0,0,1,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1]
],
person: {x : 4, y : 6},
box: [{x:4, y : 3}, {x:3,y:4} ,{x:4, y:5}, {x:5,y:5}]
/*
box : [
{x:3, y : 1},
{x:4, y : 1},
{x:4, y : 2},
{x:5, y : 5}
]
*/
},
//第六关
{
//0是空的地图
//1是板砖
//3是目标点
state:[
[0,0,0,0,1,1,1,1,1,1,1,0],
[0,0,0,0,1,0,0,1,0,0,1,0],
[0,0,0,0,1,0,0,0,0,0,1,0],
[1,1,1,1,1,0,0,1,0,0,1,0],
[3,3,3,1,1,0,0,0,0,0,1,1],
[3,0,0,1,0,0,0,0,1,0,0,1],
[3,0,0,0,0,0,0,0,0,0,0,1],
[3,0,0,1,0,0,0,0,1,0,0,1],
[3,3,3,1,1,1,0,1,0,0,1,1],
[1,1,1,1,1,0,0,0,0,0,1,0],
[0,0,0,0,1,0,0,1,0,0,1,0],
[0,0,0,0,1,1,1,1,1,1,1,0]
],
person: {x : 5, y : 10},
box: [
{x:5, y:6},
{x:6, y:3},
{x:6, y:5},
{x:6, y:7},
{x:6, y:9},
{x:7, y:2},
{x:8, y:2},
{x:9, y:6}
]
}
],
//map data
mapData : (function() {
var data = {};
return {
get: function () {
return data;
},
set: function (arg) {
data = arg;
},
//穿进来的数据在界面中是否存在;
collision: function (x, y) {
if( data.state[y][x] === 1)return true;
return false;
},
collisionBox : function(x,y) {
for(var i= 0, len= data.box.length; i< len; i++) {
if( data.box[i].x === x&& data.box[i].y === y)return data.box[i];
};
return false;
}
}
})(),
view : {
initMap : function(map) {
document.getElementById("house").innerHTML = Handlebars.compile( document.getElementById("tpl").innerHTML )( map );
},
initPerson : function(personXY) {
var per = document.createElement("div");
per.id = "person";
G.per = per;
document.getElementById("house").appendChild(per);
per.style.left = 50* personXY.x+"px";
per.style.top = 50* personXY.y+"px";
},
initBox : function(boxs) {
for(var i=0;i<boxs.length; i++) {
var box = document.createElement("div");
box.className = "box";
G.box = box;
document.getElementById("house").appendChild(box);
box.style.left = boxs[i].x*50 + "px";
box.style.top = boxs[i].y*50 + "px";
};
},
deleteBox : function() {
var eBoxs = document.getElementsByClassName("box");
var len = eBoxs.length;
while( len-- ) {
eBoxs[len].parentNode.removeChild( eBoxs[len] );
};
}
},
/*
* 0;向上
* 1:向右
* 2:向下
* 3:向左
* */
direction : 0,
step : function(xy) {
//这里面要做很多判断
/*包括:
用户当前的方向和以前是否一样,如果不一样要先转头;
如果一样的话,判断前面是否有石头, 是否有箱子;
如果前面有墙壁或者
前面有箱子,而且箱子前面有墙壁就return
把人物往前移动
如果人物的位置上有一个箱子,把箱子也移动一下;
*/
var mapData = this.mapData.get();
//对参数进行处理;
if ( typeof xy === "string" ) {
var x = 0, y = 0, xx = 0, yy = 0;
switch( xy ) {
case "left" :
if(this.direction==0){
x = -1;
xx = -2;
}else{
x = 0;
};
this.direction = 0;
break;
case "top" :
if(this.direction===1){
y = -1;
yy = -2
}else{
y = 0;
};
this.direction = 1;
break;
case "right" :
if(this.direction === 2) {
x = 1;
xx = 2;
}else{
x = 0;
};
this.direction = 2;
break;
case "bottom" :
if(this.direction ===3 ) {
y = 1;
yy = 2;
}else{
y = 0;
};
this.direction = 3;
};
//如果是墙壁就不能走
if( this.mapData.collision(mapData.person.x + x, mapData.person.y+y) ) {
return;
};
//如果碰到的是箱子, 而且箱子前面是墙壁, 就return
if( this.mapData.collisionBox(mapData.person.x+x, mapData.person.y+y) && this.mapData.collision(mapData.person.x+xx, mapData.person.y+yy)) {
return;
};
if( this.mapData.collisionBox(mapData.person.x+x, mapData.person.y+y) && this.mapData.collisionBox(mapData.person.x+xx, mapData.person.y+yy)) {
return
}
//mapData.x+xx, mapData.y+yy
mapData.person.x = mapData.person.x + x;
mapData.person.y = mapData.person.y + y;
this.per.style.left = 50* mapData.person.x+"px";
this.per.style.top = 50* mapData.person.y+"px";
this.per.className = {
0:"up",
1:"right",
2:"bottom",
3:"left"
}[this.direction];
var theBox = {};
if(theBox = this.mapData.collisionBox(mapData.person.x, mapData.person.y)) {
theBox.x = mapData.person.x+x;
theBox.y = mapData.person.y+y;
this.view.deleteBox();
this.view.initBox(mapData.box);
this.testSuccess();
};
//如果碰到了箱子,而且箱子前面不能走就return, 否则就走箱子和人物;
};
},
/*
* return Boolean;
* */
//遍历所有的box,如果在box中的所有x,y在地图中对应的值为3,全部通过就返回true
testSuccess : function() {
var mapData = this.mapData.get();
for(var i=0; i<mapData.box.length; i++) {
if(mapData.state[mapData.box[i].y][mapData.box[i].x] != 3) {
return false;
};
};
$.dialog({
content : '游戏成功, 进入下一关!',
title : 'alert',
ok : function() {
if( G.now+1 > G.level.length-1 ) {
alert("闯关成功");
return ;
}else{
//如果可用的等级大于当前的等级,就把level设置进去;
if( G.now+1 > parseInt( $.cookie('level') || 0 )) {
$.cookie('level' , G.now+1 , { expires: 7 });
};
start( G.now+1 );
return ;
};
},
cancel : function(){
location.reload();
},
lock : true
});
},
//这里面需要处理 map, 人物数据, box数据
init : function() {
//更新地图;
//this.level[0].state
this.view.initMap( this.mapData.get().state );
this.view.initPerson( this.mapData.get().person );
this.view.initBox( this.mapData.get().box );
//this.person = this.factory.Person(0,0);
//this.box = this.factory.Box([{x:0,y:1},{x:1,y:1},{x:0,y:2},{x:1,y:2}]);
if( this.hasBind ) {
return
};
this.hasBind = true;
this.controller();
},
controller : function() {
function mobileDOM() {
var mobileDOMString = '\
<div class="navbar-fixed-bottom height20percent operate-bar" >\
<div class="container height100percent">\
<div class="row text-center height100percent">\
<div class="height40percent arrow-up">\
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>\
</div>\
<div class="height30percent">\
<div class="col-xs-6 arrow-left">\
<span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>\
</div>\
<div class="col-xs-6 arrow-right">\
<span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span>\
</div>\
</div>\
<div class="height30percent arrow-down">\
<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>\
</div>\
</div>\
</div>\
</div>\
';
+function addDOM() {
$("#game").append( mobileDOMString );
}();
};
var _this = this;
if( window.util.isMobile() ) {
$(window).on("swipeLeft",function() {
_this.step("left");
}).on("swipeRight",function() {
_this.step("right");
}).on("swipeUp",function() {
_this.step("top");
}).on("swipeDown",function() {
_this.step("bottom");
});
mobileDOM();
$(".arrow-up").tap(function() {
_this.step("top");
});
$(".arrow-down").tap(function() {
_this.step("bottom");
});
$(".arrow-left").tap(function() {
_this.step("left");
});
$(".arrow-right").tap(function() {
_this.step("right");
});
}else{
$(window).on("keydown", function(ev) {
var state = "";
switch( ev.keyCode ) {
case 37 :
state = "left";
break;
case 39 :
state = "right";
break;
case 38 :
state = "top";
break;
case 40 :
state = "bottom";
break;
};
_this.step(state)
});
};
}
};
function start( level ) {
G.now = level;
G.mapData.set(G.level[level] );
G.init();
$("#game").show();
$("#select").hide();
};
function init() {
var cookieLevel = $.cookie('level') || 0;
start( cookieLevel );
};
$("#start").click(function() {
init();
});
String.prototype.repeat = String.prototype.repeat || function(num) {
return (new Array(num+1)).join( this.toString() );
};
window.onload = function() {
var cookieLevel = $.cookie('level') || 0;
$("#level").html( function() {
var index = 0;
return "<a href='###' class='btn btn-info' onclick='start({{i}})'>关卡</a> ".repeat((parseInt($.cookie('level')) || 0)+1).replace(/{{i}}/gi, function() {
return index++;
})
});
}
</script>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.
- 472.
- 473.
- 474.
- 475.
- 476.
- 477.
- 478.
- 479.
- 480.
- 481.
- 482.
- 483.
- 484.
- 485.
- 486.
- 487.
- 488.
- 489.
- 490.
- 491.
- 492.
- 493.
- 494.
- 495.
- 496.
- 497.
- 498.
- 499.
- 500.
- 501.
- 502.
- 503.
- 504.
- 505.
- 506.
- 507.
- 508.
- 509.
- 510.
- 511.
- 512.
- 513.
- 514.
- 515.
- 516.
- 517.
- 518.
- 519.
- 520.
- 521.
- 522.
- 523.
- 524.
- 525.
- 526.
- 527.
- 528.
- 529.
- 530.
- 531.
- 532.
- 533.
- 534.
- 535.
- 536.
- 537.
- 538.
- 539.
- 540.
- 541.
- 542.
- 543.
- 544.
- 545.
- 546.
- 547.
- 548.
- 549.
- 550.
- 551.
- 552.
- 553.
- 554.
- 555.
- 556.
- 557.
- 558.
- 559.
- 560.
- 561.
- 562.
- 563.
- 564.
- 565.
- 566.
- 567.
- 568.
- 569.
- 570.
- 571.
- 572.
- 573.
- 574.
- 575.
- 576.
- 577.
- 578.
- 579.
- 580.
- 581.
- 582.
- 583.
- 584.
- 585.
- 586.
- 587.
- 588.
- 589.
- 590.
- 591.
- 592.
- 593.
- 594.
- 595.
- 596.
- 597.
- 598.
- 599.
游戏一共有6关, 每一关成功通过即可解锁下一关, 地图的话其实可以多找些的,哈哈;
推箱子游戏的在线DEMO : 打开
参考:
别人写的推箱子:打开;
妙味的杜鹏老师的推箱子视频:打开