一个俄罗斯方块的源码(原创)

刚做完项目,空闲时间比较多,无聊利用上班时间写了个俄罗斯方块,欢迎大家试玩。
试玩过程中有bug或者好的建议,请在这里留言,谢谢!
如果各位兄弟需要转载请注明出处。
俄罗斯方块源码下载地址:
http://download.youkuaiyun.com/source/1561145

 

2009年8月11日修改:

根据各位兄弟的建议,修改如下:

1.似乎只有L,做漏了反L

该bug已修正

2.对于2(2还是反2忘了),其中一个的变形好像有点不对。相对于传统的变形。似乎变后左移了一格。感觉怪怪的。。

已修正

3.还真有BUG
开始游戏,调到最高级后,绿色Z形的方块落下后,再往上面加别的方块中间有一行空的。不能落下。。

这个似乎已修正^_^

4.GAME OVER后,选级别,还会有方块出来。。并下落

已修正

5.呵呵,有bug,当你挂了过后,现start 级别的下拉框里会再添加1到10级,呵呵

已修正

6.这么多代码咋连个注释都没有~,能否把思路简单的说一说
太晚了,改天再做,不好意思

7.增加了三个块,分别是加长T,加长Z和凹形块,难度加大,各位有兴趣可以再玩玩

 

 2009年8月12日修改:

昨晚花了一个多小时优化了一下,从8月11日的765行代码减少到680行。主要变动如下:

1.清除了一些用不到的局部变量,全局变量,数组比如SmallMap: [],IsMoving,TotalScore等

2.合并GetInactivateBlocks和GetActiviteBlocks为GetBlocks,通过参数isActive来判断

3.合并_getBlocksItemPosArray和_getRelativeBlocksItemPosArray为_getBlocksItemPosArray,通过参数isRelative判断

4.抽取下面的代码为一个独立函数GetBlocksFromSmallMap,因为GetNextActiviteBrocks和PlayGame都用到了

                this.BlocksObj[0].isInGameMap = true;
                var itemPos = this.GetBlocksInitPos();
                this.BlocksObj[0].x = itemPos.x;
                this.BlocksObj[0].y = itemPos.y;
                this.BlocksObj[0].AddToGameMap(this.BlocksObj[0].color, this.BlocksObj[0].isInGameMap);

5.AllowChangeShape函数清除,其内部逻辑并到ChangeShape函数里面

6.合并moving和else if (e.keyCode == 40)下的代码成为一个独立函数BlocksMoveDown

7.合并AddToSmallMap和AddToGameMap为AddToMap,去掉原来的参数,修改为isAddToSmallMap,isMoving

8.以下代码抽取出来成为 一个独立函数GetMaxAndMinItemPosArray,返回json字符串,因两处函数用到了

                    itemPosArray.ItemPosXArray.sorts();
                    itemPosArray.ItemPosYArray.sorts();
                    var maxItemPosX = itemPosArray.ItemPosXArray[itemPosArray.ItemPosXArray.length - 1];
                    var minItemPosX = itemPosArray.ItemPosXArray[0];
                    var maxItemPosY = itemPosArray.ItemPosYArray[itemPosArray.ItemPosYArray.length - 1];
                    var minItemPosY = itemPosArray.ItemPosYArray[0];

 

 

2009-08-16修改:
代码由最初的760精简到600行左右(去掉注释后的统计)
1.取消CreateBlocksShapeMaps和_createBlocksShapeMap函数,提前定义BlocksShapeMaps数组
2.重构AllowBlocksMove,统一向上,向下,向右时方块集移动的行为,取消
_allowBlocksDown函数,增加NoToBoundary函数,判断边界
3.增加代码注释和设计理念

 

以下是08-16最新更新的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title></title>
    <script language="javascript" type="text/javascript">
        /********************************************js俄罗斯方块源码***********************************************/
        //作者:高山流水 QQ:21243468
        //创建日期:2009-08-06
        //版权声明:该作品由高山流水创作,转载请注明出处,谢谢合作!
        //游戏设计说明:
        //1.由于该游戏属于二维游戏,所以布置好网格是写好该游戏的关键,无论是游戏窗口还是预览窗口、
        //方块集虚拟map等都用到了网格的概念,这样做的好处可以避免频繁的获取元素的位置,另外还可以对方块集的移动
        //进行精确的定位和变形。这里比较重要的一点就是提前定义好方块集的map,比如对于L方块集,应定义一个三乘三的正方形
        //网格,然后根据L的每一个形状,确定方块集中的每个方块在正方形网格中的位置,另外还需要保存方块集在map
        //(游戏窗口或者预览窗)中的位置,这样任意时刻,通过方块集的位置,和方块在正方形网格中的位置,就可以确定
        //方块集中的每一个方块在map中的位置。
        //2.该游戏主要用到了一些OOP的思想。比如定义一个基类base,方块集类继承自base类,其中还有对象的封装,属性,
        //枚举的定义等,当然还有事件,委托,attribute,垃圾收集器等,因为时间关系,就不做代码演示了,各位有兴趣可以自己
        //扩展一下,加深对js OOP的理解。
        //3.js内置对象的扩展:比如Array.prototype.removeAt等
        /********************************************js俄罗斯方块源码**********************************************/
        var Sys = null;
        function sys() { }
        sys.prototype = {
            GameMap: [],
            SmallMap: [],
            BlocksObj: [],
            Timer: null,
            HorizontalNum: 10, //游戏map的水平格数
            VerticalNum: 18, //游戏map的竖直格数
            IsBegin: false, //判断游戏是否已开始
            IsGameOver: false, //判断游戏是否结束
            ScoreStrategy: [100, 300, 500, 800], //得分策略
            LevelScores: [100, 20000, 40000, 60000, 80000, 100000, 120000, 140000, 160000, 200000], //分数等级
            IsInAddScore: false, //正在处理得分中
            IsPlay: false, //游戏进行中
            IsFirstPlay: true, //是否第一次玩
            SmallGridNum: 6, //预览map的格子数,为正方形
            DirectionEnum: { left: 0, right: 1, up: 2, down: 3 }, //方向的枚举
            Speeds: [1000, 900, 800, 700, 600, 500, 400, 300, 200, 100], //速度,或者说级别
            CurrentSpeed: 1000, //当前级别或者说速度
            TypeEnum: { none: 0, block: 1, blocks: 2 }, //类型
            BlocksEnum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], //0为LL,1为LR,2为T,3为ZL,4为ZR,5为I,6为F,7为长T
            BlocksNum: [4, 4, 3, 3, 3, 4, 2, 5, 5, 5], //对应BlocksEnum中每个方块集包含的方块数
            BlocksStateNum: [4, 4, 4, 2, 2, 2, 1, 4, 4, 2], //对应BlocksEnum中每个方块集的变形个数,即有多少种变形
            BlocksShapeMaps: [ //方块形状集的集合
                       [ //方块集的虚拟map集合,对应BlocksEnum,比如该map是L的map
                           [[[2, 1]], [[0, 2], [1, 2], [2, 2]]], //L中的其中一个变形
                           [[[1, 0]], [[1, 1]], [[1, 2], [2, 2]]],
                           [[[0, 1], [1, 1], [2, 1]], [[0, 2]]],
                           [[[1, 0], [2, 0]], [[2, 1]], [[2, 2]]]
                       ],
                       [
                           [[[2, 0]], [[2, 1]], [[1, 2], [2, 2]]],
                           [[[0, 1]], [[0, 2], [1, 2]], [[2, 2]]],
                           [[[0, 0], [1, 0]], [[0, 1]], [[0, 2]]],
                           [[[0, 1], [1, 1], [2, 1]], [[2, 2]]]
                       ],
                       [
                           [[[0, 0], [1, 0], [2, 0]], [[1, 1]]],
                           [[[1, 0]], [[0, 1], [1, 1]], [[1, 2]]],
                           [[[1, 1]], [[0, 2], [1, 2], [2, 2]]],
                           [[[0, 0]], [[0, 1], [1, 1]], [[0, 2]]]
                       ],
                       [
                           [[[0, 0]], [[0, 1], [1, 1]], [[1, 2]]],
                           [[[1, 1], [2, 1]], [[0, 2], [1, 2]]]
                       ],
                       [
                           [[[1, 0]], [[0, 1], [1, 1]], [[0, 2]]],
                           [[[0, 1], [1, 1]], [[1, 2], [2, 2]]]
                       ],
                       [
                           [[[0, 0]], [[0, 1]], [[0, 2]], [[0, 3]]],
                           [[[0, 3]], [[1, 3]], [[2, 3]], [[3, 3]]]
                       ],
                       [
                           [[[0, 0], [0, 1]], [[1, 0], [1, 1]]]
                       ],
                       [
                           [[[0, 0], [1, 0], [2, 0]], [[1, 1]], [[1, 2]]],
                           [[[2, 0]], [[0, 1], [1, 1], [2, 1]], [[2, 2]]],
                           [[[1, 0]], [[1, 1]], [[0, 2], [1, 2], [2, 2]]],
                           [[[0, 0]], [[0, 1], [1, 1], [2, 1]], [[0, 2]]]
                       ],
                       [
                           [[[0, 1], [1, 1], [2, 1]], [[0, 2]], [[2, 2]]],
                           [[[1, 0], [2, 0]], [[2, 1]], [[1, 2], [2, 2]]],
                           [[[0, 1], [2, 1]], [[0, 2], [1, 2], [2, 2]]],
                           [[[1, 0], [2, 0]], [[1, 1]], [[1, 2], [2, 2]]]
                       ],
                       [
                           [[[0, 0], [1, 0]], [[1, 1]], [[1, 2], [2, 2]]],
                           [[[2, 0]], [[0, 1], [1, 1], [2, 1]], [[0, 2]]]
                       ],
                      ],
            ColorEnum: [[0, 0], [-28, 0], [-56, 0], [-84, 0], [-112, 0], [-140, 0], [-168, 0], [0, 0], [-28, 0], [-56, 0]], //颜色的枚举,对应BlocksEnum
            CreateGameMap: function() {
                //创建游戏map
                for (var i = 0; i < this.VerticalNum; i++) {
                    this.GameMap.push([]);
                    for (var j = 0; j < this.HorizontalNum; j++) {
                        this.GameMap[i][j] = {};
                        this.GameMap[i][j][Sys.TypeEnum.blocks] = null;
                    }
                }
            },
            GetBlocks: function(isActive) {
                //获取方块集,isActive=true则获取的是游戏map中的方块集,否则是预览map的
                for (var i = 0; i < this.BlocksObj.length; i++) {
                    if (this.BlocksObj[i].isInGameMap && isActive)
                        return this.BlocksObj[i];
                    else
                        return this.BlocksObj[i];
                }
                return null;
            },
            AllowBlocksMove: function(isDown) {
                //是否允许方块集移动
                var blocksItem = this.GetBlocks(true);
                var itemPosArray = this._getBlocksItemPosArray(blocksItem, false);
                return this.NoBlocksInthePlace(itemPosArray, isDown, blocksItem) && this.NoToBoundary(itemPosArray, blocksItem);
            },
            GetMaxAndMinItemPosArray: function(itemPosArray) {
                //获取最大最小方块位置集合
                itemPosArray.ItemPosXArray.sorts();
                itemPosArray.ItemPosYArray.sorts();
                return { maxItemPosX: itemPosArray.ItemPosXArray[itemPosArray.ItemPosXArray.length - 1], maxItemPosY: itemPosArray.ItemPosYArray[itemPosArray.ItemPosYArray.length - 1], minItemPosX: itemPosArray.ItemPosXArray[0], minItemPosY: itemPosArray.ItemPosYArray[0] };
            },
            NoBlocksInthePlace: function(itemPosArray, isDown, blocksItem) {
                //检测游戏方格中是否已经有方块
                return this._isOverMapChild(itemPosArray, blocksItem, isDown) ? false : true;
            },
            NoToBoundary: function(itemPosArray, blocksItem) {
                //是否到达边界了
                var maxAndMinItemPosArray = this.GetMaxAndMinItemPosArray(itemPosArray);
                var isNotToBoundary = false;
                switch (blocksItem.currentDirectionEnum) {
                    case this.DirectionEnum.left:
                        isNotToBoundary = (maxAndMinItemPosArray.minItemPosX > 0)
                        break;
                    case this.DirectionEnum.right:
                        isNotToBoundary = (maxAndMinItemPosArray.maxItemPosX < this.HorizontalNum - 1)
                        break;
                    case this.DirectionEnum.down:
                        isNotToBoundary = (maxAndMinItemPosArray.maxItemPosY < this.VerticalNum - 1);
                        break;
                }
                return isNotToBoundary;
            },
            _isOverMapChild: function(itemPosArray, blocksItem, isDown) {
                //检测是否会覆盖某个游戏方格中的元素
                var isOverMapChild = false;
                for (var i = 0; i < itemPosArray.ItemPosYArray.length; i++) {
                    var itemX = itemPosArray.ItemPosXArray[i];
                    var itemY = itemPosArray.ItemPosYArray[i];
                    if (blocksItem.currentDirectionEnum == this.DirectionEnum.left && !isDown) {
                        itemX--;
                        if (itemX >= 0 && itemY >= 0) {
                            if (this.GameMap[itemY][itemX][this.TypeEnum.blocks] != null) {
                                isOverMapChild = true;
                                break;
                            }
                        }
                    }
                    if (blocksItem.currentDirectionEnum == this.DirectionEnum.right && !isDown) {
                        itemX++;
                        if (itemX < this.HorizontalNum && itemY >= 0) {
                            if (this.GameMap[itemY][itemX][this.TypeEnum.blocks] != null) {
                                isOverMapChild = true;
                                break;
                            }
                        }
                    }
                    if (isDown) {
                        itemY++;
                        if (itemY >= 0 && itemY < this.VerticalNum) {
                            if (this.GameMap[itemY][itemX][this.TypeEnum.blocks] != null) {
                                isOverMapChild = true;
                                break;
                            }
                        }
                    }
                }
                return isOverMapChild;
            },
            _getBlocksItemPosArray: function(blocksItem, isRelative) {
                //获取方块集的位置集合,isRelative=true获取的是方块相对方块集map的位置,否则是方块相对游戏map的位置
                var itemPosXArray = [];
                var itemPosYArray = [];
                for (var i = 0; i < blocksItem.blocks.length; i++) {
                    if (isRelative) {
                        itemPosXArray.push(blocksItem.blocks[i].x);
                        itemPosYArray.push(blocksItem.blocks[i].y);
                    }
                    else {
                        itemPosXArray.push(blocksItem.blocks[i].x + blocksItem.x);
                        itemPosYArray.push(blocksItem.blocks[i].y + blocksItem.y);
                    }
                }
                return { ItemPosXArray: itemPosXArray, ItemPosYArray: itemPosYArray };
            },
            GetBlocksInitPos: function(blocks) {
                //获取方块的厨师位置
                var blocksItem = null;
                if (!blocks)
                    blocksItem = this.GetBlocks(true);
                else
                    blocksItem = blocks;
                var itemPosArray = this._getBlocksItemPosArray(blocksItem, true);
                itemPosArray.ItemPosXArray = itemPosArray.ItemPosXArray.filter();
                itemPosArray.ItemPosYArray = itemPosArray.ItemPosYArray.filter();
                var childsNumX = itemPosArray.ItemPosXArray.length;
                var childsNumY = itemPosArray.ItemPosYArray.length;
                var maxAndMinItemPosArray = this.GetMaxAndMinItemPosArray(itemPosArray);
                if (blocks) //获取方块集在预览map中的初始位置
                    return { x: (this.SmallGridNum - childsNumX - 1) / 2 + 0.5 - maxAndMinItemPosArray.minItemPosX, y: (this.SmallGridNum - childsNumY - 1) / 2 + 0.5 - maxAndMinItemPosArray.minItemPosY };
                else //获取方块集在游戏map中的初始位置
                    return { x: parseInt((this.HorizontalNum - childsNumX - 1) / 2) + 1 - maxAndMinItemPosArray.minItemPosX, y: -(childsNumY + maxAndMinItemPosArray.minItemPosY) };
            },
            GetNextActiviteBrocks: function() {
                //获取下一个活动的方块集
                var blocks = this.GetBlocks(true);
                for (var i = 0; i < this.BlocksObj.length; i++) {
                    if (this.BlocksObj[i].isInGameMap) {
                        this.BlocksObj.removeAt(i);
                    }
                }
                this.BlocksObj[0].isInGameMap = true;
                var itemPos = this.GetBlocksInitPos();
                this.BlocksObj[0].x = itemPos.x;
                this.BlocksObj[0].y = itemPos.y;
                this.BlocksObj[0].AddToMap(false, false);
                this.CreateBlocks();
            },
            PlayGame: function() {
                //启动游戏
                this.IsPlay = true;
                if (!this.IsFirstPlay) {
                    this.Timer = setInterval("moving()", this.CurrentSpeed);
                    return;
                }
                if (this.BlocksObj.length == 1) {
                    var blocksItem = this.BlocksObj[0];
                    blocksItem.isInGameMap = true;
                    var itemPos = this.GetBlocksInitPos();
                    blocksItem.x = itemPos.x;
                    blocksItem.y = itemPos.y;
                    blocksItem.AddToMap(false, false);
                }
                this.CreateBlocks();
                this.NaturalMove();
            },
            AddToGameMapGrid: function() {
                //加入到游戏map网格中
                var blocks = this.GetBlocks(true);
                blocks.UseGrid(this.GameMap, blocks);
            },
            GetScore: function() {
                //分数处理
                var gameMap = this.GameMap;
                var count = 0;
                var rowIndexArray = [];
                for (var i = 0; i < this.VerticalNum; i++) { //获取满行的行数
                    var entireRow = true;
                    for (var j = 0; j < this.HorizontalNum; j++) {
                        if (gameMap[i][j][this.TypeEnum.blocks] == null) {
                            entireRow = false;
                            break;
                        }
                    }
                    if (entireRow) {
                        count++;
                        rowIndexArray.push(i);
                    }
                }
                var scoreElement = document.getElementById("score");
                var currentScore = 0;
                var score = parseInt(scoreElement.innerText);
                if (count > 0)
                    currentScore = this.ScoreStrategy[count - 1];
                if (count > 0) {
                    this.IsInAddScore = true;
                    this._FreeMapGrid(rowIndexArray);
                    var totalScore = currentScore + score;
                    scoreElement.innerText = totalScore;
                    this.CheckTheLevel();
                    this.IsInAddScore = false;
                }
            },
            CheckTheLevel: function() {
                //检测是否进入下一个级别
                var currentScore = parseInt(document.getElementById("score").innerText);
                var speedList = document.getElementById("speed");
                var currentLevel = parseInt(speedList.options[speedList.selectedIndex].text) - 1;
                var levelScore = this.LevelScores[currentLevel];
                if (currentScore >= levelScore) {
                    if (currentLevel < this.LevelScores.length) {
                        var element = document.getElementById("gameOver");
                        element.innerText = "恭喜你通过第" + (speedList.selectedIndex + 1) + "关";
                        element.style.display = "block";
                        this.PauseGame();
                        document.getElementById("btnStart").disabled = true;
                        document.getElementById("speed").disabled = true;
                        this._goToNextLevel.delay(3000);
                    }
                    else {
                        this._finishAllTheLevel(element);
                    }
                }
            },
            _goToNextLevel: function() {
                //进入下一个级别,速度加快
                Sys.IsPlay = true;
                document.getElementById("btnStart").disabled = false;
                var speedList = document.getElementById("speed");
                speedList.disabled = false;
                speedList.options[speedList.selectedIndex + 1].selected = true;
                Sys.CurrentSpeed = Sys.Speeds[speedList.selectedIndex + 1];
                Sys.Timer = setInterval("moving()", Sys.CurrentSpeed);
                var element = document.getElementById("gameOver");
                element.style.display = "none";

            },
            _finishAllTheLevel: function() {
                //完成所有的游戏级别
                this.PauseGame();
            },
            _FreeMapGrid: function(rowIndexArray) {
                //从游戏map中释放满行的网格
                var gameMap = this.GameMap;
                var startIndex = rowIndexArray[0];
                var len = rowIndexArray.length;
                var maxIndex = startIndex + len - 1;
                for (var i = startIndex; i <= maxIndex; i++) {
                    for (var j = 0; j < this.HorizontalNum; j++) {
                        if (gameMap[i][j][this.TypeEnum.blocks] != null) {
                            document.getElementById("map").removeChild(gameMap[i][j][this.TypeEnum.blocks].domElement);
                            gameMap[i][j][this.TypeEnum.blocks] = null;
                        }
                    }
                }
                this.ResetMapGrid(rowIndexArray);
            },
            ResetMapGrid: function(rowIndexArray) {
                //重置游戏网格
                var gameMap = this.GameMap;
                var maxIndex = rowIndexArray[0];
                var len = rowIndexArray.length;
                for (var i = maxIndex - 1; i >= 0; i--) {
                    for (var j = 0; j < this.HorizontalNum; j++) {
                        if (gameMap[i][j][this.TypeEnum.blocks] != null) {
                            this._resetMapElement(gameMap[i][j][this.TypeEnum.blocks].domElement, len);
                            gameMap[i + len][j][this.TypeEnum.blocks] = gameMap[i][j][this.TypeEnum.blocks];
                            gameMap[i][j][this.TypeEnum.blocks] = null;
                        }
                    }
                }
            },
            _resetMapElement: function(element, len) {
                //重置dom元素,比如共有满行两行,则之上的元素均需下降两个
                element.style.top = (parseInt(element.style.top) + 28 * len) + "px";
            },
            InitSpeed: function() {
                //初始化游戏级别
                var speedList = document.getElementById("speed");
                if (speedList.options.length == 0) {
                    for (var i = 0; i < this.Speeds.length; i++) {
                        var varItem = new Option(i + 1, this.Speeds[i]);
                        speedList.options.add(varItem);
                    }
                }
                this.SetSpeedSelected();
            },
            SetSpeedSelected: function() {
                //选中级别
                var speedList = document.getElementById("speed");
                for (var i = 0; i < speedList.options.length; i++) {
                    if (speedList.options[i].value == this.CurrentSpeed) {
                        speedList.options[i].selected = true;
                        break;
                    }
                }
            },
            GameOver: function() {
                //游戏结束
                this.IsGameOver = true;
                this.PauseGame();
                var element = document.getElementById("gameOver");
                element.innerText = "Game Over!";
                element.style.display = "block";
                document.getElementById("btnStart").value = "try again";
            },
            PauseGame: function() {
                //暂停游戏
                this.IsPlay = false;
                clearInterval(this.Timer);
            },
            CreateBlocks: function() {
                //创建方块集
                var num = this.BlocksEnum.length;
                var currentNum = num.getRandom();
                var blocks = null;
                blocks = new Blocks(0, 0, this.BlocksNum[currentNum], this.BlocksStateNum[currentNum], currentNum, this.ColorEnum[currentNum]);
                blocks.Init();
                if (this.BlocksObj.length == 3) {
                    Sys.BlocksObj.pop();
                }
                Sys.BlocksObj.push(blocks);
            },
            NaturalMove: function() {
                //自然下落
                if (!this.IsInAddScore)
                    this.Timer = setInterval("moving()", Sys.CurrentSpeed);
            },
            ClearElementsFormMapGrid: function() {
                //清除Map中的dom元素
                var map = document.getElementById("map");
                var smallMap = document.getElementById("smallMap");
                this.RemoveAllChilds(map);
                this.RemoveAllChilds(smallMap);
            },
            RemoveAllChilds: function(element) {
                //清除所有的子元素
                var len = element.childNodes.length;
                for (var i = len - 1; i >= 0; i--) {
                    element.removeChild(element.childNodes[i]);
                }
            }
        }
        function Base() {
            //定义base类
        }
        Base.prototype.AddToMap = function(isAddToSmallMap, isMoving) {
            //添加方块集到map中
            for (var i = 0; i < this.blocks.length; i++) {
                var element = null;
                if (!this.isInGameMap) { //如果方块集是在预览map中
                    element = document.createElement("DIV");
                    document.getElementById("smallMap").appendChild(element);
                    this.blocksElement.push(element);
                    this.blocks[i].domElement = element;
                }
                else
                    element = this.blocksElement[i];
                if (!isAddToSmallMap && !isMoving) //由预览map移动到游戏map时
                    document.getElementById("map").appendChild(element);
                element.style.position = "absolute";
                element.style.left = ((this.x + this.blocks[i].x) * 28) + "px"; //设置元素所在的map的位置
                element.style.top = ((this.y + this.blocks[i].y) * 28) + "px";
                element.style.backgroundPositionX = this.color[0];
                element.style.backgroundPositionY = this.color[1];
            }
        }
        Base.prototype.UseGrid = function(map, blocksItem) {
            //方块集加入到游戏map中
            for (var i = 0; i < blocksItem.blocks.length; i++) {
                var itemX = blocksItem.x + blocksItem.blocks[i].x;
                var itemY = blocksItem.y + blocksItem.blocks[i].y;
                if (blocksItem.y < 0) {
                    Sys.GameOver();
                    return;
                }
                if (map[itemY][itemX][this.type] != null)
                    map[itemY][itemX][this.type] = blocksItem.blocks[i];
                else {
                    map[itemY][itemX] = {};
                    map[itemY][itemX][this.type] = blocksItem.blocks[i];
                }
            }
            return this;
        }
        function Block(x, y, colorEnum, isInGameMap) {
            //定义方块结构体
            this.x = x;
            this.y = y;
            this.color = colorEnum;
            this.type = Sys.TypeEnum.block;
            this.isInGameMap = isInGameMap;
            this.domElement = null;
        }
        function Blocks(x, y, gridNum, state, blocksEnum, colorEnum) {
            //方块集类
            this.x = x;
            this.y = y;
            this.gridNum = gridNum; //方块集所在虚拟map的格数
            this.state = state;
            this.blocksEnum = blocksEnum;  //方块类型(比如L,I,田字形,Z等)
            this.color = colorEnum;
            this.type = Sys.TypeEnum.blocks; //废弃属性
            this.blocks = []; //方块集下的方块的集合
            this.blocksElement = []; //方块集下的方块的对应dom元素集
            this.currentState = 0; //当前的状态,比如L有四种类型的变形
            this.isInGameMap = false; //是否在游戏map中
            this.currentDirectionEnum = Sys.DirectionEnum.down; //默认方向向下
        }
        Blocks.prototype = new Base(); //继承base类
        Blocks.prototype.Init = function() {
            //初始化blocks
            var blocksPoses = Sys.BlocksShapeMaps[this.blocksEnum];
            var currentState1 = Sys.BlocksStateNum[this.blocksEnum].getRandom(); //随机获取方块集的状态
            this.currentState = currentState1;
            var blocksPos = blocksPoses[currentState1]; //获取方块集的map
            for (var i = 0; i < blocksPos.length; i++) {
                for (var j = 0; j < blocksPos[i].length; j++) {
                    var block = new Block(blocksPos[i][j][0], blocksPos[i][j][1], this.color, this.isInGameMap);
                    this.blocks.push(block);
                }
            }
            var itemPos = Sys.GetBlocksInitPos(this); //获取初始位置,也就是说在预览map中的位置
            this.x = itemPos.x;
            this.y = itemPos.y;
            this.AddToMap(true, false); //加入到预览map中
        }
        Blocks.prototype.ChangeShape = function() {
            //方块变换形状
            var gameMap = Sys.GameMap;
            var allowChangeShape = true;
            var blocksPoses = Sys.BlocksShapeMaps[this.blocksEnum];
            var num = Sys.BlocksStateNum[this.blocksEnum];
            var currentState1 = -1;
            this.currentState == num - 1 ? currentState1 = 0 : currentState1 = this.currentState + 1;
            var blocksPos = blocksPoses[currentState1];
            var k = 0;
            for (var i = 0; i < blocksPos.length; i++) { //主要是检测方块集的下一个变形是否合理
                for (var j = 0; j < blocksPos[i].length; j++) {
                    var block = this.blocks[k];
                    var itemX = this.x + blocksPos[i][j][0];
                    var itemY = this.y + blocksPos[i][j][1];
                    if ((itemX > Sys.HorizontalNum - 1) || (itemX < 0) || (itemY > Sys.VerticalNum - 1)) {
                        allowChangeShape = false;
                        break;
                    }
                    else if (itemY >= 0 && gameMap[itemY][itemX] != null && gameMap[itemY][itemX][Sys.TypeEnum.blocks] != null) {
                        allowChangeShape = false;
                        break;
                    }
                    k++;
                }
            }
            if (allowChangeShape)//如果允许变形
            {
                this.currentState == num - 1 ? this.currentState = 0 : this.currentState++; //设置下一个变形的状态
                k = 0;
                for (var i = 0; i < blocksPos.length; i++) {
                    for (var j = 0; j < blocksPos[i].length; j++) {
                        var block = this.blocks[k];
                        block.x = blocksPos[i][j][0];
                        block.y = blocksPos[i][j][1];
                        k++;
                    }
                }
                this.AddToMap(false, true); //变形后加入到游戏map中
            }
        }
        Blocks.prototype.BlocksMoveDown = function(isMoving) {
            //方块集下落
            this.currentDirectionEnum = Sys.DirectionEnum.down;
            if (!Sys.AllowBlocksMove(true)) { //如果不允许移动
                this.y = this.y;
                Sys.AddToGameMapGrid(); //固定方块集在游戏map中的位置
                Sys.GetScore(); //得分处理
                Sys.GetNextActiviteBrocks(); //获取下一个方块集
            }
            else { //下落一格
                this.y++;
                this.AddToMap(false, isMoving);
            }
        }
        Number.prototype.getRandom = function() {
            //获取0至number之间的随机数
            var num = this;
            var i = num + 1;
            while (i >= num) {
                i = Math.round(Math.random() * 10);
            }
            return i;
        }
        Array.prototype.sorts = function() { return this.sort(compare); } //数组排序,按照升序排序
        function compare(a, b) { return a - b; } //定义排序规则
        Array.prototype.removeAt = function(dx) { //清除指定索引的数组元素
            if (isNaN(dx) || dx > this.length) { return false; }
            for (var i = 0, n = 0; i < this.length; i++) {
                if (this[i] != this[dx])
                    this[n++] = this[i];
            }
            this.length -= 1;
        }
        Array.prototype.filter = function() { //清除数组中的重复值
            var arr = [];
            for (var i = 0; i < this.length; i++) {
                if (!arr.contains(this[i]))
                    arr.push(this[i]);
            }
            return arr;
        }
        Array.prototype.contains = function(item) { //检测数组是否包含某元素
            for (var i = 0; i < this.length; i++) {
                if (this[i] == item)
                    return true;
            }
            return false;
        }
        Function.prototype.delay = function(time) { var timer = setTimeout(this, time); } //函数延迟time毫秒执行
        window.onload = InitGame;
        function InitGame() {
            //初始化游戏
            Sys = new sys();
            Sys.BlocksObj = [];
            Sys.ClearElementsFormMapGrid(); //清除游戏map中的dom元素
            Sys.InitSpeed(); //初始化游戏速度
            Sys.CreateGameMap(); //创建游戏map
            Sys.CreateBlocks(); //创建方块集
        }
        function GameStart(element) {
            Sys.IsBegin = true;
            if (element.value == "start") { //开始游戏
                element.value = "pause";
                Sys.PlayGame();
                Sys.IsFirstPlay = false;
            }
            else if (element.value == "pause") { //暂停游戏
                element.value = "start"
                Sys.PauseGame();
            }
            else { //游戏结束后重新开始
                Sys = null;
                InitGame();
                element.value = "pause";
                document.getElementById("gameOver").style.display = "none";
                document.getElementById("score").innerText = "0";
                Sys.PlayGame();
                Sys.IsFirstPlay = false;
            }
        }
        function moving() {
            //移动
            Sys.GetBlocks(true).BlocksMoveDown(false);
        }
        function ChangeSpeed(e) {
            //切换级别
            var speedlist = document.getElementById("speed");
            Sys.CurrentSpeed = speedlist.options[speedlist.selectedIndex].value;
            if (!Sys.IsGameOver) {
                clearInterval(Sys.Timer);
                Sys.Timer = setInterval("moving()", Sys.CurrentSpeed);
            }
        }
        function keyDown(e) {
            //按键操作
            if (Sys.IsGameOver || !Sys.IsPlay) return;
            var blocks = Sys.GetBlocks(true);
            if (e.keyCode == 37) {  //向左
                blocks.currentDirectionEnum = Sys.DirectionEnum.left;
                if (Sys.AllowBlocksMove(false))
                    blocks.x--;
                if (blocks.x != 0)
                    blocks.AddToMap(false, true);
            }
            else if (e.keyCode == 38) {  //向上
                blocks.currentDirectionEnum = Sys.DirectionEnum.up;
                blocks.ChangeShape();
            }
            else if (e.keyCode == 39) { //向右
                blocks.currentDirectionEnum = Sys.DirectionEnum.right;
                var oldX = blocks.x;
                if (Sys.AllowBlocksMove(false))
                    blocks.x++;
                if (blocks.x != oldX)
                    blocks.AddToMap(false, true);
            }
            else if (e.keyCode == 40)  //向下
                blocks.BlocksMoveDown(true);
        }
    </script>
     <style type="text/css">
     body
     {
        background-color:#ffffff;
        overflow:hidden;
        font-size:14px;
     }
     .gameZone
     {
        position:absolute;
        left:0px;
        top:0px;
        width:100%;
        height:550px;
        background-Color:white;
     }
    .mask
    {
        position:absolute;
        left:100px;
        top:0px;
        width:300px;
        height:20px;
        background-color:White;
        border:solid 0px;
        z-index:5;
    }
    .map
    {
        position:absolute;
        left:100px;
        top:20px;
        width:280px;
        height:504px;
        background-image:url(images/tetris_grid.gif);
        border:solid 3px green;
    }
    .gameOver
    {
        position:absolute;
        left:100px;
        top:20px;
        width:280px;
        height:504px;
        font-weight:800;
        font-size:xx-large;
        color:Red;
        text-align:center;
        border:solid 3px;
        line-height:420px;
        display:none;
        filter: Alpha(Opacity=80);
        background-color:pink;
    }
     .map div
    {
     BACKGROUND-IMAGE: url(images/tetris.gif);
     WIDTH: 28px;
     BACKGROUND-REPEAT: no-repeat;
     POSITION: absolute;
     HEIGHT: 28px
    }
    .smallMap
    {
        position:absolute;
        left:400px;
        top:20px;
        width:168px;
        height:168px;
        background-color:pink;
        border:solid 2px green;
    }
    .smallMap div
    {
     BACKGROUND-IMAGE: url(images/tetris.gif);
     WIDTH: 28px;
     BACKGROUND-REPEAT: no-repeat;
     POSITION: absolute;
     HEIGHT: 28px
    }
    .start
    {
        position:absolute;
        left:400px;
        top:240px;
        width:168px;
        height:40px;
    }
     .scoreSpeed
    {
        position:absolute;
        left:400px;
        top:200px;
        width:190px;
        height:40px;
    }
    .score
    {
        color:pink;
        font-weight:bold;
        width:20px;
        height:20px;
        background-color:blue;
        padding-left:10px;
        padding-right:10px;
        font-size:medium;
    }
    .speed
    {
        color:pink;
        font-weight:bold;
        width:20px;
        height:20px;
        background-color:blue;
        padding-left:5px;
        padding-right:5px;
        font-size:medium;
    }
     .copyright
    {
        position:absolute;
        left:400px;
        top:280px;
        word-break:break-all;
        width:160px;
        height:225px;
        border:solid 2px green;
        padding:5px;
    }
    </style>
</head>
<body  οnkeydοwn="keyDown(event)">
<div class="gameZone">
<div id="mask" class="mask"></div>
<div id="map" class="map"></div>
<div id="gameOver" class="gameOver"></div>
<div id="smallMap" class="smallMap"></div>
<div id="scoreSpeed" class="scoreSpeed">得分:<span id="score" class="score">0</span></div>
<div id="start" class="start">
<input type="button" id="btnStart" value="start" οnclick="GameStart(this);" />&nbsp;
级别:<select id="speed" οnchange="ChangeSpeed();"></select>
</div>
<div id="copyright" class="copyright">
<b><center>版权所有</center></b><br />
此俄罗斯方块由高山流水开发,欢迎各位使用,
如有bug或者好的意见,请给我留言,谢谢支持!
另如需转载,请注明出处!
<br /><br />
作者:<a href="http://blog.youkuaiyun.com/46539492" target="_blank">高山流水</a><br />
QQ:21243468
</div>
</div>
</body>
</html>

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值