我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛
前言
推箱子的思路大致如下:
- 初始化一个推箱子的地图数据,数据中的0,1,2,3,4分别对应(空白区域,墙,小球,箱子和小人);
- 收集数据中对应的图片集;
- 建一个格子棋盘用来作为渲染地图数据的容器;
- 初始化页面时创建地图,根据地图数据指定对应图片的所在位置;
- 编写控制小人移到的方法;
- 编写键盘控制方向的方法,并根据方向移动小人;
- 编写判断箱子碰撞的方法来判断是碰撞的箱子还是小球;
实现
HTML代码
<div class="game-title">Qiuの推箱子</div>
<div class="container">
<div id="game-container"></div>
<div class="controller">
<div class="text">提示面板</div>
<div id="showInfo"></div>
</div>
</div>
CSS代码
/*标题*/
.game-title {
text-align: center;
line-height: 80px;
font-size: 30px;
color: #03a9f4;
font-weight: bold;
}
/* 游戏整体 */
.container {
width: auto;
height: auto;
display: flex;
flex-wrap: row nowrap;
justify-content: center;
align-items: center;
}
/* 地图容器 */
#game-container {
background-color: #ffeb3b;
position: relative;
}
/* 方格 */
#game-container div {
width: 35px;
height: 35px;
position: absolute;
}
#game-container div img {
width: 35px;
height: 35px;
position: absolute;
border-radius: 6px;
}
#game-container div.people img {
z-index: 2;
}
#game-container div.box img {
z-index: 1;
}
/* 提示语 */
.controller {
width: 150px;
height: 420px;
margin-left: 20px;
padding: 10px;
box-sizing: border-box;
background-color: #feffb1;
}
.text {
width: 100%;
height: 30px;
line-height: 30px;
margin-top: 20px;
text-align: center;
border: 2px solid black;
background-color: aquamarine;
}
#showInfo {
height: 320px;
font-size: 12px;
margin: 10px auto;
padding: 10px;
box-sizing: border-box;
border: 2px solid black;
background-color: aquamarine;
}
渲染效果如下
JS代码
// 节点参数
var container = document.getElementById("game-container");
var showInfo = document.getElementById('showInfo');//提示面板
//地图数据(0:空白区域,1:墙,2:小球,3:箱子,4:小人)
var mapdata = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 0, 3, 0, 3, 2, 1, 0, 0,
0, 0, 1, 2, 3, 0, 4, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 3, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
// 横纵坐标格子数
var globl_size = { x: 12, y: 12 };
var message = '';
// 初始化加载
window.onload = function () {
CreateMap()
};
// 创建地图
var CreateMap = function () {
// 设置容器大小
container.style.cssText = "width:" + globl_size.x * 35 + "px;height:" + globl_size.y * 35 + "px;";
// 将地图数据渲染到容器的每个格子
for (var i = 0; i < globl_size.x * globl_size.y; i++) {//144
var opeople;
var x, y;
switch (mapdata[i]) {
case 1: //墙
//设置(x,y)坐标
x = i % globl_size.x;
y = parseInt(i / globl_size.x);
// 创建格子
var appenddiv = document.createElement("div");
// 设置格子在地图中的位置
appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
// 设置格子参数
appenddiv.className = "wall";
appenddiv.x = x;
appenddiv.y = y;
// 这种image对象的方式 有一种预加载的功能,当你给他src的时候,就会开始加载图片
var wall_img = new Image();
// 墙的图片
wall_img.src = "./images/wall.png";
// 将图片标签追加到div格子中
appenddiv.appendChild(wall_img);
// 将div格子放到整张地图中
container.appendChild(appenddiv);
break;
case 2://小球
//设置(x,y)坐标
x = i % globl_size.x;
y = parseInt(i / globl_size.x);
// 创建格子
var appenddiv = document.createElement("div");
// 设置格子在地图中的位置
appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
// 设置格子参数
appenddiv.className = "ball";
appenddiv.x = x;
appenddiv.y = y;
var wall_img = new Image();
//小球图片
wall_img.src = "./images/ball.png";
// 将图片标签追加到div格子中
appenddiv.appendChild(wall_img);
// 将div格子放到整张地图中
container.appendChild(appenddiv);
break;
case 3://箱子
//设置(x,y)坐标
x = i % globl_size.x;
y = parseInt(i / globl_size.x);
// 创建格子
var appenddiv = document.createElement("div");
// 设置格子在地图中的位置
appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
// 设置格子参数
appenddiv.className = "box";
appenddiv.x = x;
appenddiv.y = y;
var wall_img = new Image();
//箱子图片
wall_img.src = "./images/box.png"
// 将图片标签追加到div格子中
appenddiv.appendChild(wall_img);
// 将div格子放到整张地图中
container.appendChild(appenddiv);
break;
case 4://小人
//设置(x,y)坐标
x = i % globl_size.x;
y = parseInt(i / globl_size.x);
// 创建格子
var appenddiv = document.createElement("div");
// 设置格子在地图中的位置
appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
// 设置格子参数
appenddiv.className = "people";
appenddiv.x = x;
appenddiv.y = y;
var wall_img = new Image();
// 小人图片
wall_img.src = "./images/people.png"
opeople = wall_img;
// 将图片标签追加到div格子中
appenddiv.appendChild(wall_img);
// 将div格子放到整张地图中
container.appendChild(appenddiv);
break;
}
}
contralPeople(opeople);
};
// 键盘控制方向
var contralPeople = function (people) {
document.onkeydown = function (event) {
event = event || window.event;
var keyCode = event.keyCode;
console.log(keyCode)
switch (keyCode) {
//左
case 37:
movePeople({ x: -1 }, people);
break;
//上
case 38:
movePeople({ y: -1 }, people);
break;
// 右
case 39:
movePeople({ x: 1 }, people);
break;
// 下
case 40:
movePeople({ y: 1 }, people);
break;
}
}
};
// 移动小人
var movePeople = function (position, people) {
//先找到小人所在的div格子
parent_div = people.parentNode;
// 箱子
var box = getClass(container, "box");
x = position.x || 0;
y = position.y || 0;
if (mapdata[parent_div.x + x + (parent_div.y + y) * globl_size.x] != 1) {
parent_div.x = parent_div.x + x;
parent_div.y = parent_div.y + y;
parent_div.style.left = parent_div.offsetLeft + x * 35 + "px";
parent_div.style.top = parent_div.offsetTop + y * 35 + "px";
for (var i = 0; i < box.length; i++) {
if (box[i].x == parent_div.x && box[i].y == parent_div.y) {
if (mapdata[box[i].x + x + (box[i].y + y) * globl_size.x] != 1) {
//检测两个箱子是否碰撞,如果碰撞,小人则弹回
if (!twoBoxJianCe(box[i], x, y)) {
box[i].x = box[i].x + x;
box[i].y = box[i].y + y;
box[i].style.left = box[i].offsetLeft + x * 35 + "px";
box[i].style.top = box[i].offsetTop + y * 35 + "px";
isOrNoSuccess();
} else {
parent_div.x = parent_div.x - x;
parent_div.y = parent_div.y - y;
parent_div.style.left = parent_div.offsetLeft - x * 35 + "px";
parent_div.style.top = parent_div.offsetTop - y * 35 + "px";
}
} else {
// 人物弹回
parent_div.x = parent_div.x - x;
parent_div.y = parent_div.y - y;
parent_div.style.left = parent_div.offsetLeft - x * 35 + "px";
parent_div.style.top = parent_div.offsetTop - y * 35 + "px";
}
}
}
}
};
// 检测两个箱子是否碰撞
var twoBoxJianCe = function (box, x, y) {
var obox = getClass(container, "box");
for (var i = 0; i < obox.length; i++) {
if (obox[i] != box) {
if (obox[i].x == box.x + x && obox[i].y == box.y + y) {
message = '箱子不能碰撞!'
showInfo.innerHTML = message
//碰撞
return true;
}
}
}
//没碰撞
return false;
};
//判断是否成功
var isOrNoSuccess = function () {
var ball = getClass(container, "ball");
var box = getClass(container, "box");
var successnum = 0;
for (var i = 0; i < box.length; i++) {
for (var j = 0; j < ball.length; j++) {
if (box[i].x == ball[j].x && box[i].y == ball[j].y) {
successnum++;
}
}
}
if (successnum == ball.length) {
message = '游戏通关了,太棒了!'
showInfo.innerHTML = message
}
};
// 找标签
var getClass = function (node, classname) {
if (node.getElementsByClassName) {
//如果存在该标签 就返回
return node.getElementsByClassName(classname);
} else {
var elems = node.getElementsByTagName(node),
defualt = [];
for (var i = 0; i < elems.length; i++) {
//遍历所有标签
if (elems[i].className.indexOf(classname) != -1) {
//查找相应类名的标签
defualt[defualt.length] = elems[i];
}
}
return defualt;
}
};