JS推箱子项目总结——地图创建与铺设简述(二)
前言
上一篇我们讲解了地图的简单创建,虽然最后我加上了二维数组的一个代码展示,但讲的还是不是很详细。所以就有写了一篇专门讲一下。
在上一篇我们其实对地图的原理有了一定的了解,就是使用循环,不断创建小方块,填充进大地图里。二维数组创建是对地图的进一步优化。
在这一篇了,我会讲解一下,使用二维数组创建箱子与终点
首先,我把上一篇的div使用函数创建模板的代码放在这。
function createEle(oCss){
//把形式参数定义为一个对象,然后对象名加.点就是对象的属性,可以随时调用。
var oBox=document.createElement("div");
oCss.parent.appendChild(oBox);
oBox.id=oCss.id;
oBox.style.width=oCss.w+"px";
oBox.style.height=oCss.h+"px";
oBox.style.position=oCss.p;
oBox.style.margin=oCss.m;
oBox.style.backgroundImage=oCss.bgi;
oBox.style.backgroundSize=oCss.bgs;
return oBox;
}
//"w"相当于oCss.w 以此类推。然后使用,(逗号)分割。
//注意属性使用字符串,就跟:
//box.style.margin="10px auto"一样,还是要用字符串形式。
var oBox=createEle({"w":800,
"h":600,
"p":"relative",
"m":"10px auto",
"bgi":"url('tu.jpg')",
"bgs":"100% 100%",
"id":"",
"parent":document.body});
这里是上一篇,创建地图的代码。
.box{width: 500px;
height:500px;
background-color:#000;
margin:50px auto;
position:relative;
verflow: hidden;}
.son{width:48px;
height:48px;
border:1px solid #f0f;
position:absolute;}
//createElement()创建元素与appendChild配套使用
//appendChild声明元素创建在哪里(哪个标签里面)
var oMap=document.createElement("div");
document.body.appendChild(oMap);
oMap.className="box";
for(var i=0;i<10;i++){
for(var j=0;j<10;j++){
var oSon=document.createElement("div");
oSon.className="son";
//定位位置
oSon.style.left=j*50+"px";
oSon.style.top=i*50+"px";
oMap.appendChild(oSon);
}
}
二维数组使用
首先我们要把创建地图与二维数组对接,从二维数组中我们可以看出地图的行列数 以及一些具体要求。
首先我们写一个10 x 10的一个二维数组,以及创建地图的基本代码。
//基础设施
function createEle(oCss){
var oBox=document.createElement("div");
oCss.parent.appendChild(oBox);
oBox.style.width=oCss.w+"px";
oBox.style.height=oCss.h+"px";
oBox.style.position=oCss.p;
oBox.style.left=oCss.l+"px";
oBox.style.top=oCss.t+"px";
return oBox;
}
//注意在数组最后一位不需要加逗号,
//我们得确认二维数组是一个完整的。
arr=[
[0,0,0,0,0,0,0,0,0,0],
[0,1,1,1,1,1,1,1,1,0],
[0,1,0,0,0,0,0,0,1,0],
[0,1,0,0,0,0,0,0,1,0],
[0,1,0,0,2,3,0,0,1,0],
[0,1,0,0,0,0,0,0,1,0],
[0,1,0,0,0,0,0,0,1,0],
[0,1,0,0,0,0,0,10,1,0],
[0,1,1,1,1,1,1,1,1,0],
[0,0,0,0,0,0,0,0,0,0]
];
//创建外面的大box
var oBox=createEle({"w":600,
"h":600,
"p":"relative",
"parent":document.body});
oBox.style.margin="20px auto";
oBox.style.backgroundColor="#000";
//算出小box的长宽
var w=oBox.clientWidth/arr.length;
var h=oBox.clientHeight/arr[0].length;
for(var row=0;row<arr.length;row++){
for(var col=0;col<arr[0].length;col++){
var oGrid=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
}
}
在这里我们就跟二维数组对接了,使用arr.length与arr[0].length作为box的行列。现在只是行列有了对应,如果我们任意改变二维数组是没有任何变化的。
我们首先得改变二维数组,然后在循环创建的地方加上一个if条件,这样才会在地图上做出想要的创建。
for(var row=0;row<arr.length;row++){
for(var col=0;col<arr[0].length;col++){
//我们把1当做障碍,2作为人物
var oGrid=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
//我们在二维数组中搜索我们的数字,以此为基础创建
//arr[row][col]
if(arr[row][col]==1){
oGrid.style.backgroundColor="#0ff";
}
if(arr[row][col]==2){
role=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
role.style.backgroundColor="#fff";
role.style.backgroundSize="100% 100%";
//把人物作为一个对象,这样就可以在其中存储一些东西。
role.row=row;
role.col=col;
}
if(arr[row][col]==3){
//原理与创建人物那段相同
var oCase=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
oCase.style.backgroundColor="#ff0";
oCase.style.backgroundSize="100% 100%";
oCase.row=row;
oCase.col=col;
}
if(arr[row][col]==10){
//原理与创建人物那段相同
var oWin=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
oWin.style.backgroundColor="#0f0";
oWin.style.backgroundSize="100% 100%";
oWin.row=row;
oWin.col=col;
}
}
}
移动
现在我们创建了一个有主角有箱子的地图,虽然还不能动,而且箱子的行动实现在于人物的移动。
document.onkeydown=function move(e){
var key=e.keyCode;//左:37 上:38 右:39 下:40
if(key==37){
//当人物左边是通路时,人物就可以行走
if(arr[role.row][role.col-1]==0){//走之前要处理内存变化
arr[role.row][role.col]=0;
role.col=role.col-1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
//当人物左边是箱子时,箱子随着人物的移动而移动
}else if(arr[role.row][role.col-1]==3){
if(arr[role.row][role.col-2]==0||arr[role.row][role.col-2]==10){
//箱子左移了,人也左移
//箱子先移动
arr[oCase.row][oCase.col]=0;//箱子离开之前,还原0
oCase.col=oCase.col-1;
oCase.style.left=oCase.col*h+"px";
arr[oCase.row][oCase.col]=3;
//人跟着动
arr[role.row][role.col]=0;
role.col=role.col-1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
}
}
}
if(key==38){
if(arr[role.row-1][role.col]==0){
arr[role.row][role.col]=0;
role.row=role.row-1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row-1][role.col]==3){
if(arr[role.row-2][role.col]==0||arr[role.row-2][role.col]==10){
arr[oCase.row][oCase.col]=0;//箱子离开之前,还原0
oCase.row=oCase.row-1;
oCase.style.top=oCase.row*w+"px";
arr[oCase.row][oCase.col]=3;
//人跟着动
arr[role.row][role.col]=0;
role.row=role.row-1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}
}
}
if(key==39){
if(arr[role.row][role.col+1]==0){
arr[role.row][role.col]=0;
role.col=role.col+1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row][role.col+1]==3){
if(arr[role.row][role.col+2]==0||arr[role.row][role.col+2]==10){
arr[oCase.row][oCase.col]=0;//箱子离开之前,还原0
oCase.col=oCase.col+1;
oCase.style.left=oCase.col*h+"px";
arr[oCase.row][oCase.col]=3;
//人跟着动
arr[role.row][role.col]=0;
role.col=role.col+1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
}
}
}
if(key==40){
if(arr[role.row+1][role.col]==0){
arr[role.row][role.col]=0;
role.row=role.row+1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row+1][role.col]==3){
if(arr[role.row+2][role.col]==0||arr[role.row+2][role.col]==10){
arr[oCase.row][oCase.col]=0;//箱子离开之前,还原0
oCase.row=oCase.row+1;
oCase.style.top=oCase.row*w+"px";
arr[oCase.row][oCase.col]=3;
//人跟着动
arr[role.row][role.col]=0;
role.row=role.row+1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}
}
}
}
解析一下:
当我们按左键时,判断人物左边是不是通路,就是arr[role.row][role.col-1]==0 二维数组中人物的左边是不是0,是的话就往左走。(走的代码有注释)
else if 当人物的左边是箱子时,我们就判断我们推不推得了这个箱子,
arr[role.row][role.col-2]==0 箱子在人物的左边,箱子的左边对于人物来说就是-2的距离。
如果推的了的话,箱子先移动人物再走。
1.我们的人物不能经过终点,箱子才可以
2.终点最好设置在边边那里
获胜
现在我们把箱子推到终点并不会发生任何事情,或许我们可以加上一个简单的条件:比如箱子与终点的位置重叠时弹出你赢了。
if(oCase.row==oWin.row&&oCase.col==oWin.col){
alert("you win!");
}
但这种方式只适合只有一个箱子一个终点时。所以我们得改进一下。
在看推箱子的代码时,我们会发现箱子与人的移动会改变二维数组的内存,也就是走过之处“片草不生”,人物与箱子的移动会把原来位置的二维数组数字改变为通路,而现在的位置二维数组数字为2或者3。
就有一个问题,当箱子被推到终点时,那里的二维数组的数字是什么?
答案是:2。
所以说当箱子推到终点时,终点的数字在二维数组上已经找不到了,在我的理解就是“取代”。
所以我们依照这个原理可以写出
function isFinished(){
var finish=true;
for(var i=0;i<arr.length;i++){
for(var j=0;j<arr[0].length;j++){
if(arr[i][j]==10){
finish=false;
}
}
}
return finish;
}
解析:
设finish初始的状态为true,遍历一遍二维数组,
arr[i][j]==10 只要有一个终点,则finish为false。
如果没有一个终点,则finish会以true返回。
然后我们在行动模式中调用函数。
var success=isFinished();
if(success===true){
alert("you win!!!");
}
哈哈哈,其实这是老师写出来的,我只是copy了一下,在课堂上老师让我们想我也没有想出使用Boolean。借口:主要我没有经常使用Boolean。
其实这个很重要的。
但我们多加了一个箱子会有种bug一样的感觉,就是人物不知道他在推哪个箱子,所以我们要在箱子里加一个ID属性,让人物识别出来。
if(arr[row][col]==3){
var oCase=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
oCase.style.backgroundColor="#ff0";
oCase.style.backgroundSize="100% 100%";
//加上ID属性
oCase.id="box"+row+col
oCase.row=row;
oCase.col=col;
}
然后在箱子的移动我们也要加上箱子id的变化。
var box=document.querySelector("#box"+(role.row-1)+role.col);
arr[box.row][box.col]=0;//箱子离开之前,还原0
box.row=box.row-1;
box.style.top=box.row*w+"px";
arr[box.row][box.col]=3;
box.id="box"+box.row+box.col;
最终代码展示
其实拼接起来就好的。。。好吧,我承认是有一点乱。
//基础设施
function createEle(oCss){
var oBox=document.createElement("div");
oCss.parent.appendChild(oBox);
oBox.style.width=oCss.w+"px";
oBox.style.height=oCss.h+"px";
oBox.style.position=oCss.p;
oBox.style.left=oCss.l+"px";
oBox.style.top=oCss.t+"px";
return oBox;
}
//注意在数组最后一位不需要加逗号,
//我们得确认二维数组是一个完整的。
arr=[
[1,1,1,1,1,1,1,1,1,1],
[1,10,0,0,0,0,0,0,0,1],
[1,1,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,3,2,3,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,1,1],
[1,0,0,0,0,0,0,0,10,1],
[1,1,1,1,1,1,1,1,1,1]
];
//创建外面的大box
var oBox=createEle({"w":600,
"h":600,
"p":"relative",
"parent":document.body});
oBox.style.margin="20px auto";
oBox.style.backgroundColor="#000";
//算出小box的长宽
var w=oBox.clientWidth/arr.length;
var h=oBox.clientHeight/arr[0].length;
for(var row=0;row<arr.length;row++){
for(var col=0;col<arr[0].length;col++){
//我们把1当做障碍,2作为人物
var oGrid=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
//我们在二维数组中搜索我们的数字,以此为基础创建
//arr[row][col]
if(arr[row][col]==1){
oGrid.style.backgroundColor="#0ff";
}
if(arr[row][col]==2){
role=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
role.style.backgroundColor="#fff";
role.style.backgroundSize="100% 100%";
//把人物作为一个对象,这样就可以在其中存储一些东西。
role.row=row;
role.col=col;
}
if(arr[row][col]==3){
var oCase=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
oCase.style.backgroundColor="#ff0";
oCase.style.backgroundSize="100% 100%";
//加上ID属性
oCase.id="box"+row+col
oCase.row=row;
oCase.col=col;
}
if(arr[row][col]==10){
//原理与创建人物那段相同
var oWin=createEle({"w":w,
"h":h,
"p":"absolute",
"parent":oBox,
"l":col*w,
"t":row*h
});
oWin.style.backgroundColor="#0f0";
oWin.style.backgroundSize="100% 100%";
oWin.row=row;
oWin.col=col;
}
}
}
document.onkeydown=function move(e){
var key=e.keyCode;//左:37 上:38 右:39 下:40
if(key==37){
//当人物左边是通路时,人物就可以行走
if(arr[role.row][role.col-1]==0){//走之前要处理内存变化
arr[role.row][role.col]=0;
role.col=role.col-1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
//当人物左边是箱子时,箱子随着人物的移动而移动
}else if(arr[role.row][role.col-1]==3){
if(arr[role.row][role.col-2]==0||arr[role.row][role.col-2]==10){
var box=document.querySelector("#box"+role.row+(role.col-1));
//箱子左移了,人也左移
//箱子先移动
arr[box.row][box.col]=0;//箱子离开之前,还原0
box.col=box.col-1;
box.style.left=box.col*h+"px";
arr[box.row][box.col]=3;
box.id="box"+box.row+box.col;
//人跟着动
arr[role.row][role.col]=0;
role.col=role.col-1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
var success=isFinished();
if(success===true){
alert("you win!");
}
}
}
}
if(key==38){
if(arr[role.row-1][role.col]==0){
arr[role.row][role.col]=0;
role.row=role.row-1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row-1][role.col]==3){
if(arr[role.row-2][role.col]==0||arr[role.row-2][role.col]==10){
var box=document.querySelector("#box"+(role.row-1)+role.col);
arr[box.row][box.col]=0;//箱子离开之前,还原0
box.row=box.row-1;
box.style.top=box.row*w+"px";
arr[box.row][box.col]=3;
box.id="box"+box.row+box.col;
//人跟着动
arr[role.row][role.col]=0;
role.row=role.row-1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
var success=isFinished();
if(success===true){
alert("you win!");
}
}
}
}
if(key==39){
if(arr[role.row][role.col+1]==0){
arr[role.row][role.col]=0;
role.col=role.col+1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row][role.col+1]==3){
if(arr[role.row][role.col+2]==0||arr[role.row][role.col+2]==10){
var box=document.querySelector("#box"+role.row+(role.col+1));
arr[box.row][box.col]=0;//箱子离开之前,还原0
box.col=box.col+1;
box.style.left=box.col*h+"px";
arr[box.row][box.col]=3;
box.id="box"+box.row+box.col;
//人跟着动
arr[role.row][role.col]=0;
role.col=role.col+1;
role.style.left=role.col*h+"px";
arr[role.row][role.col]=2;
var success=isFinished();
if(success===true){
alert("you win!");
}
}
}
}
if(key==40){
if(arr[role.row+1][role.col]==0){
arr[role.row][role.col]=0;
role.row=role.row+1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
}else if(arr[role.row+1][role.col]==3){
if(arr[role.row+2][role.col]==0||arr[role.row+2][role.col]==10){
var box=document.querySelector("#box"+(role.row+1)+role.col);
arr[box.row][box.col]=0;//箱子离开之前,还原0
box.row=box.row+1;
box.style.top=box.row*w+"px";
arr[box.row][box.col]=3;
box.id="box"+box.row+box.col;
//人跟着动
arr[role.row][role.col]=0;
role.row=role.row+1;
role.style.top=role.row*w+"px";
arr[role.row][role.col]=2;
var success=isFinished();
if(success===true){
alert("you win!");
}
}
}
}
}
function isFinished(){
var finish=true;
for(var i=0;i<arr.length;i++){
for(var j=0;j<arr[0].length;j++){
if(arr[i][j]==10){
finish=false;
}
}
}
return finish;
}