• cocos2dx游戏开发——微信打飞机学习笔记(十)——碰撞检测的搭建


    一、七说八说

           大家都发现了= =,做了那么多,发现就是摆设,完全没有打飞机的感觉,没有实现碰撞的监测。比如说呢,子弹和敌机,玩家与敌机就是需要有碰撞检测的说,然后在这篇我想会很长很长的教程中我们一步步的进行完善的说~。

    二、子弹与灰机的碰撞检测

    (1)加入爆炸的动画~(加到EnemyLayer中)

    a、通用的敌人爆炸动画的创建函数~

    Animate* EnemyLayer::playAnimation(std::string formatstring, int count)
    {
        auto animation = Animation::create();    //创建一个帧动画序列
        for (int i = 1; i < count + 1; i++)       //把对应敌人名字相对应的爆炸的图片放进去~
        {
            char szName[100] = { 0 };
            sprintf(szName, formatstring.c_str(), i);
            auto spriteFrame = SpriteFrameCache::getInstance()->spriteFrameByName(szName);
            animation->addSpriteFrame(spriteFrame);
        }
        // 下面的是爆炸的时间间隔~
        animation->setDelayPerUnit(0.08f);
        animation->setRestoreOriginalFrame(true);//设置爆炸动画播放完之后要不要回到第一帧,肯定是要的。
    
        auto animate = Animate::create(animation);//创建动画~
    
        return animate;
    }

    b、动画的创建

               因为最大的那个敌人飞机爆炸的时候是有6帧的动画,而其他的小飞机只有4帧的爆炸动画,这决定了我们调用上面动画制作的参数,所以千万不能错~

    void EnemyLayer::playEnemyExplosionAnimation(Enemy* enemy, int enemyType)
    {
        int frame = 4;
    
        if (enemyType == ENEMY_MAX)
        {
            frame = 6;
        }
        //上面根据飞机的类型选择应该播放的动画~    
    
        auto animationName = StringUtils::format("enemy%d", enemyType); 
        enemy->setIsPlayAnimation(true);//设置正在播动画
    
    
        auto animation = this->playAnimation(animationName + "_down%d.png", frame);//调用上面的函数~
      
        auto acionDone = CallFunc::create([=](){
            enemy->setVisible(false);       //炸完之后就消失~
            enemy->setIsPlayAnimation(false);//改成没有播动画~
        });
    
        auto action = Sequence::create(animation, acionDone, nullptr);
    
        enemy->getSprite()->runAction(action);
    }

             到这里就完成了敌机爆炸的动画效果~。

    (2)加入碰撞检测~(在GameScene中加入)

    a、碰撞检测

             其实就是遍历子弹的数组还有就是飞机的数组,看看有没有2个撞到一起,有的话,就life--,到0 的时候就播放飞机翘掉的动画~,这就是碰撞检测的函数(方法),下面看代码~

    void GameScene::onEnemyBulletCollsionDetection(Vector<Sprite*> BulletArray, Vector<Enemy*> EnemyArray, int enemyType)
    {
        for (auto& bullet : BulletArray)
        {
            if (bullet->isVisible())        //子弹是否可见
            {
                for (auto& enemy : EnemyArray)
                {
                    if (enemy->isVisible())       //敌机是否可见
                    {
                        Rect bulletRect = bullet->getBoundingBox();     //获得子弹和敌人的区域~
                        Rect enemyRect = enemy->getBoundingBox();
                      //如果在播动画,说明敌机已经死掉了= =,然后后面就是是不是碰在一起了。
                        if (!enemy->IsPlayAnimation() && enemyRect.intersectsRect(bulletRect))
                        {
                            enemy->loseLife();           //扣血~
                            _bullet->removeBullet(bullet);    //把子弹去掉~
                            if (enemy->getLife() == 0)      //翘掉的时候~
                            {
                                if (enemyType == ENEMY_MIN)
                                {
                                    enemy->stopAllActions();//停止飞机的所有动作(比如向下飞)           
                                    _enemyLayer->playEnemyExplosionAnimation(enemy, ENEMY_MIN);
                                    enemy->setLife(ENEMY_MIN_LIFE);
                                     //记得重置飞机的生命值,很重要的~                       
                                }
                                else if (enemyType == ENEMY_MED)
                                {
                                    enemy->stopAllActions();
                                    _enemyLayer->playEnemyExplosionAnimation(enemy, ENEMY_MED);
                                    enemy->setLife(ENEMY_MED_LIFE);
                                    
                                }
                                else if (enemyType == ENEMY_MAX)
                                {
                                    enemy->stopAllActions();
                                    _enemyLayer->playEnemyExplosionAnimation(enemy, ENEMY_MAX);
                                    enemy->setLife(ENEMY_MAX_LIFE);
                                
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    b、GameLoop

                碰撞检测其实就是整个一个gameLoop内很关键的东西,还有就是游戏里面就有一个gameLoop,控制着整个游戏,现在我们就来添加以下GameLoop

    void GameScene::gameLoop(float dt)
    {      
          //调用碰撞检测~~~~
        this->onEnemyBulletCollsionDetection(_bullet->getBulletsArray(), _enemyLayer->getEnemyArray1(), ENEMY_MIN);
        this->onEnemyBulletCollsionDetection(_bullet->getBulletsArray(), _enemyLayer->getEnemyArray2(), ENEMY_MED);
        this->onEnemyBulletCollsionDetection(_bullet->getBulletsArray(), _enemyLayer->getEnemyArray3(), ENEMY_MAX);
    
        if (!_player->getisAlive())    //如果玩家死掉的话,就结束游戏~
        {
            this->gameover();
        }
        
    }

    下面是gameover()的代码·,暂时简单的实现下~

    void GameScene::gameover()
    {
        _enemyLayer->stopAllEnemiesSpaw();
        _bullet->stopSpawBullet();
         _background->stopBackground();
    }

    最后把GameLoop加入schedule

    this->schedule(schedule_selector(GameScene::gameLoop), 1.0 / 60);

    搞定收工~。

    c、小细节~

            大家可能发现有好多很小的函数,我在这里直接调用,而以前却没有在教程中提出,由于那些事很简单的传出数据的方法,大家可以直接看源码,就很简单的会理解,在这里我就不在贴出来啦·~,要不好多好多~

    (3)效果图~

    image         image

               大家发现了,我们现在是无敌模式= =,因为我们玩家飞机死不了 = = ,所以我们要加入玩家和敌机的碰撞检测

    三、玩家和敌人的碰撞检测

    a、玩家飞机爆炸的动画~(在PlayerLayer中加入)

    void PlayerLayer::playPlayerBlowAnimation()
    {
        auto animation = Animation::create();
        for (int i = 1; i < 5; i++)
        {
            char szName[100] = { 0 };
            sprintf(szName, "hero_blowup_n%d.png", i);
            auto spriteFrame = SpriteFrameCache::getInstance()->spriteFrameByName(szName);
            animation->addSpriteFrame(spriteFrame);
        }
        // should last 2.8 seconds. And there are 14 frames.
        animation->setDelayPerUnit(0.08f);
        animation->setRestoreOriginalFrame(true);
    
        auto animate = Animate::create(animation);
        auto actionDone = CallFunc::create([=]()
        {
            _playerplane->setVisible(false);    //播完动画就消失掉~
        });
    
        auto action = Sequence::create(animate, actionDone, nullptr);
    
        _playerplane->runAction(action);
    }

             基本上跟敌机爆炸是一样的说,所以就不加过多的叙述

    b、如何死~~~

    void GameScene::onEnemyPlayerCollsionDetection(Sprite* player, Vector<Enemy*> EnemyArray, int enemyType)
    {
        for (auto& enemy : EnemyArray)
        {   
            // 敌机和玩家飞机是否活着,还有是否碰到一起~
            if (enemy->isVisible() &&
                _player->getisAlive() &&
                enemy->getBoundingBox().intersectsRect(_player->getPlayerPlane()->getBoundingBox()))
            {  
               //大家一起死= =
                enemy->stopAllActions();
                _enemyLayer->playEnemyExplosionAnimation(enemy, enemyType);
    
                _player->playPlayerBlowAnimation();
    
                switch (enemyType)//还是要记住回血= =
                {
                case ENEMY_MIN: enemy->setLife(ENEMY_MIN_LIFE); break;
                case ENEMY_MED: enemy->setLife(ENEMY_MED_LIFE); break;
                case ENEMY_MAX: enemy->setLife(ENEMY_MED_LIFE); break;
                default:
                    break;
                }
                
                _player->setisAlive(false);  //把玩家状态调成死亡~
            }
        }
    }

    (2)加入到GameLoop

    this->onEnemyPlayerCollsionDetection(_player->getPlayerPlane(), _enemyLayer->getEnemyArray1(), ENEMY_MIN);
        this->onEnemyPlayerCollsionDetection(_player->getPlayerPlane(), _enemyLayer->getEnemyArray2(), ENEMY_MED);
        this->onEnemyPlayerCollsionDetection(_player->getPlayerPlane(), _enemyLayer->getEnemyArray3(), ENEMY_MAX);

    (3)效果图~

    image

    这样就默默实现完打飞机的主要过程啦,后面的教程就是不断的进行完善了 = =,虽然还是很麻烦~

  • 相关阅读:
    设置 tableview 的背景颜色,总是有蒙层
    设置 tableview 的背景颜色,总是不生效
    bug: 在使用HMSegmentedControl时,设置selectionIndicatorEdgeInsets对左右边界没有用
    心情烦闷annoying,贴几个图!唉!annoying
    [EffectiveC++]item28:避免返回handles指向对象内部成分
    Memorize and recite an important historical speech
    NCE3
    NCE2
    015 volatile关键字 线程函数的lParam 原子操作和旋转锁.
    015 原子操作 旋转锁
  • 原文地址:https://www.cnblogs.com/BlueMountain-HaggenDazs/p/3936723.html
Copyright © 2020-2023  润新知