这里是Evankaka的博客,欢迎大家前面讨论与交流~~~~~~
转载请注明出处http://www.jb51.cc/article/p-nruhtbsh-kh.html
本章在前面的基础上@L_301_2@设计一个怪物类,并实现怪物的上方显示血条,血条跟随怪物的运动而运动。用到的血条类在上一讲中,平时我们游戏一般怪物都是头顶一个血条的,这里我们就是要实现这个功能。
cocos2d-x版本:2.2.5
工程环境:windows7+VS2010
打开方式:将工程放在cocos2d-x安装目录下的project文件夹下用VS打开
(源码免费下载)
目录:
一、更改英雄hero类
二、自定义带血条的怪物
重要说明:由于TexturePacker试用期结束了,不能再用,所以接下来的动画都不合成plist和整张的PNG。同时,之前的赵云图像太动画效果不是很好,所以换了个赵云的图片。另外,将整个项目的类都分别归档,这样更加容易看懂些,所以hero.h和hero.cpp有些函数进行了更改,同时调用的地方也改了下。这里一定要注意!
这是本章的一个效果:
(下一章的效果)
一、更改英雄hero类
赵云的图片:以下中是一部分,动画就是通过读一张一张的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,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,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,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",rocker->rocketRun); hero->setPosition(ccp(hero->getPosition().x,hero->getPosition().y+1)); //向上走 break; case 3: hero->SetAnimation("hero_run",rocker->rocketRun); if(hero->getPositionX()>=8)//不让精灵超出左边,8可以改成你喜欢的 hero->setPosition(ccp(hero->getPosition().x-1,hero->getPosition().y)); //向左走 break; case 4: hero->SetAnimation("hero_run",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); //设置动画,name_each为name_png中每一小张图片的公共名称部分 void SetAnimation(const char *name_each,bool run_directon); //停止动画 void StopAnimation(); //攻击动画 void AttackAnimation(const char *name_each,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_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,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,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,bool run_directon) { if(IsAttack||IsRunning) return; CCAnimation* animation = CCAnimation::create(); for( int i=1;i<=num;i++) { char szName[100] = {0}; sprintf(szName,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,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",1);
好了,这一篇就结束了,下一篇我们将会来讲讲智能怪物,让怪物动起来并能出动攻击!
后记:
游戏开发中美工好重要,自己为了找这几个图片,都是从GIF图片中,导入到PS中,然后再导出一张张的PNG,主要是cocos2dx不支持直接播放GIF,要是可以就好了(网上有插件,不过没试过),资源啊资源啊!不容易找也不容易用啊,