HTML+CSS+JS实现推箱子小游戏

1.实现效果

 

源码如下

index.html


<!doctype html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="Keywords" content="关键词">
		<meta name="Description" content="描述">
		<title>经典html5推箱子小游戏</title>
		<style>
		*{
			margin:0px;
			padding:0px;
		}
		body{
			overflow:hidden;
		}
		.game{
			width:560px;
			margin:50px auto;
		}
		</style>
	</head>
	<body onkeydown="doKeyDown(event)"><!--身体-->
		<div class="game">
			<canvas id="canvas" width="560" height="560"></canvas>
			<div id="msg"></div>
			<input type="button" value="上一关" onclick="NextLevel(-1)">
			<input type="button" value="下一关" onclick="NextLevel(1)">
			<input type="button" value="重玩本关" onclick="NextLevel(0)">
			<input type="button" value="游戏说明" onclick="showHelp()">
		</div>
	</body>
	<script src="js/mapdata100.js"></script>
	<script>
		var can = document.getElementById("canvas");
		var msg = document.getElementById("msg");
		var cxt = can.getContext("2d");
		var w = 35,h = 35;
		var curMap;//当前的地图
		var curLevel;//当前等级的地图
		var curMan;//初始化小人
		var iCurlevel = 0;//关卡数
		var moveTimes = 0;//移动了多少次
		//预加载所有图片
		var oImgs = {
			"block" : "images/block.gif",
			"wall" : "images/wall.png",
			"box" : "images/box.png",
			"ball" : "images/ball.png",
			"up" : "images/up.png",
			"down" : "images/down.png",
			"left" : "images/left.png",
			"right" : "images/right.png",
		}
		function imgPreload(srcs,callback){
			var count = 0,imgNum = 0,images = {};

			for(src in srcs){
				imgNum++;
			}
			for(src in srcs ){
				images[src] = new Image();
				images[src].onload = function(){
					//判断是否所有的图片都预加载完成
					if (++count >= imgNum)
					{
						callback(images);
					}
				}
				images[src].src = srcs[src];
			}
		}
		var block,wall,box,ball,up,down,left,right;
		imgPreload(oImgs,function(images){
			//console.log(images.block);
			block = images.block;
			wall = images.wall;
			box = images.box;
			ball = images.ball;
			up = images.up;
			down = images.down;
			left = images.left;
			right = images.right;
			init();
		});
		//初始化游戏
		function init(){
			//InitMap();
			//DrawMap(levels[0]);
			initLevel();//初始化对应等级的游戏
			showMoveInfo();//初始化对应等级的游戏数据
		}
		//绘制地板
		function InitMap(){
			for (var i=0;i<16 ;i++ )
			{
				for (var j=0;j<16 ;j++ )
				{
					cxt.drawImage(block,w*j,h*i,w,h);
				}
			}
		}
		//小人位置坐标
		function Point(x,y){
			this.x = x;
			this.y = y;
		}
		var perPosition = new Point(5,5);//小人的初始标值
		//绘制每个游戏关卡地图
		function DrawMap(level){
			for (var i=0;i<level.length ;i++ )
			{
				for (var j=0;j<level[i].length ;j++ )
				{
					var pic = block;//初始图片
					switch (level[i][j])
					{
					case 1://绘制墙壁
						pic = wall;
						break;
					case 2://绘制陷进
						pic = ball;
						break;
					case 3://绘制箱子
						pic = box;
						break;
					case 4://绘制小人
						pic = curMan;//小人有四个方向 具体显示哪个图片需要和上下左右方位值关联
						//获取小人的坐标位置
						perPosition.x = i;
						perPosition.y = j;
						break;
					case 5://绘制箱子及陷进位置
						pic = box;
						break;
					}
					//每个图片不一样宽 需要在对应地板的中心绘制地图
					cxt.drawImage(pic,w*j-(pic.width-w)/2,h*i-(pic.height-h),pic.width,pic.height)
				}
			}
		}
		//初始化游戏等级
		function initLevel(){
			curMap = copyArray(levels[iCurlevel]);//当前移动过的游戏地图
			curLevel = levels[iCurlevel];//当前等级的初始地图
			curMan = down;//初始化小人
			InitMap();//初始化地板
			DrawMap(curMap);//绘制出当前等级的地图
		}
		//下一关
		function NextLevel(i){
			//iCurlevel当前的地图关数
			iCurlevel = iCurlevel + i;
			if (iCurlevel<0)
			{
				iCurlevel = 0;
				return;
			}
			var len = levels.length;
			if (iCurlevel > len-1)
			{
				iCurlevel = len-1;
			}
			initLevel();//初始当前等级关卡
			moveTimes = 0;//游戏关卡移动步数清零
			showMoveInfo();//初始化当前关卡数据
		}
		//小人移动
		function go(dir){
			var p1,p2;
			switch (dir)
			{
			case "up":
				curMan = up;
				//获取小人前面的两个坐标位置来进行判断小人是否能够移动
				p1 = new Point(perPosition.x-1,perPosition.y);
				p2 = new Point(perPosition.x-2,perPosition.y);
				break;
			case "down":
				curMan = down;
				p1 = new Point(perPosition.x+1,perPosition.y);
				p2 = new Point(perPosition.x+2,perPosition.y);
				break;
			case "left":
				curMan = left;
				p1 = new Point(perPosition.x,perPosition.y-1);
				p2 = new Point(perPosition.x,perPosition.y-2);
				break;
			case "right":
				curMan = right;
				p1 = new Point(perPosition.x,perPosition.y+1);
				p2 = new Point(perPosition.x,perPosition.y+2);
				break;
			}
			//若果小人能够移动的话,更新游戏数据,并重绘地图
			if (Trygo(p1,p2))
			{
				moveTimes ++;
				showMoveInfo();
			}
			//重绘地板
			InitMap();
			//重绘当前更新了数据的地图
			DrawMap(curMap);
			//若果移动完成了进入下一关
			if (checkFinish())
			{
        //定时器解决渲染地图后再弹窗
        setTimeout(()=>{
          alert("恭喜过关!!");
				  NextLevel(1);
        },0)
				
			}
		}
		//判断是否推成功
		function checkFinish(){
			for (var i=0;i<curMap.length ;i++ )
			{
				for (var j=0;j<curMap[i].length ;j++ )
				{
					//当前移动过的地图和初始地图进行比较,若果初始地图上的陷进参数在移动之后不是箱子的话就指代没推成功
					if (curLevel[i][j] == 2 && curMap[i][j] != 3 || curLevel[i][j] == 5 && curMap[i][j] != 3)
					{
						return false;
					}
				}
			}
			return true;
		}
		//判断小人是否能够移动
		function Trygo(p1,p2){
			if(p1.x<0) return false;//若果超出地图的上边,不通过
			if(p1.y<0) return false;//若果超出地图的左边,不通过
			if(p1.x>curMap.length) return false;//若果超出地图的下边,不通过
			if(p1.y>curMap[0].length) return false;//若果超出地图的右边,不通过
			if(curMap[p1.x][p1.y]==1) return false;//若果前面是墙,不通过
			if (curMap[p1.x][p1.y]==3 || curMap[p1.x][p1.y]==5)
			{//若果小人前面是箱子那就还需要判断箱子前面有没有障碍物(箱子/墙)
				if (curMap[p2.x][p2.y]==1 || curMap[p2.x][p2.y]==3)
				{
					return false;
				}
				//若果判断不成功小人前面的箱子前进一步
				curMap[p2.x][p2.y] = 3;//更改地图对应坐标点的值
				//console.log(curMap[p2.x][p2.y]);
			}
			//若果都没判断成功小人前进一步
			curMap[p1.x][p1.y] = 4;//更改地图对应坐标点的值
			//若果小人前进了一步,小人原来的位置如何显示
			var v = curLevel[perPosition.x][perPosition.y];
			if (v!=2)//若果刚开始小人位置不是陷进的话
			{
				if (v==5)//可能是5 既有箱子又陷进
				{
					v=2;//若果小人本身就在陷进里面的话移开之后还是显示陷进
				}else{
					v=0;//小人移开之后之前小人的位置改为地板
				}
			}
			//重置小人位置的地图参数
			curMap[perPosition.x][perPosition.y] = v;
			//若果判断小人前进了一步,更新坐标值
			perPosition = p1;
			//若果小动了 返回true 指代能够移动小人
			return true;
		}
		//判断是否推成功
		//与键盘上的上下左右键关联
		function doKeyDown(event){
			switch (event.keyCode)
			{
			case 37://左键头
      case 65:
				go("left");
				break;
			case 38://上键头
      case 87:
				go("up");
				break;
			case 39://右箭头
      case 68:
				go("right");
				break;
			case 40://下箭头
      case 83:
				go("down");
				break;
			}

		}
		//完善关卡数据及游戏说明
		function showMoveInfo(){
			msg.innerHTML = "第" + (iCurlevel+1) +"/100关 移动次数: "+ moveTimes;
		}
		//游戏说明
		var showhelp = false;
		function showHelp(){
			showhelp = !showhelp;
			if (showhelp)
			{
				msg.innerHTML = "用键盘上的上、下、左、右键移动小人,把箱子全部推到小球的位置即可过关。箱子只可向前推,不能往后拉,并且小人一次只能推动一个箱子。";
			}else{
				showMoveInfo();
			}
		}

		//克隆二维数组
		function copyArray(arr){
			var b=[];//每次移动更新地图数据都先清空再添加新的地图
			for (var i=0;i<arr.length ;i++ )
			{
				b[i] = arr[i].concat();//链接两个数组
			}
			return b;
		}
	</script>
</html>

JS


//1:围墙   2:目标点   3:箱子    4:人物
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,0,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,0],
[0,0,0,0,1,1,1,3,0,3,2,1,0,0,0,0],
[0,0,0,0,1,2,0,3,4,1,1,1,0,0,0,0],
[0,0,0,0,1,1,1,1,3,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1,2,1,0,0,0,0,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,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]];

levels[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,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,1,4,0,0,1,0,0,0,0,0,0,0],
[0,0,0,0,1,0,3,3,1,0,1,1,1,0,0,0],
[0,0,0,0,1,0,3,0,1,0,1,2,1,0,0,0],
[0,0,0,0,1,1,1,0,1,1,1,2,1,0,0,0],
[0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0],
[0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0],
[0,0,0,0,0,1,0,0,0,1,1,1,1,0,0,0],
[0,0,0,0,0,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]];


levels[2]=[
[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,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,1,1,3,1,1,1,0,0,0,1,0,0,0],
[0,0,0,1,0,4,0,3,0,0,3,0,1,0,0,0],
[0,0,0,1,0,2,2,1,0,3,0,1,1,0,0,0],
[0,0,0,1,1,2,2,1,0,0,0,1,0,0,0,0],
[0,0,0,0,1,1,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]];

图片给你们放这里

 

更多关卡请留言! 

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值