这节完成了许多的功能:
1、添加小飞机、中等飞机、大飞机。
2、每种飞机的移动速度和血量不同。
3、飞机被子弹打击效果。
4、飞机被摧毁效果。

cocos2d提供的Sprite类不足以提供以上功能,所以我们需要新建一个Enemy类重写Sprite。

Enemy.h代码段

#ifndef __ENEMY_H__
#define __ENEMY_H__

#include "cocos2d.h"

//敌机类型
typedef enum 
{
    SMALL_ENEMY,MIDDLE_ENEMY,BIG_ENEMY
}EnemyType;

class Enemy : public cocos2d::Sprite {
public:
    Enemy();
    static Enemy* create(EnemyType);
    bool init(EnemyType);
    //碰撞
    void hit();
    //摧毁
    void down();

    EnemyType e_type;
    //敌机移动速度
    float e_step;
    //敌机血量
    int e_hp;   
};
#endif

这里的e_step、e_hp、e_type我直接public了,可以自行封装。

Enemy.cpp代码段

#include "Enemy.h" Enemy::Enemy() { this->e_type = SMALL_ENEMY; this->e_hp = 0; } Enemy* Enemy::create(EnemyType type) { auto enemy = new Enemy(); if( enemy && enemy->init(type) ) { enemy->autorelease(); return enemy; } delete enemy; enemy = NULL; return NULL; } //根据不同的敌机建立不同的图片效果 bool Enemy::init(EnemyType type) { this->e_type = type; switch (type) { case SMALL_ENEMY: this->e_hp = 1; this->e_step = 4; cocos2d::Sprite::initWithSpriteFrameName("enemy1.png"); break; case MIDDLE_ENEMY: this->e_hp = 6; this->e_step = 1; cocos2d::Sprite::initWithSpriteFrameName("enemy2.png"); break; case BIG_ENEMY: this->e_hp = 30; this->e_step = 0.5f; cocos2d::Sprite::initWithSpriteFrameName("enemy3_n1.png"); break; default: break; } return true; } //打击效果 void Enemy::hit() { auto animation = cocos2d::Animation::create(); switch (this->e_type) { case MIDDLE_ENEMY: animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()-> getSpriteFrameByName("enemy2_hit.png")); animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()-> getSpriteFrameByName("enemy2.png")); break; case BIG_ENEMY: animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()-> getSpriteFrameByName("enemy3_hit.png")); animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()-> getSpriteFrameByName("enemy3_n1.png")); break; default: break; } animation->setDelayPerUnit(0.2f); auto animate = cocos2d::Animate::create(animation); this->runAction(animate); } //摧毁效果 void Enemy::down() { auto animation = cocos2d::Animation::create(); switch(this->e_type) { case SMALL_ENEMY: for (int i = 0; i < 4; i++) { auto png = cocos2d::StringUtils::format("enemy1_down%d.png",i+1); animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(png)); } break; case MIDDLE_ENEMY: for (int i = 0; i < 4; i++) { auto png = cocos2d::StringUtils::format("enemy2_down%d.png",i+1); animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(png)); } break; case BIG_ENEMY: for (int i = 0; i < 6; i++) { auto png = cocos2d::StringUtils::format("enemy3_down%d.png",i+1); animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(png)); } break; default: break; } animation->setDelayPerUnit(0.1f); auto animate = cocos2d::Animate::create(animation); //CallFunc是动作,允许我们的代码作为动作执行 //Sequence是动作,作用是将多个动作按顺序依次执行 auto callFuncN = cocos2d::CallFuncN::create([](Node* node) { //Node参数是这个动作的执行者 //将自己从父容器删除并清除(定时器,动作) node->removeFromParentAndCleanup(true); }); this->runAction(cocos2d::Sequence::create(animate,callFuncN,NULL)); }

修改FlyPlane.h文件

#include "cocos2d.h"
#include "Enemy.h"

class FlyPlane : public cocos2d::Layer {
public:
    CREATE_FUNC(FlyPlane);
    bool init();
    static cocos2d::Scene* createScene();

    //定时器函数必须是void返回类型,必须有一个float类型的参数
    void update(float);
private:
    cocos2d::Point m_vec;
    //英雄子弹集合
    std::vector<cocos2d::Sprite*> h_bullets;
    //敌机集合
    std::vector<Enemy*> h_enemies;
    //创建子弹
    void createBullet(float);   
    //创建敌机
    void createSmallEnemy(float);
    void createMiddleEnemy(float);
    void createBigEnemy(float);
    void createEnemy(EnemyType);
};

修改FlyPlane.cpp文件

#include "FlyPlane.h"
#include "CommonData.h"

cocos2d::Scene* FlyPlane::createScene() {
    //1、auto是c++11的新特性,是自动根据变量的值确定变量的类型,类似var
    //2、大多数时候,cocos中的类想获取它的对象,不建议去new,而是调用它的create方法(oc语法导致)
    //调用cocos2d空间中scene类的静态create方法,返回一个cocos2d::Scene*对象给scene连接
    //‘场景’是一个自动关联的对象
    auto scene = cocos2d::Scene::create();
    auto layer = FlyPlane::create();

    //把层添加到场景里
    scene->addChild(layer);
    return scene;
}

bool FlyPlane::init() {
    //一定要先调用父类初始函数
    if( !cocos2d::Layer::init() ) {
        return false;
    }

    //使用精灵集需要两步
    //1、将美工做好的plist文件读取到缓存中
    //2、通过帧名字创建精灵并显示
    cocos2d::CCSpriteFrameCache::getInstance()->
        addSpriteFramesWithFile("shoot_background.plist");
    auto bg1 = cocos2d::Sprite::createWithSpriteFrameName("background.png");

    //把精灵bg1加到FlyPlane层中,第二个参数ZOrder表示距离用户的距离,第三个参数tag设为1
    this->addChild(bg1,-1,1);

    //默认锚点为(0.5,0.5),只会显示一半的图,必须设置锚点为(0,0)
    bg1->setAnchorPoint(cocos2d::Point(0,0));

    //texture:纹理,通过精灵找到对应的纹理,并开启抗锯齿
    bg1->getTexture()->setAliasTexParameters();

    auto bg2 = cocos2d::Sprite::createWithSpriteFrameName("background.png");
    this->addChild(bg2,2);
    bg2->setAnchorPoint(cocos2d::Point(0,0));
    bg2->getTexture()->setAliasTexParameters();

    //添加英雄
    cocos2d::CCSpriteFrameCache::getInstance()->
        addSpriteFramesWithFile("shoot.plist");
    auto hero = cocos2d::Sprite::createWithSpriteFrameName("hero1.png");    
    hero->setPosition(VISIBLE_SIZE.width / 2,100);
    this->addChild(hero,3,3);

    //为英雄添加飞行动作,动作由动画组成,所以得到动作对象前,需要先得到动画对象
    //一、创建动画对象
    //1.1通过create得到动画对象
    auto animation = cocos2d::Animation::create();  
    //1.2添加这个动画所要用的精灵帧
    animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->
        getSpriteFrameByName("hero1.png"));
    animation->addSpriteFrame(cocos2d::SpriteFrameCache::getInstance()->
        getSpriteFrameByName("hero2.png"));
    //1.3设置切换时间
    animation->setDelayPerUnit(0.2f);
    //1.4循环次数,默认为1,设为-1使其无限循环
    animation->setLoops(-1);    
    //二、根据动画对象创建动作对象
    auto animate = cocos2d::Animate::create(animation);
    //三、让hero执行这个动作
    hero->runAction(animate);


    //用单个处理事件添加鼠标监听事件
    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    //用lambda表达式处理分解事件
    //Lambda表达式:
    // {} 类似于普通函数的函数体
    // () 类似于普通函数的参数列表
    // [] 默认Lambda表达式不能访问外部的变量,如果想访问外部变量,就通过中括号传进来

    listener->onTouchBegan = [=](cocos2d::Touch* touch,cocos2d::Event*) {
        auto touchPos = touch->getLocation();
        bool isContain = hero->getBoundingBox().containsPoint(touchPos);
        if(isContain) {
            m_vec = hero->getPosition() - touchPos;//my_vector,记录touchPos指向hero的向量
        }
        return isContain;
    };

    const float leftMinX = hero->getContentSize().width / 2;    //英雄的X最小值(左边界线)
    const float rightMaxX = VISIBLE_SIZE.width - hero->getContentSize().width / 2;//英雄X最大值(右边界线)
    const float downMinY = hero->getContentSize().height / 2;       //英雄Y最小值(下边界线)
    const float upMaxY = VISIBLE_SIZE.height - hero->getContentSize().height / 2; //英雄Y最大值(上边界线)

    listener->onTouchMoved = [=](cocos2d::Touch* touch,cocos2d::Event*) {      
        auto touchPos = touch->getLocation() + m_vec;
        //让英雄跟着手指动并且不超出边界
        hero->setPosition(cocos2d::Point(MAX(leftMinX,MIN(rightMaxX,touchPos.x)),MAX(downMinY,MIN(upMaxY,touchPos.y)))); 
    };

    //将监听器添加到事件分配器上
    this->getEventdispatcher()->
        addEventListenerWithSceneGraPHPriority(listener,hero);

    //定时添加子弹
    schedule(schedule_selector(FlyPlane::createBullet),0.1f);
    //定时添加不同敌机
    schedule(schedule_selector(FlyPlane::createSmallEnemy),0.8f,2);
    schedule(schedule_selector(FlyPlane::createMiddleEnemy),10,8);
    schedule(schedule_selector(FlyPlane::createBigEnemy),20,14);
    //定时器。scheduleUpdate每帧调用一次update函数
    scheduleUpdate();

    return true;
}

void FlyPlane::update(float) {  
    auto bg1 = this->getChildByTag(1);
    auto bg2 = this->getChildByTag(2);
    //bg1下落,bg2跟随
    bg1->setPositionY(bg1->getPositionY() - 5);
    bg2->setPositionY(bg1->getPositionY() + bg1->getContentSize().height);
    if(bg2->getPositionY() <= 0) {
        bg1->setPositionY(0);
    }

    //重置迭代器
    std::vector<Enemy*>::iterator it_enemy = h_enemies.begin();
    std::vector<cocos2d::Sprite*>::iterator it_bullet = this->h_bullets.begin();

    //让子弹飞
    while( it_bullet != this->h_bullets.end() ) {       
        (*it_bullet)->setPositionY((*it_bullet)->getPositionY() + 12);                              
        //如果子弹飞出游戏区则清除
        if((*it_bullet)->getPositionY() > VISIBLE_SIZE.height) {
            this->removeChild((*it_bullet));
            it_bullet = h_bullets.erase(it_bullet);         
        } else {
            ++it_bullet;
        }
    }

    //让敌机飞
    while( it_enemy != h_enemies.end() ) {
        auto enemy = (*it_enemy);
        enemy->setPositionY(enemy->getPositionY() - enemy->e_step);
        //如果敌机飞出游戏区则清除
        if(enemy->getPositionY() <= 0) { 
            this->removeChild(enemy);
            it_enemy = h_enemies.erase(it_enemy);
        } else {        
            it_enemy++;
        }
    }

    //碰撞检测
    it_enemy = h_enemies.begin();
    it_bullet = this->h_bullets.begin();
    //第一层循环遍历敌机
    while( it_enemy != h_enemies.end()) {
        it_bullet = h_bullets.begin(); //每次遍历,子弹迭代器置于起始位置
        bool isDown = false;
        //第二层循环遍历子弹
        while(it_bullet != h_bullets.end()) {
            //如果相撞
            if((*it_bullet)->getBoundingBox().intersectsRect((*it_enemy)->getBoundingBox())) {  
            //在层中与容器中清除子弹并用isDown记录相撞
                this->removeChild((*it_bullet));                                
                it_bullet = h_bullets.erase(it_bullet);                                     
                isDown = true;                              
            } else {
                ++it_bullet;
            }
        }       
        //如果相撞,运行打击动画
        if(isDown == true) {
            (*it_enemy)->hit();
            (*it_enemy)->e_hp--;    //敌机减血
            if( (*it_enemy)->e_hp <= 0 ) { // 如果为0则被摧毁
                (*it_enemy)->down();    
                it_enemy = h_enemies.erase(it_enemy);
            }
        } else {
            ++it_enemy;
        }
    }
}

void FlyPlane::createBullet(float) {
    auto hero = this->getChildByTag(3);
    auto bullet = cocos2d::Sprite::createWithSpriteFrameName("bullet1.png");//初始子弹在shoot.plist中名字叫bullet1
    bullet->setPosition(hero->getPosition() + cocos2d::Point(0,hero->getContentSize().height / 2));//子弹初始位置
    this->addChild(bullet,0); //zorder为0,高于背景层-1,低于英雄的3
    //每创建一个子弹就存在容器中
    h_bullets.push_back(bullet);
}

void FlyPlane::createEnemy(EnemyType type) {
    auto enemy = Enemy::create(type);
    float leftMinX = enemy->getContentSize().width / 2;
    float rightMaxX = VISIBLE_SIZE.width - enemy->getContentSize().width / 2;
    float x = rand() % (int)(rightMaxX - leftMinX + 1) + leftMinX;      //产生一个[leftMinX,rightMaxX]的随机数
    float y = VISIBLE_SIZE.height;
    enemy->setPosition(x,y);
    h_enemies.push_back(enemy);
    this->addChild(enemy,0);
}


void FlyPlane::createSmallEnemy(float) {
    this->createEnemy(SMALL_ENEMY);
}

void FlyPlane::createMiddleEnemy(float) {
    this->createEnemy(MIDDLE_ENEMY);
}

void FlyPlane::createBigEnemy(float) {
    this->createEnemy(BIG_ENEMY);
}

这里有三个定时器来产生三种敌机

//定时添加不同敌机
    schedule(schedule_selector(FlyPlane::createSmallEnemy),0.8f,2);
    schedule(schedule_selector(FlyPlane::createMiddleEnemy),8);
    schedule(schedule_selector(FlyPlane::createBigEnemy),14);

在update()函数中增加对子弹和敌机碰撞添加判断

//让敌机飞
    while( it_enemy != h_enemies.end() ) {
        auto enemy = (*it_enemy);
        enemy->setPositionY(enemy->getPositionY() - enemy->e_step);
        //如果敌机飞出游戏区则清除
        if(enemy->getPositionY() <= 0) { 
            this->removeChild(enemy);
            it_enemy = h_enemies.erase(it_enemy);
        } else {        
            it_enemy++;
        }
    }

    //碰撞检测
    it_enemy = h_enemies.begin();
    it_bullet = this->h_bullets.begin();
    //第一层循环遍历敌机
    while( it_enemy != h_enemies.end()) {
        it_bullet = h_bullets.begin(); //每次遍历,子弹迭代器置于起始位置
        bool isDown = false;
        //第二层循环遍历子弹
        while(it_bullet != h_bullets.end()) {
            //如果相撞
            if((*it_bullet)->getBoundingBox().intersectsRect((*it_enemy)->getBoundingBox())) {  
            //在层中与容器中清除子弹并用isDown记录相撞
                this->removeChild((*it_bullet));                                
                it_bullet = h_bullets.erase(it_bullet);                                     
                isDown = true;                              
            } else {
                ++it_bullet;
            }
        }       
        //如果相撞,运行打击动画
        if(isDown == true) {
            (*it_enemy)->hit();
            (*it_enemy)->e_hp--;    //敌机减血
            if( (*it_enemy)->e_hp <= 0 ) { // 如果为0则被摧毁
                (*it_enemy)->down();    
                it_enemy = h_enemies.erase(it_enemy);
            }
        } else {
            ++it_enemy;
        }
    }

运行后效果如图:

基于cocos2dx的飞机大战学习[五]-添加三种敌机的更多相关文章

  1. CSS中实现动画效果-附案例

    这篇文章主要介绍了 CSS中实现动画效果并附上案例代码及实现效果,就是CSS动画样式处理,动画声明需要使用@keyframes name,后面的name是人为定义的动画名称,下面我们来看看文章的具体实现内容吧,需要的小伙伴可以参考一下

  2. ios – 围绕其中心点旋转UIImageView?

    我在UIImageView中有一个透明的png,我想围绕它的中心点旋转.代码应该非常简单:图像以正确的速度/时间和直角旋转,但其位置会发生偏移.这是一个正在发生的事情的例子:灰色方块只是为了在屏幕上显示位置.透明的png是另一个图.白色虚线显示UIImageView的中心.图像的左侧显示图像的原始位置,右侧显示使用上述代码旋转后的图像.黑色和白色圆圈位于图像文件的中心.有什么东西我不见了吗?

  3. ios – 将UIView的框架和角半径合在一起

    码:此代码是UIView的扩展.解决方法我像这样调整我的圈子视图:

  4. ios – 如何在Cocos2D 3.x中为CCSprite制作动画?

    你知道如何在新的Cocos2Dv3.x中动画CCSprite吗?许多类都被改变了,旧的方法似乎不起作用.任何的想法?谢谢.额外信息解决方法这是它的工作原理:

  5. ios5 – UIPageViewController转换速度/持续时间?

    有没有办法改变页面卷曲过渡的默认持续时间?这是快速的方式然后我希望它会是?谢谢沙尼解决方法Hy,这是使用默认转换来卷曲页面和指定卷曲速度的方法.祝你工作顺利.

  6. ios – 重用UICollectionView中的单元格时,会短暂显示重用的UICollectionViewCell的旧内容

    我正在使用UICollectionView来显示从URL异步加载的图片网格.我的集合视图使用可重用单元格来显示UICollectionViewCells.当不重复使用单元格时,所有内容都会正确显示,但是当我滚动一下时,重用的单元格会在它们开始正常行为之前短暂闪烁旧内容.以下是自定义UICollectionViewController的实现:这是自定义UICollectionViewCell的实现.

  7. 在iOS中移动UICollectionView的单元格?

    我有一个UICollectionView.I我试图给它作为SpringBoard的功能.我有能力给每个单元格摇动动画.但是我想当图标摇动时,我应该能够移动他们.为了摇动单元格,我已经在每个单元格上添加了UILongPressGesture.当手势结束时,我已经添加了一个自定义动画.还在左上角添加了一个删除按钮.长按手势代码:添加手势到集合视图回调方法单元格在inde路径项在这里工作正常为了移动单元

  8. iOS:CAShapeLayer绘制非直视图像并为其形状设置动画

    我一直在阅读有关CAShapeLayer的文档,但我仍然不太明白.根据我的理解,Layer始终是扁平的,其大小始终是矩形.另一方面,CAShapeLayer允许您定义不仅仅是矩形的图层.它可以是圆形,三角形等,只要您将它与UIBezierPaths一起使用即可.我的理解是在这里吗?

  9. ios – CGContextSaveGState:应用启动时的无效上下文0x0

    FWW我的应用程序大多是用Swift2.0编写的,在iOS9上使用Xcode7b6.解决方法我遇到同样的问题,其原因是,我正在为不同的屏幕设置不同的状态栏样式.因此,我需要在plist中添加“查看基于控制器的状态栏外观”键.如果我删除此键,警告消失.

  10. ios – 可以将视图放在彼此之上

    我正在构建一个Watch应用程序,其中我要覆盖WKInterfaceImage与一组WKInterfaceLabel对象.在StoryBoard编辑器中似乎无法做到这一点.有没有人能够为WatchApp设计出相互之间的观点?

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部