cocos2d-x 3.2 |飞机大战:碰撞与分数

cocos2d-x 3.2 |碰撞与分数
前情提要:飞机大战第五篇 实现碰撞分数
思路:游戏里物体与物体的碰撞每帧都会检测 这里我们利用前面讲过的贪吃蛇移动原理 利用update方法来实时检测
如下: 新建类----->Game
第一步:Game类(实现主要的游戏逻辑模块)
Game.h

//引入需要用到的类
#include <stdio.h>
#include "cocos2d.h"
#include "cocos-ext.h"
#include "cocosGUI.h"
#include "Bullet.h"
#include "Enemy.h"
#include "Boom.h"
#include "Tool.h"

USING_NS_CC;
using namespace cocos2d;
class Game:Layer
{
public:
    Vector<Bullet *> allBullet;//集合:子弹
    float startX,startY;
    CREATE_FUNC(Game);
    static Scene * CreateScene();
    bool init();
    virtual bool onTouchBegan(Touch *touch, Event *unused_event);//触摸检测 按下
    virtual void onTouchMoved(Touch *touch, Event *unused_event);<span style="font-family: Arial, Helvetica, sans-serif;">//触摸检测 移动</span>

    void newBullet(float t);//产生子弹
    void moveBullet(float t);//移动子弹
    Vector<Enemy *> allEnemy;//<span style="font-family: Arial, Helvetica, sans-serif;">集合:</span><span style="font-family: Arial, Helvetica, sans-serif;">敌机</span>
    void newEnemy(float t);//产生敌机
    void moveEnemy(float t);//移动敌机
    void update(float t);//游戏逻辑 碰撞检测
    int m_score;
    void reCallBack(Ref * obj);
    Vector<Tool *> allTool;//集合:道具
};
Game.cpp
#include "Game.h"
#include "BackGround.h"
#include "Plane.h"
#include "MainMenu.h"
#include "SimpleAudioEngine.h"
#include "cocosGUI.h"
#include "GameOver.h"
#include "Tool.h"
#include "Enemy.h"
using namespace ui;
using namespace CocosDenshion;
USING_NS_CC;
Scene * Game::CreateScene()
{
    auto scene=Scene::create();
    auto layer=Game::create();
    scene->addChild(layer);
    return scene;
}
bool Game::init()
{
    if (!Layer::init())
    {
        return false;
    }
    
    //创建 返回 按钮
    auto menurt=MenuItemLabel::create(Label::createWithSystemFont("返回", "", 32),CC_CALLBACK_1(Game::reCallBack, this));
    menurt->setAnchorPoint(Vec2::ZERO);
    menurt->setPosition(600-30,Director::getInstance()->getWinSize().height-36);
    menurt->setColor(Color3B::GREEN);
    
    //创建菜单
    auto menu=Menu::create(menurt,nullptr);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu,2);
    
    //添加背景
    auto bk=BackGround::create();
    this->addChild(bk);
    //添加飞机
    auto fly1=Plane::create();
    this->addChild(fly1,1);
    fly1->moveTo(100,100);
    fly1->setTag(10);
    
    //处理飞机的HP
    for (int i=0; i<fly1->hp; i++)
    {
        auto sphp=Sprite::create("hp_1.png");
        sphp->setTag(1000+i);
        this->addChild(sphp);
        sphp->setAnchorPoint(Vec2(0,1));
        sphp->setPosition(Vec2(i*sphp->getContentSize().width+3*i,Director::getInstance()->getWinSize().height));
    }

    //控制飞机飞行
    auto listener=EventListenerTouchOneByOne::create();//创建侦听
    listener->onTouchBegan=CC_CALLBACK_2(Game::onTouchBegan, this);//定义侦听的回调
    listener->onTouchMoved=CC_CALLBACK_2(Game::onTouchMoved, this);
    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);//将侦听添加到事件分发器中
    
    //产生子弹 计划任务
    this->schedule(schedule_selector(Game::newBullet),0.2);//每隔200毫秒产生一次子弹
    this->schedule(schedule_selector(Game::moveBullet),0.01);
    
    //产生敌机
    this->schedule(schedule_selector(Game::newEnemy),1);
    this->schedule(schedule_selector(Game::moveEnemy),0.01);
    
    //实现游戏逻辑
    this->scheduleUpdate();
    //分数显示器1
    this->m_score=0;
    auto tscore=TextAtlas::create("0000", "img_num_dis.png",17 , 22, "0");
    this->addChild(tscore,12);
    tscore->setTag(210);
    tscore->setPosition(Vec2(Director::getInstance()->getWinSize().width/2,
                             Director::getInstance()->getWinSize().height-64));
    
    //分数显示2
//    auto scoreLb = Label::createWithSystemFont(StringUtils::format("分数:%d",score), "", 32);
//    scoreLb->setAnchorPoint(Vec2::ZERO);
//    scoreLb->setColor(Color3B::GREEN);
//    scoreLb->setPosition(0,Director::getInstance()->getWinSize().height-36);
//    scoreLb->setTag(123);
//    this->addChild(scoreLb,2);
    return true;
}
//返回主菜单
void Game::reCallBack(Ref * obj)
{
    auto scene=MainMenu::CreateScene();
    Director::getInstance()->replaceScene(scene);
}

//按下
bool Game::onTouchBegan(Touch *touch, Event *unused_event)
{
    this->startX=touch->getLocation().x;
    this->startY=touch->getLocation().y;
    return true;
}
//移动
void Game::onTouchMoved(Touch *touch, Event *unused_event)
{
    float mx=touch->getLocation().x-startX;
    float my=touch->getLocation().y-startY;
    auto fly1=(Plane *)this->getChildByTag(10);
    fly1->moveTo(fly1->px+mx, fly1->py+my);
    this->startX=touch->getLocation().x;
    this->startY=touch->getLocation().y;
}
void Game::newBullet(float t)//产生子弹
{
    auto fly1=(Plane *)this->getChildByTag(10);
    Bullet * bt=Bullet::newBullet(1, 0,fly1->px,fly1->py);
    allBullet.pushBack(bt);
    this->addChild(bt);
    //子弹音效
    SimpleAudioEngine::getInstance()->playEffect("launch_1.wav");
}

void Game::moveBullet(float t)//移动子弹
{
    for (int i=0;i<allBullet.size();i++)
    {
        Bullet * nowB=allBullet.at(i);
        nowB->moveTo(nowB->px, nowB->py+15);
        if (nowB->py>Director::getInstance()->getWinSize().height)
        {
            allBullet.erase(i);
            this->removeChild(nowB);
            i--;
        }
    }
    
}
void Game::newEnemy(float t)
{
    int type=random()%10;
    if (type < 3)
    {
        type = 1;
    }
    else if (type > 8)
    {
        type = 2;
    }else
    {
        type = 1;
    }
    int ex=random()%(int)Director::getInstance()->getWinSize().width;
    Enemy * news=Enemy::createEnemy(type, ex, Director::getInstance()->getWinSize().height+200);
    allEnemy.pushBack(news);//将新产生的敌机添加到集合
    this->addChild(news);   //在当前GAME图层添加敌机层
}

void Game::moveEnemy(float t)
{
    for (int i=0; i<allEnemy.size(); i++)
    {
        //获取第i架敌机
        Enemy * nowE=allEnemy.at(i);
        nowE->moveTo(nowE->ex, nowE->ey-5);
        if (nowE->ey<-nowE->eSprite->getContentSize().height)
        {
            allEnemy.erase(i);
            this->removeChild(nowE);
            i--;
        }
    }
}
void Game::update(float t)
{
    //创建一个Label层 获取计数器标签
    //auto scoreLb = (Label *)this->getChildByTag(123);
    //碰撞检测
    if (allEnemy.size()==0 || allBullet.size()==0)
    {
        return;
    }
    auto fly1=(Plane *)this->getChildByTag(10);
    //判断飞机和道具
    for (int j = 0; j<allTool.size(); j++)
    {
        //得到第j架敌机
        Tool * nowTool=allTool.at(j);
        Rect br(fly1->px,
                fly1->py,
                fly1->getChildByTag(10)->getContentSize().width,
                fly1->getChildByTag(10)->getContentSize().height);
        //敌机的矩形大小
        Rect er(nowTool->tx,
                nowTool->ty,
                nowTool->sp->getContentSize().width,
                nowTool->sp->getContentSize().height);
        if (br.intersectsRect(er))
        {//碰撞检测到两个矩形相交
            //判断吃到哪种道具
            switch (nowTool->type) {
                case 1://hp
                {
                    fly1->hp++;
                    int i=fly1->hp-1;
                    auto sphp=Sprite::create("hp_1.png");
                    sphp->setTag(1000+i);
                    this->addChild(sphp);
                    sphp->setAnchorPoint(Vec2(0,1));
                    sphp->setPosition(Vec2(i*sphp->getContentSize().width+3*i,Director::getInstance()->getWinSize().height));
                }
                    break;
                case 2://炸雷
                {
                    //所有敌机都销毁
                    while (allEnemy.size()>0)
                    {
                        Enemy * nowEnemy=allEnemy.at(0);
                        Boom * boom=Boom::createBoom(2, nowEnemy->ex, nowEnemy->ey);
                        this->addChild(boom,10);
                        //爆炸一次 总增加分数
                        this->m_score+=300;
                        allEnemy.eraseObject(nowEnemy);
                        nowEnemy->removeFromParentAndCleanup(true);
                    }
                    //播放音效
                    SimpleAudioEngine::getInstance()->playEffect("launch_1.wav");
                    //播放爆炸粒子
                    Boom *  boom=Boom::createBoom(2,
                                               Director::getInstance()->getWinSize().width/2,
                                               Director::getInstance()->getWinSize().height/2);
                    this->addChild(boom,15);
                }
                    
                    break;
                case 3://激光
                    
                    break;
                case 4://散弹
                    
                    break;
                    

            }
            //敌机消失
            nowTool->unscheduleAllSelectors();
            nowTool->removeFromParentAndCleanup(true);
            allTool.eraseObject(nowTool);
            j--;
        }
    
    }
    
    for (int j = 0; j<allEnemy.size(); j++)
    {
        //得到第j架敌机
        Enemy * nowEnemy=allEnemy.at(j);
        //子弹的矩形大小
        Rect br(fly1->px,
                fly1->py,
                fly1->getChildByTag(10)->getContentSize().width,
                fly1->getChildByTag(10)->getContentSize().height);
        //敌机的矩形大小 
        Rect er(nowEnemy->ex,
                nowEnemy->ey,
                nowEnemy->eSprite->getContentSize().width,
                nowEnemy->eSprite->getContentSize().height);
        if (br.intersectsRect(er))
        {//碰撞检测到两个矩形相交
            //敌机消失
            allEnemy.eraseObject(nowEnemy);
            nowEnemy->removeFromParentAndCleanup(true);
            j--;
            //掉血音效
            SimpleAudioEngine::getInstance()->playEffect("skill_1.wav");
            //我方Hp--
            if (fly1->hp>0)
            {
                this->removeChildByTag(1000+fly1->hp-1);
                fly1->hp=fly1->hp-1;
            }
            if(fly1->hp<=0)
            {//Game Over
                //创建一个场景
                auto scene=GameOver::createScene();
                
                //将场景覆盖到Game Over 并释放之前场景
                Director::getInstance()->replaceScene(scene);
            }
        }
    }
    //判断子弹 是否碰到敌机
    for (int i=0; i<allBullet.size(); i++)
    {
        
        //得到第i颗子弹
        Bullet * nowBullet=allBullet.at(i);
        for (int j = 0; j<allEnemy.size(); j++)
        {
            //得到第j架敌机
            Enemy * nowEnemy=allEnemy.at(j);
            //子弹的矩形大小
            Rect br(nowBullet->px,
                    nowBullet->py,
                    nowBullet->bt->getContentSize().width,
                    nowBullet->bt->getContentSize().height);
            //敌机的矩形大小
            Rect er(nowEnemy->ex,
                    nowEnemy->ey,
                    nowEnemy->eSprite->getContentSize().width,
                    nowEnemy->eSprite->getContentSize().height);
            if (br.intersectsRect(er))
            {
                    //检测到两个矩形相交 子弹消失
                    allBullet.eraseObject(nowBullet);
                    nowBullet->removeFromParentAndCleanup(true);
                    i--;
                    nowEnemy->hp=nowEnemy->hp-1;
                    if(nowEnemy->hp<=0)
                    {

                        //爆炸
                        if(nowEnemy->type==1)
                        {
                            Boom * boom=Boom::createBoom(1, nowEnemy->ex, nowEnemy->ey);
                            this->addChild(boom);
                            //scoreLb->setString(StringUtils::format("分数:%d",score+=40));
                            //增加分数
                            this->m_score+=40;
                        }
                        else
                        {
                            Boom * boom=Boom::createBoom(2, nowEnemy->ex, nowEnemy->ey);
                            this->addChild(boom);
                            //scoreLb->setString(StringUtils::format("分数:%d",score+=60));
                            this->m_score+=60;
                        }
                        //分数增加器
                        auto score1=(TextAtlas *)this->getChildByTag(210);
                        score1->setString(StringUtils::format("%d",m_score));
                        
                        //爆炸音效
                        SimpleAudioEngine::getInstance()->playEffect("launch_2.wav");
                        
                        //道具处理
                        if (nowEnemy->toolID>0) {
                            //掉落道具
                            auto tool=Tool::newTool(nowEnemy->toolID,nowEnemy->ex,nowEnemy->ey);
                            this->addChild(tool);
                            allTool.pushBack(tool);
                        }
                        
                        allEnemy.eraseObject(nowEnemy);
                        nowEnemy->removeFromParentAndCleanup(true);
                        j--;
                        
                    }
                    break;//退出这次循环
            }
        }
    }
}

总结:至此利用5个篇章简单实现了一下飞机大战的主要核心内容,希望对读者有帮
后期还有两个番外篇:游戏分数保存+安卓导出调试(因为安卓实在是让人蛋疼)
ps:游戏中用到的素材与音效请自行替换。


你可能感兴趣的:(核心,Random,逻辑,碰撞检测,分数)