您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x之怪物系统

2014-05-02 15:41 330 查看
这次接着上次的分析,上次加了武器系统,这回增加怪物系统

原文出处http://bbs.9ria.com/thread-242991-1-1.html

MonsterSystem.h

#ifndef __MONSTER_SYSTEM_H__
#define __MONSTER_SYSTEM_H__
#include "cocos2d.h"
#include "MonsterSprite.h"

#include "BulletsSprite.h"
typedef struct MonsterUtils{
float initBlood;// 初始化气血
float initSpeed;// 初始化速度
float defend;// 怪物的防御力
float hurt;// 怪物的伤害值
char* monsName;// 在设置怪物的时候的通用名字
char* picName;// 怪物的图片
char* fileName;// 怪物所对应的plist 文件的名字
int   type;// 怪物类型
int   runCount;// 奔跑动画张数
int   actCount;// 攻击动画张数
int   detCount;// 死亡动画张数
float maxRun;// 最大移动距离
char* attackRangeRec;//是在怪物身上划定一个受到的攻击范围 这样可以让不规则的 图片 看起来受到攻击的时候更逼真一点 字符串的 格式是这样的{{x,y},{w, h}}
} Monster;
class DefenderGameLayer;
// 此类是生产和销毁系统
class MonsterSystem{
public:
MonsterSystem();
~MonsterSystem();
cocos2d::CCArray* getIdleMonsterArry();// 用来保存空闲的怪物
cocos2d::CCArray* getRunMonsterArray();// 用来保存正在奔跑中的怪物
void addMonster(int type,int count);// 用于主线程调用来远远不断的产生怪物
void setDefenderGameLayer(DefenderGameLayer* defenderGameLayer);
bool collisionDetection(BulletsSprite* bulletsSprite);// 传入弓箭 检测是否和怪物发生碰撞
void recoverMonster(MonsterSprite* monsterSprite);// 回收怪物
private:
cocos2d::CCArray* idleMonsterArry;// 用来保存空闲的怪物
cocos2d::CCArray* runMonsterArray;// 用来保存正在奔跑中的怪物
MonsterSprite*    productMonster(int type);//根据类型来产生响应的怪物的数量
DefenderGameLayer* defenderGameLayer;// 游戏主类
void addDefenderGameLayer(MonsterSprite* monsterSprite);// 把奔跑中的怪物添加到 主界面里面
Monster dutu;// 每次添加新的怪物都需要在这里添加一个 并且在构造方法里面初始化
};
#endif


MonsterSystem.cpp

#include "MonsterSystem.h"
#include "DefenderGameLayer.h"
USING_NS_CC;
MonsterSystem::MonsterSystem(){

idleMonsterArry= CCArray::create();// 用来保存空闲的怪物
idleMonsterArry->retain();
this->runMonsterArray=CCArray::create(); // 用来保存正在奔跑中的怪物
this->runMonsterArray->retain();
/**********************************************************************
float initBlood;// 初始化气血
float initSpeed;// 初始化速度
float defend;// 怪物的防御力
float hurt;// 怪物的伤害值
char* picName;// 怪物的图片
char* fileName;// 怪物所对应的plist 文件的名字
int   type;// 怪物类型
int   runCount;// 奔跑动画张数
int   actCount;// 攻击动画张数
int   detCount;// 死亡动画张数
float maxRun;// 最大移动距离
float minX; // 下面的这四个参数其实 是在怪物身上划定一个受到的攻击范围 这样可以让不规则的 图片 看起来受到攻击的时候更逼真一点
float minY;
float maxX;
float maxY;
************************************************************************/
this->dutu.initBlood=100;
this->dutu.initSpeed=5;
this->dutu.defend=1;
this->dutu.hurt=10;
this->dutu.monsName="dutu";
this->dutu.picName="monster/dutu.png";
this->dutu.fileName="monster/dutu.plist";
this->dutu.type=1;
this->dutu.runCount=8;
this->dutu.actCount=14;
this->dutu.detCount=8;
this->dutu.maxRun=800*0.14;
this->dutu.attackRangeRec="{{70,45},{30,110}}";

}

////根据类型来产生响应的怪物
MonsterSprite*    MonsterSystem::productMonster(int type){
if(type==1){
MonsterSprite* sp=MonsterSprite::createWithMonsterRul(dutu.fileName,CCTextureCache::sharedTextureCache()->textureForKey(dutu.picName),dutu.monsName,dutu.runCount,dutu.actCount,dutu.detCount);
sp->setHurt(dutu.hurt);
sp->setDefense(dutu.defend);
sp->setBlood(dutu.initBlood);
sp->setSpeed(dutu.initSpeed);
sp->setmaxRemoving(dutu.maxRun);
sp->setMonType(dutu.type);
sp->setMonState(1);
sp->setAttackRange(CCRectFromString(dutu.attackRangeRec));
sp->setMonsterSystemUtils(this);
return sp;
}
return NULL;
}
// 把奔跑中的怪物添加到 主界面里面
void MonsterSystem::addDefenderGameLayer(MonsterSprite* monsterSprite){
// 获取0-1 之间的数
float ran=CCRANDOM_0_1();
CCSize size=this->defenderGameLayer->getContentSize();
float x=size.width;
float temp=size.height*ran+monsterSprite->getContentSize().height/2;//得到随机放置的纵坐标
float y=0;//初始化y值
if (temp>=size.height){//如果超过了界限
y=size.height-monsterSprite->getContentSize().height/2;//则让精灵的正上方与屏幕对齐
}else{
if(ran!=0){
if (size.height*ran<monsterSprite->getContentSize().height/2){
y=temp+10;
}else {
y=size.height*ran;
}
////////这里我加了一个部分,源代码只是考虑了下半部分,而没有考虑上半部分
/////////else if(size.height*ran>size.height-monsterSprite->getContentSize().height/2){  y=temp-10;   }

}else {
y=monsterSprite->getContentSize().height/2;
}
}
monsterSprite->setAnchorPoint(ccp(0,0.5));
monsterSprite->setPosition(ccp(x,y));

if(this->defenderGameLayer){
this->defenderGameLayer->addChild(monsterSprite,2);
monsterSprite->runAnimation();
}
this->getRunMonsterArray()->addObject(monsterSprite);
}

// 传入弓箭 检测是否和怪物发生碰撞
bool MonsterSystem::(BulletsSprite* bulletsSprite){
bool iscon=false;
if (this->getRunMonsterArray())
{
// 下面是检测 弓箭 是否和怪物发生碰撞
for(int i=0;i<this->getRunMonsterArray()->count();i++){
MonsterSprite* monsterSprite=(MonsterSprite*)this->getRunMonsterArray()->objectAtIndex(i);
// 怪物的状态必须不是死亡的状态
if (monsterSprite->getMonState()!=4)
{
// 判断当前的怪物所受攻击的区域时候和弓箭 是否发生碰撞
iscon=bulletsSprite->boundingBox().intersectsRect(monsterSprite->converNowRect());
if (iscon)
{
// 表示怪物受到攻击 怪物要进行掉血 操作
monsterSprite->fallBlood(bulletsSprite->getHurt());
iscon=true;
break;
}else{
continue;
}
}

}
}
return iscon;
}

void MonsterSystem::recoverMonster(MonsterSprite* monsterSprite){
// 把死掉的怪物回收以下
this->getRunMonsterArray()->removeObject(monsterSprite,false);
// 从界面上移除掉
this->defenderGameLayer->removeChild(monsterSprite,false);
// 还原怪物的 部分属性
if(monsterSprite->getMonType()==1){
monsterSprite->setBlood(dutu.initBlood);
monsterSprite->setPosition(CCPointZero);
monsterSprite->setMonType(dutu.type);
// 停掉所有动画
monsterSprite->stopAllActions();
}
this->getIdleMonsterArry()->addObject(monsterSprite);
}

;// 用于主线程调用来远远不断的产生怪物
void MonsterSystem::addMonster(int type,int count){

for(int i=0;i<count;i++){
MonsterSprite* runmon=NULL;

for(int j=0;j<this->getIdleMonsterArry()->count();j++){
MonsterSprite* temmon=(MonsterSprite*)this->getIdleMonsterArry()->objectAtIndex(j);
if (temmon->getMonType()==type){
runmon=temmon;
break;
}

}
// 如果从空闲的线程 得到了需要的 怪物类型  就添加到界面上 反之 则需要创建一个
if (runmon){
this->getIdleMonsterArry()->removeObject(runmon,false);
this->addDefenderGameLayer(runmon);
}else {
MonsterSprite* temmon= this->productMonster(type);
if (temmon)
{
this->getIdleMonsterArry()->addObject( this->productMonster(type));
i--;//这里是把新创建的monster加入到空闲数组中,这样就能够重新检索一遍以便调用addDefenderGameLayer()
}else {
break;
}

}

}

}
void MonsterSystem::setDefenderGameLayer(DefenderGameLayer* defenderGameLayer){
this->defenderGameLayer=defenderGameLayer;
}

CCArray* MonsterSystem::getRunMonsterArray(){
return this->runMonsterArray;

}
CCArray* MonsterSystem::getIdleMonsterArry(){
return this->idleMonsterArry;
}

MonsterSystem::~MonsterSystem(){
if (idleMonsterArry)
{
this->idleMonsterArry->autorelease();
}
if (runMonsterArray)
{
this->runMonsterArray->autorelease();
}

}
MonsterSprite.h

#ifndef __MONSTER_SPRITE_H__
#define __MONSTER_SPRITE_H__
#include "cocos2d.h"
class MonsterSystem;
class MonsterSprite:public cocos2d::CCSprite{
public:
MonsterSprite(void);
~MonsterSprite(void);
void moveRun();// 移动函数
CC_SYNTHESIZE(float,hurt,Hurt);//伤害值
CC_SYNTHESIZE(float,defense,Defense);//防御值
CC_SYNTHESIZE(float,speed,Speed);//移动速度
CC_SYNTHESIZE(float,maxRemoving,maxRemoving);// 移动的最大距离
CC_SYNTHESIZE(float,blood,Blood);// 怪物气血值
CC_SYNTHESIZE(int,monType,MonType);// 怪物类型
CC_SYNTHESIZE(int,monState,MonState);// 怪物状态 1 静止状态  2 行动状态 3 攻击状态 4 死亡状态
CC_SYNTHESIZE(cocos2d::CCRect,attackRange,AttackRange);// 接受攻击的范围

void runAnimation();// 执行奔跑动画
void deathAnimation();// 执行死亡动画
void attackAnimation();// 执行攻击动画
void fallBlood(float hurt);// 这个是接受攻击 主要改变 该怪物的气血值 和血条的显示
// 第一个参数的意思是 加载的plist 文件的名字 第二个是 plist 对应的图片纹理 第三个是 图片的通用名字 第四个 走路动画图片张数,第五个是 攻击时候的参数  第六个是 死亡动画的张数
// 在这里贴别说明一点为了达到动画的通用性 我们规定 plist 中的图片命名格式是这样的 pic-1编号 是跑步图片 pic-2编号是 攻击图片 pic-x编号是死亡图片
static MonsterSprite* createWithMonsterRul(const char* filename,cocos2d::CC
b9fb
Texture2D* ccTexture2D,const char* pic,int runcount,int attackcount,int deathcout );
void setMonsterSystemUtils(MonsterSystem* monsterSystem);
cocos2d::CCRect converNowRect();// 这个方法是把最初设计的攻击范围 转化到当前 界面的坐标系中的矩形
protected:
cocos2d::CCArray* runArray;//奔跑动画序列帧
cocos2d::CCArray* deathArray;//死亡动画序列帧
cocos2d::CCArray* attackArray;//攻击动画序列帧
cocos2d::CCProgressTimer* bloodBwlid;// 这个是血条
virtual void deathAnimationCallBack(cocos2d::CCNode* pSed);// 死亡动画回调函数
virtual void attackAnimationCallBack(cocos2d::CCNode* pSed);// 攻击动画回调函数
virtual void runAnimationCallBack(cocos2d::CCNode* pSed);//奔跑动画回调函数
virtual bool setUpdateView();
static MonsterSprite* createWithSpriteFrame(cocos2d::CCSpriteFrame *pSpriteFrame);
MonsterSystem* monsterSystem;
void myload(float tim);

};
#endif


MosterSprite.cpp

#include "MonsterSprite.h"
#include "MonsterSystem.h"
USING_NS_CC;
MonsterSprite::MonsterSprite(void){
runArray=CCArray::create();//奔跑动画序列帧
runArray->retain();
deathArray=CCArray::create();//死亡动画序列帧
deathArray->retain();
attackArray=CCArray::create();//攻击动画序列帧
attackArray->retain();

}
MonsterSprite* MonsterSprite::createWithMonsterRul(const char* filename,CCTexture2D* ccTexture2D,const char* pic,int runcount,int attackcount,int deathcout ){
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(filename,ccTexture2D);//打开缓冲文件
CCSpriteFrame* temp=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("%s-10.png",pic)->getCString());//怪物需要一张图片作为初始化的画面
MonsterSprite* monst=MonsterSprite::createWithSpriteFrame(temp);//创建一个初始化的怪物精灵
if (monst&&monst->setUpdateView()&&ccTexture2D){
// 初始化 奔跑动画序列帧
for(int i=0;i<runcount;i++){

monst->runArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("%s-1%d.png",pic,i)->getCString()));
}
// 初始化 攻击动画 序列帧
for(int i=0;i<attackcount;i++){
monst->attackArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("%s-2%d.png",pic,i)->getCString()));
}

// 初始化 死亡动画 序列帧
for(int i=0;i<deathcount;i++){
monst->deathArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("%s-3%d.png",pic,i)->getCString()));
}
// 初始化血条

return monst;
}else {
return NULL;
}
}
MonsterSprite* MonsterSprite::createWithSpriteFrame(CCSpriteFrame *pSpriteFrame){//创建怪物精灵对象
MonsterSprite* monSter=new MonsterSprite();
if (pSpriteFrame&&monSter&&monSter->initWithSpriteFrame(pSpriteFrame))//如果初始化怪物精灵成功,则将MonsterSprite加入内存管理计数器
{
monSter->autorelease();
return monSter;
}
CC_SAFE_DELETE(monSter);
return NULL;
}

bool MonsterSprite::setUpdateView(){
bool isRet=false;
do
{
// 添加血条的背景图片
CCSprite* bloodbackimg=CCSprite::createWithTexture(CCTextureCache::sharedTextureCache()->textureForKey("game/monster_blood_frame.png"));
CC_BREAK_IF(!bloodbackimg);	//增加血条框精灵
bloodbackimg->setPosition(ccp(this->getContentSize().width/2,this->getContentSize().height+2));//放到距离怪物上方2高度的正上方
this->addChild(bloodbackimg,1);//添加血条框到怪物

// 添加进度条
CCSprite* blood=CCSprite::createWithTexture(CCTextureCache::sharedTextureCache()->textureForKey("game/monster_blood.png"));
CC_BREAK_IF(!blood);//增加血条进度框
this->bloodBwlid=CCProgressTimer::create(blood);//将血条绑定为进度条
CC_BREAK_IF(!bloodBwlid);
bloodBwlid->setType(kCCProgressTimerTypeBar);// 设置成横向的
//可以看作是按矩形显示效果的进度条类型
bloodBwlid->setMidpoint(ccp(0,0));
//  用来设定进度条横向前进的方向从左向右或是从右向左
bloodBwlid->setBarChangeRate(ccp(1,0));

bloodBwlid->setPosition(ccp(this->getContentSize().width/2,this->getContentSize().height+2));
bloodBwlid->setPercentage(100);
this->addChild(bloodBwlid,2);
isRet=true;
} while (0);
return isRet;

}

// 执行奔跑动画
void MonsterSprite::runAnimation(){

this->setMonState(2);
this->stopAllActions();
if(this->runArray->count()>0){
CCAnimation *animation=CCAnimation::createWithSpriteFrames(runArray,0.15f);
CCAnimate *animate=CCAnimate::create(animation);
CCCallFuncN *onComplete =  CCCallFuncN::create(this, callfuncN_selector(MonsterSprite::runAnimationCallBack));
CCSequence* pse=CCSequence::create(animate,onComplete,NULL);
// 一直执行奔跑动画
this->runAction(CCRepeatForever::create(pse));

this->schedule(schedule_selector(MonsterSprite::myload),0.15);
}
}

void MonsterSprite::myload(float tie){
if (this->getMonState()==2){
this->moveRun();
}
}

void MonsterSprite::runAnimationCallBack(CCNode* pSed){

}

// 执行死亡动画
void MonsterSprite::deathAnimation(){
this->setMonState(4);
this->stopAllActions();
if(this->deathArray->count()>0){
CCAnimation *animation=CCAnimation::createWithSpriteFrames(deathArray,0.15f);
CCAnimate *animate=CCAnimate::create(animation);
CCCallFuncN *onComplete =  CCCallFuncN::create(this, callfuncN_selector(MonsterSprite::deathAnimationCallBack));
CCSequence* pse=CCSequence::create(animate,onComplete,NULL);
this->runAction(pse);
}
}

void MonsterSprite::deathAnimationCallBack(CCNode* pSed){
if(this->monsterSystem){
this->monsterSystem->recoverMonster(this);
}
this->unscheduleAllSelectors();
}

// 执行攻击动画
void MonsterSprite::attackAnimation(){
this->setMonState(3);
this->stopAllActions();
if(this->attackArray->count()>0){
CCAnimation *animation=CCAnimation::createWithSpriteFrames(attackArray,0.15f);
CCAnimate *animate=CCAnimate::create(animation);
CCCallFuncN *onComplete =  CCCallFuncN::create(this, callfuncN_selector(MonsterSprite::attackAnimationCallBack));
CCSequence* pse=CCSequence::create(animate,onComplete,NULL);
this->runAction(CCRepeatForever::create(pse));
}
}
// 这个是接受攻击 主要改变 该怪物的气血值 和血条的显示
void MonsterSprite::fallBlood(float hurted){
float temp=this->getBlood();
// 按照 一点防御 能抵挡10%的伤害 来计算
this->setBlood(temp-(hurted-this->getDefense()*0.1));
if(this->getBlood()<=0){
this->bloodBwlid->setPercentage(0);
this->deathAnimation();
}else {
this->bloodBwlid->setPercentage(this->getBlood());
}
}

void MonsterSprite::attackAnimationCallBack(CCNode* pSed){
CCLOG("donghuazhixing2");

this->unscheduleAllSelectors();
}

void MonsterSprite::moveRun(){
int x=this->getPositionX();
if(this->getMonState()==2){
// 当X 的坐标小于 最小的距离是 需要调用 攻击动画
x=x-this->getSpeed();
this->setPositionX(x);
if(x<=this->getmaxRemoving()){
this->attackAnimation();
}
}

}

CCRect MonsterSprite::converNowRect(){
// 得到当前的 怪物的所在的矩形
CCRect monsret=this->boundingBox();
float x=monsret.getMinX()+this->getAttackRange().getMinX();
float y=monsret.getMinY()-this->getAttackRange().getMinY();
return CCRect(x,y,this->getAttackRange().getMaxX(),this->getAttackRange().getMaxY());
}

void MonsterSprite::setMonsterSystemUtils(MonsterSystem* monsterSystem){
this->monsterSystem=monsterSystem;
}
MonsterSprite::~MonsterSprite(void){
if (runArray)
{
runArray->autorelease();
}

if (deathArray)
{
deathArray->autorelease();
}

if (attackArray)
{
attackArray->autorelease();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cocos2d-x学习