js-俄罗斯方块-面向对象-中介模式-完整版

1.设置Game为中介者类

2.方块的状态

俄罗斯方块中,下落的方块形态一共有7种,每一种又有不同的状态(方向)

S型、Z型、J型、L型、O型、T型、I

这些形态都用一个4*4的矩阵表示

3 方块的表示

使用二维数组去表示俄罗斯方

比如上图的T我们使用二维数组

[

[0,0,0,0],

[1,1,1,0],

[1,1,0,0],

[0,0,0,0],

]

块的方块状态

将所有的俄罗斯方块的类型和状态都放到一个JSON中,JSON是一个三维数组

4 渲染方块

5 地图类

需要一个地图,来显示已经到底的方块,此时的表格只是一个显示的dom,没有办法实时进行显示,因为每一帧要清除画布,所以要想持久,就需要让数据持久起来,所以维持一个地图类,用来持久已经到底的方块

6.方块的下落状态

方块下落很简单,就是给Block.row++就可以了,但是怎么停止?

此时提出了一个“预判断”的概念,也就是每一次方块下落的时候需要进行一次预先判断,当前方块的下一次运动位置去和地图的(mapCode)进行位置判断,如果此时mapCode在相同的位置也有方块存在,则停止下落。

7.渲染地图

当前方块到底之后,不会渲染当前的状态,只会消失,因为是mapCode一直在维护底部的持久状态,所以一旦方块到底后,就要将数据给mapCode进行持久更新

8.方块的左右移动

其实就是增加事件监听,然后通过check方法预判断是否有能力移动

9.方块的旋转

按上键让方块按照顺时针的方向旋转

但是此时会发生一个问题,方块在旋转的过程中不会顾及左右是否有已有的颜色格子

此时可以对方块进行一次“备份”,将旧的方块备份一份,然后让新block的和已有的mapCode进行一一比对,如果新的有重合就打回原形

10.方块消行

方块消行本质就是mapCode的每一项数组的遍历,如果某一项数组中有都不为0了,就说明该消行了

11. 判断游戏结束

地图的第一行的mapCode有不为0的了就判定死亡了

每次方块到底的时候进行一次判断

12.设置预览框

俄罗斯方块有一个重要的逻辑就是预览,下一次的方块 会 提前展示,所以我们可以设置一个nextBlock当做下一次出场的方块

13.加分设置不同档 、不同速度、加不同分

index.html

<style>
    *{
        margin: 0;
        padding: 0;
    }
    html{
        height: 100%;

    }
    body{
        background: url(images/bg2.png) repeat-x center bottom, -webkit-linear-gradient(top,skyblue,white);
        overflow: hidden;
        background-size: 20%;
        padding-top: 20px;
    }
    table{
       margin: 0 auto;
        border-collapse: collapse;
        background: #525252;
        float: left;
        margin-right: 20px;
    }
    td{
        width: 25px;height: 25px;
        border: 1px solid rgb(68, 37, 37);
    }
    .c1{
        background: url(images/1.jpg) no-repeat;
        background-size: cover;
    }
    .c2{
         background: url(images/2.jpg) no-repeat;
         background-size: cover;
    }
    .c3{
         background: url(images/3.jpg) no-repeat;
         background-size: cover;
    }
    .c4{
         background: url(images/4.jpg) no-repeat;
         background-size: cover;
    }
    .c5{
        background: url(images/5.jpg) no-repeat;
        background-size: cover;
    }
    .c6{
         background: url(images/6.jpg) no-repeat;
         background-size: cover;
    }
    .c7{
         background: url(images/7.jpg) no-repeat;
         background-size: cover;
    }
    h2{
        width: 100%;
        float: left;
    }
</style>
<body>
    <h2 id="f">帧编号:0</h2>
    <h2 id="score">分数:0</h2>
<script src="js/jquery-3.2.1.min.js"></script>    
<script src="js/Game.js"></script>
<script src="js/Block_JSON.js"></script>
<script src="js/Block.js"></script>
<script src="js/Map.js"></script>
<script>
      var game = new Game() 
</script>
</body>
</html>

Game.js

(function () {
     window.Game = function() { 
        //行列
        this.row = 20;
        this.col = 12;
        //实例block
        this.block = new Block();
        //实例下一个Block
        this.nextBlock = new Block();
        //定时器
        this.start()
        //实例地图
        this.map = new Map(this);
        //初始化
        this.init()
        //初始化分数
        this.score = 0;
        //初始化 速度
        this.during = 19;
        //键盘监听事件
        this.bindEvent();
    }
    Game.prototype.init = function () {
        //创建游戏table
        $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>");
                $td.appendTo($tr)
            }
            $tr.appendTo($table)
        }
        $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>");
                $td2.appendTo($tr2)
            }
            $tr2.appendTo($table2)
        }
        //上树
        $table.appendTo("body");
        $table2.appendTo("body");
    }
    //渲染 矩阵中方块的颜色,不同类型,添加不同类设置不同颜色
    Game.prototype.setColor = function(row,col,num){
        $(".tab1").find("tr").eq(row).find("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<4;i++){
            for(var j=0;j<4;j++){
                $(".tab2").find("tr").eq(i).children("td").eq(j).removeClass();
            }
        }
    }
    //键盘监听事件
    Game.prototype.bindEvent = function(){
        var self = this;
        $(document).keydown(function(event){
            //左键
            if(event.keyCode == 37){
                self.block.checkLeft()
            }
            //右键
            else if(event.keyCode == 39){
                self.block.checkRight()
            }
            //空格一键到底  按空格键
            else if(event.keyCode == 32){
                //console.log(event.keyCode);
                self.block.checkBlockEnd();
            }
            //旋转 按上键
            else if(event.keyCode == 38){
                //console.log(event.keyCode);
                self.block.checkRot();
            }
        })
    }
    //定时器
    Game.prototype.start = function(){
        
        var self = this;
        //帧编号
        this.f = 0
        this.timer = setInterval(function () {
            self.f++;
            //渲染帧编号
            $("#f").html("帧编号:"+self.f)
            self.clear();
            //渲染方块
            self.block.render();
            //渲染下一个方块
            self.setNextColor();
            // 渲染地图
            self.map.render(self);
            //方块下落
            self.f % self.during == 0 && self.block.checkDown();
            
        },20)
    }
})()

Block.js

(function () {
    window.Block = function () {
        //console.log(blocks)
        //随机7种方块类型中的某一种
        //第一:7种类型
        var allType = ["S","Z","J","L","I","O","T"];
        //第二:从7种类型的方块中选一种
        this.type = allType[parseInt(Math.random() * allType.length)];
        //第三:7种类型方块中的某一种方块  一共有几种状态;
        this.allDir = blocks[this.type].length;
        //第四:7种类型方块中的某一种方块的某一种状态的下标
        this.dir = parseInt(Math.random() * this.allDir);

        //第五:获取到  7种类型方块中的某一种方块的某一种状态
        this.code = blocks[this.type][this.dir];
        //初始化从第一行还是
        this.row = 0;
        //初始化居中显示 从第四列开始
        this.col = 4;
    }
    Block.prototype.render = function () {
        //渲染4*4矩阵
        for(var i=0;i<4;i++){
            for(j=0;j<4;j++){
               if(this.code[i][j] != 0){
                   //如果矩阵中 某一项不等于零,则渲染颜色
                   game.setColor(i+this.row,j+this.col,this.code[i][j]);
               }
            }
        }   
    }
    //判断能否下落
    Block.prototype.check = function(row,col){
        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.checkDown = function(){
        // 判断当前地图的位置和自己方块的位置是否有重合this.row+1指的是预判断
        // 预判断就是在下一次方块将要到达的位置是否有对应的地图不为0
        if(this.check(this.row + 1, this.col)){
            this.row++; 
        }
        else{
            // 下落到底的状态,渲染预览框的方块
            game.block = game.nextBlock;
            // 让预览框的方块再次渲染新的       
            game.nextBlock = new Block();
            //到底后 地图渲染
            this.readerMap();
            //消行
            game.map.checkRemove();
            //死亡判断
            this.checkOver();
        }
        
    }
    //死亡判断
    Block.prototype.checkOver = function () {
        //mapCode 第一行,中有一个不是0则游戏结束
        for(var i=0;i<game.col;i++){
            if(game.map.mapCode[0][i] != 0){
                clearInterval(game.timer);
                alert("游戏结束,您当前的得分是"+ game.score);
            }
        }
    }
    //判断能否向左
    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.checkBlockEnd = function () {
        while(this.check(this.row + 1, this.col)){
            this.row ++;
        }
    }
    //旋转
    Block.prototype.checkRot = function () {
        //旋转能力判断
        //备份旧的形状方向
        var oddDir = this.dir;
        //改变新的
        this.dir++;
        //如果当前的dir大于最后一种方向,回到第一种状态
        if(this.dir > this.allDir -1){
            this.dir = 0;
        }
        
        //改变之后渲染新的code
        this.code = blocks[this.type][this.dir];
        //渲染之后的新方块判断,是否有能力渲染
        if(!this.check(this.row,this.col)){
            console.log(this.dir);
           //进入判断说明重合了,打回原形再次渲染
            this.dir = oddDir;
            this.code = blocks[this.type][this.dir];
        }
        
    }
    //到底的方块让地图进行渲染
    Block.prototype.readerMap = function(){
        for(var i=0;i<4;i++){
            for(var j=0;j<4;j++){
                if(this.code[i][j] !== 0){
                    game.map.mapCode[this.row + i][this.col + j] = this.code[i][j];
                }
            }
        }
    }
})()

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, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0],
            [1, 2, 3, 4, 3, 4, 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++){
                if(this.mapCode[i][j] != 0){
                    game.setColor(i,j,this.mapCode[i][j]);
                }
               //$("tr").eq(i).children("td").eq(j).html(this.mapCode[i][j]);
            }
        }
    }
    //消行
    Map.prototype.checkRemove = function (mapGame) {
         // 消行规则:当前的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]);

                //分数增加,根据不同的速度决定加多少分数
                if(game.during<=30 && game.during >= 20){
                    game.score += 10;
                }else if(game.during >=10 && game.during<20){
                    game.score += 20;
                }else{
                    game.score+=30;
                }
                // 渲染分数
                $("#score").html("分数:" + game.score)
                if(game.score % 100 == 0){
                    during -= 5;
                    if(during <=0){
                        during = 1;
                    }
                }
            }
        }
      
    }
})()

JSON.js

var blocks = {
    "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, 0, 0, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 7, 0, 0],
            [7, 7, 0, 0],
            [0, 7, 0, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 7, 0, 0],
            [7, 7, 7, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 7, 0, 0],
            [0, 7, 7, 0],
            [0, 7, 0, 0],
            [0, 0, 0, 0]
        ]
    ]
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值