/** @format */ import {ECSSystem} from '../lib/ECSSystem' import {GenFilterKey} from '../lib/ECSComponent' import {FightWorld} from '../worlds/FightWorld' import {ComMovable} from '../components/ComMovable' import {ComTransform} from '../components/ComTransform' import {ComBullet} from '../components/ComBullet' import {ComCocosNode} from '../components/ComCocosNode' import {ComRole} from '../components/ComRole' import {ComAttackable} from '../components/ComAttackable' import {ComDie} from '../components/ComDie' import {ComEnemy} from '../components/ComEnemy' import {ComFriend} from '../components/ComFriend' import {Data, Mgr} from '../../GameControl' import {EntityIndex} from '../lib/Const' import {SkillConfig} from '../../config/SkillConfig' import {EventBulletEjection, EventRoleTip} from '../core/NodeEvent' import { BUFF_EFFECT_TYPE, BUFF_TYPE, BULLET_EFFECT_TYPE, BULLET_TYPE, ENTRY, FRAME_ANI_NAME, GAME_ROLE_TIP, ROLE_TYPE, SKILL_EFFECT_TYPE, } from '../../enums/Enum' import {IAttackEffect} from '../core/GameInterface' import {IBulletConfig} from '../../config/BulletConfig' import {ComFrameAni} from '../components/ComFrameAni' const FILTER_BULLET = GenFilterKey([ComBullet, ComMovable, ComCocosNode, ComTransform]) const FILTER_FRIEND_ROLE = GenFilterKey([ComRole, ComCocosNode, ComTransform, ComFriend], [ComDie]) const FILTER_ENEMY_ROLE = GenFilterKey([ComRole, ComCocosNode, ComTransform, ComEnemy], [ComDie]) export class SysBullet 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 { let filter = world.getFilter(FILTER_BULLET) let friendsFilter = world.getFilter(FILTER_FRIEND_ROLE) let enemiesFilter = world.getFilter(FILTER_ENEMY_ROLE) let changeHpByAttack = (comBullet: ComBullet, roleEntity) => { let bulletCfg = comBullet.bulletCfg Mgr.audio.playSFX(bulletCfg.sound) if (comBullet.bulletCfg.type == BULLET_TYPE.normal) { //目标敌人掉血 let comRoleEnemy = world.getComponent(roleEntity, ComRole) let comEnemyCocosNode = world.getComponent(roleEntity, ComCocosNode) //基地免疫 if (comRoleEnemy.roleCfg.type == ROLE_TYPE.base) { let effectParmIndex = bulletCfg.effectType.findIndex( value => value == BULLET_EFFECT_TYPE.castleVoid, ) if (effectParmIndex >= 0) return } //是否闪避 let isDodge = comRoleEnemy && Math.getProb( comBullet.fightData.hit - comRoleEnemy.dodge > 0 ? 0 : (comRoleEnemy.dodge - comBullet.fightData.hit) / Data.game.rateNum, ) if (!isDodge) { let attackEffect: IAttackEffect = {isBack: false, isCrit: comBullet.isCrit} let hurt = world.getHurtByAttackRole(comBullet.fightData, roleEntity, attackEffect) let decrease = 0 let effectParmIndex = bulletCfg.effectType.findIndex(value => value == BULLET_EFFECT_TYPE.ejection) if (effectParmIndex >= 0) decrease = bulletCfg.effectParm[effectParmIndex][0] hurt *= Math.pow(1 - decrease / Data.game.rateNum, comBullet.ejectionEnemies.length) if (hurt < 0) hurt = 0 //远程伤害免疫为1点 if (hurt > 1 && comRoleEnemy.buffs.some(buff => buff.buffCfg.buffType == BUFF_TYPE.rangedImmune)) { hurt = 1 } world.changeHpByHurt(roleEntity, hurt, comBullet.isCrit, comBullet.bulletCfg.hitID) //暂时屏蔽子弹特效 //world.changeHpByHurt(roleEntity, hurt, comBullet.isCrit, 0) if (!world.isDie(comBullet.fightData.roleEntity)) { let createComRole = world.getComponent(comBullet.fightData.roleEntity, ComRole) for (let buff of createComRole.buffs) { if (buff.buffCfg.buffType == BUFF_TYPE.attackAddBabyHP) { //攻击让宝宝加血 let addHPNum = (hurt * buff.buffCfg.attrRate[0]) / Data.game.rateNum createComRole.babys.forEach(baby => { world.addHP(addHPNum, baby) }) } } } //吸血 if (comBullet.fightData.entryMap.get(ENTRY.hurt2HP)?.num > 0) { let addHPNum = (comBullet.fightData.entryMap.get(ENTRY.hurt2HP).num * hurt) / Data.game.rateNum world.addHP(addHPNum, comBullet.fightData.roleEntity) } } else { comEnemyCocosNode.events.push(new EventRoleTip(GAME_ROLE_TIP.missTip, 0, 'miss')) } } else if (comBullet.bulletCfg.type == BULLET_TYPE.skill) { world.createCardBulletSkill(comBullet, roleEntity) } } filter.walk((bulletEntity: number) => { let comCocosNode = world.getComponent(bulletEntity, ComCocosNode) if (!comCocosNode.loaded) return let comBullet = world.getComponent(bulletEntity, ComBullet) let comMovable = world.getComponent(bulletEntity, ComMovable) let bulletTrans = world.getComponent(bulletEntity, ComTransform) let bulletCfg = comBullet.bulletCfg //产生碰撞 if (comBullet.cObject.containsBody.size > 0) { let containsArr = comBullet.cObject.containsBody.keysArr() for (let i = 0; i < containsArr.length; i++) { let roleEntity = containsArr[i] if ( bulletCfg.isEjection && roleEntity == comBullet.ejectionEnemy && comMovable.pointIdx >= comMovable.points.length ) { changeHpByAttack(comBullet, roleEntity) //推入弹中数组 comBullet.ejectionEnemies.push(roleEntity) //连线的终点改为角色 if (bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.line)) { let lastEjectionAni = comBullet.ejectionAnis[comBullet.ejectionAnis.length - 1] let lastComFrameAni = world.getComponent(lastEjectionAni, ComFrameAni) if (lastComFrameAni) { lastComFrameAni.lineEndEntity = roleEntity } } //子弹移除 if (comBullet.ejectionEnemies.length >= bulletCfg.maxHitNum) { world.removeBulletEntity(bulletEntity) } else { //子弹弹射 let targetFilter = comBullet.group == Data.game.gFriendBullet ? enemiesFilter : friendsFilter let minDistance = Infinity let nearestTrans: ComTransform = null let nearestEntity: EntityIndex = null let ejectionParam: number[] = null for (let i = 0; i < bulletCfg.effectType.length; i++) { let type = bulletCfg.effectType[i] if (type == BULLET_EFFECT_TYPE.ejection) { ejectionParam = bulletCfg.effectParm[i] } } let maxAttackRange = ejectionParam ? ejectionParam[1] : Data.game.fightSizeMaxX - Data.game.fightSizeMinX let decrease = ejectionParam ? ejectionParam[0] : 0 let moreTimesHurt = ejectionParam ? ejectionParam[2] : true targetFilter.walk((enemyEntity: number) => { let otherTrans = world.getComponent(enemyEntity, ComTransform) let dx = otherTrans.x - bulletTrans.x let dy = otherTrans.y - bulletTrans.y let distance = Math.sqrt(dx * dx + dy * dy) //不等于弹射目标不能弹基地 if ( distance < minDistance && enemyEntity != comBullet.ejectionEnemy && !world.isBase(enemyEntity) && (moreTimesHurt || (!moreTimesHurt && !comBullet.ejectionEnemies.includes(enemyEntity))) ) { minDistance = distance nearestTrans = otherTrans nearestEntity = enemyEntity } return false }) if (nearestTrans && minDistance < maxAttackRange) { comBullet.ejectionEnemy = nearestEntity world.initBulletDir(bulletTrans, nearestTrans, comMovable, comBullet, comCocosNode) comMovable.speed = bulletCfg.moveSpeed //comCocosNode.events.push(new EventBulletEjection(bulletTrans.x, bulletTrans.y)) //创建连线特效 if (bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.line)) { let aniEntity = world.createAni(FRAME_ANI_NAME.lightLine, 0) let comFrameAni = world.getComponent(aniEntity, ComFrameAni) let startComTrans = world.getComponent(roleEntity, ComTransform) comFrameAni.lineStartPos = cc.v2(startComTrans.x, startComTrans.y) if (!world.isDie(roleEntity)) comFrameAni.lineStartEntity = roleEntity comFrameAni.lineEndEntity = bulletEntity comBullet.ejectionAnis.push(aniEntity) } return true } else { world.removeBulletEntity(bulletEntity) } } } else if (!bulletCfg.isEjection && !comBullet.hitEnemies.includes(roleEntity)) { if (comBullet.bulletCfg.type == BULLET_TYPE.normal) { comBullet.hitEnemies.push(roleEntity) if (comBullet.hitEnemies.length <= bulletCfg.maxHitNum) { changeHpByAttack(comBullet, roleEntity) } //子弹移除 if (comBullet.hitEnemies.length >= bulletCfg.maxHitNum) { world.removeBulletEntity(bulletEntity) } } } } } return false }) } }