cocos2dx - 制作纵版射击游戏:喵星战争 (三)

注:本教程主要来自《Cocos2D-x权威指南》满硕泉著 机械工业出版社,如需要更详细的内容,请支持并购买正版实体书籍

2013/11/03 更新

在上一个教程里,我们完成了对于主角小猫的定义以及基本功能的实现,现在我们已经有了主场景和主角了,接下来我们要为游戏添加另一个主要部分 - 敌人。本节里会讲解怎么添加打飞机游戏的敌人,以及一些敌人的基本功能实现。

敌人狗博士的定义以及实现

首先创建一个类文件GameObjEnemy.h/cpp,在GameObjEnemy.h里,初始化定义我们的敌人类

 1 #include "cocos2d.h"
 2 using namespace cocos2d;
 3 
 4 class GameObjEnemy : public CCNode
 5 {
 6 public:
 7     CCSprite * mainbody;  //敌人的主体
 8     
 9     int type;      // 敌人移动模式的种类
10     bool isLife;  // 敌人是否被消灭了
11     
12     // memory control
13     GameObjEnemy(void);
14     virtual ~GameObjEnemy(void);
15     
16     // redefine onEnter and onExit method to customize object
17     virtual void onEnter();
18     virtual void onExit();
19     
20     void setType(int var);
21     void moveStart();      // 开始移动
22     void restart();           // 重新开始移动
23 };  
GameObjEnemy.h

在这个类定义里,敌人有三个公共变量,mainbody用来作为敌人主体的CCSprite,type表示敌人的移动模式种类, isLife表示敌人是否存在。公共函数除了基本的四个必须函数之外,还添加了三个用于处理敌人移动的函数 void setType(int var), void moveStart(), void restart(),接下来我们在GameObjEnemy.cpp里对敌人类进行初步实现 - 完成四个基本函数的重写。

 1 #include "GameObjEnemy.h"
 2 
 3 // method of object create and release
 4 GameObjEnemy::GameObjEnemy()
 5 {}
 6 
 7 GameObjEnemy::~GameObjEnemy()
 8 {}
 9 
10 void GameObjEnemy::onEnter()
11 {
12     CCNode::onEnter();
13     this -> setContentSize(CCSizeMake(99, 111));
14     mainbody = CCSprite::create("DrDog1.png");
15     
16     // init animation
17     CCAnimation * ani = CCAnimation::create();
18     ani -> addSpriteFrameWithFileName("DrDog1.png");
19     ani -> addSpriteFrameWithFileName("DrDog2.png");
20     ani -> setDelayPerUnit(0.1f);
21     ani -> setRestoreOriginalFrame(true);
22     mainbody -> runAction(CCRepeatForever::create(CCAnimate::create(ani)));
23     addChild(mainbody);
24     
25     isLife = true;
26 }
27 
28 void GameObjEnemy::onExit()
29 {
30     CCNode::onExit();
31 }
32 
33 void GameObjEnemy::setType(int var)
34 {}
35 
36 void GameObjEnemy::moveStart()
37 {}
38 
39 void GameObjEnemy::restart()
40 {}
GameObjEnemy.cpp

在onEnter()函数里,实现了敌人狗博士的三个部分

1. 对象大小,敌人是一个宽99,高111的对象

2. 敌人主体,以DrDog1.png为初始帧循环播放动作的CCSprite对象

3. 敌人生存判断值,初始化为true

在完成了这些基础后,我们就可以尝试将敌人狗博士放到主场景里面看看效果了。

在GameScene.h中加入GameObjEnemy.h头文件,并添加一个private参数CCArray * enemy,因为敌人不止一个,所以需要用CCArray来装载这些敌人

#include "GameObjEnemy.h"

// in class GameMain: public CCLayer, add below as private value
CCArray * enemys;

在GameScene.cpp的bool GameMain::inti()函数里加入生成enemy对象的部分

// build the enemy
    enemys = new CCArray();
    enemys -> initWithCapacity(3);
    for (int i = 0; i < enemys -> capacity(); i ++) {
        int type = i + 1;
        GameObjEnemy * enemy = new GameObjEnemy();
        enemy -> setPosition(ccp(size.width/4 * type, size.height - 50));
        enemy -> setScale(0.5);
        enemy -> setType(type);
        enemys -> addObject(enemy);
        addChild(enemy, 1); // enemy's zOrder is 1
    }
    enemys -> retain();

注意这里对于enemys的初始化定义,我们使用的是new CCArray()而不是create(),然后再用initWithCapacity()初始化enemys的capacity,为了以后我们处理每一个敌人而进行的遍历作铺垫,调试并运行程序,我们就能看到敌人狗博士出现在我们主角的面前了。

当然我们的敌人还需要向主角靠近,光站着那里就不是打飞机游戏的敌人了,于是我们需要为狗博士加入移动的功能,就是针对以下三个函数进行具体实现,void setType(int var), void moveStart(), void restart()。

void GameObjEnemy::setType(int var)
{
    type = var;
}

这个很简单,设置敌人移动的种类,只需要将var值传给type变量就可以了

 1 void GameObjEnemy::moveStart()
 2 {
 3     isLife = true;
 4     int type = CCRANDOM_0_1() * 4;
 5     // move as Bezier
 6     ccBezierConfig bezier1;
 7     bezier1.controlPoint_1 = CCPointMake(this -> getPosition().x + 400, 330);
 8     bezier1.controlPoint_2 = CCPointMake(this -> getPosition().x - 400, 280);
 9     bezier1.endPosition = CCPointMake(this -> getPosition().x, -70);
10     CCBezierTo * bezierBy1 = CCBezierTo::create(6, bezier1);
11     // 6 is the time of bezierby1
12     ccBezierConfig bezier2;
13     bezier2.controlPoint_1 = CCPointMake(this -> getPosition().x - 400, 330);
14     bezier2.controlPoint_2 = CCPointMake(this -> getPosition().x + 400, 280);
15     bezier2.endPosition = CCPointMake(this -> getPosition().x, -70);
16     CCBezierTo * bezierBy2 = CCBezierTo::create(6, bezier2);
17     
18     switch (type) {
19         case 0:
20         case 1:
21             this -> runAction(CCSequence::create(CCMoveBy::create(6, ccp(0, -600)), CCCallFuncN::create(this, callfuncN_selector(GameObjEnemy::restart)), NULL));
22             break;
23         case 2:
24             this -> runAction(CCSequence::create(bezierBy1, CCCallFuncN::create(this, callfuncN_selector(GameObjEnemy::restart)), NULL));
25             break;
26         case 3:
27             this -> runAction(CCSequence::create(bezierBy2, CCCallFuncN::create(this, callfuncN_selector(GameObjEnemy::restart)), NULL));
28             break;
29     }
30 }
void moveStart()

这是控制敌人移动的主要函数,首先我们要搞清楚我们需要多少种敌人的移动模式,这里我们设置三种移动方式

1. 直线

2. 贝塞尔曲线移动1 bezier1

3. 贝塞尔曲线移动2 bezier2

然后我们用一个随机生成0~3的函数以及switch来决定狗博士的移动方式

 1 void GameObjEnemy::restart()
 2 {
 3     mainbody -> setVisible(true);
 4     CCSize size = CCDirector::sharedDirector() -> getWinSize();
 5     this -> setPosition(ccp(size.width/4 * type, size.height + 50));
 6     
 7     isLife = true;
 8     
 9     mainbody -> setVisible(true);
10     
11     this -> moveStart();
12 }
void restart()

由于我们需要敌人不停地出现,所以当一批敌人完成之前的移动之后,就用这个restart()函数再生成一次移动,在moveStart()里用callfuncN_selector()调用而达到循环的效果。

最后在GameScene.cpp的bool GameMain::inti()函数里生成enemy对象部分的for循环里加入以下enmey->moveStart(),实现狗博士的移动

// build the enemy
   ……
    for (int i = 0; i < enemys -> capacity(); i ++) {
        ……
        enemy -> moveStart();
    }
……

编译并运行游戏,我们就可以看到敌人狗博士不停地向我们主角冲来了

OK, 到这里位置,我们的主角和敌人都准备好了,接下来就轮到打飞机游戏很重要的一部分 - 子弹了,请继续关注

posted @ 2013-11-03 11:56  fuutou  阅读(546)  评论(0编辑  收藏  举报