实现一个简易的俄罗斯方块
index.html
<!--
* @Author: zhouwenbo 2660841146@qq.com
* @Date: 2023-02-03 20:17:29
* @LastEditors: zhouwenbo 2660841146@qq.com
* @LastEditTime: 2023-02-05 19:34:54
* @FilePath: \俄罗斯方块\index.html
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https:
-->
<!--
主要思路:
使用定时器,每秒渲染一次
更新分数
清空路径
渲染单元格和预览单元格
渲染地图
判断下落
若单元格停止
判断游戏状态
重新初始化下落时间
判断消行
-->
<!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>
<style>
* {
margin: 0;
padding: 0;
}
body {
overflow: hidden;
height: 100%;
padding-top: 20px;
padding-left: 50px;
}
table {
border-collapse: collapse;
/*合并边框*/
margin: 0 auto;
float: left;
margin-right: 20px;
}
td {
border: 1px solid black;
width: 25px;
height: 25px;
}
.c1 {
background: blue;
}
</style>
</head>
<body>
<div>
<div>
<span onclick='start()'>Start Game</span>
<span id='score' style="padding-left: 160px;">积分:0</span>
<span style="padding-left: 20px;">Next</span>
</div>
<div id="tableDiv">
</div>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/cellThreeList.js"></script>
<script>
// let button = $("<button onclick='start()'>开始</button>");
// let span = $("<span id='score'>分数:0</span>");
// $(button).appendTo("body")
// $(span).appendTo("body")
//初始化地图
let table = $("<table></table>");
table.addClass('tab1');
//渲染表格
for (let i = 0; i < 20; i++) {
let tr = $("<tr></tr>")
for (let j = 0; j < 12; j++) {
let td = $("<td></td>")
td.appendTo(tr);
}
tr.appendTo(table);
}
//初始化预览窗口
let table2 = $("<table></table>");
table2.addClass('tab2');
for (let i = 0; i < 3; i++) {
let tr = $("<tr></tr>")
for (let j = 0; j < 3; j++) {
let td = $("<td></td>")
td.appendTo(tr);
}
tr.appendTo(table2);
}
$(table).appendTo("#tableDiv")
$(table2).appendTo("#tableDiv")
let game
function start() {
game = new Game();
}
//主控制函数
//下落速度
window.constTimer = 1000;
function Game() {
//设置行和列
this.row = 20;
this.col = 12;
//实例化单元格
this.cells = new Cells();
//实例化下一个block
this.nextBlock = new Cells();
//实例化地图
this.map = new TableMap();
//启动定时器
this.start(window.constTimer);
//事件监听
this.bindEvent();
//分数
this.score = 0;
}
//清屏功能
Game.prototype.clear = function () {
for (let i = 0; i < this.row; i++) {
for (let j = 0; j < this.col; j++) {
$(".tab1").find("tr").eq(i).children("td").eq(j).removeClass();
}
}
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
$(".tab2").find("tr").eq(i).children("td").eq(j).removeClass();
}
}
}
Game.prototype.setColor = function (row, col, num) {
// debugger;
//给对应单元格上色
$(".tab1").find("tr").eq(row).children("td").eq(col).addClass("c" + num)
}
//渲染下一个单元格的颜色
Game.prototype.setNextColor = function (row, col, num) {
// debugger;
//给对应单元格上色
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (this.nextBlock.code[i][j] != 0) {
$(".tab2").find("tr").eq(i).children("td").eq(j).addClass("c" + this.nextBlock.code[i][j])
}
}
}
}
Game.prototype.bindEvent = function () {
//备份
// debugger
let self = this;
$(document).keydown(function (event) {
// console.log(event.keyCode);
if (event.keyCode == 65) {
//判断是否可以向左移动
debugger
self.cells.checkLeft()
}
else if (event.keyCode == 68) {
//判断是否可以向右移动
self.cells.checkRight()
}
else if (event.keyCode == 83) {
// debugger
//加快下落速度
window.constTimer = 250;
// window.boolResive = false;
clearInterval(self.timer);
self.start(window.constTimer);
}
else if (event.keyCode == 87) {
self.cells.rotate();
}
})
}
Game.prototype.start = function (constTimer) {
let self = this;
this.timer = setInterval(function () {
//渲染分数
$("#score").html(`积分:${self.score}`);
//清屏
self.clear();
//渲染单元格
self.cells.render();
//渲染预览单元格
self.setNextColor();
//渲染地图
self.map.render();
//下落
self.cells.checkDown();
}, constTimer)
}
//单元格控制
//矩阵行
const constRow = 3;
//矩阵列
const constCol = 3;
function Cells() {
// this.cells = [
// [0,1,0],
// [0,1,0],
// [0,1,0]
// ]
//罗列所有的类型
let allType = ["L", "C", "O"]
//随机出一种类型,得到一个随机小数,乘以长度取整后得到随机的状态
this.type = allType[parseInt(Math.random() * allType.length)];
// console.log(this.type);
//获取当前类型的形状的数量(PS:不同的的类型形状数量不同)
this.allDir = cellsAll[this.type].length;
this.dir = parseInt(Math.random() * this.allDir);
this.code = cellsAll[this.type][this.dir]
//初始的行
this.row = 0;
//初始的列
this.col = 5;
}
Cells.prototype.render = function () {
// debugger;
//渲染单元格
for (let i = 0; i < constRow; i++) {
for (let j = 0; j < constCol; j++) {
//如果矩阵中不为零的单元格需要有颜色
if (this.code[i][j] != 0) {
game.setColor(i + this.row, j + this.col, this.code[i][j]);
}
}
}
}
Cells.prototype.check = function (row, col) {
//判断单元格是否与地图重叠
// debugger
for (let i = 0; i < constRow; i++) {
for (let j = 0; j < constCol; j++) {
//如果矩阵中不为零的单元格需要有颜色
// if(i+row>19){
// return false;
// }
if (this.code[i][j] != 0 && game.map.mapCode[i + row][j + col] != 0) {
return false;
}
}
}
return true;
};
//判断当前单元格是否能过够下落
Cells.prototype.checkDown = function () {
//判断地图和单元格是否重叠,this.row+1指的是预判断
if (this.check(this.row + 1, this.col)) {
this.row++;
} else {
//此时单元格停止
//将下一个单元格渲染到本次
game.cells = game.nextBlock;
//重新渲染预览框的单元格
game.nextBlock = new Cells();
// window.boolResive = true;
//将单元格渲染到地图上
this.renderMap();
//重置刷新时间(新单元格回到原来的下落速度)
window.constTimer = 1000;
clearInterval(game.timer);
game.start(window.constTimer);
//判断消行
game.map.checkRemove()
//判断游戏是否结束
this.gameOver()
}
}
//判断单元格是否可以向左移动
Cells.prototype.checkLeft = function () {
//判断是否可以向左
// debugger
if (this.check(this.row, this.col - 1)) {
this.col--;
}
}
//判断单元格是否可以向右移动
Cells.prototype.checkRight = function () {
//判断是否可以向右
if (this.check(this.row, this.col + 1)) {
this.col++;
}
}
//旋转方法
Cells.prototype.rotate = function () {
//保存旧形状的方向
let oldDir = this.dir;
//改变新的形状
this.dir++;
//判断如果索引值越位,重新初始化形状数值
if (this.dir > this.allDir - 1) {
this.dir = 0;
}
//渲染新的形状
this.code = cellsAll[this.type][this.dir];
//判断单元格是否可以旋转
if (!this.check(this.row, this.col)) {
//与地图重合,回到旧的形状
this.dir = oldDir;
//再次渲染单元格
this.code = cellsAll[this.type][this.dir];
}
}
//降落落地的单元格渲染到地图中
Cells.prototype.renderMap = function () {
for (let i = 0; i < constRow; i++) {
for (let j = 0; j < constCol; j++) {
if (this.code[i][j] != 0) {
//改变地图数据
game.map.mapCode[this.row + i][this.col + j] = this.code[i][j];
}
}
}
}
//检查游戏是否结束
Cells.prototype.gameOver = function () {
for (let i = 0; i < game.col; i++) {
//检查地图数组的第一行,若有不为零的项则游戏终止
if (game.map.mapCode[0][i] != 0) {
clearInterval(game.timer);
alert("游戏结束," + $("#score").text());
}
}
}
//表格地图控制
function TableMap() {
this.mapCode = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
]
//地图的行列数
this.maprow = 20;
this.mapcol = 12;
}
//持久化地图
TableMap.prototype.render = function () {
// debugger;
//渲染单元格
for (let i = 0; i < this.maprow; i++) {
for (let j = 0; j < this.mapcol; j++) {
//如果矩阵中不为零的单元格需要有颜色
if (this.mapCode[i][j] != 0) {
game.setColor(i, j, this.mapCode[i][j])
}
}
}
}
//地图消行
TableMap.prototype.checkRemove = function () {
//判断map行,全是0的话消除
for (let i = 0; i < this.maprow; i++) {
if (this.mapCode[i].indexOf(0) == -1) {
//删除一行
this.mapCode.splice(i, 1);
//头部添加一行
this.mapCode.unshift([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
//分数增加
game.score++;
}
}
}
// setInterval(function(){
// if(window.boolResive){
// game.start(window.constTimer);
// }
// },1)
</script>
</body>
</html>
cellThreeList.js
let cellsAll = {
"L":[
[
[0,1,0],
[0,1,0],
[0,1,0]
],
[
[1,1,1],
[0,0,0],
[0,0,0]
]
],
"C":[
[
[1,1,0],
[1,0,0],
[0,0,0]
],
[
[1,0,0],
[1,1,0],
[0,0,0]
],
[
[0,1,0],
[1,1,0],
[0,0,0]
],
[
[1,1,0],
[0,1,0],
[0,0,0]
]
],
"O":[
[
[1,1,0],
[1,1,0],
[0,0,0]
]
]
}