开发cocos2d-x 游戏 实战篇(4)之 怪物系统

其中关于怪物类 我这里要仔细讲解一下  在一个游戏中我们的怪物 常常是这样的  有攻击动画  有走路动画  有死亡动画 目前我没考虑收到攻击的动画 考虑太多只会增加开始游戏的难度 我们先把最基本的 实现 慢慢来扩展

     我的怪物的图片是从66rpg 上下载的  然后用TexturePacker  把众多的动画 所需要的 图片处理成一张图片  减少加载图片的次数 通过这个工具以后会生成一张图片和一个plist 文件。 在我的代码中大家可以看到如何使用

    下面贴出怪物类的主要代码


  1. #ifndef __MONSTER_SPRITE_H__
  2. #define __MONSTER_SPRITE_H__
  3. #include "cocos2d.h"
  4. class MonsterSystem;
  5. class MonsterSprite:public cocos2d::CCSprite{
  6. public:
  7.         MonsterSprite(void);
  8.         ~MonsterSprite(void);
  9.         void moveRun();// 移动函数
  10.         CC_SYNTHESIZE(float,hurt,Hurt);//伤害值
  11.         CC_SYNTHESIZE(float,defense,Defense);//防御值
  12.         CC_SYNTHESIZE(float,speed,Speed);//移动速度
  13.         CC_SYNTHESIZE(float,maxRemoving,maxRemoving);// 移动的最大距离
  14.         CC_SYNTHESIZE(float,blood,Blood);// 怪物气血值
  15.         CC_SYNTHESIZE(int,monType,MonType);// 怪物类型
  16.         CC_SYNTHESIZE(int,monState,MonState);// 怪物状态 1 静止状态  2 行动状态 3 攻击状态 4 死亡状态
  17.         CC_SYNTHESIZE(cocos2d::CCRect,attackRange,AttackRange);// 接受攻击的范围
  18.         
  19.         void runAnimation();// 执行奔跑动画
  20.         void deathAnimation();// 执行死亡动画
  21.         void attackAnimation();// 执行攻击动画
  22.         void fallBlood(float hurt);// 这个是接受攻击 主要改变 该怪物的气血值 和血条的显示
  23.         // 第一个参数的意思是 加载的plist 文件的名字 第二个是 plist 对应的图片纹理 第三个是 图片的通用名字 第四个 走路动画图片张数,第五个是 攻击时候的参数  第六个是 死亡动画的张数
  24.         // 在这里贴别说明一点为了达到动画的通用性 我们规定 plist 中的图片命名格式是这样的 pic-1编号 是跑步图片 pic-2编号是 攻击图片 pic-x编号是死亡图片
  25.         static MonsterSprite* createWithMonsterRul(const char* filename,cocos2d::CCTexture2D* ccTexture2D,const char* pic,int runcount,int attackcount,int deathcout );
  26.         void setMonsterSystemUtils(MonsterSystem* monsterSystem);
  27.         cocos2d::CCRect converNowRect();// 这个方法是把最初设计的攻击范围 转化到当前 界面的坐标系中的矩形
  28. protected:
  29.         cocos2d::CCArray* runArray;//奔跑动画序列帧
  30.         cocos2d::CCArray* deathArray;//死亡动画序列帧
  31.         cocos2d::CCArray* attackArray;//攻击动画序列帧  
  32.         cocos2d::CCProgressTimer* bloodBwlid;// 这个是血条
  33.         virtual void deathAnimationCallBack(cocos2d::CCNode* pSed);// 死亡动画回调函数
  34.         virtual void attackAnimationCallBack(cocos2d::CCNode* pSed);// 攻击动画回调函数
  35.         virtual void runAnimationCallBack(cocos2d::CCNode* pSed);//奔跑动画回调函数
  36.         virtual bool setUpdateView();
  37.         static MonsterSprite* createWithSpriteFrame(cocos2d::CCSpriteFrame *pSpriteFrame); 
  38.         MonsterSystem* monsterSystem; 
  39.         void myload(float tim);

  40. };
  41. #endif
复制代码
基本上每个代码都有注释 不懂的大家可以留言给我,我会细心给大家讲解。 这里我要特别讲解一下 在这个里面有这样的一个参数叫
CC_SYNTHESIZE(cocos2d::CCRect,attackRange,AttackRange);// 接受攻击的范围

大家要特别主要这行代码  我先讲解一下 为什么会出现这样的一个参数 首先是否发生碰撞并不是 和怪物精灵 直接发生碰撞  而是和这个参数对比 。这一点是问什么呢

我给大家上传一张图


     为了看的明显我把透明部分给弄成了红的当大家看到这样一张图片的时候如果按照我们最开始的做法让弓箭直接和怪物所在的矩形发生碰撞  你会看到弓箭 还没打到怪物就消失了 这不是我们愿意看到的 为了打到游戏的逼真性我们规定只要当弓箭碰撞到蓝色区域的时候 才能算碰撞。所以就会出现这样的一个参数。哈哈是不是有点麻烦,呵呵好的游戏都是考虑尽量详细的情况。自夸一下别介意啊。不过还需特别注意一点我们的这个矩形在判断是否发生碰撞的时候需要转化成整个屏幕的坐标系

主要代码如下


  1. CCRect MonsterSprite::converNowRect(){
  2.     // 得到当前的 怪物的所在的矩形
  3.         CCRect monsret=this->boundingBox();
  4.         float x=monsret.getMinX()+this->getAttackRange().getMinX();
  5.         float y=monsret.getMinY()-this->getAttackRange().getMinY();
  6.         return CCRect(x,y,this->getAttackRange().getMaxX(),this->getAttackRange().getMaxY());
  7. }
复制代码
怪物类讲解完了我们下面说下我们的怪物系统 包含 怪物系统包含 释放怪物  回收怪物 和弓箭的碰撞主要代码如下
  1. #ifndef __MONSTER_SYSTEM_H__
  2. #define __MONSTER_SYSTEM_H__
  3. #include "cocos2d.h"
  4. #include "MonsterSprite.h"

  5. #include "BulletsSprite.h"
  6. typedef struct MonsterUtils{
  7.         float initBlood;// 初始化气血
  8.         float initSpeed;// 初始化速度
  9.         float defend;// 怪物的防御力
  10.         float hurt;// 怪物的伤害值
  11.         char* monsName;// 在设置怪物的时候的通用名字
  12.         char* picName;// 怪物的图片
  13.         char* fileName;// 怪物所对应的plist 文件的名字
  14.         int   type;// 怪物类型
  15.         int   runCount;// 奔跑动画张数
  16.         int   actCount;// 攻击动画张数
  17.         int   detCount;// 死亡动画张数
  18.         float maxRun;// 最大移动距离        
  19.         char* attackRangeRec;//是在怪物身上划定一个受到的攻击范围 这样可以让不规则的 图片 看起来受到攻击的时候更逼真一点 字符串的 格式是这样的{{x,y},{w, h}}
  20. } Monster;
  21. class DefenderGameLayer;
  22. // 此类是生产和销毁系统
  23. class MonsterSystem{
  24. public:
  25.         MonsterSystem();
  26.         ~MonsterSystem();
  27.         cocos2d::CCArray* getIdleMonsterArry();// 用来保存空闲的怪物
  28.         cocos2d::CCArray* getRunMonsterArray();// 用来保存正在奔跑中的怪物
  29.         void addMonster(int type,int count);// 用于主线程调用来远远不断的产生怪物
  30.         void setDefenderGameLayer(DefenderGameLayer* defenderGameLayer);
  31.         bool collisionDetection(BulletsSprite* bulletsSprite);// 传入弓箭 检测是否和怪物发生碰撞
  32.         void recoverMonster(MonsterSprite* monsterSprite);// 回收怪物
  33. private:
  34.         cocos2d::CCArray* idleMonsterArry;// 用来保存空闲的怪物
  35.         cocos2d::CCArray* runMonsterArray;// 用来保存正在奔跑中的怪物
  36.     MonsterSprite*    productMonster(int type);//根据类型来产生响应的怪物的数量 
  37.         DefenderGameLayer* defenderGameLayer;// 游戏主类
  38.         void addDefenderGameLayer(MonsterSprite* monsterSprite);// 把奔跑中的怪物添加到 主界面里面
  39.         Monster dutu;// 每次添加新的怪物都需要在这里添加一个 并且在构造方法里面初始化
  40. };
  41. #endif
复制代码
我的代码的注释还很详细的 呵呵不过大家要注意下 本来今天的任务是很轻松的可以搞定的但是在这里犯了一个很低级的错误 就是两个头文件相互包含  出现的错误 我都不知道为啥 后来一个在C++ 群里面叫七月的兄弟帮我解决了 非常感谢他 当两个头文件相互引用的时候 要杜绝这种情况 。至于为什么 大家可以百度搜一下。这里
  1. class DefenderGameLayer;
复制代码
我就是用前置声明 ,然后在对应的CPP 文件里面  引入头文件 我今天看一篇文章所尽量吧引入头文件的操作放在CPP 文件里面。这里要特别注意下 要不报错让你蛋疼的找不到错误。具体可以看这个文章的说明 查看详细其实在这里一个重要可以优化的地方就是我在这个类里面生命的这个 怪物结构体 这个本应该放到一个配置文件中的 然后通过读取配置文件来创建响应的怪物 这里 为了加快游戏的开发 我先放到这里 等后期我讲解游戏优化的时候  把这一块更改一下。下面如果上面的代码你都看懂了并且实现了 你运行将会看到如下的界面 
哈哈赌徒很多吧 这么赌徒出现是不是要干掉他  这个在碰撞检测里面有具体的实现主要代码如下
  1. // 传入弓箭 检测是否和怪物发生碰撞
  2. bool MonsterSystem::collisionDetection(BulletsSprite* bulletsSprite){
  3.         bool iscon=false;
  4.         if (this->getRunMonsterArray())
  5.         {
  6.                 // 下面是检测 弓箭 是否和怪物发生碰撞
  7.                 for(int i=0;i<this->getRunMonsterArray()->count();i++){
  8.                         MonsterSprite* monsterSprite=(MonsterSprite*)this->getRunMonsterArray()->objectAtIndex(i);
  9.                         // 怪物的状态必须不是死亡的状态
  10.                         if (monsterSprite->getMonState()!=4) 
  11.                         {
  12.                                 // 判断当前的怪物所受攻击的区域时候和弓箭 是否发生碰撞
  13.                             iscon=bulletsSprite->boundingBox().intersectsRect(monsterSprite->converNowRect());
  14.                                 if (iscon)
  15.                                 {
  16.                                         // 表示怪物受到攻击 怪物要进行掉血 操作
  17.                                         monsterSprite->fallBlood(bulletsSprite->getHurt());
  18.                                         iscon=true;
  19.                                         break;
  20.                                 }else{
  21.                                         continue;
  22.                                 }
  23.                         }

  24.                 }
  25.         }
  26.         return iscon;
  27. }
复制代码
不过大家注意一下这个版本 是有问题的就是怪物可以源源不断的产生。如果你要是一直运行估计内存会受不了 这是为什么呢 因为我 每一秒让产生两个怪物这已经大于我们干掉一个怪物的速度了。这个问题怎么解决呢 这就是以后章节的内容 及关卡系统 大家对于关卡系统是不是也很感兴趣啊。呵呵这个放到以后的章节里面进行讲述。 到此为止我们的怪物系统就产生了    对于以上还有的问题就是没有设置炮台的血量 没有给其掉血 让其死亡,这个将是下一章所讲述的内容。让武器系统更好的配合怪物系统,让咱们的游戏看起来是一个可以玩的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值