zl程序教程

您现在的位置是:首页 >  其他

当前栏目

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

游戏微信笔记学习开发 搭建 飞机 cocos2dx
2023-09-14 09:11:26 时间

一、七说八说

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

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

(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

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