基于JS的俄罗斯方块-附源码

前言

最近在整理一些旧的文档,发现了以前用js写的小游戏.发出来分享一下.

功能说明

仿照以前game boy的俄罗斯方块游戏
[左][右]控制移动,[上]控制旋转,[下]加速下降.[Esc]是暂停
消除行可得分,分数越高方块默认下降速度越快 可以看得到得分及下一方块信息

在这里插入图片描述

页面主要包含三个对象

1.主体(方块要堆积的地方)
2.下一方块提示
3.信息区

设计上比较关键的几个方法,在代码中有简单注释

1.设置了一个数组用来初始化所有方块类型
2.用两个变量记录当前方块及下一方块
3.方块的初始化方法,旋转方法
4.方块的碰撞检测方法
5.行消除方法,得分计算
6.方块自动下降及速度控制

详细代码

<html>
<style>
    .c {
        margin: 1px;
        width: 19px;
        height: 19px;
        background: red;
        position: absolute;
    }

    .d {
        margin: 1px;
        width: 19px;
        height: 19px;
        background: gray;
        position: absolute;
    }

    .f {
        top: 0px;
        left: 0px;
        background: black;
        position: absolute;
    }

    .info {
        top: 0px;
        background: black;
        position: absolute;
        color: white;
    }
</style>
<body></body>
<html>
<script>
    var over = false;
    var stop = false;
    var level = 1;
    //定义方块形状
    var shapes = (
        "0,1,1,1,2,1,3,1;" +
        "1,0,1,1,1,2,2,2;" +
        "2,0,2,1,2,2,1,2;" +
        "0,1,1,1,1,2,2,2;" +
        "1,2,2,2,2,1,3,1;" +
        "1,1,2,1,1,2,2,2;" +
        "0,2,1,2,1,1,2,2").split(";");
    //定义下一方块形状
    var nextShape = null;

    /**
     * 创建方块元素
     * @param tag 元素标签
     * @param css 样式
     */
    function create(tag, css) {
        var elm = document.createElement(tag);
        elm.className = css;
        document.body.appendChild(elm);
        return elm;
    }

    /**
     * 获得下落的方块
     * @param c css样式名称
     * @param t 方块坐标点集合,方块样式集合
     * @param x 初始位置x位置
     * @param y 初始位置y位置
     */
    function Tetris(c, t, x, y) {
        var c = c ? c : "c";
        //当前方块
        this.divs = [create("div", c), create("div", c), create("div", c), create("div", c)];
        //下一方块
        if ("d" != c) {
            this.nextDivs = [create("div", c), create("div", c), create("div", c), create("div", c)];
        }
        /**
         * 重置
         */
        this.reset = function () {
            this.x = typeof x != 'undefined' ? x : 3;
            this.y = typeof y != 'undefined' ? y : 0;
            this.shape = t ? t : (nextShape ? nextShape : shapes[Math.floor(Math.random() * (shapes.length - 0.00001))].split(","));
            if ("d" != c) {
                nextShape = t ? t : shapes[Math.floor(Math.random() * (shapes.length - 0.00001))].split(",");
            }
            this.show();
            if (this.field && this.field.check(this.shape, this.x, this.y, 'v') == 'D') {
                over = true;
                this.field.fixShape(this.shape, this.x, this.y);
                alert('game over');
            }
        };
        /**
         * 显示
         */
        this.show = function () {
            //当前方块组装
            for (var i in this.divs) {
                this.divs[i].style.left = (this.shape[i * 2] * 1 + this.x) * 20 + 'px';
                this.divs[i].style.top = (this.shape[i * 2 + 1] * 1 + this.y) * 20 + 'px';
            }
            if ("d" != c) {
                //下一方块组装
                for (var i in this.nextDivs) {
                    this.nextDivs[i].style.left = (nextShape[i * 2] * 1 + 16) * 20 + 'px';
                    this.nextDivs[i].style.top = (nextShape[i * 2 + 1] * 1 + 0) * 20 + 'px';
                }
            }
        };
        this.field = null;
        /**
         * 左右移动
         * @param step
         */
        this.hMove = function (step) {
            if(stop) return;
            var r = this.field.check(this.shape, this.x - -step, this.y, 'h');
            if (r != 'N' && r == 0) {
                this.x -= -step;
                this.show();
            }
        };
        /**
         * 向下移动
         */
        this.vMove = function () {
            if(stop) return;
            if (this.field.check(this.shape, this.x, this.y - -1, 'v') == 'N') {
                this.y++;
                this.show();
            }
            else {
                //冻结方块
                this.field.fixShape(this.shape, this.x, this.y);
                //查找填满的行,并消除
                this.field.findFull();
                //重置方块
                this.reset();
            }
        };
        /**
         * 旋转
         */
        this.rotate = function () {
            if(stop) return;
            var s = this.shape;
            var newShape = [3 - s[1], s[0], 3 - s[3], s[2], 3 - s[5], s[4], 3 - s[7], s[6]];
            var r = this.field.check(newShape, this.x, this.y, 'h');
            if (r == 'D') return;
            if (r == 0) {
                this.shape = newShape;
                this.show();
            }
            else if (this.field.check(newShape, this.x - r, this.y, 'h') == 0) {
                this.x -= r;
                this.shape = newShape;
                this.show();
            }
        };
        /**
         * 暂停开始
         * @param step
         */
        this.stop = function () {
            stop=!stop;
            if(stop){
                document.getElementById("stop").innerText=("stop");
            }else{
                document.getElementById("stop").innerText=("begin");
            }
        };
        //重置
        this.reset();
    }

    /**
     * 指定背景和初始化操作
     * @param w  宽(格字数)
     * @param h  高(格字数)
     * @constructor
     */
    function Field(w, h) {
        //默认宽15格
        this.width = w ? w : 15;
        //默认高25格
        this.height = h ? h : 25;
        //显示
        this.show = function () {
            //创建背景画布
            var f = create("div", "f");
            f.style.width = this.width * 20 + 'px';
            f.style.height = this.height * 20 + 'px';
            //创建下一个方块信息框
            var info = create("div", "info");
            info.style.width = 4 * 20 + 'px';
            info.style.height = 4 * 20 + 'px';
            info.style.top = 0 * 20 + 'px';
            info.style.left = (this.width + 1) * 20 + 'px';
            //创建分数框
            var scoreDiv = create("div", "info");
            scoreDiv.style.width = 4 * 20 + 'px';
            scoreDiv.style.height = 8 * 20 + 'px';
            scoreDiv.style.top = 5 * 20 + 'px';
            scoreDiv.style.left = (this.width + 1) * 20 + 'px';
            //得分
            var sourceInfo = document.createElement("p");
            sourceInfo.id = "sourceInfo";
            sourceInfo.innerText = "SOURCE:";
            scoreDiv.appendChild(sourceInfo);
            var source = document.createElement("p");
            source.id = "source";
            source.innerText = "0";
            scoreDiv.appendChild(source);
            //级别
            var level = document.createElement("p");
            level.id = "level";
            level.innerText = "level: 1";
            scoreDiv.appendChild(level);
            //状态
            var stop = document.createElement("p");
            stop.id = "stop";
            stop.innerText = "begin";
            scoreDiv.appendChild(stop);
        };
        //查找拼接完整的一行
        this.findFull = function () {
            //计算一次消除多少行
            var removeLineCount = 0;
            //计算消除行
            for (var l = 0; l < this.height; l++) {
                var s = 0;
                for (var i = 0; i < this.width; i++) {
                    s += this[l * this.width + i] ? 1 : 0;
                }
                if (s == this.width) {
                    removeLineCount++;
                    //消除行
                    this.removeLine(l);
                }
            }
            //计算得分
            var source = parseInt(document.getElementById("source").innerText);
            switch (removeLineCount) {
                case 0:
                    document.getElementById("source").innerText=(source+0);
                    break;
                case 1:
                    document.getElementById("source").innerText=(source+10);
                    break;
                case 2:
                    document.getElementById("source").innerText=(source+30);
                    break;
                case 3:
                    document.getElementById("source").innerText=(source+60);
                    break;
                case 4:
                    document.getElementById("source").innerText=(source+100);
                    break;
            }
            //计算级别
            if(source/50>=level){
                level++;
                document.getElementById("level").innerText=("level: "+level);
                clearInterval(timer);
                timer=window.setInterval("if(!over&&!stop)s.vMove();", 400/level);
            }

        };
        /**
         * 消除行
         * @param line 行号
         */
        this.removeLine = function (line) {
            for (var i = 0; i < this.width; i++) {
                document.body.removeChild(this[line * this.width + i]);
            }
            for (var l = line; l > 0; l--) {
                for (var i = 0; i < this.width; i++) {
                    this[l * this.width - -i] = this[(l - 1) * this.width - -i];
                    if (this[l * this.width - -i]) this[l * this.width - -i].style.top = l * 20 + 'px';
                }
            }
        };
        /**
         * 旋转检查
         * @param shape 方块集合
         * @param x
         * @param y
         * @param d
         * @returns {*}
         */
        this.check = function (shape, x, y, d) {
            var r1 = 0, r2 = 'N';
            for (var i = 0; i < 8; i += 2) {
                if (shape[i] - -x < 0 && shape[i] - -x < r1) {
                    r1 = shape[i] - -x;
                }
                else if (shape[i] - -x >= this.width && shape[i] - -x > r1) {
                    r1 = shape[i] - -x;
                }
                if (shape[i + 1] - -y >= this.height || this[shape[i] - -x - -(shape[i + 1] - -y) * this.width]) {
                    r2 = 'D'
                }
            }
            if (d == 'h' && r2 == 'N') return r1 > 0 ? r1 - this.width - -1 : r1;
            else return r2;
        };
        /**
         * 冻结的下落方块
         * @param shape
         * @param x
         * @param y
         */
        this.fixShape = function (shape, x, y) {
            //冻结方块
            var d = new Tetris("d", shape, x, y);
            d.show();
            for (var i = 0; i < 8; i += 2) {
                this[shape[i] - -x - -(shape[i + 1] - -y) * this.width] = d.divs[i / 2];
            }
        };
    }

    var f = new Field();
    f.show();

    var s = new Tetris();
    s.field = f;
    s.show();

    //定时器,游戏未结束的情况下,每0.5s向下移动方块
    var timer = window.setInterval("if(!over&&!stop)s.vMove();", 500);
    //键盘监听
    document.onkeydown = function (e) {
        if (over) return;
        var e = window.event ? window.event : e;
        switch (e.keyCode) {
            case 38: //up
                s.rotate();
                break;
            case 40: //down
                s.vMove();
                break;
            case 37: //left
                s.hMove(-1);
                break;
            case 39: //right
                s.hMove(1);
                break;
            case 27: //ESC暂停,开始
                s.stop();
                break;
        }
    }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值