123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- /** @format */
- import {ECSSystem} from '../lib/ECSSystem'
- import {GenFilterKey} from '../lib/ECSComponent'
- import {FightWorld} from '../worlds/FightWorld'
- import {ComDie} from '../components/ComDie'
- import {ComFindEnemy} from '../components/ComFindEnemy'
- import {ComRole} from '../components/ComRole'
- import {ComTransform} from '../components/ComTransform'
- import {cCollider} from '../../collision/Collider'
- import {ShapeType} from '../../collision/Shape'
- import {EventType} from '../core/NodeEvent'
- import {ComCocosNode} from '../components/ComCocosNode'
- import {ComAttackable} from '../components/ComAttackable'
- import {Data} from '../../GameControl'
- import {ComFriend} from '../components/ComFriend'
- import {ComEnemy} from '../components/ComEnemy'
- import {cObject} from '../../collision/Object'
- import {ROLE_TYPE, SKILL_TYPE} from '../../enums/Enum'
- import {ComSkillAbel} from '../components/ComSkillAbel'
- import {ComBehaviorTree} from '../components/ComBehaviorTree'
- export const FILTER_FIND_ENEMY = GenFilterKey(
- [ComFindEnemy, ComRole, ComAttackable, ComTransform, ComCocosNode, ComBehaviorTree],
- [ComDie],
- )
- export const FILTER_CAN_ATTACK_FRIEND = GenFilterKey(
- [ComRole, ComTransform, ComCocosNode, ComFriend, ComBehaviorTree],
- [ComDie],
- )
- export const FILTER_CAN_ATTACK_ENEMY = GenFilterKey(
- [ComRole, ComTransform, ComCocosNode, ComEnemy, ComBehaviorTree],
- [ComDie],
- )
- export class SysFindEnemy extends ECSSystem {
- /** 连接 */
- public onAdd(world: FightWorld): void {}
- /** 断开连接 */
- public onRemove(world: FightWorld): void {}
- /** 添加实体 */
- public onEntityEnter(world: FightWorld, entity: number): void {}
- /** */
- public onEntityLeave(world: FightWorld, entity: number): void {}
- /** 更新 */
- public onUpdate(world: FightWorld, dt: number): void {
- cCollider.inst.update(dt)
- let filter = world.getFilter(FILTER_FIND_ENEMY)
- let canAttackFriendFilter = world.getFilter(FILTER_CAN_ATTACK_FRIEND)
- let canAttackEnemyFilter = world.getFilter(FILTER_CAN_ATTACK_ENEMY)
- filter.walk((entity: number) => {
- let comRole: ComRole = world.getComponent(entity, ComRole)
- let comFindEnemy: ComFindEnemy = world.getComponent(entity, ComFindEnemy)
- let comAttackable: ComAttackable = world.getComponent(entity, ComAttackable)
- let comTransform: ComTransform = world.getComponent(entity, ComTransform)
- let comSkillAbel = world.getComponent(entity, ComSkillAbel)
- //目标角色死亡
- if (world.isDie(comFindEnemy.enemy)) {
- //console.log('SysFindEnemy 目标角色已死亡-------->', comFindEnemy.enemy)
- comFindEnemy.enemy = 0
- }
- //顶盾的角色不寻敌
- if (comSkillAbel?.isInShield) {
- return
- }
- //自己打的人死了,换目标
- if (comAttackable.isMelee) {
- for (let i = comAttackable.beAttacks.length - 1; i >= 0; i--) {
- let attack = comAttackable.beAttacks[i]
- let comBeAttackTransform = world.getComponent(attack, ComTransform)
- let dir = Infinity
- if (comBeAttackTransform) {
- dir = cc.Vec2.distance(
- cc.v2(comTransform.x, comTransform.y),
- cc.v2(comBeAttackTransform.x, comBeAttackTransform.y),
- )
- }
- //去掉死亡包围角色 和 攻击范围外的包围
- if (world.isDie(attack) || dir > Data.game.meleeRange + 10) {
- if (dir > Data.game.meleeRange + 10 && !world.isDie(attack)) {
- cc.warn('SysFindEnemy 攻击范围外的包围角色-------->', attack)
- comAttackable.curAttack = 0
- }
- comAttackable.beAttacks.splice(i, 1)
- }
- }
- if (comAttackable.curAttack && world.isDie(comAttackable.curAttack)) {
- let nextAttack = 0
- // 自己被包围优先攻击自己的正面,让刺客发挥效果
- comAttackable.beAttacks.sort((a, b) => {
- let aComTransform = world.getComponent(a, ComTransform)
- let bComTransform = world.getComponent(b, ComTransform)
- if (!aComTransform || !bComTransform) return 0
- return (
- Math.abs(bComTransform.dir.x - comTransform.dir.x) -
- Math.abs(aComTransform.dir.x - comTransform.dir.x)
- )
- })
- if (comAttackable.beAttacks.length > 0) nextAttack = comAttackable.beAttacks[0]
- comAttackable.curAttack = nextAttack
- }
- if (world.isDie(comFindEnemy.willAttackMelee)) {
- comFindEnemy.willAttackMelee = 0
- }
- if (world.isDie(comFindEnemy.willBeAttackMelee)) {
- comFindEnemy.willBeAttackMelee = 0
- }
- //去掉Y轴探测的人
- if (comFindEnemy.cObjectMeleeX.containsBody.size > 0) {
- comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
- let otherComAttackable: ComAttackable = world.getComponent(otherEntity, ComAttackable)
- if (
- comFindEnemy.cObject.containsBody.get(otherEntity) ||
- !otherComAttackable ||
- !otherComAttackable.isMelee
- ) {
- comFindEnemy.cObjectMeleeX.containsBody.delete(otherEntity)
- }
- })
- }
- }
- let findCloseEnemy = () => {
- //寻找最近的存活目标并且加载到场景的敌方单位
- let minDistance = Infinity
- let minDistanceY = Infinity
- let minDistanceMeleeY = Infinity
- let canAttackFilter = comRole.group == Data.game.gFriend ? canAttackEnemyFilter : canAttackFriendFilter
- let minDistanceFunc = (otherEntity: number) => {
- let otherComTransform: ComTransform = world.getComponent(otherEntity, ComTransform)
- let otherComCocosNode: ComCocosNode = world.getComponent(otherEntity, ComCocosNode)
- let otherComRole: ComRole = world.getComponent(otherEntity, ComRole)
- if (!otherComCocosNode?.loaded) return
- //正在背刺的刺客不能被寻敌
- let comEnemySkillAble = world.getComponent(otherEntity, ComSkillAbel)
- if (
- comEnemySkillAble &&
- comEnemySkillAble.skillConfig &&
- comEnemySkillAble.skillConfig.type == SKILL_TYPE.moveBack &&
- comSkillAbel.dirty
- ) {
- return
- }
- let dx = comTransform.x - otherComTransform.x
- let dy = comTransform.y - otherComTransform.y
- let distance = dx * dx + dy * dy
- if (world.isBase(otherComRole)) {
- // 强制修改基地的距离,让优先级低于近战攻击范围内的敌人
- //distance = Data.game.meleeRange * Data.game.meleeRange + 10
- distance = Infinity
- }
- let distanceY = Math.abs(dy)
- if (distance <= minDistance) {
- minDistance = distance
- comFindEnemy.enemy = otherEntity
- }
- //行为树的修改导致这个打近战去掉了
- // if (comAttackable.isMelee) {
- // let otherComAttackable = world.getComponent(otherEntity, ComAttackable)
- // if (distanceY < minDistanceY && minDistanceMeleeY == Infinity) {
- // minDistanceY = distanceY
- // comFindEnemy.enemy = otherEntity
- // }
- // // 近战优先攻击近战
- // if (otherComAttackable && otherComAttackable.isMelee && distanceY < minDistanceMeleeY) {
- // minDistanceMeleeY = distanceY
- // comFindEnemy.enemy = otherEntity
- // }
- // }
- return false
- }
- if (comFindEnemy.cObjectMeleeX && comFindEnemy.cObjectMeleeX.containsBody.size > 0) {
- comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
- minDistanceFunc(otherEntity)
- })
- } else {
- canAttackFilter.walk(minDistanceFunc)
- }
- }
- //远程永远攻击最近的目标
- //近战角色在攻击范围内没有敌人并且没有被近战锁定(一直更新最近的目标),或者自己的敌人死亡
- if (
- !comAttackable.isMelee ||
- (comAttackable.isMelee &&
- !comAttackable.curAttack &&
- !comFindEnemy.willAttackMelee &&
- !comFindEnemy.willBeAttackMelee)
- ) {
- findCloseEnemy()
- }
- // //先以X轴探测到的敌人为首选目标
- // if (
- // comAttackable.isMelee &&
- // !comAttackable.curAttack &&
- // !comFindEnemy.willAttackMelee &&
- // !comFindEnemy.willBeAttackMelee &&
- // comFindEnemy.cObjectMeleeX.containsBody.size > 0
- // ) {
- // let minDistanceX = Infinity
- // comFindEnemy.cObjectMeleeX.containsBody.forEach((body, otherEntity) => {
- // let otherComTransform: ComTransform = world.getComponent(otherEntity, ComTransform)
- // let otherComCocosNode: ComCocosNode = world.getComponent(otherEntity, ComCocosNode)
- // if (!otherComCocosNode?.loaded) return
- // let dx = comTransform.x - otherComTransform.x
- // let distanceX = dx * dx
- // if (distanceX <= minDistanceX) {
- // comFindEnemy.enemy = otherEntity
- // }
- // })
- // }
- //不在攻击中,最近的敌人刚好在攻击范围可以准备攻击了
- if (
- comAttackable.isMelee &&
- !comAttackable.curAttack &&
- !comFindEnemy.willAttackMelee &&
- !comFindEnemy.willBeAttackMelee &&
- comFindEnemy.attackCObject.containsBody.has(comFindEnemy.enemy)
- ) {
- //如果敌军没有其他人即将攻击他,让敌军静止等待
- let enemyComRole = world.getComponent(comFindEnemy.enemy, ComRole)
- let enemyComFindEnemy = world.getComponent(comFindEnemy.enemy, ComFindEnemy)
- let enemyComAttackable = world.getComponent(comFindEnemy.enemy, ComAttackable)
- comFindEnemy.willAttackMelee = comFindEnemy.enemy
- if (
- !enemyComAttackable.curAttack &&
- !enemyComFindEnemy.willBeAttackMelee &&
- !enemyComFindEnemy.willAttackMelee
- ) {
- enemyComFindEnemy.willBeAttackMelee = entity
- //敌人准备去攻击X轴的敌人,被Y轴更近的敌人拦截,这里要把自己的寻敌置空
- enemyComFindEnemy.enemy = 0
- }
- comFindEnemy.enemy = 0
- }
- //绘制攻击范围碰撞体
- //world.drawDebug(entity, comFindEnemy.cObjectMeleeX)
- //world.drawDebug(entity, comFindEnemy.cObject)
- return false
- })
- }
- }
|