SysFindEnemy.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /** @format */
  2. import {ECSSystem} from '../lib/ECSSystem'
  3. import {GenFilterKey} from '../lib/ECSComponent'
  4. import {FightWorld} from '../worlds/FightWorld'
  5. import {ComDie} from '../components/ComDie'
  6. import {ComFindEnemy} from '../components/ComFindEnemy'
  7. import {ComRole} from '../components/ComRole'
  8. import {ComTransform} from '../components/ComTransform'
  9. import {cCollider} from '../../collision/Collider'
  10. import {ShapeType} from '../../collision/Shape'
  11. import {EventType} from '../core/NodeEvent'
  12. import {ComCocosNode} from '../components/ComCocosNode'
  13. import {ComAttackable} from '../components/ComAttackable'
  14. import {Data} from '../../GameControl'
  15. import {ComFriend} from '../components/ComFriend'
  16. import {ComEnemy} from '../components/ComEnemy'
  17. import {cObject} from '../../collision/Object'
  18. import {ROLE_TYPE, SKILL_TYPE} from '../../enums/Enum'
  19. import {ComSkillAbel} from '../components/ComSkillAbel'
  20. import {ComBehaviorTree} from '../components/ComBehaviorTree'
  21. export const FILTER_FIND_ENEMY = GenFilterKey(
  22. [ComFindEnemy, ComRole, ComAttackable, ComTransform, ComCocosNode, ComBehaviorTree],
  23. [ComDie],
  24. )
  25. export const FILTER_CAN_ATTACK_FRIEND = GenFilterKey(
  26. [ComRole, ComTransform, ComCocosNode, ComFriend, ComBehaviorTree],
  27. [ComDie],
  28. )
  29. export const FILTER_CAN_ATTACK_ENEMY = GenFilterKey(
  30. [ComRole, ComTransform, ComCocosNode, ComEnemy, ComBehaviorTree],
  31. [ComDie],
  32. )
  33. export class SysFindEnemy extends ECSSystem {
  34. /** 连接 */
  35. public onAdd(world: FightWorld): void {}
  36. /** 断开连接 */
  37. public onRemove(world: FightWorld): void {}
  38. /** 添加实体 */
  39. public onEntityEnter(world: FightWorld, entity: number): void {}
  40. /** */
  41. public onEntityLeave(world: FightWorld, entity: number): void {}
  42. /** 更新 */
  43. public onUpdate(world: FightWorld, dt: number): void {
  44. cCollider.inst.update(dt)
  45. let filter = world.getFilter(FILTER_FIND_ENEMY)
  46. let canAttackFriendFilter = world.getFilter(FILTER_CAN_ATTACK_FRIEND)
  47. let canAttackEnemyFilter = world.getFilter(FILTER_CAN_ATTACK_ENEMY)
  48. filter.walk((entity: number) => {
  49. let comRole: ComRole = world.getComponent(entity, ComRole)
  50. let comFindEnemy: ComFindEnemy = world.getComponent(entity, ComFindEnemy)
  51. let comAttackable: ComAttackable = world.getComponent(entity, ComAttackable)
  52. let comTransform: ComTransform = world.getComponent(entity, ComTransform)
  53. let comSkillAbel = world.getComponent(entity, ComSkillAbel)
  54. //目标角色死亡
  55. if (world.isDie(comFindEnemy.enemy)) {
  56. //console.log('SysFindEnemy 目标角色已死亡-------->', comFindEnemy.enemy)
  57. comFindEnemy.enemy = 0
  58. }
  59. //顶盾的角色不寻敌
  60. if (comSkillAbel?.isInShield) {
  61. return
  62. }
  63. //自己打的人死了,换目标
  64. if (comAttackable.isMelee) {
  65. for (let i = comAttackable.beAttacks.length - 1; i >= 0; i--) {
  66. let attack = comAttackable.beAttacks[i]
  67. let comBeAttackTransform = world.getComponent(attack, ComTransform)
  68. let dir = Infinity
  69. if (comBeAttackTransform) {
  70. dir = cc.Vec2.distance(
  71. cc.v2(comTransform.x, comTransform.y),
  72. cc.v2(comBeAttackTransform.x, comBeAttackTransform.y),
  73. )
  74. }
  75. //去掉死亡包围角色 和 攻击范围外的包围
  76. if (world.isDie(attack) || dir > Data.game.meleeRange + 10) {
  77. if (dir > Data.game.meleeRange + 10 && !world.isDie(attack)) {
  78. cc.warn('SysFindEnemy 攻击范围外的包围角色-------->', attack)
  79. comAttackable.curAttack = 0
  80. }
  81. comAttackable.beAttacks.splice(i, 1)
  82. }
  83. }
  84. if (comAttackable.curAttack && world.isDie(comAttackable.curAttack)) {
  85. let nextAttack = 0
  86. // 自己被包围优先攻击自己的正面,让刺客发挥效果
  87. comAttackable.beAttacks.sort((a, b) => {
  88. let aComTransform = world.getComponent(a, ComTransform)
  89. let bComTransform = world.getComponent(b, ComTransform)
  90. if (!aComTransform || !bComTransform) return 0
  91. return (
  92. Math.abs(bComTransform.dir.x - comTransform.dir.x) -
  93. Math.abs(aComTransform.dir.x - comTransform.dir.x)
  94. )
  95. })
  96. if (comAttackable.beAttacks.length > 0) nextAttack = comAttackable.beAttacks[0]
  97. comAttackable.curAttack = nextAttack
  98. }
  99. if (world.isDie(comFindEnemy.willAttackMelee)) {
  100. comFindEnemy.willAttackMelee = 0
  101. }
  102. if (world.isDie(comFindEnemy.willBeAttackMelee)) {
  103. comFindEnemy.willBeAttackMelee = 0
  104. }
  105. //去掉Y轴探测的人
  106. if (comFindEnemy.cObjectMeleeX.containsBody.size > 0) {
  107. comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
  108. let otherComAttackable: ComAttackable = world.getComponent(otherEntity, ComAttackable)
  109. if (
  110. comFindEnemy.cObject.containsBody.get(otherEntity) ||
  111. !otherComAttackable ||
  112. !otherComAttackable.isMelee
  113. ) {
  114. comFindEnemy.cObjectMeleeX.containsBody.delete(otherEntity)
  115. }
  116. })
  117. }
  118. }
  119. let findCloseEnemy = () => {
  120. //寻找最近的存活目标并且加载到场景的敌方单位
  121. let minDistance = Infinity
  122. let minDistanceY = Infinity
  123. let minDistanceMeleeY = Infinity
  124. let canAttackFilter = comRole.group == Data.game.gFriend ? canAttackEnemyFilter : canAttackFriendFilter
  125. let minDistanceFunc = (otherEntity: number) => {
  126. let otherComTransform: ComTransform = world.getComponent(otherEntity, ComTransform)
  127. let otherComCocosNode: ComCocosNode = world.getComponent(otherEntity, ComCocosNode)
  128. let otherComRole: ComRole = world.getComponent(otherEntity, ComRole)
  129. if (!otherComCocosNode?.loaded) return
  130. //正在背刺的刺客不能被寻敌
  131. let comEnemySkillAble = world.getComponent(otherEntity, ComSkillAbel)
  132. if (
  133. comEnemySkillAble &&
  134. comEnemySkillAble.skillConfig &&
  135. comEnemySkillAble.skillConfig.type == SKILL_TYPE.moveBack &&
  136. comSkillAbel.dirty
  137. ) {
  138. return
  139. }
  140. let dx = comTransform.x - otherComTransform.x
  141. let dy = comTransform.y - otherComTransform.y
  142. let distance = dx * dx + dy * dy
  143. if (world.isBase(otherComRole)) {
  144. // 强制修改基地的距离,让优先级低于近战攻击范围内的敌人
  145. //distance = Data.game.meleeRange * Data.game.meleeRange + 10
  146. distance = Infinity
  147. }
  148. let distanceY = Math.abs(dy)
  149. if (distance <= minDistance) {
  150. minDistance = distance
  151. comFindEnemy.enemy = otherEntity
  152. }
  153. //行为树的修改导致这个打近战去掉了
  154. // if (comAttackable.isMelee) {
  155. // let otherComAttackable = world.getComponent(otherEntity, ComAttackable)
  156. // if (distanceY < minDistanceY && minDistanceMeleeY == Infinity) {
  157. // minDistanceY = distanceY
  158. // comFindEnemy.enemy = otherEntity
  159. // }
  160. // // 近战优先攻击近战
  161. // if (otherComAttackable && otherComAttackable.isMelee && distanceY < minDistanceMeleeY) {
  162. // minDistanceMeleeY = distanceY
  163. // comFindEnemy.enemy = otherEntity
  164. // }
  165. // }
  166. return false
  167. }
  168. if (comFindEnemy.cObjectMeleeX && comFindEnemy.cObjectMeleeX.containsBody.size > 0) {
  169. comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
  170. minDistanceFunc(otherEntity)
  171. })
  172. } else {
  173. canAttackFilter.walk(minDistanceFunc)
  174. }
  175. }
  176. //远程永远攻击最近的目标
  177. //近战角色在攻击范围内没有敌人并且没有被近战锁定(一直更新最近的目标),或者自己的敌人死亡
  178. if (
  179. !comAttackable.isMelee ||
  180. (comAttackable.isMelee &&
  181. !comAttackable.curAttack &&
  182. !comFindEnemy.willAttackMelee &&
  183. !comFindEnemy.willBeAttackMelee)
  184. ) {
  185. findCloseEnemy()
  186. }
  187. // //先以X轴探测到的敌人为首选目标
  188. // if (
  189. // comAttackable.isMelee &&
  190. // !comAttackable.curAttack &&
  191. // !comFindEnemy.willAttackMelee &&
  192. // !comFindEnemy.willBeAttackMelee &&
  193. // comFindEnemy.cObjectMeleeX.containsBody.size > 0
  194. // ) {
  195. // let minDistanceX = Infinity
  196. // comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
  197. // let otherComTransform: ComTransform = world.getComponent(otherEntity, ComTransform)
  198. // let otherComCocosNode: ComCocosNode = world.getComponent(otherEntity, ComCocosNode)
  199. // if (!otherComCocosNode?.loaded) return
  200. // let dx = comTransform.x - otherComTransform.x
  201. // let distanceX = dx * dx
  202. // if (distanceX <= minDistanceX) {
  203. // comFindEnemy.enemy = otherEntity
  204. // }
  205. // })
  206. // }
  207. //不在攻击中,最近的敌人刚好在攻击范围可以准备攻击了
  208. if (
  209. comAttackable.isMelee &&
  210. !comAttackable.curAttack &&
  211. !comFindEnemy.willAttackMelee &&
  212. !comFindEnemy.willBeAttackMelee &&
  213. comFindEnemy.attackCObject.containsBody.has(comFindEnemy.enemy)
  214. ) {
  215. //如果敌军没有其他人即将攻击他,让敌军静止等待
  216. let enemyComRole = world.getComponent(comFindEnemy.enemy, ComRole)
  217. let enemyComFindEnemy = world.getComponent(comFindEnemy.enemy, ComFindEnemy)
  218. let enemyComAttackable = world.getComponent(comFindEnemy.enemy, ComAttackable)
  219. comFindEnemy.willAttackMelee = comFindEnemy.enemy
  220. if (
  221. !enemyComAttackable.curAttack &&
  222. !enemyComFindEnemy.willBeAttackMelee &&
  223. !enemyComFindEnemy.willAttackMelee
  224. ) {
  225. enemyComFindEnemy.willBeAttackMelee = entity
  226. //敌人准备去攻击X轴的敌人,被Y轴更近的敌人拦截,这里要把自己的寻敌置空
  227. enemyComFindEnemy.enemy = 0
  228. }
  229. comFindEnemy.enemy = 0
  230. }
  231. //绘制攻击范围碰撞体
  232. //world.drawDebug(entity, comFindEnemy.cObjectMeleeX)
  233. //world.drawDebug(entity, comFindEnemy.cObject)
  234. return false
  235. })
  236. }
  237. }