图片 3

纯JS实现俄罗斯方块,打造属于你的游戏帝国

上面是俄罗丝四方的截图: 请到此处下载源码: 俄罗丝方块 在线演示
下载地址上面是代码: 复制代码 代码如下:

  纯JS俄罗丝方块,构建归于您的游乐帝国。

意气风发:写在开辟前

得分:0

  本文原始小编博客
http://www.cnblogs.com/toutou

   
俄罗丝方块,是黄金时代款大家小时候都玩过的小游戏,小编要好也是望着书上的思绪,学着用
斯维夫特来写这么些小游戏,在写这几个游戏的经过中,除了部分职位的计量,数据模型和透亮
Swift 语言之外,最好领会UIKIt框架中的 Quartz2D 这些知识点。是本身在简书上边找的,是有关 Quartz2D 那么些知识点的,看它自己觉着也就够学习。经过这两日的整理,丰硕以为在写那一个在此以前,一定要理清楚思路,你或者会花不菲时日在它下面,你要明白了,怎么写就变的相反简单了。

级别:

  俄罗丝四方(Tetris,
乌克兰(УКРАЇНА卡塔 尔(阿拉伯语:قطر‎语:Тетрис卡塔尔国是生机勃勃款TV游戏机和掌中游戏机游戏,它由俄罗丝人阿列克谢·帕Kit诺夫发明,故得此名。
俄罗丝方块的基本准则是运动、旋转和陈设游戏活动输出的各样方块,使之排列成完整的风流浪漫行或多行並且肃清得分。由于上手轻松、老少皆宜,进而分明,风靡世界。
那正是说,我们的难题来了,学开掘机技能哪家强?图片 1

二:具体开销思路及主要性代码

版权全数
此俄罗斯方块由高山流水开采,招待各位使用,
如有bug或许好的眼光,请给自家留言,谢谢扶持! 另如需转发,请注明出处!
附带,宣传转手动和自动己的MVC qq群:45660795,款待参加!

正文原创来自博客园 请叫作者头头哥的博客,
请尊重版权,跳转至原博文预览。

   
作者在博客的最上面附上了整机的代码,大家能够在Git上下载到它,你要也运用Git,就顺手给本身个小点儿吧
O(∩_∩)O哈哈~。。

作者:高山流水
QQ:21243468

 

  1》游戏分界面包车型地铁结构规划

  俄罗丝方块能够说是风靡全世界,老少皆知的生龙活虎款游戏,
那么大家作为web开垦是还是不是足以接收代码轻松完结那一个小游戏呢?

    那些里面包车型大巴Label 和 Button
就相当的少废话了,那不是我们的第豆蔻梢头,看看这几个效率大家也就一笔带过了啊!珍视是大家选用的方面说的施用
Quartz2D 那么些知识画出来表格。它单看正是三个N * M
的报表,在它里面将要运维大家的俄罗丝小方块,在上面包车型大巴代码里面也会详细的辨证它的成立。

  html代码部分:

 
  图片 2

  

 

 1 <!doctype html>
 2 <html>
 3 <head>
 4 </head>
 5 <body>
 6     <h2 style="background-color:yellow;">博客园:请叫我头头哥</h2>
 7     <div id="box"></div>
 8     <div id="info">
 9         NEXT:
10         <div id="next"></div>
11         <div id="text"></div>
12     </div>
13 </body>
14 </html>

     
上面是大家绘制上面网格视图的不二法门,上边全数代码方法里面包车型客车有一点点参数是定义成全局变量的,大家能够下载完整版的代码去看看。在代码中也加了多数的笺注,相信都能看的接头的。

  css部分:

 // MARK: 绘制俄罗斯方库网格的方法
    func creatcells(rows:Int,cols:Int,cellwidth:Int,cellHeight:Int) -> Void {

        // 开始创建路径
        CGContextBeginPath(CTX)
        // 绘制横向网格对应的路径
        for  i  in 0...TETRIS_Row {

            CGContextMoveToPoint(CTX, 0, CGFloat(i  *  CELL_Size))
            CGContextAddLineToPoint(CTX, CGFloat(TETRIS_Cols * CELL_Size), CGFloat(i * CELL_Size))

        }
        // 绘制纵向的网格对应路径
        for  i  in 0...TETRIS_Cols {

            CGContextMoveToPoint(CTX, CGFloat(i  *  CELL_Size),0)
            CGContextAddLineToPoint(CTX, CGFloat(i * CELL_Size), CGFloat(TETRIS_Row * CELL_Size))

        }
        // 关闭
        CGContextClosePath(CTX)

        // 设置笔触颜色
        CGContextSetStrokeColorWithColor(CTX, UIColor(red: 0.9 , green: 0.9 , blue: 0.9,alpha: 1).CGColor)
        // 设置效线条粗细
        CGContextSetLineWidth(CTX, CGFloat(STROKE_Width))
        // 绘制线条
        CGContextStrokePath(CTX)

    }

  

   

body {
        background: blue;
        font: 25px / 25px ËÎÌå;
    }

    #box {
        float: left;
        width: 252px;
        border: #999 20px ridge;
        color: #9f9;
        text-shadow: 2px 3px 1px #0f0;
    }

    #info {
        float: left;
        color: #cfc;
        padding: 24px;
    }

    #next {
        padding: 8px;
        width: 105px;
        color: #9f9;
        text-shadow: 2px 3px 1px #0f0;
    }

   
2》小游戏的数据模型

  js部分:

     
  1:
游戏的四十16日游分界面是多个 N * M
的网格,每一张网格展现一张图纸,但对于大家的话,作者门就得用三个二维数组来定义,纪录每一块的行和列!来保存游戏的情景。大家在最早阶把每七个小块的游状态都伊始化为
0 ,看上边代码。

  

    // 定义用于纪录方块游戏状态的二维数组
    var tetris_status = [[Int]]()

    // MARK初始化游戏状态
    func initTetrisStatus() -> Void {

        let tmpRow = Array.init(count: TETRIS_Cols, repeatedValue: NO_Block)
        tetris_status  = Array.init(count: TETRIS_Row, repeatedValue: tmpRow)

    }
 1 var map = eval("[" + Array(23).join("0x801,") + "0xfff]");
 2     var tatris = [[0x6600], [0x2222, 0xf00], [0xc600, 0x2640], [0x6c00, 0x4620], [0x4460, 0x2e0, 0x6220, 0x740], [0x2260, 0xe20, 0x6440, 0x4700], [0x2620, 0x720, 0x2320, 0x2700]];
 3     var char = { x: "\u3000", s: "\u25a0", t: "\u25a1" };
 4     var keycom = { "38": "rotate(1)", "40": "down()", "37": "move(2,1)", "39": "move(0.5,-1)", "32": "0;pause=!pause" };
 5     var dia, pos, bak, run, next, pause = false, info = { speed: 1, lines: 0, score: 0 };
 6 
 7     // 开始时间
 8     function start() {
 9         dia = next.d;
10         bak = pos = {
11             fk: [],
12             y: 0,
13             x: 4,
14             s: next.s
15         };
16         nextdia();
17         document.getElementById("next").innerHTML = (next.d[next.s % next.d.length] | 0x10000).toString(2).slice(-16).replace(/..../g, "$&<br/>").replace(/1/g, char.t).replace(/0/g, char.x);
18         document.getElementById("text").innerHTML = "SCORE:" + info.score + "<br/><br/>LINES:" + info.lines + "<br/><br/>SPEED:" + info.speed;
19         rotate(0);
20         run = setInterval("pause||down()", ~ ~(Math.pow(1.3, 12 - info.speed) * 30 + 20));
21     }
22 
23     // 游戏结束时事件
24     function over() {
25         document.onkeydown = null;
26 
27         // confirm, 是否再来一局
28         var end = confirm("游戏结束, 是再来一局");
29         if (end) {
30             window.location.href = window.location.href;
31         } else {
32             alert("骚年,自制力不错!");
33         }
34     }
35 
36     function nextdia() {
37         next = { d: tatris[~ ~(Math.random() * 7)], s: ~ ~(Math.random() * 4) };
38     }
39 
40     function update(t) {
41         bak = { fk: pos.fk.slice(0), y: pos.y, x: pos.x, s: pos.s };
42         if (t) return;
43         for (var i = 0, a2 = ""; i < 22; i++) a2 += map[i].toString(2).slice(1, -1) + "<br/>";
44         for (var i = 0, n; i < 4; i++)
45             if (/([^0]+)/.test(bak.fk[i].toString(2).replace(/1/g, char.t)))
46                 a2 = a2.substr(0, n = (bak.y + i + 1) * 15 - RegExp.$_.length - 4) + RegExp.$1 + a2.slice(n + RegExp.$1.length);
47         document.getElementById("box").innerHTML = a2.replace(/1/g, char.s).replace(/0/g, char.x);
48     }
49 
50     function is() {
51         for (var i = 0; i < 4; i++)
52             if ((pos.fk[i] & map[pos.y + i]) != 0)
53                 return pos = bak;
54     }
55 
56     function rotate(r) {
57         var f = dia[pos.s = (pos.s + r) % dia.length];
58         for (var i = 0; i < 4; i++)
59             pos.fk[i] = (f >> (12 - i * 4) & 15) << pos.x;
60         update(is());
61     }
62 
63     function down() {
64         ++pos.y;
65         if (is()) {
66             for (var i = 0, r = 0; i < 4 && pos.y + i < 22; i++)
67                 if ((map[pos.y + i] |= pos.fk[i]) == 0xfff) {
68                     map.splice(pos.y + i, 1), map.unshift(0x801);
69                     ++info.lines % 20 == 0 && info.speed++, r++;
70                 }
71             clearInterval(run);
72             if (map[1] != 0x801)
73                 return over();
74             info.score += ~ ~(Math.pow(r, 1.5) * 10) + 2;
75             start();
76         }
77         update();
78     }
79 
80     function move(t, k) {
81         pos.x += k;
82         for (var i = 0; i < 4; i++)
83             pos.fk[i] *= t;
84         update(is());
85     }
86 
87     document.onkeydown = function (e) {
88         eval("pause||" + keycom[(e ? e : event).keyCode]);
89     };
90     nextdia();
91     start();

       2:
游戏的历程中有一头处于“下降”状态的四个方块,那多个方块大家也会是要记录,才得以做它的旋转、向左、向右等等的拍卖。大家就用多个数组包罗着多个方块,那现实到那多个方块呢?大家就用一个布局体去呈现你那多少个方块它的
X、Y值和颜色。

  落时间效益果与利益图:

struct Block {

    var X:Int
    var Y:Int
    var Color:Int
    var description:String {

        return "Block[X=\(X),Y=\(Y),Color=\(Color)]"
    }
}

图片 3

    3:在俄罗丝四方那些游乐中,你也迟早得精晓有如何方块的整合能够下落,那也是叁个数据源!你也得定义好,在历次要减少的时候你就自由收取这些而数据源里面包车型地铁数目,让它轻巧的现身回降。那些干活儿也便是你要在初叶化上边要记录的三个正在减弱的方框数组的时候做的事了,下边是那么些个结合的数据源。

   别的提供源码下载。

        // 几种可能的组合方块
        self.blockArr = [

            // 第一种可能出现的组合 Z
            [
                Block(X:TETRIS_Cols/2 - 1,Y:0,Color:1),
                Block(X:TETRIS_Cols/2,Y:0,Color:1),
                Block(X:TETRIS_Cols/2,Y:1,Color:1),
                Block(X:TETRIS_Cols/2 + 1,Y:1,Color:1)

            ],
            // 第二种可能出现的组合 反Z
            [
                Block(X:TETRIS_Cols/2 + 1,Y:0,Color:2),
                Block(X:TETRIS_Cols/2,Y:0,Color:2),
                Block(X:TETRIS_Cols/2,Y:1,Color:2),
                Block(X:TETRIS_Cols/2 - 1,Y:1,Color:2)

            ],
            // 第三种可能出现的组合 田
            [
                Block(X:TETRIS_Cols/2 - 1,Y:0,Color:3),
                Block(X:TETRIS_Cols/2,Y:0,Color:3),
                Block(X:TETRIS_Cols/2 - 1,Y:1,Color:3),
                Block(X:TETRIS_Cols/2 ,Y:1,Color:3)

            ],
            // 第四种可能出现的组合 L
            [
                Block(X:TETRIS_Cols/2 - 1,Y:0,Color:4),
                Block(X:TETRIS_Cols/2 - 1,Y:1,Color:4),
                Block(X:TETRIS_Cols/2 - 1,Y:2,Color:4),
                Block(X:TETRIS_Cols/2 ,Y:2,Color:4)

            ],
            // 第五种可能出现的组合 J
            [
                Block(X:TETRIS_Cols/2,Y:0,Color:5),
                Block(X:TETRIS_Cols/2,Y:1,Color:5),
                Block(X:TETRIS_Cols/2,Y:2,Color:5),
                Block(X:TETRIS_Cols/2 - 1,Y:2,Color:5)

            ],
            // 第六种可能出现的组合 ——
            [
                Block(X:TETRIS_Cols/2,Y:0,Color:6),
                Block(X:TETRIS_Cols/2,Y:1,Color:6),
                Block(X:TETRIS_Cols/2,Y:2,Color:6),
                Block(X:TETRIS_Cols/2,Y:3,Color:6)

            ],
            // 第七种可能出现的组合 土缺一
            [
                Block(X:TETRIS_Cols/2,Y:0,Color:7),
                Block(X:TETRIS_Cols/2-1,Y:1,Color:7),
                Block(X:TETRIS_Cols/2,Y:1,Color:7),
                Block(X:TETRIS_Cols/2 + 1,Y:1,Color:7)

            ],
        ]

  特此表明:全数评价和私信都会在第不寻常间回复。也招待园子的大大们指正错误,协同进步。

     
 随机抽取下跌

  正文原始小编博客
http://www.cnblogs.com/toutou

   // 定义纪录 “正在下掉的四个方块” 位置
    var currentFall = [Block]()
    func initBlock() -> Void {

        // 生成一个在 0 - blockArr.count  之间的随机数
        let rand =  Int(arc4random()) % blockArr.count
        // 随机取出 blockArr 数组中的某个元素为正在下掉的方块组合
        currentFall = blockArr[rand]

    }

 

 3》
游戏逻辑管理