<!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>俄罗斯方块</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
overflow: hidden;
background-image: url("images/风景.webp");
/* 使背景图片保持大小。不受页面放大缩小的影响 */
background-size: 100%;
background-position-x: center;
background-repeat: no-repeat;
}
table{
border-collapse: collapse;
margin:20px auto;
float: left;
margin-right: 50px;
background-color: #252525;
}
td{
width: 30px;
height: 30px;
border: 1px solid rgb(84, 111, 112);
}
.c1{
background-color: aqua;
}
.c2{
background-color: rgb(230, 157, 89);
}
.c3{
background-color: rgb(58, 37, 175);
}
.c4{
background-color: rgb(192, 41, 159);
}
.c5{
background-color: rgb(194, 214, 83);
}
.c6{
background-color: rgb(26, 8, 8);
}
.c7{
background-color: rgb(226, 202, 196);
}
h2{
color: aliceblue;
}
</style>
</head>
<body>
<h2 id="score">分数:0</h2>
<h2 id="f">帧编号:0</h2>
</body>
</html>
<script src="js/jquery-3.4.1.js"></script>
<script src="js/GAME.js"></script>
<script src="js/block.js"></script>
<script src="js/block_json.js"></script>
<script src="js/Map.js"></script>
<script>
var game=new Game();
// var map=new Map();
// var block=new block();
// var block=new block();
// block.render();
// console.log(fk);
// var block=new block();
// block.render();
</script>
block_json.js
//俄罗斯方块有7种,4个方向
//用二维数组表示方块的状态
// [
// [0,0,0,0,0],
// [1,1,1,0,0],
// [0,1,0,0,0],
// [0,1,0,0,0]
// ]
//用三维数组表示俄罗斯方块的各个形态
var fk={
"S":[
[
[0,1,1,0],
[1,1,0,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,1,0,0],
[0,1,1,0],
[0,0,1,0],
[0,0,0,0]
],
],
"Z":[
[
[2,2,0,0],
[0,2,2,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,0,2,0],
[0,2,2,0],
[0,2,0,0],
[0,0,0,0]
],
],
"J":[
[
[0,3,0,0],
[0,3,0,0],
[3,3,0,0],
[0,0,0,0]
],
[
[3,0,0,0],
[3,3,3,0],
[0,0,0,0],
[0,0,0,0]
],
[
[0,3,3,0],
[0,3,0,0],
[0,3,0,0],
[0,0,0,0]
],
[
[3,3,3,0],
[0,0,3,0],
[0,0,0,0],
[0,0,0,0]
],
],
"L":[
[
[0,4,0,0],
[0,4,0,0],
[0,4,4,0],
[0,0,0,0]
],
[
[4,4,4,0],
[4,0,0,0],
[0,0,0,0],
[0,0,0,0]
],
[
[4,4,0,0],
[0,4,0,0],
[0,4,0,0],
[0,0,0,0]
],
[
[0,0,4,0],
[4,4,4,0],
[0,0,0,0],
[0,0,0,0]
],
],
"I":[
[
[0,5,0,0],
[0,5,0,0],
[0,5,0,0],
[0,5,0,0]
],
[
[5,5,5,5],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
]
],
"O":[
[
[0,6,6,0],
[0,6,6,0],
[0,0,0,0],
[0,0,0,0]
],
],
"T":[
[
[7,7,7,0],
[0,7,0,0],
[0,7,0,0],
[0,0,0,0]
],
[
[0,0,7,0],
[7,7,7,0],
[0,0,7,0],
[0,0,0,0]
],
[
[0,7,0,0],
[0,7,0,0],
[7,7,7,0],
[0,0,0,0]
],
[
[7,0,0,0],
[7,7,7,0],
[7,0,0,0],
[0,0,0,0]
],
],
}
block.js
(function () {
window.block=function(){
// this.block=[
// [0,1,1,0],
// [1,1,0,0],
// [0,0,0,0],
// [0,0,0,0]
// ];
//1.得到随机的方块
var allType=["S","Z","J","L","I","O","T"];
//2.从所有的类型中随机得到一种
this.type=allType[parseInt(Math.random()*allType.length)];
//3.得到随机图案的不同状态
this.allDar=fk[this.type].length;
//4.通过当前的allDar的长度随机得到不同的数字
this.dir=parseInt(Math.random()*this.allDar)
//得到随机的方块
this.code=fk[this.type][this.dir];
//初始的行
this.row=0;
//初始的列,因为要居中显示,所以列要为4
this.col=4;
}
block.prototype.render=function(){
//渲染四行四列的方块
for (i = 0; i < 4; i++) {
for(var j=0;j<4;j++){
//判断四行四列中不等于0的
if (this.code[i][j]!=0) {
game.setColor(i+this.row,j+this.col,this.code[i][j])
}
}
}
}
block.prototype.check=function(row,col){
//能力判断方法,判断对应位置的方块和地图是否都有不为0的情况,如果有返回true,否则返回false
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (this.code[i][j]!=0 && game.map.mapCode[i+row][j+col]!=0) {
return false;
}
}
}
return true;
}
//判断是否有向左移动的能力
block.prototype.checkLeft=function(){
//判断是否可以向左
if (this.check(this.row,this.col-1)) {
this.col--;
}
}
//判断是否有向右移动的能力
block.prototype.checkRight=function(){
//判断是否可以向右
if (this.check(this.row,this.col+1)) {
this.col++;
}
}
//一键到底
block.prototype.checkBotton=function(){
if (this.check(this.row+1,this.col)) {
//改变方向
this.row++;
}
}
//方块的旋转
block.prototype.checkRot=function(){
//备份旧的形状方向
var oldDir=this.dir;
//改变新的
this.dir++;
if (this.dir>this.allDar-1) {
this.dir=0;
}
//改变方向之后渲染新的方块方向
this.code=fk[this.type][this.dir];
// console.log(this.dir);
//渲染之后的方块需要判断,是否有能力渲染
if (!this.check(this.row,this.col)) {
//重合,打回原形
this.dir=oldDir;
//再次渲染方块
this.code=fk[this.type][this.dir]
}
}
//方块下落,判断当前的位置是否能下落
block.prototype.checkDown=function(){
//判断当前地图的位置和方块的位置是否重合,this.row+1是预判断
if (this.check(this.row+1,this.col)) {
this.row++;
}else{
//此时就是下落到底的状态,渲染新的方块
game.block=game.nextblock;//预测下一次
game.nextblock=new block();
//方块到底了,渲染到地图的code中
this.renderMap();
//判断是否可以消行
game.map.CheckRemove();
//判断是否游戏结束
this.checkOver();
}
}
//将已经到底的方块渲染到地图上
block.prototype.renderMap=function(){
for (var i = 0; i < 4; i++) {
//将现在已有的方块渲染到Map的mapCode上
for (var j = 0; j < 4; j++) {
if (this.code[i][j]!==0) {
//改变地图的mapCode数据
game.map.mapCode[this.row+i][this.col+j]=this.code[i][j];
}
}
}
}
//判断结束
block.prototype.checkOver=function(){
for (var i = 0; i < game.col; i++) {
if (game.map.mapCode[0][i]!=0) {
clearInterval(game.time);
alert("游戏结束,您当前的分数为"+game.score);
}
}
}
})()
Game.js
//最外层用IIFE包裹起来 实际中多个方法并行开发,将多个js文件打包成一个js文件,没有IIFE会造成作用域和命名的冲突
(function(){
window.Game=function(mapGame) {
//初始化
this.row=20;
this.col=12;
//初始化
this.init();
//实例化方块
this.block=new block();
//实例化下一个方块
this.nextblock=new block();
//实例化地图
this.map=new Map(this);
//启动定时器
this.start();
//事件监听
this.bindEvent();
//分数
this.score=0;
//速度
this.during=30;
}
Game.prototype.init=function(){
//初始化大表格
var $table=$("<table></table>")
$table.addClass("tab1");
for (var i = 0; i < this.row; i++) {
$tr=$("<tr></tr>")
for (var j = 0; j < this.col; j++) {
$td=$("<td></td>")
$tr.append($td)
}
$table.append($tr);
}
//初始化预览窗口
var $table2=$("<table></table>")
$table2.addClass("tab2");
for (var i = 0; i < 4; i++) {
$tr2=$("<tr></tr>")
for (var j = 0; j < 4; j++) {
$td2=$("<td></td>")
$tr2.append($td2)
}
$table2.append($tr2);
}
$("body").append($table);
$("body").append($table2);
}
Game.prototype.setColor=function(row,col,num){
//给对应的有颜色的方块添加类名
$(".tab1").find("tr").eq(row).children("td").eq(col).addClass("c"+num)
}
Game.prototype.setnextColor=function(row,col,num){
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; 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.clear=function(){
for (var i = 0; i < this.row; i++) {
for (var j = 0; j < this.col; j++) {
$(".tab1").find("tr").eq(i).children("td").eq(j).removeClass();
}
}
for (var i = 0; i < this.row; i++) {
for (var j = 0; j < this.col; j++) {
$(".tab2").find("tr").eq(i).children("td").eq(j).removeClass();
}
}
};
Game.prototype.bindEvent=function(){
//备份
var self=this;
$(document).keydown(function(event){
// console.log(event.keyCode);
if (event.keyCode==37) {
//判断是否有向左移动的能力
self.block.checkLeft();
}
else if(event.keyCode==39){
//判断是否有向右移动的能力
self.block.checkRight()
}
else if(event.keyCode==40){
self.block.checkBotton()
}
else if(event.keyCode==38){
self.block.checkRot()
}
// console.log(event.keyCode)
})
}
Game.prototype.start=function(){
var self=this;
//帧编号
this.f=0;
this.time=setInterval(function(){
self.f++;
//渲染帧编号
document.getElementById("f").innerHTML="帧编号:"+self.f;
//清屏
self.clear();
//渲染方块
self.block.render();
//渲染预览方块
self.setnextColor();
//渲染地图
self.map.render(self);
//下落
self.f % self.during == 0 && self.block.checkDown()
},20)
}
})()
Map.js
(function(){
window.Map=function(){
//地图的矩阵
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],
]
}
Map.prototype.render=function(mapGame){
// 渲染地图
for (var i = 0; i < mapGame.row; i++) {
for (var j = 0; j < mapGame.col; j++) {
//当方块到底之后,不会渲染当前的状态,只会消失,是mapCode一直在维持底部的持状态
if (this.mapCode[i][j]!=0) {
game.setColor(i,j,this.mapCode[i][j])
}
}
}
}
Map.prototype.CheckRemove=function(){
//判断当前的MapCode是否该消行
//如果当前行的每一个元素都不是0,则消掉此行
for (var i = 0; i < 20; 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+=10;
//渲染分数
document.getElementById("score").innerHTML="分数:"+game.score;
if (game.score%100==0) {
game.during-=5 ;
}
}
}
}
})()