参考以下教学视频编写
教学视频:Canvas画布实现推箱子游戏-HTML5前端设计JavaScript原生开发_哔哩哔哩_bilibili
箱子地图
Boxdata.js
//1:围墙 2:目标点 3:箱子 4:角色 5:在目标点的箱子
var levels = [];
levels[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,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,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,1,2,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,1,0,3,0,4,1,0,0,0,0,0],
[0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,1,1,1,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,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,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,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
]
1.地图绘制
pushBox.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="Boxdata.js"></script>
</head>
<body>
<canvas id="mycanvas" height="800" width="800">
</canvas>
<script>
/** @type {HTMLCanvasElement} */
var canv = document.getElementById("mycanvas");
var ctx = canv.getContext("2d");
var level = levels[0];
var g={
wall:{color:'#333',data:[]},
target:{color:'#9f3',data:[]},
box:{color:'rgba(255,50,0,0.8)',data:[]},
player:{color:'rgba(255,220,0,0.8)',data:[]}
}
var objects = ['wall','target','box','player'];
for(let i=0;i<16;i++){
for(let j=0;j<16;j++){
let d=level[i][j];
let id = i*16+j;
if(d>0){
if(d==5){
g['target'].data.push(id);
g['box'].data.push(id);
}else{
g[objects[d-1]].data.push(id);
}
}
}
}
g['wall'].data.forEach(n=>drawRRect('wall',n))
g['target'].data.forEach(n=>drawRRect('target',n))
g['box'].data.forEach(n=>drawRRect('box',n))
g['player'].data.forEach(n=>drawRRect('player',n))
// 绘制圆角矩形
function drawRRect(object,id){
let w = 800/16,r=5,m=2;
let [x,y] = [id%16*w,~~(id/16)*w]; //~~取整
ctx.save();
if(object=='target'){
r=24
}
ctx.beginPath();
ctx.moveTo(x,y+r);
ctx.arcTo(x,y+w-m,x+w-m,y+w-m,r);
ctx.arcTo(x+w-m,y+w-m,x+w-m,y+w-m-r,r);
ctx.arcTo(x+w-m,y,x,y,r);
ctx.arcTo(x,y,x,y+w-m,r);
ctx.fillStyle=g[object].color;
ctx.fill();
ctx.restore();
}
</script>
</body>
</html>
2.移动玩家角色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="Boxdata.js"></script>
</head>
<body>
<canvas id="mycanvas" height="800" width="800">
</canvas>
<script>
/** @type {HTMLCanvasElement} */
var canv = document.getElementById("mycanvas");
var ctx = canv.getContext("2d");
var level = levels[0];
var g={
wall:{color:'#333',data:[]},
target:{color:'#9f3',data:[]},
box:{color:'rgba(255,50,0,0.8)',data:[]},
player:{color:'rgba(255,220,0,0.8)',data:[]}
}
var objects = ['wall','target','box','player'];
for(let i=0;i<16;i++){
for(let j=0;j<16;j++){
let d=level[i][j];
let id = i*16+j;
if(d>0){
if(d==5){
g['target'].data.push(id);
g['box'].data.push(id);
}else{
g[objects[d-1]].data.push(id);
}
}
}
}
g['wall'].data.forEach(n=>drawRRect('wall',n))
g['target'].data.forEach(n=>drawRRect('target',n))
g['box'].data.forEach(n=>drawRRect('box',n))
g['player'].data.forEach(n=>drawRRect('player',n))
// 绘制圆角矩形
function drawRRect(object,id){
let w = 800/16,r=5,m=2;
let [x,y] = [id%16*w,~~(id/16)*w]; //~~取整
ctx.save();
if(object=='target'){
r=24
}
ctx.beginPath();
ctx.moveTo(x,y+r);
ctx.arcTo(x,y+w-m,x+w-m,y+w-m,r);
ctx.arcTo(x+w-m,y+w-m,x+w-m,y+w-m-r,r);
ctx.arcTo(x+w-m,y,x,y,r);
ctx.arcTo(x,y,x,y+w-m,r);
ctx.fillStyle=g[object].color;
ctx.fill();
ctx.restore();
}
//添加键盘监听
document.addEventListener('keydown',ev=>{
//方向键,根据方向键,dir移动的id
let dir = [-1,-16,1,16][ev.keyCode-37]
console.log(ev.code,ev.keyCode,dir)
let player = g.player.data[0]
let index = g['player'].data.indexOf(player)
console.log(player,index)
move('player',player,dir)
})
//移动玩家角色和箱子
function move(who,id,dir){
let next = id+dir
let index = g[who].data.indexOf(id)
g[who].data[index]=next
//重绘地图
ctx.clearRect(0,0,800,800)
objects.forEach(obj=>g[obj].data.forEach(n=>drawRRect(obj,n)))
}
</script>
</body>
</html>
3. 添加撞墙判断,移动箱子和过关判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="Boxdata.js"></script>
</head>
<body>
<canvas id="mycanvas" height="800" width="800">
</canvas>
<script>
/** @type {HTMLCanvasElement} */
var canv = document.getElementById("mycanvas");
var ctx = canv.getContext("2d");
var level = levels[0];
var g={
wall:{color:'#333',data:[]},
target:{color:'#9f3',data:[]},
box:{color:'rgba(255,50,0,0.8)',data:[]},
player:{color:'rgba(255,220,0,0.8)',data:[]}
}
var objects = ['wall','target','box','player'];
for(let i=0;i<16;i++){
for(let j=0;j<16;j++){
let d=level[i][j];
let id = i*16+j;
if(d>0){
if(d==5){
g['target'].data.push(id);
g['box'].data.push(id);
}else{
g[objects[d-1]].data.push(id);
}
}
}
}
g['wall'].data.forEach(n=>drawRRect('wall',n))
g['target'].data.forEach(n=>drawRRect('target',n))
g['box'].data.forEach(n=>drawRRect('box',n))
g['player'].data.forEach(n=>drawRRect('player',n))
// 绘制圆角矩形
function drawRRect(object,id){
let w = 800/16,r=5,m=2;
let [x,y] = [id%16*w,~~(id/16)*w]; //~~取整
ctx.save();
if(object=='target'){
r=24
}
ctx.beginPath();
ctx.moveTo(x,y+r);
ctx.arcTo(x,y+w-m,x+w-m,y+w-m,r);
ctx.arcTo(x+w-m,y+w-m,x+w-m,y+w-m-r,r);
ctx.arcTo(x+w-m,y,x,y,r);
ctx.arcTo(x,y,x,y+w-m,r);
ctx.fillStyle=g[object].color;
ctx.fill();
ctx.restore();
}
//添加键盘监听
document.addEventListener('keydown',ev=>{
//方向键,根据方向键,dir移动的id
let dir = [-1,-16,1,16][ev.keyCode-37]
let playerid = g.player.data[0]
let next = playerid+dir
//判断是否撞墙
if(g.wall.data.includes(next)) return
//判断是否移动箱子
if(g.box.data.includes(next)){
let boxid=next
let boxnext = boxid+dir
//判断箱子是否撞墙或撞箱子
if(g.wall.data.includes(boxnext)||g.box.data.includes(boxnext)) return
move('box',boxid,dir)
}
//移动玩家角色
move('player',playerid,dir)
//判断游戏结束
checkOver()
})
//移动玩家角色和箱子
function move(who,id,dir){
let next = id+dir
let index = g[who].data.indexOf(id)
g[who].data[index]=next
//重绘地图
ctx.clearRect(0,0,800,800)
objects.forEach(obj=>g[obj].data.forEach(n=>drawRRect(obj,n)))
}
//判断游戏结束
function checkOver(){
let win = g.box.data.every(b=>g.target.data.includes(b))
if(win){
setTimeout(()=>{
alert("恭喜过关!")
},100)
}
}
</script>
</body>
</html>