视频学习ES6+jQuery制作俄罗斯方块 代码

2 篇文章 0 订阅

1、HTML代码

<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <title>瓜娃子</title>
	<meta name="viewport" content="width=device-width,initial-scale=1">
    <script
			src="jquery.js">
	</script>
</head>
<body style="background: #aaa;position: fixed">
	<script src="js/index.js"></script>
</body>
</html>

2、js代码

//定义游戏数据    宽度10格 高度20格
blocks = [
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[2, 2, 2, 0, 0, 0, 0, 0, 0, 0],
];

//封装场地类
class Map {
	//设置格子大小 30
	size = 30;
	//设置格子的间距
	margin = 5;
	//创建格子的元素列表
	blocks = [];
	
	//封装显示场地的方法
	show() {
		//在页面中创建一个div 来代表我们的场地
		var map = $('<div></div>')
		//设置宽高
				.width(10 * this.size + 9 * this.margin)
				.height(20 * this.size + 19 * this.margin)
				//设置基础样式
				.css({
					backgroundColor: '#ccc',
					position: 'absolute'
				})
				//追加到body中
				.appendTo('body');
		//循环20*10次创建小格子
		
		for (var y = 0; y < 20; y++) {
			//每行创建一个
			this.blocks.push([]);
			for (var x = 0; x < 10; x++) {
				//循环创建小格子
				this.blocks[y].push($('<div></div>')
						//设置宽高
								.width(this.size)
								.height(this.size)
								//设置基础样式
								.css({
									backgroundColor: 'white',
									position: 'absolute'
								})
								//设置坐标
								.offset({
									left: x * (this.size + this.margin),
									top: y * (this.size + this.margin)
								})
								//追加到地图中
								.appendTo(map)
				);
			}
		}
	}
	
	//封装砖块的渲染方法
	render() {
		
		//遍历砖块的数据,给对应的砖块div设置颜色
		//空格子0白色,可移动方块1蓝色,固定方块2黑色
		for (var y = 0; y < 20; y++) {
			for (var x = 0; x < 10; x++) {
				switch (blocks[y][x]) {
					case 0:
						this.blocks[y][x].css('backgroundColor', 'white');
						break;
					case 1:
						this.blocks[y][x].css('backgroundColor', 'blue');
						break;
					case 2:
						this.blocks[y][x].css('background-color', 'black');
						break;
				}
			}
		}
	}
	
	//封装砖块的改变方法
	//@param1 prev num 旧的砖块数据
	//@param2 next num 新的砖块数据
	change(prev, next) {
		for (var y = 0; y < 20; y++) {
			for (var x = 0; x < 10; x++) {
				//判断当前砖块数据是否为prev 将其转变为next
				if (blocks[y][x] == prev) {
					blocks[y][x] = next;
				}
			}
		}
	}


//封装玩家移动方法
	
	//封装向左移动的方法
	left() {
		//要判断左移的前提条件
		var flag = true;
		//循环找到可移动砖块,并观察其x是否为0,为0 则说明移动到了左边界
		for (var y = 0; y < 20; y++) {
			for (var x = 0; x < 10; x++) {
				//如果有任何一个可移动格子移动到边界,则左移全部结束 flag为false
				if (blocks[y][x] == '1' && x == 0) {
					flag = false;
					//还需要判断可移动格子的左边是否碰到固定砖块2,碰到则左移也结束
				} else if (blocks[y][x] == 1 && blocks[y][x - 1] == 2) {
					flag = false;
				}
			}
		}
		//当flag为true时,说明不在边界,当flag为false时,说明在边界,则不移动
		if (flag) {
			for (var y = 0; y < 20; y++) {
				for (var x = 0; x < 10; x++) {
					//判断当前砖块是否为可移动砖块
					if (blocks[y][x] == '1') {
						//把这个格子本身设置为0
						blocks[y][x] = 0;
						//把这个格子左边设置为1
						blocks[y][x - 1] = 1;
					}
				}
			}
		}
		//让形状的原点左移
		//实例化Shape后shape下的origin属性
		shape.origin[1]--;
		
		//左移后立刻渲染,放置玩家移动过快导致间隔函数没有渲染
		map.render();
	}
	
	
	//向右移动
	right() {
		//要判断右移的前提条件
		var flag = true;
		//循环找到可移动砖块,并观察其x是否为9,为9 则说明移动到了右边界
		//循环要注意,最先移动的格子是最右边的,所有要从右到左循环遍历
		for (var y = 19; y >= 0; y--) {
			for (var x = 9; x >= 0; x--) {
				//如果有任何一个可移动格子移动到边界,则右移全部结束 flag为false
				if (blocks[y][x] == '1' && x == 9) {
					flag = false;
					//还需要判断可移动格子的左边是否碰到固定砖块2,碰到则左移也结束
				} else if (blocks[y][x] == 1 && blocks[y][x + 1] == 2) {
					flag = false;
				}
			}
		}
		//当flag为true时,说明不在边界,当flag为false时,说明在边界,则不移动
		if (flag) {
			for (var y = 19; y >= 0; y--) {
				for (var x = 9; x >= 0; x--) {
					//判断当前砖块是否为可移动砖块
					if (blocks[y][x] == '1') {
						//把这个格子本身设置为0
						blocks[y][x] = 0;
						//把这个格子右边设置为1
						blocks[y][x + 1] = 1;
					}
				}
			}
		}
		//让形状原点右移动
		shape.origin[1]++;
		
		//右移后立刻渲染,放置玩家移动过快导致间隔函数没有渲染
		map.render();
	}
	
	
	//向下移动
	down() {
		//要判断下移的前提条件
		var flag = true;
		//循环找到可移动砖块,并观察其y是否为19,为19 则说明移动到了下边界
		//循环要注意,最先移动的格子是最下边的,所有要从下到上循环遍历
		for (var y = 19; y >= 0; y--) {
			for (var x = 9; x >= 0; x--) {
				//如果有任何一个可移动格子移动到边界,则下移全部结束 flag为false
				if (blocks[y][x] == '1' && y == 19) {
					flag = false;
					//还需要判断可移动格子的下边是否碰到固定砖块2,碰到则下移也结束
				} else if (blocks[y][x] == 1 && blocks[y + 1][x] == 2) {
					flag = false;
				}
			}
		}
		//当flag为true时,说明不在边界,当flag为false时,说明在边界,则不移动
		if (flag) {
			for (var y = 19; y >= 0; y--) {
				for (var x = 9; x >= 0; x--) {
					//判断当前砖块是否为可移动砖块
					if (blocks[y][x] == '1') {
						//把这个格子本身设置为0
						blocks[y][x] = 0;
						//把这个格子下边设置为1
						blocks[y + 1][x] = 1;
					}
				}
			}
		}
		//让形状原点下移动
		shape.origin[0]++;
		
		//右移后立刻渲染,放置玩家移动过快导致间隔函数没有渲染
		map.render();
	}
	
	//封装可移动方块的检测方法,如果地图中已经没有可移动砖块,添加一个
	moveTest() {
		var flag = true;
		for (var y = 19; y >= 0; y--) {
			for (var x = 9; x >= 0; x--) {
				if (blocks[y][x] == 1) {
					flag = false;
				}
			}
		}
		if (flag) {
			shape.addShape();
		}
	}
	
	//封装底部的检测
	bottomTest() {
		var flag = false;
		shape.getPos(shape.type, shape.angle).forEach(pos => {
			//判断当前形状的砖块是否到达底部
			if (pos[0] >= 19) {
				flag = true;
				//判断当前形状的方块下方是否为固定方块
			} else if (blocks[pos[0] + 1][pos[1]] == 2) {
				flag = true;
			}
		});
		if (flag) {
			//把目前场地中所有的可移动方块转变成固定方块
			this.change(1, 2);
		}
	}
	
	//消除检测
	clearTest() {
		blocks.forEach((row, y) => {
			//检测这一行是否全部为固定方块
			var flag = row.every(block => {
				return block == 2;
			});
			if (flag) {
				//消除这一行
				blocks.splice(y, 1);
				//在砖块数据的最上方补一行
				blocks.unshift([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
				
			}
		});
	}
	
}

//封装形状类shape
class Shape {
	//定义一个属性,代表形状类型0~6   7种类型
	type = 0;
	//形状的角度     4个角度
	angle = 0;
	//形状数据
	shapes = [
		//1\定义 一字型 数据
		[
			[
				[1, 1, 1, 1],
				[0, 0, 0, 0],
				[0, 0, 0, 0],
				[0, 0, 0, 0],
			],
			[
				[0, 1, 0, 0],
				[0, 1, 0, 0],
				[0, 1, 0, 0],
				[0, 1, 0, 0],
			],
			[
				[1, 1, 1, 1],
				[0, 0, 0, 0],
				[0, 0, 0, 0],
				[0, 0, 0, 0],
			],
			[
				[0, 1, 0, 0],
				[0, 1, 0, 0],
				[0, 1, 0, 0],
				[0, 1, 0, 0],
			]
		],
		//2\定义 T字形 数据
		[
			[
				[0, 1, 0],
				[1, 1, 1],
				[0, 0, 0]
			],
			[
				[0, 1, 0],
				[0, 1, 1],
				[0, 1, 0]
			],
			[
				[0, 0, 0],
				[1, 1, 1],
				[0, 1, 0]
			],
			[
				[0, 1, 0],
				[1, 1, 0],
				[0, 1, 0]
			]
		],
		//3\定义Z字形数据
		[
			[
				[0, 1, 1],
				[1, 1, 0],
				[0, 0, 0]
			],
			[
				[1, 0, 0],
				[1, 1, 0],
				[0, 1, 0]
			],
			[
				[0, 0, 0],
				[0, 1, 1],
				[1, 1, 0]
			],
			[
				[1, 0, 0],
				[1, 1, 0],
				[0, 1, 0]
			]
		],
		//4\定义7字形数据
		[
			[
				[1, 1, 1],
				[1, 0, 0],
				[0, 0, 0]
			],
			[
				[1, 1, 0],
				[0, 1, 0],
				[0, 1, 0]
			],
			[
				[0, 0, 1],
				[1, 1, 1],
				[0, 0, 0]
			],
			[
				[0, 1, 0],
				[0, 1, 0],
				[0, 1, 1]
			]
		],
		//5\定义反7字形数据
		[
			[
				[1, 1, 1],
				[0, 0, 1],
				[0, 0, 0]
			],
			[
				[0, 0, 1],
				[0, 0, 1],
				[0, 1, 1]
			],
			[
				[0, 0, 0],
				[1, 0, 0],
				[1, 1, 1]
			],
			[
				[1, 1, 0],
				[1, 0, 0],
				[1, 0, 0]
			]
		],
		//6\定义反Z字形数据
		[
			[
				[1, 1, 0],
				[0, 1, 1],
				[0, 0, 0]
			],
			[
				[0, 1, 0],
				[1, 1, 0],
				[1, 0, 0]
			],
			[
				[0, 0, 0],
				[1, 1, 0],
				[0, 1, 1]
			],
			[
				[0, 0, 1],
				[0, 1, 1],
				[0, 1, 0]
			]
		],
		//定义田字类
		[
			[
				[1, 1],
				[1, 1]
			],
			[
				[1, 1],
				[1, 1]
			],
			[
				[1, 1],
				[1, 1]
			],
			[
				[1, 1],
				[1, 1]
			],
		]
	
	];
	//定义形状的原点
	origin = [0, 3];
	
	//封装形状砖块坐标推导方法的工具
	getPos(type, angle) {
		//获取相对应形状的数据
		var shape = this.shapes[type][angle];
		//储存形状的坐标
		var pos = [];
		
		//遍历形状数据,根据原点, 推算出可移动方块的坐标
		//row即item  y 即index
		shape.forEach((row, y) => {
			row.forEach((block, x) => {
				if (block == 1) {
					pos.push([this.origin[0] + y, this.origin[1] + x]);
				}
			});
		});
		return pos;
	}
	
	//封装显示形状方法
	show() {
		//调用getPos方法,获得可移动砖块的坐标,把对应坐标数据设置为1即可
		this.getPos(this.type, this.angle).forEach(pos => {
			blocks[pos[0]][pos[1]] = 1;
		});
	}
	
	//封装新增形状方法
	addShape() {
		//重置形状原点坐标
		this.origin = [0, 3];
		//重置形状的角度angle
		this.angle = 0;
		
		//生成随机形状 0~6    向下取整
		this.type = Math.floor(Math.random() * 7);
		//检测这个新的形状是否会与固定方块重合
		var flag = true;
		this.getPos(this.type, this.angle).forEach(pos => {
			if (blocks[pos[0]][pos[1]] == 2) {
				flag = false;
			}
		});
		if (flag) {
			//显示新的形状
			this.show();
		} else {
			clearInterval(timer);
			//游戏结束
			console.log('游戏结束');
			alert('游戏结束');
		}
	}
	
	//封装形状旋转方法
	rotate() {
		//根据旧的角度 得到新的角度
		//对this.angle+1除4取余数 只剩下0,1,2,3
		var newAngle = (this.angle + 1) % 4;
		
		//判断新的方块是否会与固定方块重合
		//判断方块是否会超出边界   //forEach中的pos相当于item
		//根据推导坐标方法,推导出下次旋转后的坐标,循环判断
		var flag = true;
		this.getPos(this.type, newAngle).forEach(pos => {
			//判断旋转后的方块是否有出边界的
			if (pos[0] > 19) {
				flag = false;
			} else if (pos[1] < 0 || pos[1] > 9) {
				flag = false;
			} else if (blocks[pos[0]][pos[1]] == 2) {
				flag = false;
			}
		});
		
		//当flag为true时 才通过
		if (flag) {
			//设置新的角度
			this.angle = newAngle;
			
			//清除旧方块
			map.change(1, 0);
			
			//显示新的方块
			this.show();
			
			//渲染地图
			map.render();
		}
		
		
	}
}

//实例化的调用
var map = new Map();
var shape = new Shape();
map.show();
map.render();


//创建定时器,每隔一秒帮忙刷新场地数据
var timer = setInterval(function () {
	map.bottomTest();
	map.clearTest();
	map.down();
	map.moveTest();
	map.render();
}, 1000);

//提供玩家操作的接口
$(document).keydown((event) => {
	console.log(event.key);
	switch (event.key) {
		case 'ArrowUp':
			shape.rotate();
			break;
		case 'ArrowDown':
			map.down();
			break;
		case 'ArrowLeft':
			map.left();
			break;
		case 'ArrowRight':
			map.right();
			break;
	}
});
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值