cocos2d-x之怪物系统

来源:互联网 发布:世界各国软件行业排名 编辑:程序博客网 时间:2024/06/10 01:14
 这次接着上次的分析,上次加了武器系统,这回增加怪物系统 
        原文出处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
原创粉丝点击