SysAttack.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /** @format */
  2. import {ComAttackable} from '../components/ComAttackable'
  3. import {ComRole} from '../components/ComRole'
  4. import {ComTransform} from '../components/ComTransform'
  5. import {ECSSystem} from '../lib/ECSSystem'
  6. import {FightWorld} from '../worlds/FightWorld'
  7. import {ComFindEnemy} from '../components/ComFindEnemy'
  8. import {ComCocosNode} from '../components/ComCocosNode'
  9. import {Data, Mgr} from '../../GameControl'
  10. import {cBody} from '../../collision/Body'
  11. import {ComDie} from '../components/ComDie'
  12. import {GenFilterKey} from '../lib/ECSComponent'
  13. import {EventRoleTip} from '../core/NodeEvent'
  14. import {BUFF_TYPE, ENTRY, FRAME_ANI_NAME, GAME_ROLE_TIP} from '../../enums/Enum'
  15. import {IAttackEffect} from '../core/GameInterface'
  16. import {ComBullet} from '../components/ComBullet'
  17. import {ComBehaviorTree} from '../components/ComBehaviorTree'
  18. const FILTER_ATTACKABLE = GenFilterKey([ComTransform, ComAttackable, ComRole, ComCocosNode, ComBehaviorTree], [ComDie])
  19. export class SysAttack extends ECSSystem {
  20. /** 连接 */
  21. public onAdd(world: FightWorld): void {}
  22. /** 断开连接 */
  23. public onRemove(world: FightWorld): void {}
  24. /** 添加实体 */
  25. public onEntityEnter(world: FightWorld, entity: number): void {}
  26. /** */
  27. public onEntityLeave(world: FightWorld, entity: number): void {}
  28. /** 更新 */
  29. public onUpdate(world: FightWorld, dt: number): void {
  30. let filter = world.getFilter(FILTER_ATTACKABLE)
  31. let rate = Data.game.rateNum
  32. filter.walk((entity: number) => {
  33. let comRole = world.getComponent(entity, ComRole)
  34. let comAttackable = world.getComponent(entity, ComAttackable)
  35. let comTransform = world.getComponent(entity, ComTransform)
  36. let comCocosNode = world.getComponent(entity, ComCocosNode)
  37. if (!comAttackable.dirty) return
  38. comAttackable.countDown -= dt
  39. if (comAttackable.countDown <= 0) {
  40. comAttackable.dirty = false
  41. }
  42. if (!comAttackable.hurtFrameCompleted && comAttackable.countDown <= comAttackable.hurtFrame) {
  43. let comFindEnemy = world.getComponent(entity, ComFindEnemy)
  44. let comRoleEnemy = world.getComponent(comAttackable.curAttack, ComRole)
  45. let comTransformEnemy = world.getComponent(comAttackable.curAttack, ComTransform)
  46. if (world.isDie(comAttackable.curAttack)) return
  47. comAttackable.hurtFrameCompleted = true
  48. comRole.attackNum += 1
  49. let iAttack: IAttackEffect = {
  50. isCrit: Math.getProb(comRole.attackCrit / rate),
  51. isBack: Math.sign(comTransform.dir.x) == Math.sign(comTransformEnemy.dir.x),
  52. }
  53. //闪避率=1-(1+命中/10000)*(1-闪避/10000) 闪避率0%-90%
  54. let dodgeRate = 1 - (1 + comRole.hit / Data.game.rateNum) * (1 - comRoleEnemy.dodge / Data.game.rateNum)
  55. dodgeRate = Math.max(dodgeRate, 0)
  56. dodgeRate = Math.min(dodgeRate, 0.9)
  57. let isDodge = comRoleEnemy && Math.getProb(dodgeRate)
  58. let hurt = 0
  59. let isKill = false
  60. if (comAttackable.isMelee) {
  61. hurt = world.getHurtByAttackRole(comRole, comAttackable.curAttack, iAttack)
  62. Mgr.audio.playSFX(comRole.roleCfg.sound)
  63. if (!isDodge) {
  64. if (hurt > 0) {
  65. //被反弹伤害
  66. world.changeHpByRebound(entity, comAttackable.curAttack)
  67. //普攻吸血
  68. if (comRole.entryMap.get(ENTRY.hurt2HP)?.num > 0) {
  69. let addHPNum = (comRole.entryMap.get(ENTRY.hurt2HP).num * hurt) / Data.game.rateNum
  70. world.addHP(addHPNum, entity)
  71. }
  72. }
  73. // world.changeHpByHurt(
  74. // comAttackable.curAttack,
  75. // hurt,
  76. // iAttack.isCrit,
  77. // comRole.roleCfg.hitID ? comRole.roleCfg.hitID : FRAME_ANI_NAME.normalHurt,
  78. // )
  79. //临时屏蔽近战攻击特效
  80. world.changeHpByHurt(comAttackable.curAttack, hurt, iAttack.isCrit, comRole.roleCfg.hitID)
  81. //杀人+1
  82. if (world.isDie(comRoleEnemy)) {
  83. comRole.killNum += 1
  84. isKill = true
  85. }
  86. } else {
  87. let curAttackCocosNode = world.getComponent(comAttackable.curAttack, ComCocosNode)
  88. curAttackCocosNode.events.push(new EventRoleTip(GAME_ROLE_TIP.missTip, 0, 'miss'))
  89. }
  90. //处理近战buff
  91. comRole.buffs.forEach(buff => {
  92. let buffConfig = buff.buffCfg
  93. if (buffConfig.buffType == BUFF_TYPE.attackGetHp && hurt > 0 && !isDodge) {
  94. //攻击吸血
  95. let addHPNum = (hurt * buffConfig.attrRate[0]) / rate
  96. world.addHP(addHPNum, entity)
  97. } else if (buffConfig.buffType == BUFF_TYPE.killNum && isKill) {
  98. //根据杀敌加攻击
  99. comRole.attack += (comRole.roleCfg.attack * buffConfig.attrRate[0]) / rate
  100. }
  101. })
  102. } else {
  103. let bullets = world.createBulletEntity(entity, iAttack.isCrit)
  104. bullets.forEach(bullet => {
  105. let comBullet = world.getComponent(bullet, ComBullet)
  106. comBullet.fightData.attackNum = comRole.attackNum
  107. })
  108. }
  109. let sputterRate: number = 0
  110. comRole.buffs.forEach(buff => {
  111. // 溅射比例
  112. if (buff.buffCfg.buffType == BUFF_TYPE.sputter && buff.buffCfg.attrRate[0] > sputterRate) {
  113. sputterRate = buff.buffCfg.attrRate[0]
  114. }
  115. })
  116. if (sputterRate > 0 && !isDodge) {
  117. iAttack.sputter = sputterRate
  118. comFindEnemy.attackCObject.containsBody.forEach((cBody: cBody, entityOther: number) => {
  119. // 溅射
  120. if (entityOther != comAttackable.curAttack && !world.isDie(entityOther)) {
  121. let otherComTransform = world.getComponent(entityOther, ComTransform)
  122. if (
  123. (comTransform.dir.x > 0 &&
  124. otherComTransform.x - comTransform.x >= Data.game.meleeRange / 2) ||
  125. (!(comTransform.dir.x > 0) &&
  126. otherComTransform.x - comTransform.x <= Data.game.meleeRange / 2)
  127. ) {
  128. world.changeHpByHurt(
  129. entityOther,
  130. world.getHurtByAttackRole(comRole, entityOther, iAttack),
  131. false,
  132. 0,
  133. )
  134. }
  135. }
  136. })
  137. }
  138. }
  139. return false
  140. })
  141. }
  142. }