在第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);
}
效果
至此我们的第二步已经完成了,运行下可以看到一个窗口中我们的英雄站在那里(帧数不同是录制问题.):
结语
基础Role一次性构建完,之后调用就可以了,后续通过其他理解BoundingBox。
下一篇,实现摇杆的添加和Hero的控制。