cocos2dx - 制作纵版射击游戏:喵星战争 (三)
注:本教程主要来自《Cocos2D-x权威指南》满硕泉著 机械工业出版社,如需要更详细的内容,请支持并购买正版实体书籍
2013/11/03 更新
在上一个教程里,我们完成了对于主角小猫的定义以及基本功能的实现,现在我们已经有了主场景和主角了,接下来我们要为游戏添加另一个主要部分 - 敌人。本节里会讲解怎么添加打飞机游戏的敌人,以及一些敌人的基本功能实现。
敌人狗博士的定义以及实现
首先创建一个类文件GameObjEnemy.h/cpp,在GameObjEnemy.h里,初始化定义我们的敌人类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 };
在这个类定义里,敌人有三个公共变量,mainbody用来作为敌人主体的CCSprite,type表示敌人的移动模式种类, isLife表示敌人是否存在。公共函数除了基本的四个必须函数之外,还添加了三个用于处理敌人移动的函数 void setType(int var), void moveStart(), void restart(),接下来我们在GameObjEnemy.cpp里对敌人类进行初步实现 - 完成四个基本函数的重写。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 {}
在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变量就可以了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
这是控制敌人移动的主要函数,首先我们要搞清楚我们需要多少种敌人的移动模式,这里我们设置三种移动方式
1. 直线
2. 贝塞尔曲线移动1 bezier1
3. 贝塞尔曲线移动2 bezier2
然后我们用一个随机生成0~3的函数以及switch来决定狗博士的移动方式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
由于我们需要敌人不停地出现,所以当一批敌人完成之前的移动之后,就用这个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, 到这里位置,我们的主角和敌人都准备好了,接下来就轮到打飞机游戏很重要的一部分 - 子弹了,请继续关注