在第1课中,我们介绍了怎样添加地图,没有掌握的童鞋可以回去复习一下。在这一课中,我们实现生成一个基础的Role类,Hero继承Role类创建(我们敌人Enemy也会继承这个类)。最后把它放在我们的GameLayer中。

开发环境

Win64 : vs2010

Cocos2d-x v3.4Final

TexturePackerGUI

MapEdit

代码构建

角色Role

基础类Role

这是基础类,所有的角色都继承他。

受限篇幅,下面代码贴出一部分看注释吧。

.h

typedef struct _BoundingBox

{

Rect actual;

Rect original;

}BoundingBox;

typedef enum {

ACTION_STATE_NONE = 0,

ACTION_STATE_IDLE,

ACTION_STATE_WALK,

...

ACTION_STATE_DEAD

}ActionState;

//基础角色类,主角和NPC都需要继承它

//单纯的控制播放动画,何时播放它在具体的类里面设置

class Role :public Sprite

{

public:

Role(void);

~Role(void);

/* 角色状态设定,初始化角色状态等 */

CC_SYNTHESIZE(std::string,Name,Name); //角色名称

CC_SYNTHESIZE(float,curtLifevalue,CurtLifeValue); //角色当前生命值

...

/* 需要用creatNomalAnimation创建,只有普通动画,有受伤判定,无攻击判定 */

CC_SYNTHESIZE_RETAIN(Action*, m_pidleaction, IdleAction); //角色空闲时序列

CC_SYNTHESIZE_RETAIN(Action*, m_pwalkaction, WalkAction); //角色移动时动画帧序列

...

void Role::callBackAction(Node* pSender); //动画执行完毕的通用回调处理

/* 下面是所有的动画回调函数,用来执行此动画, */

virtual void runIdleAction(); //执行闲置动画

virtual void runWalkAction(); //执行移动行走动画

...

BoundingBox createBoundingBox(Vec2 origin,Size size);

CC_SYNTHESIZE(BoundingBox, m_bodyBox, BodyBox); //身体碰撞盒子

CC_SYNTHESIZE(BoundingBox, m_hitBox, HitBox); //攻击碰撞盒子

virtual void setPosition(const Vec2 &position);

void updateBoxes();

protected:

static Animation* createNomalAnimation(const char* formatStr, int frameCount, int fps);

static Animation* createAttackAnimation(const char* formatStr, int frameCountBegan, int frameCountEnd,int fps);

private:

bool changeState(ActionState actionState);

ActionState proActionState;

}

CC_SYNTHESIZE(float,curtLifevalue,CurtLifeValue);宏定义。

我们可以通过target->getCurtLifeValue()获得target的curtLifevalue,也可以通过set改变curtLifevalue的值。curtLifevalue是Role内部的一个私有成员。

其他宏功能类似。

.cpp

//各种动作

void Role::runIdleAction()

{ //通过changeState判断是否可以变更状态,之后执行动作

if(changeState(ACTION_STATE_IDLE))

{

this->runAction(m_pidleaction);

}

}

...

Animation* Role::createAttackAnimation(const char* formatStr, int frameCountBegan, int frameCountEnd,int fps)

{

//通过frameCountBegan,frameCountEnd从SpriteFrameCache中创建一个动作

Vector pFrames;

for(int i = frameCountBegan; i < frameCountEnd; i++ )

{

const char* imgName = String::createWithFormat(formatStr, i)->getCString();

SpriteFrame *pFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(imgName);

pFrames.insert(i-frameCountBegan,pFrame);

}

return Animation::createWithSpriteFrames(pFrames, 1.0f / fps);

}

...

bool Role::changeState(ActionState actionState)

{

//允许改变状态,死了和状态不变不会在接受其他状态改变指令

if(currActionState == ACTION_STATE_DEAD || currActionState == actionState)

{

return false;

}

this->stopAllActions();

this->currActionState = actionState;

return true;

}

...

BoundingBox Role::createBoundingBox(Vec2 origin, Size size)

{

//创建一个BoundingBox,用于设置身体碰撞和攻击碰撞检测

BoundingBox boundingBox;

boundingBox.original.origin= origin;

boundingBox.original.size= size;

boundingBox.actual.origin = this->getPosition() + boundingBox.original.origin;

boundingBox.actual.size= size;

return boundingBox;

}

void Role::updateBoxes()

{

//通过方向刷行盒子位置

bool isFlippedX = this->isFlippedX();

float x = 0.0f;

if(isFlippedX)

{

x = this->getPosition().x - m_hitBox.original.origin.x;

}else

{

x = this->getPosition().x + m_hitBox.original.origin.x;

}

m_hitBox.actual.origin = Vec2(x, this->getPosition().y + m_hitBox.original.origin.y);

m_bodyBox.actual.origin = this->getPosition() + m_bodyBox.original.origin;

}

void Role::setPosition(const Vec2 &position)

{

//每次重新设定坐标的时候刷新盒子

Sprite::setPosition(position);

this->updateBoxes();

}

英雄Hero

主角类

还是比较长的,关注下注释,.h只有一个init没啥好说的。

.cpp

this->initWithSpriteFrameName("boy_idle_00.png");

//站立时播放动画

Animation *idleAnim = this->createNomalAnimation("boy_idle_d.png", 3, 5);

this->setIdleAction(RepeatForever::create(Animate::create(idleAnim)));

...

//普通攻击A,分出招和收招,期间夹杂攻击判定.自己可以通过调节fps控制出招速度之类的

Animation *attackAnima1 = this->createAttackAnimation("boy_attack_00_d.png", 0, 4, 10);

Animation *attackAnima2 = this->createAttackAnimation("boy_attack_00_d.png", 4, 8, 15);

this->setNomalAttackA(Sequence::create(

Animate::create(attackAnima1),

//CallFuncN::create(CC_CALLBACK_1(Hero::attackCallBackAction,this)),

Animate::create(attackAnima2),

Role::createIdleCallbackFunc(),

NULL));

...

//碰撞盒子设定

this->m_bodyBox = this->createBoundingBox(Vec2(0,30), Size(30,60));

this->m_hitBox = this->createBoundingBox(Vec2(35,50), Size(80, 90));

游戏Game

GameLayer

.cpp

init中

1this->addHero();

实现方法是:

void GameLayer::addHero()

{

m_pHero = Hero::create();

m_pHero->setPosition(_visibleOrigin + Vec2(100, 50));

m_pHero->runIdleAction();

m_pHero->setLocalZOrder(_visibleSize.height - m_pHero->getPositionY());

this->addChild(m_pHero);

}

效果

至此我们的第二步已经完成了,运行下可以看到一个窗口中我们的英雄站在那里(帧数不同是录制问题.):


20150209121909895.gif

结语

基础Role一次性构建完,之后调用就可以了,后续通过其他理解BoundingBox。

下一篇,实现摇杆的添加和Hero的控制。