这里是Evankaka的博客,欢迎大家前面讨论与交流~~~~~~
转载请注明出处http://blog.csdn.net/evankaka/article/details/42494743
本章在前面的基础上Cocos2d-x 自定义血条及其美化----之游戏开发《赵云要格斗》(4)设计一个怪物类,并实现怪物的上方显示血条,血条跟随怪物的运动而运动。用到的血条类在上一讲中,平时我们游戏一般怪物都是头顶一个血条的,这里我们就是要实现这个功能。
cocos2d-x版本:2.2.5
工程环境:windows7+VS2010
打开方式:将工程放在cocos2d-x安装目录下的project文件夹下用VS打开
目录:
一、更改英雄hero类
二、自定义带血条的怪物
重要说明:由于TexturePacker试用期结束了,不能再用,所以接下来的动画都不合成plist和整张的PNG。同时,之前的赵云图像太动画效果不是很好,所以换了个赵云的图片。另外,将整个项目的类都分别归档,这样更加容易看懂些,所以hero.h和hero.cpp有些函数进行了更改,同时调用的地方也改了下。这里一定要注意!
这是本章的一个效果:
赵云的图片:以下中是一部分,动画就是通过读一张一张的PNG图片来实现的(没有再合成Plist和整张PNG)
更改后的英雄类Hero.h(类的函数和变量还是不变的,使用方法还是不变的,只不SetAnimation函数参数更改变了)
#ifndef __HERO_H__
#define __HERO_H__
#include "cocos2d.h"
using namespace cocos2d;
class Hero:public cocos2d::CCNode
{
public:
Hero(void);
~Hero(void);
//根据图片名创建英雄
void InitHeroSprite(char *hero_name);
//设置动画,num为图片数目,run_directon为精灵脸朝向,false朝右,name_each为name_png中每一小张图片的公共名称部分
void SetAnimation(const char *name_each,const unsigned int num,bool run_directon);
//停止动画
void StopAnimation();
//攻击动画
void AttackAnimation(const char *name_each,const unsigned int num,bool run_directon);
//攻击动画结束
void AttackEnd();
//判断英雄是否运动到了窗口的中间位置,visibleSize为当前窗口的大小
bool JudgePositona(CCSize visibleSize);
//判断是否在跑动画
bool IsRunning;
//判断是否在攻击动画
bool IsAttack;
//英雄运动的方向
bool HeroDirecton;
CREATE_FUNC(Hero);
private:
CCSprite* m_HeroSprite;//精灵
char *Hero_name;//用来保存初始状态的精灵图片名称
};
#endif // __HERO_H__
#include "Hero.h"
USING_NS_CC;
Hero::Hero(void)
{
IsRunning=false;//没在放动画
HeroDirecton=false;//向右运动
Hero_name=NULL;
IsAttack=false;
}
Hero::~Hero(void)
{
}
void Hero::InitHeroSprite(char *hero_name)
{
Hero_name=hero_name;
this->m_HeroSprite=CCSprite::create(hero_name);
this->addChild(m_HeroSprite);
}
void Hero::SetAnimation(const char *name_each,unsigned int num,bool run_directon)
{
if(HeroDirecton!=run_directon)
{ HeroDirecton=run_directon;
m_HeroSprite->setFlipX(run_directon);
}
if(IsRunning)
return;
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<=num;i++)
{
char szName[100] = {0};
sprintf(szName,"%s%d.png",name_each,i);
animation->addSpriteFrameWithFileName(szName); //加载动画的帧
}
animation->setDelayPerUnit(0.1f);
animation->setRestoreOriginalFrame(true);
animation->setLoops(-1); //动画循环
if(HeroDirecton!=run_directon)
{ HeroDirecton=run_directon;
}
//将动画包装成一个动作
CCAnimate* act=CCAnimate::create(animation);
m_HeroSprite->runAction(act);
IsRunning=true;
}
void Hero::StopAnimation()
{
if(!IsRunning)
return;
m_HeroSprite->stopAllActions();//当前精灵停止所有动画
//恢复精灵原来的初始化贴图
this->removeChild(m_HeroSprite,TRUE);//把原来的精灵删除掉
m_HeroSprite=CCSprite::create(Hero_name);//恢复精灵原来的贴图样子
m_HeroSprite->setFlipX(HeroDirecton);
this->addChild(m_HeroSprite);
IsRunning=false;
}
void Hero::AttackAnimation(const char *name_each,const unsigned int num,bool run_directon)
{
if(IsAttack)
return;
IsAttack=true;
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<=num;i++)
{
char szName[100] = {0};
sprintf(szName,"%s%d.png",name_each,i);
animation->addSpriteFrameWithFileName(szName); //加载动画的帧
}
animation->setDelayPerUnit(0.05f);
animation->setRestoreOriginalFrame(true);
animation->setLoops(1); //动画循环
if(HeroDirecton!=run_directon)
{ HeroDirecton=run_directon;
}
//将动画包装成一个动作
CCAnimate* act=CCAnimate::create(animation);
//创建回调动作,攻击结束后调用AttackEnd()
CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(Hero::AttackEnd));
//创建连续动作
CCActionInterval* attackact=CCSequence::create(act,callFunc,NULL);
m_HeroSprite->runAction(attackact);
}
void Hero::AttackEnd()
{
//恢复精灵原来的初始化贴图
this->removeChild(m_HeroSprite,TRUE);//把原来的精灵删除掉
m_HeroSprite=CCSprite::create(Hero_name);//恢复精灵原来的贴图样子
m_HeroSprite->setFlipX(HeroDirecton);
this->addChild(m_HeroSprite);
IsAttack=false;
}
bool Hero::JudgePositona (CCSize visibleSize)
{
if(this->getPositionX()!=visibleSize.width/2)//精灵到达左边
return false;
else
return true;//到达中间位置
}
记得在用的地方要改下SetAnimation,其它地方都不变,只不SetAnimation函数参数更改变了
void HelloWorld::update(float delta)
{
//判断是否按下摇杆及其类型
CCSize visibleSize1 = CCDirector::sharedDirector()->getVisibleSize();//得到窗口大小
switch(rocker->rocketDirection)
{
case 1:
hero->SetAnimation("hero_run",8,rocker->rocketRun);
if(hero->getPositionX()<=visibleSize1.width-8)//不让精灵超出右边,8可以改成你喜欢的
{
if(!hero->JudgePositona(visibleSize1)||mymap->JudgeMap(hero,visibleSize1))//精灵没到达窗口中间位置或者地图已经移动到边缘了,精灵才可以移动,否则只播放动画
hero->setPosition(ccp(hero->getPosition().x+1,hero->getPosition().y)); //向右走
//下面是移动地图
mymap->MoveMap(hero,visibleSize1);
}
break;
case 2:
hero->SetAnimation("hero_run",8,rocker->rocketRun);
hero->setPosition(ccp(hero->getPosition().x, hero->getPosition().y+1)); //向上走
break;
case 3:
hero->SetAnimation("hero_run",8,rocker->rocketRun);
if(hero->getPositionX()>=8)//不让精灵超出左边,8可以改成你喜欢的
hero->setPosition(ccp(hero->getPosition().x-1,hero->getPosition().y)); //向左走
break;
case 4:
hero->SetAnimation("hero_run",8,rocker->rocketRun);
hero->setPosition(ccp(hero->getPosition().x,hero->getPosition().y-1)); //向下走
break;
case 0:
hero->StopAnimation();//停止所有动画和运动
break;
}
//判断是否出动攻击
if(btn->isTouch)
{
if(hero->IsAttack)//英雄没在攻击
return;
hero->AttackAnimation("hero_attack",20,rocker->rocketRun);
m_pProgressView->setCurrentProgress(m_pProgressView->getCurrentProgress()-10); //更改血量
}
}
效果:和以前相比,赵云的图片更加清楚了些,而且攻击的图片也比较顺了一点(20张图片啊!)
这里的血条用到了前面的自定义血条,思路就是把上篇自定义的血条类ProgressView应用在Monster中,得到Monster类中怪物的位置,然后根据这个位置来设置血条成员变量的位置(一般在上方),最后把怪物精灵和血条类都addchild()进来就行了
下面这是怪物的资源:(一部分,动画也是通过一张一张的播放的)
Monster.h:
#ifndef __Monster_H__
#define __Monster_H__
#include "cocos2d.h"
#include "ProgressView.h"
USING_NS_CC;
class Monster:public cocos2d::CCNode
{
public:
Monster(void);
~Monster(void);
//根据图片名创建怪物,不带血条
void InitMonsterSprite(char *name);
//带血条的怪物
void InitMonsterSprite(char *name,char *xue_back,char* xue_fore);
//设置动画,num为图片数目,run_directon为精灵脸朝向,false朝右,name_each为name_png中每一小张图片的公共名称部分
void SetAnimation(const char *name_each,const unsigned int num,bool run_directon);
//停止动画
void StopAnimation();
//攻击动画
void AttackAnimation(const char *name_each,const unsigned int num,bool run_directon);
//攻击动画结束
void AttackEnd();
//返回英雄
CCSprite* GetSprite();
//判断是否在跑动画
bool IsRunning;
//判断是否在攻击动画
bool IsAttack;
//英雄运动的方向
bool MonsterDirecton;
CREATE_FUNC(Monster);
private:
CCSprite* m_MonsterSprite;//怪物精灵
char *Monster_name;//用来保存初始状态的精灵图片名称
ProgressView* Monster_xue;//怪物血条
};
#endif // __HERO_H__
Monster.cpp:
#include "Monster.h"
USING_NS_CC;
Monster::Monster(void)
{
IsRunning=false;//没在放动画
MonsterDirecton=TRUE;//向右运动
Monster_name=NULL;
IsAttack=false;
Monster_xue=NULL;
}
Monster::~ Monster(void)
{
}
CCSprite* Monster::GetSprite()
{
return m_MonsterSprite;
}
void Monster::InitMonsterSprite(char *name)
{
Monster_name=name;
this->m_MonsterSprite=CCSprite::create(name);
m_MonsterSprite->setFlipX(MonsterDirecton);
this->addChild(m_MonsterSprite);
}
void Monster::InitMonsterSprite(char *name,char *xue_back,char* xue_fore)
{
InitMonsterSprite(name);
//设置怪物的血条
Monster_xue = new ProgressView();
Monster_xue->setPosition(ccp(m_MonsterSprite->getPositionX()+25, m_MonsterSprite->getPositionY()+50));//设置在怪物上头
//Monster_xue->setScale(2.2f);
Monster_xue->setBackgroundTexture(xue_back);
Monster_xue->setForegroundTexture(xue_fore);
Monster_xue->setTotalProgress(300.0f);
Monster_xue->setCurrentProgress(300.0f);
this->addChild(Monster_xue);
}
void Monster::SetAnimation(const char *name_each,unsigned int num,bool run_directon)
{
if(MonsterDirecton!=run_directon)
{ MonsterDirecton=run_directon;
m_MonsterSprite->setFlipX(run_directon);
}
if(IsRunning||IsAttack)
return;
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<=num;i++)
{
char szName[100] = {0};
sprintf(szName,"%s%d.png",name_each,i);
animation->addSpriteFrameWithFileName(szName); //加载动画的帧
}
animation->setDelayPerUnit(2.8f / 14.0f);
animation->setRestoreOriginalFrame(true);
animation->setLoops(-1); //动画循环
//将动画包装成一个动作
CCAnimate* act=CCAnimate::create(animation);
m_MonsterSprite->runAction(act);
IsRunning=true;
}
void Monster::StopAnimation()
{
if(!IsRunning)
return;
m_MonsterSprite->stopAllActions();//当前精灵停止所有动画
//恢复精灵原来的初始化贴图
this->removeChild(m_MonsterSprite,TRUE);//把原来的精灵删除掉
m_MonsterSprite=CCSprite::create(Monster_name);//恢复精灵原来的贴图样子
m_MonsterSprite->setFlipX(MonsterDirecton);
this->addChild(m_MonsterSprite);
IsRunning=false;
}
void Monster::AttackAnimation(const char *name_each,const unsigned int num,bool run_directon)
{
if(IsAttack||IsRunning)
return;
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<=num;i++)
{
char szName[100] = {0};
sprintf(szName,"%s%d.png",name_each,i);
animation->addSpriteFrameWithFileName(szName); //加载动画的帧
}
animation->setDelayPerUnit(2.8f / 14.0f);
animation->setRestoreOriginalFrame(true);
animation->setLoops(1); //动画循环1次
//将动画包装成一个动作
CCAnimate* act=CCAnimate::create(animation);
//创建回调动作,攻击结束后调用AttackEnd()
CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(Monster::AttackEnd));
//创建连续动作
CCActionInterval* attackact=CCSequence::create(act,callFunc,NULL);
m_MonsterSprite->runAction(attackact);
IsAttack=true;
}
void Monster::AttackEnd()
{
//恢复精灵原来的初始化贴图
this->removeChild(m_MonsterSprite,TRUE);//把原来的精灵删除掉
m_MonsterSprite=CCSprite::create(Monster_name);//恢复精灵原来的贴图样子
m_MonsterSprite->setFlipX(MonsterDirecton);
this->addChild(m_MonsterSprite);
IsAttack=false;
}
HelloWorldScene.h添加头文件 #include "Monster.h"
HelloWorldScene.h添加成员变量: Monster *monster1;//怪物种类1
HelloWorldScene.cpp的Init()函数进行初始化:
这是不带血条的怪物:
//添加怪物
monster1=Monster::create();
monster1->InitMonsterSprite("monster.png");
//monster1->InitMonsterSprite("monster.png","xue_back.png","xue_fore.png");
monster1->setPosition(ccp(visibleSize.width-150,visibleSize.height/2));
this->addChild(monster1,1);
这是带血条的怪物:
//添加怪物
monster1=Monster::create();
//monster1->InitMonsterSprite("monster.png");
monster1->InitMonsterSprite("monster.png","xue_back.png","xue_fore.png");
monster1->setPosition(ccp(visibleSize.width-150,visibleSize.height/2));
this->addChild(monster1,1);
好了,这一篇就结束了,下一篇我们将会来讲讲智能怪物,让怪物动起来并能出动攻击!
下面是血条跟随怪物移动的效果(下一章的效果)
后记:
游戏开发中美工好重要,自己为了找这几个图片,都是从GIF图片中,导入到PS中,然后再导出一张张的PNG,主要是cocos2dx不支持直接播放GIF,要是可以就好了(网上有插件,不过没试过),资源啊资源啊!不容易找也不容易用啊,