转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。
资源为网上寻找的,仅研究学习用,若是侵犯版权请通知本人整改。
上一篇:Cocos3.4 横版游戏制作-《KillBear》-添加地图
在这一篇中,我们实现生成一个基础的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);宏定义
我们可以通过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<SpriteFrame*> 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_%02d.png",3,5);
this->setIdleAction(RepeatForever::create(Animate::create(idleAnim)));
...
//普通攻击A,分出招和收招,期间夹杂攻击判定.自己可以通过调节fps控制出招速度之类的
Animation *attackAnima1 = this->createAttackAnimation("boy_attack_00_%02d.png",0,4,10);
Animation *attackAnima2 = this->createAttackAnimation("boy_attack_00_%02d.png",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中
this->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的控制