zoukankan      html  css  js  c++  java
  • Chrome自带恐龙小游戏的源码研究(七)

      在上一篇《Chrome自带恐龙小游戏的源码研究(六)》中研究了恐龙的跳跃过程,这一篇研究恐龙与障碍物之间的碰撞检测。

    碰撞盒子

      游戏中采用的是矩形(非旋转矩形)碰撞。这类碰撞优点是计算比较简单,缺点是对不规则物体的检测不够精确。如果不做更为精细的处理,结果会像下图:

     

    如图所示,两个盒子虽然有重叠部分,但实际情况是恐龙和仙人掌之间并未发生碰撞。为了解决这个问题,需要建立多个碰撞盒子:

    不过这样还是有问题,观察图片,恐龙和仙人掌都有四个碰撞盒子,如果每次Game Loop里都对这些盒子进行碰撞检测,那么结果是每次需要进行4X4=16次计算,如果物体或者盒子很多,就会导致运算量大大增加,造成严重的性能问题。为改进这一点,只需要先检测两个大盒子之间是否碰撞,如果没有,则略去里面小盒子的碰撞检测。反之则对里面的小盒子做碰撞检测。游戏中使用CollisionBox构造函数创建碰撞盒子:

    /**
    * 碰撞盒子
    * @param x    {number} 盒子x坐标
    * @param y    {number} 盒子y坐标
    * @param w    {number} 盒子宽度
    * @param h    {number} 盒子高度
    */
    function CollisionBox(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
    }

    使用boxCompare方法检测两个盒子是否发生碰撞:

     1 /**
     2 * 碰撞检测
     3 * @param tRexBox {Object} 霸王龙的碰撞盒子
     4 * @param obstacleBox {Object} 障碍物的碰撞盒子
     5 */
     6 function boxCompare(tRexBox, obstacleBox) {
     7     var tRexBoxX = tRexBox.x,
     8         tRexBoxY = tRexBox.y,
     9         obstacleBoxX = obstacleBox.x,
    10         obstacleBoxY = obstacleBox.y;
    11 
    12     return tRexBoxX < obstacleBoxX + obstacleBox.width && tRexBoxX + tRexBox.width > obstacleBoxX && tRexBoxY < obstacleBoxY + obstacleBox.height && tRexBox.height + tRexBoxY > obstacleBoxY;
    13 }

    建立碰撞盒子

      接下来要为恐龙和障碍物建立碰撞盒子。游戏中为恐龙建立了6个碰撞盒子,分布在头、躯干和脚,同时它还有闪避状态:

            Trex.collisionBoxes = {
                DUCKING:[
                    new CollisionBox(1,18,55,25)
                ],
                RUNNING: [
                    new CollisionBox(22, 0, 17, 16),
                    new CollisionBox(1, 18, 30, 9),
                    new CollisionBox(10, 35, 14, 8),
                    new CollisionBox(1, 24, 29, 5),
                    new CollisionBox(5, 30, 21, 4),
                    new CollisionBox(9, 34, 15, 4)
                ]
            };

    障碍物的碰撞盒子定义在Obstacle.types中:

     1 Obstacle.types = [{
     2     type: 'CACTUS_SMALL',
     3      17,
     4     height: 35,
     5     yPos: 105,
     6     multipleSpeed: 4,
     7     minGap: 120,
     8     minSpeed: 0,
     9     collisionBoxes: [new CollisionBox(0, 7, 5, 27), new CollisionBox(4, 0, 6, 34), new CollisionBox(10, 4, 7, 14)]
    10 },
    11 {
    12     type: 'CACTUS_LARGE',
    13      25,
    14     height: 50,
    15     yPos: 90,
    16     multipleSpeed: 7,
    17     minGap: 120,
    18     minSpeed: 0,
    19     collisionBoxes: [new CollisionBox(0, 12, 7, 38), new CollisionBox(8, 0, 7, 49), new CollisionBox(13, 10, 10, 38)]
    20 },
    21 {
    22     type: 'PTERODACTYL',
    23      46,
    24     height: 40,
    25     yPos: [100, 75, 50],
    26     // Variable height mobile.
    27     multipleSpeed: 999,
    28     minSpeed: 8.5,
    29     minGap: 150,
    30     collisionBoxes: [new CollisionBox(15, 15, 16, 5), new CollisionBox(18, 21, 24, 6), new CollisionBox(2, 14, 4, 3), new CollisionBox(6, 10, 4, 7), new CollisionBox(10, 8, 6, 9)],
    31     numFrames: 2,
    32     frameRate: 1000 / 6,
    33     speedOffset: .8
    34 }];
    View Code

    不过这只是定义了障碍物数量为1的情况,复数的障碍物需要在创建时修正碰撞盒子:

    1 if (this.size > 1) {//只针对仙人掌
    2     this.collisionBoxes[1].width = this.width - this.collisionBoxes[0].width - this.collisionBoxes[2].width;
    3     this.collisionBoxes[2].x = this.width - this.collisionBoxes[2].width;
    4 }

    下图分别为单数和复数的盒子。

    最后执行碰撞检测:

     1 function checkForCollision(obstacle, tRex) {
     2         //创建最外层的大盒子
     3     var tRexBox = new CollisionBox(tRex.xPos + 1, tRex.yPos + 1, tRex.config.WIDTH - 2, tRex.config.HEIGHT - 2);
     4     var obstacleBox = new CollisionBox(obstacle.xPos + 1, obstacle.yPos + 1, obstacle.typeConfig.width * obstacle.size - 2, obstacle.typeConfig.height - 2);
     5 
     6     }
     7     if (boxCompare(tRexBox, obstacleBox)) {
     8         var collisionBoxes = obstacle.collisionBoxes;
     9         var tRexCollisionBoxes = tRex.ducking ? Trex.collisionBoxes.DUCKING: Trex.collisionBoxes.RUNNING;
    10 
    11         for (var t = 0; t < tRexCollisionBoxes.length; t++) {
    12             for (var i = 0; i < collisionBoxes.length; i++) {
    13                 //修正盒子
    14                 var adjTrexBox = createAdjustedCollisionBox(tRexCollisionBoxes[t], tRexBox);
    15                 var adjObstacleBox = createAdjustedCollisionBox(collisionBoxes[i], obstacleBox);
    16                 var crashed = boxCompare(adjTrexBox, adjObstacleBox);
    17 
    18                 if (crashed) {
    19                     return [adjTrexBox, adjObstacleBox];
    20                 }
    21             }
    22         }
    23     }
    24     return false;
    25 }
    View Code
    //修正盒子,将相对坐标转为画布坐标
    function createAdjustedCollisionBox(box, adjustment) {
        return new CollisionBox(box.x + adjustment.x, box.y + adjustment.y, box.width, box.height);
    }
    View Code

    以下是最终运行效果,打开控制台就能看到碰撞输出:

     

    后记

      通过建立碰撞盒子进行碰撞检测在应用上非常广泛,著名的街机游戏《街霸》和《拳皇》就是采用了这种方式:

     

    可以看到游戏中对人物建立了多个碰撞盒子,红色代表攻击区域,蓝色代表可以被攻击的区域,绿色区域之间不能重叠,用来推挤对手。

  • 相关阅读:
    模式识别: 线性分类器
    Graph Cuts学习笔记2014.5.16----1
    图像处理程序框架—MFC相关知识点
    图像处理程序框架—MFC相关知识点
    【ML】人脸识别
    【视觉】两个赞的开发文档
    【调研】在总体为n的情况下,多少样本有代表性?
    【ubuntu】upload files
    【git】git pull
    【spark】with mongodb
  • 原文地址:https://www.cnblogs.com/undefined000/p/trex_7.html
Copyright © 2011-2022 走看看