cocos2d-x之怪物系统

这次接着上次的分析,上次加了武器系统,这回增加怪物系统

原文出处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::CCTexture2D* 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();
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值