Cocos2d-x血条跟随怪物运动--之游戏开发《赵云要格斗》(5)cocos2dx 3.3移植版
源码:git@github.com:baidang201/ARPG_Zhaoyun.git ////////////////////////////////////////////////////////////////////////////////////本章在前面的基础上《Cocos2d-x自定义血条及其美化--之游戏开发《赵云要格斗》(4)》设计一个怪物类,并实现怪物
本章在前面的基础上《Cocos2d-x自定义血条及其美化--之游戏开发《赵云要格斗》(4)》设计一个怪物类,并实现怪物的上方显示血条,血条跟随怪物的运动而运动。用到的血条类在上一讲中,平时我们游戏一般怪物都是头顶一个血条的,这里我们就是要实现这个功能。
Cocos2d-x版本:2.2.5
工程环境:windows7+VS2010
打开方式:将工程放在cocos2d-x安装目录下的project文件夹下用VS打开
重要说明:由于TexturePacker试用期结束了,不能再用,所以接下来的动画都不合成plist和整张的PNG。同时,之前的赵云图像太动画效果不是很好,所以换了个赵云的图片。另外,将整个项目的类都分别归档,这样更加容易看懂些,所以hero.h和hero.cpp有些函数进行了更改,同时调用的地方也改了下。这里一定要注意!
这是本章的一个效果:
(下一章的效果)
一、更改英雄hero类
赵云的图片:以下中是一部分,动画就是通过读一张一张的PNG图片来实现的(没有再合成Plist和整张PNG)
更改后的英雄类Hero.h(类的函数和变量还是不变的,使用方法还是不变的,只不SetAnimation函数参数更改变了)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#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__
|
更改后的英雄类Hero.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#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函数参数更改变了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
#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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#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()函数进行初始化:
这是不带血条的怪物:
1
2
3
4
5
6
|
//添加怪物
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);
|
这是带血条的怪物:
1
2
3
4
5
6
|
//添加怪物
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);
|
好了,这一篇就结束了,下一篇我们将会来讲讲智能怪物,让怪物动起来并能出动攻击!
下面是血条跟随怪物移动的效果。
源码下载:血条跟随怪物运动
//
总结下TexturePacker纹理的调用和多个图片调用的区别。
1 压缩纹理的调用
将压缩纹理图片载入全局纹理缓存CCSpriteFrameCache-》获取精灵框帧CCSpriteFrame,将特定序列的精灵框帧增加到列表-》使用列表初始化动画Animation-》使用动画包装成动作CCAnimate
2 多个图片的调用
使用创建动画对象Animation->动画增加每一帧的图片->动画包装成动作CCAnimate
:如下是示例代码:
CCSpriteFrameCache *m_frameCache=CCSpriteFrameCache::sharedSpriteFrameCache();
m_frameCache->addSpriteFramesWithFile(name_plist,name_png);
//用一个列表保存所有的CCSpriteFrameCache
Vector<CCSpriteFrame*> frameArray = Vector<CCSpriteFrame*>();
unsigned int i;
for(i=startIndex;i<=num;i++)
{
CCSpriteFrame* frame=m_frameCache->spriteFrameByName(CCString::createWithFormat("%s%d.png", actNameInNamePng, i)->getCString());
frameArray.pushBack(frame);
}
//使用列表创建动画对象
Animation* animation=Animation::createWithSpriteFrames(frameArray);
animation->setLoops(-1);//表示无限循环播放
animation->setDelayPerUnit(0.1f);//每两张图片的时间隔,图片数目越少,间隔最小就越小
//将动画包装成一个动作
CCAnimate* act=CCAnimate::create(animation);
m_HeroSprite->runAction(act);
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);
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)