注:本教程主要来自《Cocos2D-x权威指南》满硕泉著 机械工业出版社,如需要更详细的内容,请支持并购买正版实体书籍
2013/10/28 更新
在上一个教程里,我们完成了搭建游戏的基本场景GameMain,接下来我们可以开始在这个场景里添砖加瓦了,本节里会讲解怎么添加一个打飞机游戏的主角,以及一些主角的基本功能实现。
主角小猫的定义以及实现
首先创建一个类文件GameObjHero.h/GameObjHero.cpp,在GameObjHero.h里面,如下初始化定义我们的主角类
1 #include "cocos2d.h" 2 3 using namespace cocos2d; 4 5 class GameObjHero : public CCNode, public CCTargetedTouchDelegate 6 { 7 public: 8 // memeory control 9 GameObjHero(void); 10 virtual ~GameObjHero(void); 11 12 // if we need to add a CCNode object into a scene 13 // need to redefine onEnter and onExit method to customize our object 14 virtual void onEnter(); 15 virtual void onExit(); 16 }; 17 18 GameObjHero Class
因为我们的主角是一个需要画在屏幕上的对象,且可被玩家通过触摸而控制,所以主角类继承自CCNode和CCTargetedTouchDelegate类,前者为主角类提供生成对象的基础,后者为主角类提供处理触摸的方法。而在我们的初始定义里,为了提供一个较为清晰的思路,一开始并没有添加太多其他实现用途的参数或者函数,而是简单的加入了四个基本函数
GameObjHero(void); //构造函数
virtual ~GameOjbHero(void); //析构函数
virtual void onEnter(); //重定义进入CCNode的对象函数
virtual void onExit(); //重定义离开CCNode的对象函数
这是我们这个主角类的根基,在实现好这四个函数的继承上我们再添加其他更多的主角类特征,接下来在GameObjHero.cpp里对这主角类进行初步实现
1 #include "GameObjHero.h" 2 3 GameObjHero::GameObjHero() 4 {} 5 6 GameObjHero::~GameObjHero() 7 {} 8 9 void GameObjHero::onEnter() 10 { 11 CCNode::onEnter(); 12 13 this -> setContentSize(CCSizeMake(85, 90)); // 85, 90 is the size of catBody1.png 14 CCDirector * pDirector = CCDirector::sharedDirector(); 15 16 // mainbody animation 17 CCSprite * mainsprite = CCSprite::create("catBody1.png"); 18 CCAnimation * ani = CCAnimation::create(); 19 ani -> addSpriteFrameWithFileName("catBody1.png"); 20 ani -> addSpriteFrameWithFileName("catBody2-4.png"); 21 ani -> addSpriteFrameWithFileName("catBody3.png"); 22 ani -> addSpriteFrameWithFileName("catBody2-4.png"); 23 ani -> setDelayPerUnit(0.1f); 24 ani -> setRestoreOriginalFrame(true); 25 mainsprite -> runAction(CCRepeatForever::create(CCAnimate::create(ani))); 26 addChild(mainsprite); 27 28 // tail animation 29 CCSprite * tail = CCSprite::create("catTail.png"); 30 tail -> setAnchorPoint(ccp(0.5, 1)); 31 tail -> setPosition(ccp(-5, -29)); // this position is inside a 85 x 90 content 32 tail -> setScale(0.5); 33 tail -> setRotation(20); 34 tail -> runAction(CCRepeatForever::create((CCActionInterval *) CCSequence::create(CCRotateBy::create(0.5, -40), CCRotateBy::create(0.5, 40), NULL))); 35 addChild(tail); 36 } 37 38 void GameObjHero::onExit() 39 { 40 CCNode::onExit(); 41 }
在onEnter()函数里,主要实现了主角小猫的三个部分
1. 对象大小,主角是一个宽85,高90的对象
2. 主角主体,以catBody1.png为初始帧循环播放动作的CCSprite对象
3. 主角尾巴,以catTail.png为贴图,(0.5,1)为旋转点循环旋转20°动作的CCSprite对象
在完成了这些基础后,我们就可以尝试将我们的主角小猫放到主场景里面看看效果了。
在GameScene.h中加入GameObjHero.h头文件,并添加一个private参数hero
#include "GameObjHero.h"
// in class GameMain: public CCLayer, add below
private:
GameObjHero * hero;
在GameScene.cpp的bool GameMain::init()函数里加入生成hero对象的部分
// build the hero
hero = new GameObjHero();
hero -> setPosition(ccp(size.width/2, -50));
hero -> setScale(0.5);
addChild(hero, 2, 1); // hero's zOrder is 2, tag is 1
hero -> runAction(CCMoveBy::create(0.5, ccp(0, 150)));
运行程序,这个时候我们就能看到我们的小猫出现在游戏场景上了
PS:这里有一个要注意的地方,传统飞机游戏都是用竖屏玩的,但是这个时候我们运行游戏还是显示的横屏,要更改这个很简单,在项目的ios目录下找到RootViewController.mm, 将里面的supportedInterfaceOrientations返回参数改为UIInterfaceOrientationMaskPortrait就可以了,具体如下
// For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
- (NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
//return UIInterfaceOrientationMaskLandscape;
return UIInterfaceOrientationMaskPortrait;
#endif
}
作为一个飞机游戏的主角,当然要能受到玩家的控制,这里采取了传统的触摸控制来实现这一个功能。
首先加入一个bool变量来判断主角是否被玩家的触摸控制和一个CCPoint变量获得触摸的偏移位置,在GameObjHero类中加入一下public变量
public:
CCPoint offset;
bool isControl;
然后加入一个获取触摸位置的函数和重写五个和触摸相关的函数,同样也是作为public函数使用
// redefine touch method
bool containsTouchLocation(CCTouch * touch); // 获得触摸的位置,判断是否在控制范围内并返回判断结果
virtual bool ccTouchBegan(CCTouch * touch, CCEvent * event); // 处理触摸开始时效果的函数
virtual void ccTouchMoved(CCTouch * touch, CCEvent * event); // 处理触摸移动时效果的函数
virtual void ccTouchEnded(CCTouch * touch, CCEvent * event); // 处理触摸结束时效果的函数
// Memory control with touchDelegate
virtual void touchDelegateRetain(); // 获得触摸delegate
virtual void touchDelegateRelease();// 释放触摸delegate
接下来我们看这些函数的具体实现,在GameObjHero.cpp中加入以下函数实现
1 bool GameObjHero::containsTouchLocation(CCTouch * touch) 2 { 3 CCSize size = getContentSize(); 4 CCPoint pos = getPosition(); 5 CCRect pRect = CCRectMake(pos.x - size.width/2, pos.y - size.height/2, size.width, size.height); 6 7 CCPoint location = touch -> getLocationInView(); 8 location = CCDirector::sharedDirector() -> convertToGL(location); 9 return pRect.containsPoint(location); 10 }
构造一个当前的有效区域,获得触摸位置后,用containsPoint函数判断触摸位置是否在当前的有效区域内。
1 bool GameObjHero::ccTouchBegan(CCTouch * touch, CCEvent * event) 2 { 3 if (!containsTouchLocation(touch)) { 4 return false; 5 } 6 else 7 { 8 isControl = true; 9 CCPoint touchPoint = touch -> getLocationInView(); 10 touchPoint = CCDirector::sharedDirector() -> convertToGL(touchPoint); 11 offset.x = touchPoint.x - this -> getPosition().x; 12 offset.y = touchPoint.y - this -> getPosition().y; 13 } 14 return true; 15 }
判断触摸点是否在有效区域内,若无效,返回false,否则将isControl赋值为true并获得触摸的偏移位置。
1 void GameObjHero::ccTouchMoved(CCTouch * touch, CCEvent * event) 2 { 3 if (isControl) { 4 CCPoint touchPoint = touch -> getLocationInView(); 5 touchPoint = CCDirector::sharedDirector() -> convertToGL(touchPoint); 6 float x = touchPoint.x - offset.x; 7 float y = touchPoint.y - offset.y; 8 9 this -> setPosition(x, y); 10 } 11 }
判断isControl是否为true,若为true,则通过偏移变量计算出主角的最新位置并进行设置
1 void GameObjHero::ccTouchEnded(CCTouch * touch, CCEvent * event) 2 { 3 if (isControl) { 4 isControl = false; 5 } 6 }
判断isControl是否为true,若为true,则将isControl重新赋值为false.
void GameObjHero::touchDelegateRetain()
{
this -> retain();
}
void GameObjHero::touchDelegateRelease()
{
this -> release();
}
重写获得与释放触摸delegate函数。
最后记得在onEnter函数中激活触摸功能以及加入两个变量的初始化, 在onExit函数中加入去除触摸delegate
void GameObjHero::onEnter()
{
// enable touch
pDirector -> getTouchDispatcher() -> addTargetedDelegate(this, 0, true);
......
// init touch related variable
offset = ccp(0, 0);
isControl = false;
......
}
void GameObjHero::onExit()
{
CCDirector * pDirector = CCDirector::sharedDirector();
pDirector -> getTouchDispatcher() -> removeDelegate(this);
CCNode::onExit();
}
编译并运行游戏,现在我们可以通过触摸来控制我们的小猫主角了!!
(小猫的实现到这里基本完成了,接下来我要介绍怎么加入飞机游戏里的敌人 - 狗博士,请继续关注)