文档库 最新最全的文档下载
当前位置:文档库 › cocos2d-x 大型ARPG手游研发----精灵的八面玲珑

cocos2d-x 大型ARPG手游研发----精灵的八面玲珑

cocos2d-x 大型ARPG手游研发----精灵的八面玲珑
cocos2d-x 大型ARPG手游研发----精灵的八面玲珑

继续上一篇文章继续聊吧,这章内容会比较多,也会附上代码,很多朋友加了群,大家在群里面探讨了很多东西,这让大家都觉得受益匪浅,这便是极好的,废话不多了,精灵是游戏的重要组成部分,那ARPG里面的精灵必然是要做得很细的,因为精灵要能动,能跑,能打,甚至要能做各种交互动作等等。

大家可以看一下下面的题,是精灵制作的流程思路:

上图的人物素材来自于网络流传的梦幻西游,地图还有其他素材是以前公司同事制作的,如果游戏正式上线,会换一套完整的自制的素材。图中大家可以看到一个人物有很多部件组合而成,高端一点的游戏甚至部件多达几十上百种,甚至做出骨骼动画。不过以我现在的做法是按照帧动画方式实现各个人物的动作,人物的body部分细节处理会很多,还有大家看到图中的字体(字体渲染描边,我做的是最简单的了,两个LABEL合成在一起,效果能达到就行),由于人物要有方向,而且我们一次性就做8方向的人物动画,那就需要8个方向的连帧图片:

首先,要组装起来我们首先要建一个实体角色类,这个类里面不放别的,就统一放角色的部件属性:

MainRoledata.h类

#ifndef _MAIN_ROLE_DATA_

#define _MAIN_ROLE_DATA_

https://www.wendangku.net/doc/fc2619368.html,

#include "cocos2d.h"

#include "../Commen_ActionToDo.h"

#include "../Commen_Direction.h"

USING_NS_CC;

class MainRoledata

{

public :

//人物的TAG

int tags;

//人物姓名

CCString* spiritname;

//人物初始坐标

CCPoint nowpoint;

//人物默认像素图

CCString* spiritUrl;

//人物站立像素图路径

CCString* spiritUrl_zhan;

//人物跑动像素图路径

CCString* spiritUrl_pao;

//人物攻击像素图路径

CCString* spiritUrl_attack;

//人物施法像素图路径/增加人物BUF

CCString* spiritUrl_magic;

//人物站立最大帧

int maxcut_zhan;

//人物跑动最大帧

int maxcut_pao;

//人物战斗最大帧

int maxcut_attack;

//人物施法最大帧

int maxcut_magic;

//人物当前动作

Commen_ActionToDo acttodo;

//人物当前朝向

Commen_Direction dir;

//动画时间

float actiontime;

};

#endif

枚举几个方向,和动作的类:

enum Commen_Direction

{

up=0,

down=1,

lefts=2,

rigth=3,

rigth_up=4,

rigth_down=5,

left_down=6,

left_up=7

};

enum Commen_ActionToDo

{

run=1,

stand=2,

attack=3,

death=4,

funny=5,

magicup=6

};

OK,然后配置精灵数据,建了一个GetNPCData.cpp,GetNPCData.h,主要就是拿来初始化数据,大致的思路是要将上面的Model填充数据,相信大家能够用很多种方式去实现,填充数据(读取XML配置文件,直接写在代码中配置);

接下来我们正式组装完整的八面玲珑的精灵,建立SpiritsPlayer.cpp,SpiritsPlayer.h;

文件内容如下:

#ifndef _SPIRIT_PLAYER_

#define _SPIRIT_PLAYER_

https://www.wendangku.net/doc/fc2619368.html,

#include "cocos2d.h"

#include "../Commen_ActionToDo.h"

#include "../Commen_Direction.h"

#include "../GameData/MainRoledata.h"

#include "../Commen/PublicShowUI.h"

#include "../Effects/EffectsCommen.h"

USING_NS_CC;

class SpiritsPlayer : cocos2d::CCSprite

{

public:

CCSprite* npc;

CCSprite* yinzi;

CCSprite* sp_liaotianbd;

PublicShowUI* p_ui_name;

CCArray *stringArray;

CCAnimate* playdonghua;

CCAnimate* playdonghua2;

Commen_Direction move_dir;

bool endflag;

bool endflag2;

bool thiszhujiao_flag;

void Spirits_talkabout_hid();

SpiritsPlayer(MainRoledata roledata,int zOrder,bool zhujiaoflag);

~SpiritsPlayer(void);

CCAnimation* getNowAnt(MainRoledata roledata);

CCAnimate* updateNowAnt(MainRoledata roledata);

void updateNpcPoint(CCPoint newpoint);

void moveTomap_dir(CCPoint newpoint);

void moveTomap_move(int uestime,CCPoint newpoint,bool npcflag);

//人物移动完成的回调

void moveoverCallBack(void);

//普通NPC移动完成的回调

void moveoverCallBackforNpc(void);

//根据点击坐标获得人物的朝向

Commen_Direction getNowPointDir(CCPoint newpoint);

// 触摸点是否在精灵上

bool isTouchInside(CCPoint thisPos);

//移动方式

void movemethod(int uestime,CCPoint newpoint);

private:

//角色基本数据

MainRoledata thisroledata;

CCFiniteTimeAction *actall;

CCActionInterval* act_moveto_zi;

CCActionInterval* act_moveto_npc;

CCActionInterval* act_moveto_yinzi;

CCActionInterval* act_moveto_eff;

CCActionInterval* act_moveto_eff_zhujiao;

CCFiniteTimeAction *actbackfun;

int flag ;

private:

CCRect rect();

};

#endif//_SPIRIT_PLAYER_

#include "../ImagePaths.h"

#include "../GameData/GetNPCData.h"

#include "../Commen/FontChina.h"

SpiritsPlayer::SpiritsPlayer(MainRoledata roledata,int zOrder,bool zhujiaoflag) {

//先初始化部分数据

thisroledata = roledata;

act_moveto_zi =NULL;

act_moveto_npc =NULL;

act_moveto_yinzi =NULL;

actall=NULL;

thiszhujiao_flag = zhujiaoflag;

p_ui_name = new PublicShowUI();

flag = 0;

npc = SpiritsPlayer::create(roledata.spiritUrl->getCString());

if(npc==NULL)

{

CCLog("图层路径有误,请检查路径");

return;

}

//设置NPC初始位置坐标(该坐标取决于当前画层)

npc->setPosition(roledata.nowpoint);

//NPC动画设置

playdonghua = SpiritsPlayer::updateNowAnt(roledata);

npc->runAction(playdonghua);

/**开始添加角色各部件**/

//添加角色名称

CCLabelTTF* label = CCLabelTTF::create(roledata.spiritname->getCString(), "微软雅黑",12);

label->setColor(ccWHITE);

label->setDirty(true);

label->setPosition(ccp(npc->getContentSize().width/2,npc->getContentSize().height+ 6));

CCLabelTTF* labelback =

CCLabelTTF::create(roledata.spiritname->getCString(), "微软雅黑",12);

labelback->setColor(ccBLACK);

labelback->setDirty(true);

labelback->setPosition(ccp(npc->getContentSize().width/2+1,npc->getContentSize(). height+6-1));

//添加NPC人物脚下阴影

yinzi = CCSprite::create(p_yinzi);

if(yinzi==NULL)

{

CCLog("图层路径有误,请检查路径");

return;

}

if(zhujiaoflag==true)

{

yinzi->setPosition(ccp(npc->getContentSize().width/2,12));

}

else

{

yinzi->setPosition(ccp(npc->getContentSize().width/2,1));

}

npc->addChild(yinzi,-1,110);

npc->addChild(label,2,111);

npc->addChild(labelback,1,112);

}

cocos2d::CCRect SpiritsPlayer::rect()

{

//获取精灵区域大小

return CCRectMake(npc->getPositionX()- npc->getContentSize().width * npc->getAnchorPoint().x,npc->getPositionY()-npc->getContentSize().height* npc->getAnchorPoint().y,npc->getContentSize().width,

npc->getContentSize().height);

}

bool SpiritsPlayer::isTouchInside(CCPoint thisPos)

{

CCPoint localPos = thisPos;

CCRect rc = rect();

bool isTouched = rc.containsPoint(localPos);

if (isTouched == true) {

CCLog(FontChina::G2U("触发点击"));

}else

{

CCLog(FontChina::G2U("未点击"));

}

return isTouched;

}

void SpiritsPlayer::Spirits_talkabout_hid()

{

CCLog(FontChina::G2U("************调用了*****************")); }

CCAnimate* SpiritsPlayer::updateNowAnt(MainRoledata roledata)

{

//NPC动画

CCAnimation* donghua = SpiritsPlayer::getNowAnt(roledata);

if(roledata.actiontime>0)

{

donghua->setDelayPerUnit(roledata.actiontime/roledata.maxcut_zhan);

}

else

{

donghua->setDelayPerUnit(2.0f/15.0f);//执行默认时间

}

donghua->setRestoreOriginalFrame(true);

donghua->setLoops(-1);

CCAnimate* playdonghua = CCAnimate::create(donghua);

return playdonghua;

}

/*************

* 主角位移移动

*************/

void SpiritsPlayer::moveTomap_move(int uestime, CCPoint newpoint,bool npcflag) {

if(npcflag==true)

{

actbackfun = CCCallFunc::create(this,

callfunc_selector(SpiritsPlayer::moveoverCallBackforNpc));

}

else

{

actbackfun = CCCallFunc::create(this,

callfunc_selector(SpiritsPlayer::moveoverCallBack));

}

movemethod(uestime,newpoint);

}

void SpiritsPlayer::movemethod(int uestime,CCPoint newpoint)

{

npc->stopAction(actall);

act_moveto_npc = CCMoveTo::create(uestime,ccp(newpoint.x,newpoint.y+20));

actall = CCSequence::create(act_moveto_npc,actbackfun,NULL);

npc->runAction(actall);

}

/*************

* 改变移动方向

*************/

void SpiritsPlayer::moveTomap_dir(CCPoint newpoint)

{

GetNPCData npcdata = GetNPCData();

npcdata.GetNPCchapter1();

move_dir=SpiritsPlayer::getNowPointDir(newpoint);

npcdata.role_player.dir=move_dir;

npcdata.role_player.acttodo = run;

npcdata.role_player.actiontime=0.5;

npc->stopAction(playdonghua);

playdonghua = SpiritsPlayer::updateNowAnt(npcdata.role_player);

npc->runAction(playdonghua);

}

/*************

* 根据点击坐标获得人物的朝向

*************/

Commen_Direction SpiritsPlayer::getNowPointDir(CCPoint newpoint) {

Commen_Direction thisdir = rigth_down; //默认为右下

//计算移动数据

float center_x,center_y,npc_x,npc_y;

int move_x,move_y;

//更新NPC方向,状态

CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

CCSize size = CCDirector::sharedDirector()->getWinSize();

center_x = size.width/2;

center_y = size.height/2;

npc_x = npc->getPositionX();

npc_y = npc->getPositionY();

move_x = (int)(npc_x -newpoint.x );

move_y = (int)(npc_y -newpoint.y - 20);

if(move_x>=10&&move_y<=-10)

{

//左上

thisdir = left_up;

}

else if(move_x>=10&&move_y>=10)

{

//左下

thisdir = left_down;

}

else if(move_x<=-10&&move_y<=-10)

{

//右上

thisdir = rigth_up;

}

else if(move_x<=-10&&move_y>=10)

{

//右下

thisdir =rigth_down;

}

else if(move_x>-10&&move_x<10&&move_y>0) {

//下

thisdir =down;

}

else if(move_x>-10&&move_x<10&&move_y<0) {

//上

thisdir =up;

}

else if(move_x>0&&move_y>-10&&move_y<10) {

//左

thisdir = lefts;

}

else if(move_x<0&&move_y>-10&&move_y<10) {

//右

thisdir =rigth;

}

return thisdir;

}

/*************

* 移动完成后的回调

*************/

void SpiritsPlayer::moveoverCallBack()

{

//移动完成之后恢复站立状态

GetNPCData npcdata = GetNPCData();

npcdata.GetNPCchapter1();

npcdata.role_player.dir=move_dir;

npcdata.role_player.acttodo = stand;

npcdata.role_player.actiontime=1.1f;

npc->stopAction(playdonghua);

playdonghua = SpiritsPlayer::updateNowAnt(npcdata.role_player);

npc->runAction(playdonghua);

}

/*************

* 普通NPC移动完成后的回调

*************/

void SpiritsPlayer::moveoverCallBackforNpc()

{

}

/*************

* 点击瞬移至此

*************/

void SpiritsPlayer::updateNpcPoint(CCPoint newpoint)

{

p_ui_name->updataGameText(ccp(newpoint.x,newpoint.y+npc->getContentSize().he ight/2+10));

npc->setPosition(newpoint);

yinzi->setPosition(ccp(newpoint.x,newpoint.y-npc->getContentSize().height/2+5)); }

/*********************

* 八方向人物动作合成器

*********************/

CCAnimation* SpiritsPlayer::getNowAnt(MainRoledata roledata)

{

CCAnimation* thisdonghua = CCAnimation::create();

switch (roledata.dir)

{

case up:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s06%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s06%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case down:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s04%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s04%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case lefts:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s05%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s05%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case rigth:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s07%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s07%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case rigth_up:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s03%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s03%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

for(int i = 0; i<=roledata.maxcut_attack ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s03%03d.png",roledata.spiritUrl_attack->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case magicup:

for(int i = 0; i<=roledata.maxcut_magic ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s03%03d.png",roledata.spiritUrl_magic->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case rigth_down:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[1000] = {0};

sprintf(donghuaurl,"%s00%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s00%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

for(int i = 0; i<=roledata.maxcut_attack ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s00%03d.png",roledata.spiritUrl_attack->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case magicup:

for(int i = 0; i<=roledata.maxcut_magic ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s00%03d.png",roledata.spiritUrl_magic->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case left_down:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s01%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s01%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

for(int i = 0; i<=roledata.maxcut_attack ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s01%03d.png",roledata.spiritUrl_attack->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case magicup:

for(int i = 0; i<=roledata.maxcut_magic ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s01%03d.png",roledata.spiritUrl_magic->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

case left_up:

switch (roledata.acttodo)

{

case run:

for(int i = 0; i<=roledata.maxcut_pao ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s02%03d.png",roledata.spiritUrl_pao->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case stand:

for(int i = 0; i<=roledata.maxcut_zhan ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s02%03d.png",roledata.spiritUrl_zhan->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case attack:

for(int i = 0; i<=roledata.maxcut_attack ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s02%03d.png",roledata.spiritUrl_attack->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case magicup:

for(int i = 0; i<=roledata.maxcut_magic ; i++)

{

char donghuaurl[100] = {0};

sprintf(donghuaurl,"%s02%03d.png",roledata.spiritUrl_magic->getCString(),i);

thisdonghua->addSpriteFrameWithFileName(donghuaurl);

}

break;

case death:

break;

case funny:

break;

default:

break;

}

break;

default:

break;

}

return thisdonghua;

}

SpiritsPlayer::~SpiritsPlayer(void)

{

}

sprintf(donghuaurl,"%s06%03d.png",roledata.spiritUrl_pao->getCS tring(),i);

总体思路就是,我们通过了帧连接的拼接来构成动画,通过我们之前写好的model数据来定义我们任务的朝向等问题

比如00000代表右,01000就代表右上,这个也得根据自己素材的模型来写不同的处理逻辑,万变不离其中;

如果我们的图片是在一张大图的集合中,我们可以同过CCRect来处理获取帧图片方式!

CCAnimation* getNowAnt(MainRoledata roledata);

CCAnimate* updateNowAnt(MainRoledata roledata);

通过这两个方法集合,我们就能获取到八面玲珑的朝向,甚至我们连,后续的动画机制也加入了,比如,跑动,打斗,做各种动作等!

Commen_Direction SpiritsPlayer::getNowPointDir(CCPoint newpoint); //获取朝向

void SpiritsPlayer::moveTomap_dir(CCPoint newpoint) //改变朝向方法

以上两个方法,我们是专门处理,之后精灵移动,移动完之后还得恢复到站立状态,移动过程中改变人物朝向问题!所以要考虑的很清楚

很清晰,思路清楚了,才能方便以后的拓展。

OK了,有了以上的精灵类,将其实例化到一个简单的图片地图上,他就会动了;

添加的时候我们直接addchild方法!!

SpiritsPlayer* role_main = new

SpiritsPlayer(basedatas->role_player,1,false);

nowmap->addChild(role_main->npc, 999);

nowmap 暂且可以用一张图片CCSprite代替!!!

相关文档