• javascript异步编程系列【八】Jscex版火拼俄罗斯


    一.简介

    俄罗斯方块(Tetris, 俄文:Тетрис)是一款风靡全球的电视游戏机和掌上游戏机游戏,它由俄罗斯人阿列克谢·帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。

    els2

    二.需求分析

    (完全按照QQ游戏的制作,如下图:)

    els

    三.技术分析与实现

    1.方块位置定位

    解决方案:建立盒子模型

    els3els4els5els6els7els8els9

    由于长条的存在,所以建立一个4*4的盒子模型,任何一个方块都会存在该盒子当中,方块的定位就===盒子的定位。

    2.颜色状态的生成与保存

    随机生成颜色:

     function randomColor() {
            //16进制方式表示颜色0-F
            var arrHex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
            var strHex = "#";
            var index;
            for (var i = 0; i < 6; i++) {
                //取得0-15之间的随机整数
                index = Math.round(Math.random() * 15);
                strHex += arrHex[index];
            }
            return strHex;

     } 

        

    颜色保存:(那一个方块的一种状态做示例)

       var diamonds = new Array();
        diamonds[0] = { x: appearPosition.position.x + 1, y: appearPosition.position.y, diamondColor: color };
        diamonds[1] = { x: appearPosition.position.x + 0, y: appearPosition.position.y + 1, diamondColor: color };
        diamonds[2] = { x: appearPosition.position.x + 1, y: appearPosition.position.y + 1, diamondColor: color };
        diamonds[3] = { x: appearPosition.position.x + 2, y: appearPosition.position.y + 1, diamondColor: color };

    所有生成的方块有个diamondColor属性,用于存颜色。appearPosition.position是盒子模型的位置。

    3.碰撞检测

    碰撞分两种,一种是元素与左右墙壁和底部的碰撞,另外一种是方块与底部方块的接触碰撞

    a.元素与左右墙壁和底部的碰撞

        a.1元素与底部的碰撞检测

      if (diamonds[i].y * height + height >= canvasHeight) {
            appearPosition.position.x = Math.round(appearPosition.position.x);
            appearPosition.position.y = Math.round(appearPosition.position.y);
            createElement();
            breakTag = 1;

       }  

     

    a.2元素与左右墙壁的碰撞检测

       function returnRightOrLeft() {
            var max_X = 11;
            for (i = 0; i < diamonds.length; i++) {
                if (diamonds[i].x > max_X) {
                    max_X = diamonds[i].x;
                }
            }
            if (max_X != 11) appearPosition.position.x = appearPosition.position.x - (max_X - 11);
            var min_X = 0;
            for (i = 0; i < diamonds.length; i++) {
                if (diamonds[i].x < min_X) {
                    min_X = diamonds[i].x;
                }
            }
            if (min_X != 0) appearPosition.position.x = appearPosition.position.x - min_X;
        }

    b.元素与元素碰撞检测

        //判断下面是否有元素
        for (j = 0; j < bottomElement.length; j++) {
            if (bottomElement[j].x == diamonds[i].x) {
                if (Math.round(bottomElement[j].y) == Math.round(diamonds[i].y + 1)) {
                    appearPosition.position.x = Math.round(appearPosition.position.x);
                    appearPosition.position.y = Math.round(appearPosition.position.y);
                    createElement();
                    breakTag = 1;
                }
            }
        }
        //判断arrayOne是否在arrayTwo的右边
        function IsAtRight(arrayOne, arrayTwo) {
            for (i = 0; i < arrayOne.length; i++) {
                for (j = 0; j < arrayTwo.length; j++) {
                    if (Math.round(arrayOne[i].y) == Math.round(arrayTwo[j].y)) {
                        if (arrayTwo[j].x == arrayOne[i].x + 1) return true;
                    }
                }
            }
            return false;
        }
        //判D断arrayOne是否在arrayTwo的左边
        function IsAtLeft(arrayOne, arrayTwo) {
            for (i = 0; i < arrayOne.length; i++) {
                for (j = 0; j < arrayTwo.length; j++) {
                    if (Math.round(arrayOne[i].y) == Math.round(arrayTwo[j].y)) {
                        if (arrayTwo[j].x == arrayOne[i].x - 1) return true;
                    }
                }
            }
            return false;
        }

    4.方块变形

        var direction = 0;
        if (e.keyCode == 87) {
            direction++;
            direction %= 4;
        }

    W键是变形,0123分别代表四种。

    如果是长条或者只有两种状态的直接  if (direction % 2 == 0) {},如果是正方块直接忽略direction,因为它就一种形状。

    5.键盘捕获(目前WSAD+空格,W是变形,S和空格都是加速,IE9和FF异常,建议在谷歌浏览器下运行)

        document.onkeydown = function (e) {
            if (e.keyCode == 65) {
                for (i = 0; i < diamonds.length; i++) {
                    if (diamonds[i].x == 0) {
                        return;
                    }
                }
                if (IsAtLeft(diamonds, bottomElement)) {
                    return;
                }
                appearPosition.position.x -= 1;
            }
            if (e.keyCode == 87) {
                direction++;
                direction %= 4;
            }
            if (e.keyCode == 68) {
                for (i = 0; i < diamonds.length; i++) {
                    if (diamonds[i].x == 11) {
                        return;
                    }
                }
                if (IsAtRight(diamonds, bottomElement)) {
                    return;
                }
                appearPosition.position.x += 1;
            }
            if (e.keyCode == 32) {
                delay = 1;
            }
            if (e.keyCode == 83) {
                delay = 1;
            }
        }
        document.onkeyup = function (e) {
            if (e.keyCode == 32) {
                delay = 20;
            }
            if (e.keyCode == 83) {
                delay = 20;
            }
        }
      

    6.消除加分

        //一行满了的话,消除并加分
        function clearUp() {
            for (var line = 0; line < 21; line++) {
                var count = 0;
                for (var i = 0; i < bottomElement.length; i++) {
                    if (bottomElement[i].y == line) {
                        count++;
                    }
                }
                if (count == 12) clearByLineNum(line);
            }
            // if(count==12)
        }
        function clearByLineNum(num) {
            //以上的元素下降一行
            score++;
            var count = 0;
            for (i = 0; i < bottomElement.length; i++) {
                if (bottomElement[i].y == num) {
                    count++;
                }
            }
            for (var j = 0; j < count; j++) {
                for (var i = 0; i < bottomElement.length; i++) {
                    if (bottomElement[i].y == num) {
                        bottomElement.splice(i, 1);
                        break;
                    }
                }
            }
            for (i = 0; i < bottomElement.length; i++) {
                if (bottomElement[i].y < num) {
                    bottomElement[i].y += 1;
                }
            }
        }
    消除加分有一个潜在的逻辑就是,在该行以上的元素的位置下降一个格子。

    7.控制核心Jscex  Show Time

        var JropAsync = eval(Jscex.compile("async", function () {
            var breakTag = 0;
            while (true) {
                color = randomColor();
                rectBlockIndex = MR() * 7 | 0;
                direction = MR() * 3 | 0;
                $await(Jscex.Async.sleep(1));
                while (true) {
                    for (i = 0; i < diamonds.length; i++) {
                        if (diamonds[i].y * height + height >= 525) {
                            appearPosition.position.x = Math.round(appearPosition.position.x);
                            appearPosition.position.y = Math.round(appearPosition.position.y);
                            createElement();
                            breakTag = 1;
                        }
                        //判D断?下?面?是?否?有D元a素?
                        for (j = 0; j < bottomElement.length; j++) {
                            if (bottomElement[j].x == diamonds[i].x) {
                                if (Math.round(bottomElement[j].y) == Math.round(diamonds[i].y + 1)) {
                                    appearPosition.position.x = Math.round(appearPosition.position.x);
                                    appearPosition.position.y = Math.round(appearPosition.position.y);
                                    createElement();
                                    breakTag = 1;
                                }
                            }
                        }
                    }
                    if (breakTag == 1) {
                        for (i = 0; i < diamonds.length; i++) {
                            //alert(diamonds[i].x + "____" + diamonds[i].y)
                            bottomElement.push(diamonds[i]);
                        }
                        clearUp();
                        //清?空?下?降μ的?元a素?
                        diamonds.splice(0, diamonds.length);
                        appearPosition = { position: { x: 4, y: -2 }, direction: 0 };
                        breakTag = 0;
                        break;
                    }
                    appearPosition.position.y += step;
                    draw();
                    $await(Jscex.Async.sleep(delay));
                }
            }
        }));

    这是也整个俄罗斯方块的控制核心,由两个while循环构成,简单大方

    四.在线演示

    操作指南:W变形  A左移 D右移     (谷歌浏览器:S加速 空格加速,其他浏览器慎重按此键,该死的浏览器兼容)

    火拼俄罗斯

    Your browser does not support the canvas element.
    得分:0

    最新的Jscex 库,请上https://github.com/JeffreyZhao/jscex或者http://www.sndacode.com/projects/jscex/wiki下载吧····

    五.同步

    本文已同步更新至:

    HTML5实验室【目录】:   http://www.cnblogs.com/iamzhanglei/archive/2011/11/06/2237870.html

  • 相关阅读:
    如何写工程代码——重新认识面向对象
    java 利用同步工具类控制线程
    java简易excel导入导出工具(封装POI)
    二叉搜索树的简单介绍
    spring security 配置多个AuthenticationProvider
    spring和UEditor结合
    继承后的执行顺序
    【转】WPF中实现自定义虚拟容器(实现VirtualizingPanel)
    <译>自学WPF系列(1)
    <译>C#使用设计模式和软件设计原则构建应用程序 PartIII
  • 原文地址:https://www.cnblogs.com/iamzhanglei/p/2171930.html
Copyright © 2020-2023  润新知