javascript 推箱子游戏介绍及问题
最近没什么事情,我的一个亲戚在学校学习PHP,课程中老师让他们编写一个javascript版本的推箱子小游戏,他没什么头绪,就来问我,我当时很闲,就随口答应他包在我身上。结果真正写的时候还是花了点时间,最后写出来的成品也有各种问题,在这里希望大家能一起探讨学习!(大神们请屏蔽鄙人的粗糙简单)
首先看一下最终的效果图,,不好意思,只是做了个简化版本,图中黄色的块是我们控制来推动的盒子,粉红色的块是被推的盒子,红色的块表示最终要被推到的位置,黑色的快表示墙,盒子不能穿过墙,游戏的方向控制使用wasd四个按键,分别表示上下左右,玩起来没有任何意思,这里简述一下盒子推动的思路:
首先,推箱子最少需要两个箱子,一个箱子a用键盘来控制移动,另外一个箱子则是被推动的箱子b,用键盘来控制箱子a移动很简单,使用键盘事件onkeydown,用keyCode来选择你要移动箱子所使用的键,一般常用 wasd这四个键,被推的箱子b如果要实现被推着走,需要两步来完成,第一步是判断两个箱子相碰撞,因为只有当两个箱子配到一起的时候才可能发生推着走的事情,当确定两个箱子碰到以后,我们再次按下前后左右键,我们需要把箱子a移动的距离与之对应的加到箱子b的身上,但这里要判断箱子a移动的方向,如果箱子a是从左边往右边移动20px,那么箱子b也应该向右边移动20px,如果是从箱子a是从上边往下边移动20px,那么箱子b也应该往下方移动20px,以此类推,从右边往左边推和从下边往上边推也是一样的,这样就有推箱子的效果。(大神有其他方法也请告诉小弟,多谢)
第二个问题就是游戏地图的创建,其实我使用的是很常见的一种创建方式,我自己给他取了个名字,叫做数组地图,主要是因为他很形象模拟地图,数组写成什么样子,最后生成的地图就是什么样子,比如
[
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,6,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,1,1,1,2,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,4,1,1,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
]
这个数组看起来像是一个矩形,实际上就是一个数组,只是我们人为的把他排列成一个矩形的样子,之所以这样做就是为了依照我们排列的样子来创建地图,首先我们看到这个数组里有很多1,还有3,4,2,他们分别表示不同的类型,比如说1表示可以行走的地方,4表示不能行走的地方,3表示箱子a初始化时候的位置,2表示箱子最终要被推到的地方,6表示被推的箱子b初始化的位置,我们在css表里面写好对应的样式,比如 .pos1{width:20px;height:20px;background:#666;float:left}, .pos2{width:20px;height:20px;background:red;float:left}, .pos3{width:20px;height:20px;background:yellow;float:left},.pos4{width:20px;height:20px;background:black;float:left},.pos6{width:20px;height:20px;background:pink;float:left},写好这些样式以后,开始用js循环整个数组,再循环的过程中不断创建div,而每一个div都要给他们一个class,至于这个class是什么则根据数组样式来赋值,比如数组里的第一个值是1,那么对应的样式就是.pos1,如果数组里的样式是2,那么对应的class就是.pos2,以此类推,每创建一个div就把它插入到父盒子里面,因为每一个小div都有浮动属性,他们自然会一个一个排开,最终就会平凑成数组展现出来的样式。这种地图创建方好处就是非常容易修改地图样式,并且可以很直观的修改地图,只要修改数组就等于修改了地图,简单的游戏中常用这种方式。
式。下面是代码:
this.gameBox = document.getElementById('game_box'); //父盒子
for(var i=0;i<this.map.length;i++){
this.litBox = document.createElement('div');
this.litBox.className = "pos"+this.map[i];
this.gameBox.appendChild(this.litBox);
}
第三个问题就是推箱子时候,当箱子遇到class为.pos4的div时候,也就是遇到墙的时候,不能把箱子推过去,这个问题肯定有更好的解决方法,因为我在这个例子中所有的障碍都是用div完成,所以我们看到的那一列或者一黑色竖障碍都是div,我原本希望使用上面说的碰撞检测的方法来处理,但是发现这个方法检测多个连续的元素时候不是很好用,不过也有可能是我用不对,我最终的使用的方法比较愚蠢,将所有的class为.pos4的div全部选中,用循环得到每个div的上下左右值,并把他们放到一个数组里,然后在我们每次按下按键的时候都检测一次当前箱子的位置。并把这个位置拿到数组里面的去循环比较,看看是否有一样的值,如果有一个一样的,那么表示箱子碰到了障碍,只是这种做法比较耗损性能,毕竟在不停的循环检测,所以不是很推荐,不过我暂时也没想出其他方法(求大神赐教!!!)
第四个问题就是,这个例子只是演示了推一个子箱子,实际的游戏中为了增加难度会有很多被推的箱子,至于如何实现,相信大家也有自己的想法了。
/*******以下是整个案例代码(因本人技术有限,大神就当成反面教材吧) 请大家多多指教***************/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Document</title>
<style>
*{margin:0px;padding:0px;}
#game_box{width:500px;height:500px;margin:150px auto;position:relative;}
.pos1{width:20px;height:20px;background: #666;float: left;}
.pos2{width:20px;height:20px;background: red;float: left;}
.pos3{width:20px;height:20px;background:#666;float: left;}
.pos4{width:20px;height:20px;background:black;float: left;}
.pos6{width:20px;height:20px;background: #666;float: left;}
.begin{width:20px;height:20px;background:yellow;position: absolute;top:0;left:0px;z-index:1000;}
.target{width:20px;height:20px;background:pink;position: absolute;top:0;left:0px;z-index:1000;}
</style>
</head>
<body>
<div id="game_box"></div>
</body>
<script>
var game = {
gameBox:0, //外层的大盒子
litBox:0, //里面的每一个小格子
beginLeft:0, //运动的盒子最开始距离左边的距离
beginRight:0, //运动的盒子最开始距离上边的距离
targetLeft:0, //将要推动的盒子最开始距离左边的距离
targetTop:0, //将要推动的盒子最开始距离上边的距离
mObj:0, //运动的盒子元素
mBox:0, //被推动的盒子
prevleft:0, //记录运动的盒子上一步距离左边的位置
prevtop:0, //记录运动的盒子上一步距离上边的位置
pushprevleft:0,
pushprevtop:0,
iftouch:false, //记录是否碰撞到目标盒子
prev:0, //保存之前按下的方向值
direct:0,
last:0,
//地图数组
map:[
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,1,1,1,2,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,4,1,1,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,6,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,4,4,4,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
],
//创建地图
createMap:function(){
this.gameBox = document.getElementById('game_box');
for(var i=0;i<this.map.length;i++){
this.litBox = document.createElement('div');
this.litBox.className = "pos"+this.map[i];
this.gameBox.appendChild(this.litBox);
if(this.map[i]==3){
this.beginLeft = this.litBox.offsetLeft;
this.beginRight = this.litBox.offsetTop;
}
if(this.map[i]==6){
this.targetLeft = this.litBox.offsetLeft;
this.targetTop = this.litBox.offsetTop;
}
}
},
//获取class方法
getClass:function(classname,parent){
var par = parent||document;
var pele = par.getElementsByTagName('*');
var arr=[];
for(var i=0;i<pele.length;i++){
var pclass = pele[i].className.split(' ');
for(var j=0;j<pclass.length;j++){
if(pclass[j] == classname){
arr.push(pele[i]);
break;
}
}
}
if(arr.length == 1){
return arr[0];
}else{
return arr;
}
},
//创建将要移动的盒子
createObj:function(){
this.mObj = document.createElement('div');
this.mObj.className = "begin";
this.gameBox.appendChild(this.mObj);
this.mObj.style.left = this.beginLeft+'px';
this.mObj.style.top = this.beginRight+'px';
},
//创建将要被推的盒子
createMbox:function(){
this.mBox = document.createElement('div');
this.mBox.className = "target";
this.gameBox.appendChild(this.mBox);
this.mBox.style.left = this.targetLeft+'px';
this.mBox.style.top = this.targetTop+'px';
},
//控制盒子移动
move:function(obj){
_this = this;
document.onkeydown=function(ev){
_this.prevleft = obj.offsetLeft;
_this.prevtop = obj.offsetTop;
_this.pushprevleft = _this.mBox.offsetLeft;
_this.pushprevtop = _this.mBox.offsetTop;
var oev = ev || event;
var key = oev.keyCode;
if(key == 87){
obj.style.top=obj.offsetTop-20+'px';
}
else if(key == 68){
obj.style.left=obj.offsetLeft+20+'px';
}
else if(key == 83){
obj.style.top=obj.offsetTop+20+'px';
}
else if(key == 65){
obj.style.left=obj.offsetLeft-20+'px';
}
_this.rang(_this.mObj,1);
_this.current(_this.mObj,1);
_this.pushbox(_this.iftouch?key:0);
}
},
rang:function(obj,no2){
if(no2==1){
if(obj.offsetLeft<=0){
obj.style.left=0+'px';
}
if(obj.offsetLeft>=this.gameBox.offsetWidth-this.mObj.offsetWidth){
obj.style.left=this.gameBox.offsetWidth-this.mObj.offsetWidth+'px';
}
if(obj.offsetTop<=0){
obj.style.top=0+'px';
}
if(obj.offsetTop>=this.gameBox.offsetHeight-this.mObj.offsetHeight){
obj.style.top = this.gameBox.offsetHeight-this.mObj.offsetHeight+'px';
}
}
if(no2==2){
if(obj.offsetLeft<0){
obj.style.left=0+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetLeft>this.gameBox.offsetWidth-this.mObj.offsetWidth){
obj.style.left=this.gameBox.offsetWidth-this.mObj.offsetWidth+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetTop<0){
obj.style.top=0+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetTop>this.gameBox.offsetHeight-this.mObj.offsetHeight){
obj.style.top = this.gameBox.offsetHeight-this.mObj.offsetHeight+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
}
},
//不能触碰的区域
forbidden:function(){
var totalBox = this.getClass('pos4');
var arr=[];
for(var i=0;i<totalBox.length;i++){
var json = {};
json.left = totalBox[i].offsetLeft;
json.top = totalBox[i].offsetTop;
json.right = totalBox[i].offsetLeft+20;
json.bottom = totalBox[i].offsetTop+20;
arr.push(json);
}
return arr;
},
//盒子当前的位置判断
current:function(obj,no){
var notouch = this.forbidden();
var curleft = obj.offsetLeft;
var curright = obj.offsetLeft+20;
var curtop = obj.offsetTop;
var curbottom= obj.offsetTop+20;
for(var i =0;i<notouch.length;i++){
if(curleft == notouch[i].left && curtop == notouch[i].top){ //如果碰到黑色的墙就退回到前一步的位置
if(no==1){
obj.style.top = this.prevtop+'px';
obj.style.left = this.prevleft+'px';
}
if(no==2){
obj.style.top = _this.pushprevtop+'px';
obj.style.left = _this.pushprevleft+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
}
}
},
//检测碰撞
crash:function(){
if(this.mObj.offsetLeft==this.mBox.offsetLeft-20&&this.mObj.offsetTop==this.mBox.offsetTop){
//left
this.iftouch = true;
this.direct = 'left';
this.last=2;
}
else if(this.mObj.offsetLeft==this.mBox.offsetLeft+20&&this.mObj.offsetTop==this.mBox.offsetTop){
//right
this.iftouch = true;
this.direct = 'right';
this.last=2;
}
else if(this.mObj.offsetTop==this.mBox.offsetTop-20&&this.mObj.offsetLeft==this.mBox.offsetLeft){
//top
this.iftouch = true;
this.direct = 'top';
this.last=2;
}
else if(this.mObj.offsetTop==this.mBox.offsetTop+20&&this.mObj.offsetLeft==this.mBox.offsetLeft){
//bottom
this.iftouch = true;
this.direct = 'bottom';
this.last=2;
}
},
//推盒子方法
pushbox:function(key){
this.crash();
//判断回传的keycode是多少来检测用户往哪个方向推箱子
if(key){
if(this.direct == 'left'){ //检测到从左边往右边推箱子
if(key!=68){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.left=this.mBox.offsetLeft+20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'top'){ //检测到从上往下推箱子
if(key!=83){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.top=this.mBox.offsetTop+20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'bottom'){ //检测到从下往上推箱子
if(key!=87){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.top=this.mBox.offsetTop-20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'right'){ //检测到从右往左推箱子
if(key!=65){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.left=this.mBox.offsetLeft-20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
}
},
//初始化对象
init:function(){
this.createMap();
this.createObj();
this.createMbox();
this.move(this.mObj);
this.forbidden();
}
}
game.init();
</script>
</html>
javascript 推箱子游戏介绍及问题的更多相关文章
- JavaScript 推箱子游戏
推箱子游戏的 逻辑非常简单,但是如果不动手的话,还是不太清楚.我在这里讲一下自己的思路. 制作推箱子,首先要有自己的设计素材.如下我也是网上找的素材 第二步,理清游戏的规则. 游戏规则: 1.小人将箱 ...
- javascript --推箱子
<head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" ...
- JavaScript写一个小乌龟推箱子游戏
推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例: 推箱子游戏的在线DEMO : 打开 如下是效果图: 这个拖箱子游戏做了移动端的适配, 我使用 ...
- OC推箱子
#include<stdio.h> #include<stdlib.h> int main(void) { char sr;//存储用户输入的指令 //绘制地图 char a[ ...
- c语言游戏推箱子
前两天做了推箱子小游戏,看似简单的一个小游戏背后却 有巨大的秘密,这秘密就是一大堆逻辑. 自从学习了函数过后,的确是解决了很多问题,而且调用很方便,尽管我现在都不是很会调用. 写完一个函数,准备测试一 ...
- 用C#制作推箱子小游戏
思路分析: 一.制作一个地图 二.地图中放置墙.箱子.人.目标等 三.让小人动起来完成推箱子动作 游戏制作: 1.按照上述地图制作一个地图 (12行×13列) 地图可以看做是行和列组成的,即可以看做 ...
- hdu.1254.推箱子(bfs + 优先队列)
推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- [游戏模版17] Win32 推箱子 迷宫
>_<:Here introduce a simple game: >_<:resource >_<:only can push a box and finally ...
- [转]Flash ActionScript2.0面向对象游戏开发-推箱子
本文转自:http://www.alixixi.com/Dev/W3C/Flash/2007/2007070868666.html 概述: Flash ActionScript2.0是一种面向对向的编 ...
随机推荐
- Smarty3.1.3安装使用
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Verdana } span.s1 { } Smarty简介 Smarty是一个PHP的模板引 ...
- 第二十一章 Django的分页与cookie
第二十一章 Django的分页与cookie 第一课 模板 1.模板的继承 在Template目录下新建模板master.html <!DOCTYPE html> <html lan ...
- dubbox系列【三】——简单的dubbox提供者+消费者示例
1.dubbox-provider示例 在eclipse中建立maven project,名为provider-parent,包含两个maven medule:provider-api 和 provi ...
- 蓝桥杯 求最大值 dp
这题很暴力的一个DP,d[i][j]表示前i个数对选择一些Ai的和为j的最大Bi和. 状态转移方程: dp[i][j]=max(dp[i][j],dp[i-1][j-sc[i].a]+sc[i].b) ...
- 开发工具类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数 ...
- Quartz基本使用
1.Quartz概述:简单的说就是java的一个定时任务的框架,没有那么复杂的解释,跟前端的定时器一样.在了解它之前,首先熟悉几个概念. 2.基本概念 2.1 Job:表示一个工作,要执行的具体内容. ...
- MAVEN自动发布更新本地和远程仓库
1.本地仓库 的更新 mvn clean package install 2.远程 仓库 的更新 mvn clean package deploy 2.1工程文件pom.xml的设置 <bu ...
- WPF文本框只允许输入数字
XAML代码 < TextBox Height="23" HorizontalAlignment="Left" Margin="100,5, ...
- GOF23种设计模式精解
创建型 1. Factory Method(工厂方法) 2. Abstract Factory(抽象工厂) 3. Builder(建造者) 4. Prototype(原型) 5. Singleton( ...
- echarts中地图提示"TypeError:i is undefined"
1.错误描述 2.错误原因 刚开始地图的数据源是由静态数据提供,后来修改成从数据库中获取,请求数据的方法成功后调用地图方法,但是初始化时未调用数据请求方法,导致地图核心js报错 3.解决办法 初始化时 ...