Skip to content

battle模块代码导读

highkay edited this page Mar 23, 2016 · 4 revisions

对象

BattleField

  • 战斗逻辑的核心类,包含管理所有英雄,敌人,技能等view model和关卡数据,关卡逻辑的功能
  • 和其他界面的交互,例如升级英雄,释放技能,买活等都是通过发送或者监听事件(EVENT)来实现的
  • 精灵层级和继承关系(从右向左) 关系图
虚拟层级ZORDER_OFFSET
  • 因为cocos的精灵类如果当作容器addChild之后,对精灵的操作会作用到child上,想要单独维护child比较麻烦,所以在BattleField的根容器this.container中实现了一个全局的“虚拟层级”ZORDER_OFFSET
  • 首先通过包装的addSprite(s)方法添加一个精灵,这个时候会在该精灵的zindex的基础上预留CONSTS.MAX_ATTACHMENTS_ON_SPRITE数量的zindex,相当于占位符;在往这个精灵添加child的时候,需要使用addSpriteRelatedNode(s)方法来添加child,根据每个child自身相对于这个精灵的zindex的偏移(一般命名为xxx_ZORDER_OFFSET)来保证实现了正确的基于精灵的层级(遮挡效果)
  • 这是一个简单的静态模拟,目前还不支持动态的排序

BattleUnit

  • 重要的精灵单位父类,包含绝大部分的英雄和敌人的共通逻辑
  • 通过update方法累计时间间隔,当累计的dt超过model类中的atk_period属性值(行动间隔)的时候,会触发onMove方法,即执行该精灵单位的AI,需要子类自行实现
  • 所有打印cc.log的方法都需要由子类来实现逻辑
  • 控制血条的逻辑init/show/hide/refreshLifeBar
  • 控制buff图标的逻辑add/remove/show/hide/refreshBuff
  • 控制伤害数字的逻辑showDamageNumber

HeroUnit

  • 继承自BattleUnit,大部分业务逻辑都在父类中
  • 每个HeroUnit对应一个Hero的对象并且包装了从中读取对应属性值的方法
  • update中增加了计算复活时间的逻辑
  • onMove中实现了攻击任意一个存活敌人
  • onDead实现了死亡的一系列动画切换和状态变更
  • onRevive实现了复活的一系列动画切换和状态变更
  • 构造ctor中增加了墓碑精灵的初始化
  • onEnter中增加了离线死亡/复活状态的判定和切换逻辑

EnemyUnit

  • 继承自BattleUnit,大部分业务逻辑都在父类
  • 每个EnemyUnit对应一个Enemy对象并且包装了从中读取对应属性值的方法
  • onMove中实现了攻击任意一个存活英雄
  • onVanish实现了掉落的逻辑

ActiveSkill

  • 主动技能实现类,通过读取Skill对象中的属性来实现类型对应的动画效果和逻辑
  • 主动技能分为一次型TYPE_ONCE,效果型TYPE_BUFF和持续型TYPE_CONTINUOUS
  • 主动技能的作用对象分为单个敌人ONE_ENEMY,多个敌人MULTI_ENEMY,单个英雄ONE_HERO和多个英雄MULTI_HERO
  • 一般情况下作用对象和动画效果的数量一致,但是效果类型(effect)为"fs_enemy_once"的比较特殊,动画效果是全屏的,只有一个
  • preshow为技能的前置动画,非必须,根据Skill中的配置来决定是否播放
  • 一次技能释放的流程为 构造函数ctor->释放cast->前置动画[preshow]->确认目标对象updateTargets->初始化效果的资源initRes->播放技能动画效果playEffectAnimationOnTargets->buff结算[startBuffEffect/clearBuffEffect]->技能结束onCastFinish->效果结算affectTargets->释放动画资源releaseEffectAnimations->持续类型技能判定
  • 当技能的目标为0时,调用waitForNextCast来延迟0.1秒轮询,直到目标不为0,调用recast重新释放一次技能
  • 持续型主动技能通过对duration属性和当前技能释放时间的计算来主动调用recast重新释放一次技能,并且累计技能释放的持续时间,直到超过duration

DamageNumber

  • 显示技能效果的图片数字精灵,加载gfx/HookGame/alpha.ccs中的BattleNum导出的json文件,也就是fnt控件
  • 如果val为正数,也就是伤害效果,则加载root节点下的battle_num控件(红色字体);如果为负数,也就是治愈效果,则加载root节点下的recover_num控件(绿色字体)
  • 暴击时(ctr),精灵拉伸动画会增大4倍(2->8)
  • 该精灵用到了池化对象(cc.pool),需要额外实现unuse和reuse方法,并且用create方法来获取对象

FairyUnit

  • 战斗中每隔CONSTS.flySpirit_interval_time会加入(showFairy)一个小精灵对象,该对象可以被点击杀死,获得(_createChest)一个宝箱精灵(ChestUnit)
  • 小精灵单位有两种AI(行动轨迹),从左向右或者从右向左

ChestUnit

  • 每杀死一个小精灵单位(FairyUnit)的时候会生成一个宝箱精灵(ChestUnit),点击宝箱精灵可以随机得到一个奖励列表(CONSTS.click_chest_random_events)中的奖励,可能是一种资源,例如金币,也可能是一个buff技能

Loot

  • Loot首先根据掉落的内容生成(Loot.generateLoots)一系列的动画精灵(lootSprites),然后需要手动添加这些精灵到战斗场景中
  • Loot根据展现效果分成两大类,金币(gold)和其他资源,金币根据4个图形等级10个数量等级生成若干精灵

初始化流程(仅一次)

  1. 构造英雄容器(heroUnits)和敌人容器(enemyUnits),背景精灵,绑定相关事件
  2. 读取gfx/HookGame/alpha.ccs的BattleLayer中的sprites这个容器内的控件(hero1-7,enemy1-7,hero_center,enemy_center)位置信息
  3. 根据存档(PlayerData)中的关卡信息初始化战斗(initBattle)
  4. 根据关卡信息(bg属性)加载对应的背景图片资源(loadStageBackground)
  5. 根据存档中的英雄模型Hero数据创建HeroUnit并且加入到英雄容器和战斗场景中(addHeroIntoBattle)

战斗流程

  1. 根据关卡信息初始化当前战斗的敌人数据,如果是普通关卡,按照配置数据随机生成若干敌人数据,如果是Boss关卡,则直接读取Boss数据生成敌人
  2. 根据敌人数据创建敌人模型Enemy数据创建EnemUnit并且加入到敌人容器和战斗场景中(addEnemyIntoBattle)
  3. 更新敌人容器中敌人的总血量并且更新总血条
  4. 发一个EVENT.BATTLE_START事件提醒顶部的面板更新数据,例如关卡序号,boss战斗按钮等
  5. 敌人被添加进战斗的时候,并不能直接被getAllLived获取到,只有在所有的动画都播放完毕后,设置ready为true才可以
  6. 每当一个EnemyUnit死亡的时候会调用battle的onEnemyDead,如果所有的敌人都被消灭,则判定战斗胜利,调用onBattleWin
  7. Boss关卡胜利后,会更新关卡数据;非Boss关卡胜利则累计存档中的stage_battle_num值,进入下一关,直到符合进入Boss关卡的条件(couldFightBossBattle)
  8. 当符合条件之后,也可以通过点击顶部面板中的按钮来随时进入和退出Boss战斗
  9. 延迟一秒后,重新开始战斗流程

其他

解锁英雄

如果通过英雄和技能面板解锁了新的英雄(从0级升级到1级),会发送一个EVENT.HERO_UPGRADE,判断英雄等级,并且根据id调用addHeroIntoBattle

发动技能

通过面板或者小精灵宝箱(ChestUnit)释放技能,会发送一个EVENT.CAST_SKILL,根据event.getUserData获取到skill对象创建一个ActiveSkill对象并且调用cast