/** @format */ import {ECSWorld} from '../lib/ECSWorld' import {IRoleConfig, RoleConfig} from '../../config/RoleConfig' import {Data, Mgr} from '../../GameControl' import {cCollider} from '../../collision/Collider' import {ComRole} from '../components/ComRole' import {ComAttackable} from '../components/ComAttackable' import {ComType, EntityIndex} from '../lib/Const' import {ComCocosNode} from '../components/ComCocosNode' import { EventGraphicsDraw, EventHurtOrAdd, EventRoleTip, EventRun, EventSlowDown, EventStand, EventType, } from '../core/NodeEvent' import {ComTransform} from '../components/ComTransform' import {ComMovable} from '../components/ComMovable' import {ComNodeConfig} from '../components/ComNodeConfig' import {IStageRolePosConfig, StageRolePosConfig} from '../../config/StageRolePosConfig' import {ComEnemy} from '../components/ComEnemy' import {ComFriend} from '../components/ComFriend' import {ISkillConfig, SkillConfig} from '../../config/SkillConfig' import {ComFindEnemy} from '../components/ComFindEnemy' import {BulletConfig} from '../../config/BulletConfig' import {ComBullet} from '../components/ComBullet' import {ComBehaviorTree} from '../components/ComBehaviorTree' import {BT} from '../../behaviorTree/BehaviorTree' import {Log} from '../../utils/LogUtils' import { ANI_TYPE, ATTR_NAME, BUFF_ANI_TYPE, BUFF_EFFECT_TYPE, BUFF_TYPE, BULLET_EFFECT_TYPE, BULLET_FLY_TYPE, BULLET_TYPE, ENTRY, GAME_LAYER, GAME_PREFAB_TYPE, GAME_ROLE_TIP, GAME_SCALE_TYPE, GAME_TYPE, GAME_WIN_TYPE, HIT_ANI_TYPE, LANGUAGE_TYPE, MONSTER_TYPE, NEGATIVE_TYPE, ROLE_TYPE, SKILL_DIR_TYPE, SKILL_EFFECT_TYPE, SKILL_TYPE, START_POS, } from '../../enums/Enum' import {BuffConfig} from '../../config/BuffConfig' import {ccUtils} from '../../utils/ccUtils' import {ComRoleSpine} from '../components/ComRoleSpine' import {EntryObj, IAttackEffect, IBuff, IFightData} from '../core/GameInterface' import {ComSkill} from '../components/ComSkill' import {ComDizzy} from '../components/ComDizzy' import {ComSkillAbel} from '../components/ComSkillAbel' import {FrameAniConfig} from '../../config/FrameAniConfig' import {ComFrameAni} from '../components/ComFrameAni' import {EntryConfig} from '../../config/EntryConfig' import {TalentConfig} from '../../config/TalentConfig' import {IBaseAttr, ICard, IRole} from '../../interface/GlobalInterface' import {ComEnter} from '../components/ComEnter' import {ArmorConfig} from '../../config/ArmorConfig' import {ConstValue} from '../../data/ConstValue' import {SysHasSkill} from '../systems/SysHasSkill' import {SysFindEnemy} from '../systems/SysFindEnemy' import {SysBullet} from '../systems/SysBullet' import {SysBehaviorTree} from '../systems/SysBehaviorTree' import {SysBuff} from '../systems/SysBuff' import {SysSkillAbel} from '../systems/SysSkillAbel' import {SysSkill} from '../systems/SysSkill' import {SysMovable} from '../systems/SysMovable' import {SysAttack} from '../systems/SysAttack' import {SysDizzy} from '../systems/SysDizzy' import {SysDie} from '../systems/SysDie' import {SysLifeTime} from '../systems/SysLifeTime' import {SysFrameAni} from '../systems/SysFrameAni' import {SysRoleState} from '../systems/SysRoleState' import {SysCocosView} from '../systems/SysCocosView' import {SysEnter} from '../systems/SysEnter' import GameUI from '../../zuma/FightCore' import {CastleSkillConfig} from '../../config/CastleSkillConfig' import {idNum} from '../../proto/typedef' import {SysCastleSkill} from '../systems/SysCastleSkill' import {ShapeType} from '../../collision/Shape' import {ComHasSkill} from '../components/ComHasSkill' import FrameAnimation from '../../uiutils/FrameAnimation' import {EventProcess} from '../core/EventProcess' import FightCore from '../../zuma/FightCore' import {ZumabuffConfig} from '../../config/ZumabuffConfig' import {RoleSpineProcess} from '../core/RoleSpineProcess' export class FightWorld extends ECSWorld { //创建单例 static instance: FightWorld static getInstance() { if (!FightWorld.instance) { FightWorld.instance = new FightWorld() FightWorld.instance.createWorldCocosView() } return FightWorld.instance } fightCore: FightCore rolePosMap: Map init() { this.rolePosMap = new Map() this.rolePosMap.set(Data.game.gFriend, []) this.rolePosMap.set(Data.game.gEnemy, []) for (let key in StageRolePosConfig) { if (+key <= 100) { this.rolePosMap.get(Data.game.gEnemy).push(StageRolePosConfig[key]) } else if (+key > 100 && +key <= 200) { this.rolePosMap.get(Data.game.gFriend).push(StageRolePosConfig[key]) } } this.initEntry() this.fightCore.registerTouchHandler(this.getSystem(SysCocosView)) } createWorldCocosView() { //添加系统顺序不能错,保证行为树的判断能正常执行 this.createEntity() // 创建0号实体 this.addSystem(new SysHasSkill()) // 是否有技能施放 this.addSystem(new SysFindEnemy()) // 寻敌锁定 this.addSystem(new SysBullet()) // 子弹系统(在移动系统之前判断) this.addSystem(new SysBehaviorTree()) // 行为树 this.addSystem(new SysBuff()) // buff光环系统 this.addSystem(new SysSkillAbel()) // 技能吟唱 this.addSystem(new SysSkill()) // 技能持续生效 this.addSystem(new SysMovable()) // 移动 this.addSystem(new SysAttack()) // 攻击动作 this.addSystem(new SysDizzy()) // 晕眩 this.addSystem(new SysDie()) // 死亡 this.addSystem(new SysLifeTime()) // 生命时间倒计时 this.addSystem(new SysFrameAni()) // 特效 this.addSystem(new SysRoleState()) // role state this.addSystem(new SysCocosView()) // cocos view this.addSystem(new SysEnter()) // 角色入场 } //-------------------------------角色----------------------------------------- public createRoleEntity( IDOrCfg: number | IRoleConfig, isEnemy?: boolean, posCfgID?: number, iRole?: IRole, dropOutGoods?: idNum, isExtraEnemy?: boolean, ): EntityIndex { let roleCfg: IRoleConfig if (typeof IDOrCfg == 'number') { roleCfg = RoleConfig[IDOrCfg] } else { roleCfg = IDOrCfg } if (!roleCfg) { console.error('没有这个角色配置----------->', IDOrCfg) } let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[GAME_LAYER.role] comMap.prefabName = GAME_PREFAB_TYPE.role let entitySpine = this.createEntity() // 添加spineNode let comSpineMap = this.addComponent(entitySpine, ComNodeConfig) comSpineMap.id = 1 comSpineMap.layer = GAME_LAYER[GAME_LAYER.roleSpine] comSpineMap.prefabName = GAME_PREFAB_TYPE.roleSpine //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) comTrans.x = isEnemy ? Data.game.fightSizeMaxX : Data.game.fightSizeMinX if (posCfgID > 0 && roleCfg.type != ROLE_TYPE.base) { comTrans.x = StageRolePosConfig[posCfgID].posX } let posArr = this.rolePosMap.get(isEnemy ? Data.game.gEnemy : Data.game.gFriend) //id为1的是基地 comTrans.y = posCfgID > 0 ? StageRolePosConfig[posCfgID].posY : roleCfg.type == ROLE_TYPE.base ? StageRolePosConfig[1].posY : posArr[Math.randomRangeInt(0, posArr.length - 1)].posY if (isEnemy) { this.addComponent(entity, ComEnemy) } else { this.addComponent(entity, ComFriend) } // 添加spineNode transform let comSpineTrans = this.addComponent(entitySpine, ComTransform) comSpineTrans.x = comTrans.x comSpineTrans.y = comTrans.y let comRoleSpine = this.addComponent(entitySpine, ComRoleSpine) comRoleSpine.roleCfg = roleCfg comRoleSpine.group = isEnemy ? Data.game.gEnemy : Data.game.gFriend let comRole = this.addComponent(entity, ComRole) comRole.roleCfg = roleCfg comRole.drop = dropOutGoods let spineData: sp.spine.SkeletonData = Data.main.roleSpineMap.get(roleCfg.url)?.getRuntimeData() comRole.width = spineData ? (spineData.width * roleCfg.gameScale[GAME_SCALE_TYPE.spine]) / 100 : 60 comRole.height = spineData ? (spineData.height * roleCfg.gameScale[GAME_SCALE_TYPE.spine]) / 100 : 100 comRole.spineEntity = entitySpine comTrans.halfHeight = comRole.height / 2 let baseAttr: IBaseAttr = iRole ? iRole : roleCfg Mgr.global.changeBaseAttr(comRole, baseAttr) comRole.attackRange = roleCfg.attackRange comRole.attackCD = roleCfg.attackCD == Data.game.cdMax ? Infinity : roleCfg.attackCD comRole.killNum = 0 comRole.attackNum = 0 comRole.group = isEnemy ? Data.game.gEnemy : Data.game.gFriend comRole.skills.length = 0 comRole.skillCDs.length = 0 comRole.enterCDs.length = 0 comRole.skillCountDowns.length = 0 comRole.babys.length = 0 comRole.parent = 0 comRole.parentRoleID = 0 comRole.HPDirty = true comRole.transDirty = false comRole.transID = 0 comRole.buffs.length = 0 comRole.entryMap.clear() comRole.equips = null //所有技能 let allSkill = [] let allSkillCDs = [] let allEnterCDs = [] //人物技能 roleCfg.skills.forEach((skill, index) => { if (skill) { allSkill.push(skill) allSkillCDs.push(roleCfg.skillCDs[index]) allEnterCDs.push(roleCfg.enterCDs[index]) } }) //天赋词条 for (let id of Data.user.talents) { this.putEntry2Map(comRole, this.convertEntry2Obj(TalentConfig[id].entryID)) } //装备词条 if (iRole) { comRole.equips = iRole.equips for (let iEquip of iRole.equips) { if (iEquip) { if (iEquip.cfg.entry && iEquip.cfg.entry < ENTRY.textShow) { for (let i = 1; i <= iEquip.cfg.quality; i++) { let ID = Math.floor(iEquip.cfg.ID / 100) * 100 + i if (ArmorConfig[ID.toString()].entry) this.putEntry2Map(comRole, this.convertEntry2Obj(ArmorConfig[ID.toString()].entry)) } } //装备技能 iEquip.cfg.skills?.forEach((skill, index) => { if (skill) { allSkill.push(skill) allSkillCDs.push(iEquip.cfg.skillCDs[index]) allEnterCDs.push(iEquip.cfg.enterCDs[index]) } }) } } } //遗迹词条 if (Data.game.gameType == GAME_TYPE.relic) { //基础属性 if (Data.main.relicAdd[roleCfg.profession]) { let keys = Object.keys(ATTR_NAME) for (let attrKey of keys) { if (Data.main.relicAdd[roleCfg.profession][attrKey]) { comRole[attrKey] *= 1 + Data.main.relicAdd[roleCfg.profession][attrKey] / Data.game.rateNum } } } for (let entry of Data.game.relicEntryArr) { this.putEntry2Map(comRole, this.convertEntry2Obj(entry)) } } if (comRole.entryMap.get(ENTRY.startShieldHP)?.num) { comRole.shieldHP = comRole.entryMap.get(ENTRY.startShieldHP).num } allSkill.forEach((skill, index) => { if (skill && SkillConfig[skill]) { comRole.skills.push(SkillConfig[skill]) comRole.skillCDs.push(allSkillCDs[index]) comRole.enterCDs.push(allEnterCDs[index]) let cd = allSkillCDs[index] if (cd == Data.game.cdMax) cd = Infinity if (cd > 0 && cd != Infinity && comRole.entryMap.get(ENTRY.skillCD)?.num) { cd *= 1 - comRole.entryMap.get(ENTRY.skillCD).num / Data.game.rateNum if (cd < 0) cd = 0 } //入场CD let enterCD = allEnterCDs[index] comRole.skillCountDowns.push(enterCD > 0 && cd != Infinity ? enterCD : cd) } else { console.error('没有这个技能配置----------->', allSkill[index]) } }) let attackTime = Infinity let castTime = new Array(allSkill.length).fill(0) //spine没有技能动作 let enterTime = 0 let dieTime = 0 if (spineData) { for (let i = 1; i <= roleCfg.skills.length; i++) { if (spineData.findAnimation(`skill${i}`)) { castTime[i - 1] = spineData.findAnimation(`skill${i}`).duration } } if (spineData.findAnimation('skill') && castTime.length > 0) { castTime[0] = spineData.findAnimation('skill').duration } if (spineData.findAnimation('enter')) { enterTime = spineData.findAnimation('enter').duration } if (spineData.findAnimation('attack')) { attackTime = spineData.findAnimation('attack').duration } if (spineData.findAnimation('die')) { dieTime = spineData.findAnimation('die').duration } } comRole.attackTime = attackTime comRole.castTime = castTime comRole.enterTime = enterTime comRole.dieTime = dieTime //血量等词条装备处理完后处理 comRole.nowHP = comRole.HP comRole.lastHP = comRole.HP comRole.shieldHP = 0 comRole.lastShieldHP = 0 comRole.isExtraEnemy = isExtraEnemy //处理gameUI显示 if (this.fightCore) { let entities = this.fightCore.roleEntityMap.get(roleCfg.ID) if (!entities) { entities = [] this.fightCore.roleEntityMap.set(roleCfg.ID, entities) } entities.push(entity) if (roleCfg.type == MONSTER_TYPE.boss) { if (this.fightCore.stageInfo.type == GAME_WIN_TYPE.boss) { } this.fightCore.showBossHP(comRole) } } return entity } setRoleHP(entity, HP) { if (!HP) return let comRole = this.getComponent(entity, ComRole) if (!comRole) return comRole.HP = HP comRole.lastHP = HP comRole.nowHP = HP } public initRoleBehavior(comBehavior: ComBehaviorTree, roleConfig: IRoleConfig) { let findEnemyNode = new BT.FindEnemyNode() let meleeMonitorNode = new BT.MeleeMonitorNode() let meleeXMonitorNode = new BT.MeleeXMonitorNode() let attackMonitorNode = new BT.AttackMonitorNode() let attackNode = new BT.AttackNode() let meleeWalkToTargetNode = new BT.MeleeWalkToTargetNode(roleConfig.moveSpeed * 1.5) let stopNode = new BT.StopNode() let hasAttackEnemy = new BT.HasAttackEnemyNode() let hasBeAttackNode = new BT.HasBeAttackNode() let willAttackNode = new BT.WillAttackNode() let willBeAttackNode = new BT.WillBeAttackNode() let willAttackNotWillAttackNode = new BT.WillAttackNotWillAttackNode() let stopAttackNode = new BT.StopAttackNode() let beDizzyNode = new BT.BeDizzyNode() let notBeDizzyNode = new BT.InverterNode(new BT.BeDizzyNode()) let dizzyNode = new BT.DizzyNode() let skillNode = new BT.SkillNode() let hasSkillNode = new BT.HasSkillNode() let walkToCloseXTargetNode = new BT.WalkToCloseTargetNode(roleConfig.moveSpeed, true) let walkToCloseTargetNode = new BT.WalkToCloseTargetNode(roleConfig.moveSpeed, false) let notFindEnemyNode = new BT.InverterNode(findEnemyNode) let notMeleeMonitorNode = new BT.InverterNode(meleeMonitorNode) let notMeleeXMonitorNode = new BT.InverterNode(meleeXMonitorNode) let notAttackMonitorNode = new BT.InverterNode(attackMonitorNode) let notHasAttackEnemy = new BT.InverterNode(hasAttackEnemy) let notWillBeAttackNode = new BT.InverterNode(willBeAttackNode) let notWillAttackNode = new BT.InverterNode(willAttackNode) let notHasBeAttackNode = new BT.InverterNode(hasBeAttackNode) let notHasSkillNode = new BT.InverterNode(hasSkillNode) let notCastSkillNode = new BT.InverterNode(new BT.CastSkillNode()) let stopSkillNode = new BT.StopSkillNode() let shootRoot = new BT.RootSelectorNode( [ // 晕眩 new BT.SequenceNode([beDizzyNode, stopNode, stopSkillNode, stopAttackNode, dizzyNode]), // 放技能 new BT.SequenceNode([notBeDizzyNode, hasSkillNode, stopNode, stopAttackNode, skillNode]), // 远程攻击范围有敌人,攻击最近的敌人 new BT.SequenceNode([notBeDizzyNode, attackMonitorNode, stopNode, attackNode]), // 远程攻击范围没有敌人,场上有敌军, 往最近敌方X轴方向移动 new BT.SequenceNode([ notBeDizzyNode, notHasSkillNode, findEnemyNode, notAttackMonitorNode, walkToCloseTargetNode, ]), // 没有敌人停止移动 new BT.SequenceNode([notFindEnemyNode, stopNode]), ], false, ) let meleeRoot = new BT.RootSelectorNode([ // 晕眩 new BT.SequenceNode([beDizzyNode, stopNode, stopSkillNode, stopAttackNode, dizzyNode]), // 放技能 new BT.SequenceNode([notBeDizzyNode, hasSkillNode, stopNode, stopAttackNode, skillNode]), // X轴Y轴近战探测范围没有敌人,场上有敌军, 往最近敌方X轴方向移动 new BT.SequenceNode([ notBeDizzyNode, notHasSkillNode, findEnemyNode, notHasAttackEnemy, notWillBeAttackNode, notWillAttackNode, notMeleeXMonitorNode, notMeleeMonitorNode, walkToCloseXTargetNode, ]), // X轴近战探测范围有敌人,往最近敌方X轴方向移动,直到进入攻击范围 new BT.SequenceNode([ notBeDizzyNode, notHasSkillNode, findEnemyNode, notHasAttackEnemy, notWillBeAttackNode, notWillAttackNode, meleeXMonitorNode, walkToCloseXTargetNode, ]), // X轴近战攻击范围没有敌人,没有被近战即将攻击, 往最近Y轴的敌方方向移动 new BT.SequenceNode([ notBeDizzyNode, notHasSkillNode, findEnemyNode, notHasAttackEnemy, notWillBeAttackNode, notWillAttackNode, notMeleeXMonitorNode, meleeMonitorNode, walkToCloseTargetNode, ]), // 自己即将被攻击,停止 new BT.SequenceNode([notBeDizzyNode, notHasSkillNode, notHasAttackEnemy, willBeAttackNode, stopNode]), // 自己即将攻击敌人,跑到攻击点 new BT.SequenceNode([ notBeDizzyNode, notHasAttackEnemy, // notHasBeAttackNode, willAttackNode, willAttackNotWillAttackNode, meleeWalkToTargetNode, ]), // 到达了攻击地点,继续攻击 new BT.SequenceNode([notBeDizzyNode, hasAttackEnemy, stopNode, attackNode]), // 停止移动 new BT.SequenceNode([notFindEnemyNode, stopNode]), ]) comBehavior.root = roleConfig.attackRange > Data.game.meleeRange ? shootRoot : meleeRoot if (roleConfig.attackRange == 0) comBehavior.root = null } public changeMoveSpeed(entity: EntityIndex, speed: number) { let comMovable = this.getComponent(entity, ComMovable) let comCocosNode = this.getComponent(entity, ComCocosNode) let comRole = this.getComponent(entity, ComRole) if (!comMovable || !comCocosNode) return let isChange = comMovable.speed != speed comMovable.speed = speed //同步spine战立和移动 let comSpineNode = this.getComponent(comRole?.spineEntity, ComCocosNode) if (comMovable.speed > 0) { isChange && comCocosNode.events.push(new EventRun()) && comSpineNode?.events.push(new EventRun()) } else { comMovable.points.length = 0 comMovable.pointIdx = 0 isChange && comCocosNode.events.push(new EventStand()) && comSpineNode?.events.push(new EventStand()) } } public changeRoleRun(entity: EntityIndex, isRun: boolean) { let comRole = this.getComponent(entity, ComRole) if (!comRole) return let comSpineNode = this.getComponent(comRole.spineEntity, ComCocosNode) comSpineNode?.node.getComponent(RoleSpineProcess).processEvent(isRun ? new EventRun() : new EventStand()) } isDie(idOrCom: EntityIndex | ComRole) { let comRole: ComRole if (typeof idOrCom == 'number') { if (!idOrCom) return true comRole = this.getComponent(idOrCom, ComRole) } else { comRole = idOrCom } return !comRole || comRole.nowHP + comRole.shieldHP <= 0 } isEnter(id: EntityIndex) { let comEnter = this.getComponent(id, ComEnter) return comEnter != null } isBase(idOrCom: EntityIndex | ComRole) { return this.isRoleType(idOrCom, ROLE_TYPE.base) } isBoss(idOrCom: EntityIndex | ComRole) { return this.isRoleType(idOrCom, MONSTER_TYPE.boss) } isRoleType(idOrCom: EntityIndex | ComRole, type: ROLE_TYPE | MONSTER_TYPE) { let comRole: ComRole if (typeof idOrCom == 'number') { if (!idOrCom) return false comRole = this.getComponent(idOrCom, ComRole) } else { comRole = idOrCom } return !comRole || comRole.roleCfg.type === type } //-------------------------战斗扣血加血----------------------------------------------- //普攻扣血 changeHpByHurt(role: EntityIndex, hurtHP: number, isCrit: boolean, HitAniID: number) { if (!hurtHP) return let changeHPRole = this.getComponent(role, ComRole) if (changeHPRole.invincible) return let changeHPComCocosNode = this.getComponent(role, ComCocosNode) changeHPRole.lastHP = changeHPRole.nowHP changeHPRole.lastShieldHP = changeHPRole.shieldHP changeHPComCocosNode.events.push( new EventRoleTip( isCrit ? GAME_ROLE_TIP.critTip : GAME_ROLE_TIP.damageTip, -hurtHP, `-${Math.toKMBNum(hurtHP)}`, ), ) let comSpineNode = this.getComponent(changeHPRole.spineEntity, ComCocosNode) comSpineNode?.events.push(new EventHurtOrAdd(-hurtHP, isCrit)) if (changeHPRole.shieldHP > 0) { changeHPRole.shieldHP -= hurtHP if (changeHPRole.shieldHP < 0) { changeHPRole.nowHP += changeHPRole.shieldHP changeHPRole.shieldHP = 0 } } else { changeHPRole.nowHP -= hurtHP } changeHPRole.HPDirty = true if (!this.isBase(changeHPRole) && changeHPRole.roleCfg.type != ROLE_TYPE.totem && HitAniID > 0) { this.createAni(HitAniID, role) } } getDefenseRate(defenseObj: IFightData, attackObj?: IFightData) { let ignoreDefenseE = attackObj?.entryMap.get(ENTRY.ignoreDefense)?.num || 0 return ( 1 - (defenseObj.defense * (1 - ignoreDefenseE / Data.game.rateNum)) / (defenseObj.defense + Data.game.defenseConst) ) } getSpellDefenseRate(fightData: IFightData, attackObj?: IFightData) { let ignoreDefenseE = attackObj?.entryMap.get(ENTRY.ignoreDefense)?.num || 0 return ( 1 - (fightData.spellDefense * (1 - ignoreDefenseE / Data.game.rateNum)) / (fightData.spellDefense + Data.game.defenseConst) ) } //攻击扣血值 getHurtByAttackRole(attackObj: IFightData, role: EntityIndex, attackEffect: IAttackEffect): number { let hurtHP = 0 let changeHPRole = this.getComponent(role, ComRole) let changeHPComCocosNode = this.getComponent(role, ComCocosNode) if (this.isDie(changeHPRole) || !changeHPComCocosNode || !changeHPComCocosNode.loaded) return hurtHP let critAddAttack = 0 let rateNum = Data.game.rateNum let attack = attackObj.attack let spellAttack = attackObj.spellAttack let realAttack = attackObj.realAttack // 所有的比例加伤 let hurtAddRate = 0 let realHurtAdd: number = 0 attackObj.buffs.forEach(buff => { let buffConfig = buff.buffCfg if (buffConfig.buffType == BUFF_TYPE.backAddHurt && attackEffect.isBack) { //后背加伤(万分比) hurtAddRate += buffConfig.attrRate[0] } else if (buffConfig.buffType == BUFF_TYPE.realByHp) { //血量比例加真实攻击(万分比) realHurtAdd += attackObj.nowHP * (buffConfig.attrRate[0] / rateNum) } else if ( buffConfig.buffType == BUFF_TYPE.attackNumAddHurt && attackObj.attackNum % buffConfig.attrNum[0] == 0 ) { //N弹加伤(万分比) hurtAddRate += buffConfig.attrRate[0] } }) //普攻对boss加伤 if (attackObj.entryMap.get(ENTRY.boosHurt)?.num && changeHPRole.roleCfg.type == MONSTER_TYPE.boss) { hurtAddRate += attackObj.entryMap.get(ENTRY.boosHurt).num } changeHPRole.buffs.forEach(buff => { let buffConfig = buff.buffCfg if (buffConfig.buffType == BUFF_TYPE.shieldReduceHurt) { //顶盾减伤(万分比) hurtAddRate += buffConfig.attrRate[0] } }) //暴击 if (attackEffect.isCrit) { attack *= attackObj.critNum / rateNum spellAttack *= attackObj.critNum / rateNum realAttack *= attackObj.critNum / rateNum } //溅射 if (attackEffect.sputter) { attack *= attackEffect.sputter / rateNum spellAttack *= attackEffect.sputter / rateNum realAttack *= attackEffect.sputter / rateNum } if (attack || spellAttack || realAttack) { //物理伤害 物理攻击*(1-物理防御/(物理防御+防御常数)) let hurt = attack * this.getDefenseRate(changeHPRole, attackObj) //魔法伤害 魔法攻击*(1-魔法防御/(魔法防御+防御常数)) let spellHurt = spellAttack * this.getSpellDefenseRate(changeHPRole, attackObj) //真实伤害 真实攻击 let realHurt = realAttack realHurt += realHurtAdd let endHurtRate = 1 + hurtAddRate / rateNum if (endHurtRate < 0) endHurtRate = 0 hurtHP = (hurt + spellHurt + realHurt) * (1 + Data.game.curHurtRate / rateNum) * endHurtRate } //普攻减伤 if (changeHPRole.entryMap.get(ENTRY.hurtReduce)?.num > 0) { hurtHP -= changeHPRole.entryMap.get(ENTRY.hurtReduce).num } if (hurtHP < 0) hurtHP = 0 return hurtHP } //技能加减血 changeHpBySkill(skill: ComSkill, role: EntityIndex) { let changeHPRole = this.getComponent(role, ComRole) let changeHPComCocosNode = this.getComponent(role, ComCocosNode) if ( this.isDie(changeHPRole) || (this.isBase(changeHPRole) && !skill.skillCfg.effectType.includes(SKILL_EFFECT_TYPE.hurtBase)) || changeHPRole.invincible || !changeHPComCocosNode || !changeHPComCocosNode.loaded ) return let fightData = skill.fightData if ( (skill.skillCfg.type == SKILL_TYPE.normal || skill.skillCfg.type == SKILL_TYPE.attackBack) && skill.skillCfg.hurtRate ) { let rateNum = Data.game.rateNum let hurtHP = 0 let attack = fightData.attack let spellAttack = fightData.spellAttack let realAttack = fightData.realAttack let hurtAddRate = skill.skillCfg.hurtRate //技能加伤 if (fightData.entryMap.get(ENTRY.skillHurtRate)?.num) { hurtAddRate += fightData.entryMap.get(ENTRY.skillHurtRate).num } //技能对boss加伤 if (fightData.entryMap.get(ENTRY.boosHurt)?.num && changeHPRole.roleCfg.type == MONSTER_TYPE.boss) { hurtAddRate += fightData.entryMap.get(ENTRY.boosHurt).num } if (attack || spellAttack || realAttack) { //物理伤害 物理攻击*(1-物理防御/(物理防御+防御常数)) let hurt = attack * this.getDefenseRate(changeHPRole) //魔法伤害 魔法攻击*(1-魔法防御/(魔法防御+防御常数)) let spellHurt = spellAttack * this.getSpellDefenseRate(changeHPRole) //真实伤害 真实攻击 let realHurt = realAttack hurtHP = (hurt + spellHurt + realHurt) * (1 + Data.game.curHurtRate / rateNum) * (hurtAddRate / rateNum) } //技能减伤 if (changeHPRole.entryMap.get(ENTRY.hurtReduce)?.num > 0) { hurtHP -= changeHPRole.entryMap.get(ENTRY.hurtReduce).num } if (hurtHP < 0) hurtHP = 0 //受击特效统一处理,这里是0 this.changeHpByHurt(role, hurtHP, false, 0) } let addNum = 0 if (skill.skillCfg.type == SKILL_TYPE.addHP) { addNum = (skill.skillCfg.hurtRate / Data.game.rateNum) * fightData.spellAttack let moreAddNum = 0 if (addNum + changeHPRole.nowHP > changeHPRole.HP) { moreAddNum = addNum + changeHPRole.nowHP - changeHPRole.HP addNum = changeHPRole.HP - changeHPRole.nowHP } for (let i = 0; i < skill.skillCfg.effectType.length; i++) { if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addExtraHP) { if (changeHPRole.nowHP / changeHPRole.HP < skill.skillCfg.effectParm[i][0] / Data.game.rateNum) { addNum += skill.skillCfg.effectParm[i][1] } } else if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addRateHP) { addNum += (skill.skillCfg.effectParm[i][0] / Data.game.rateNum) * changeHPRole.HP } } //增加治疗量 if (fightData.entryMap.get(ENTRY.addHealing)?.num) { addNum *= 1 + fightData.entryMap.get(ENTRY.addHealing).num / Data.game.rateNum } //受治疗增加量 if (changeHPRole.entryMap.get(ENTRY.healingMore)?.num) { addNum *= 1 + changeHPRole.entryMap.get(ENTRY.healingMore).num / Data.game.rateNum } //多的治疗量转为白血盾 if (changeHPRole.entryMap.get(ENTRY.healing2Shield)?.num && moreAddNum) { changeHPRole.shieldHP += (changeHPRole.entryMap.get(ENTRY.healing2Shield).num / Data.game.rateNum) * moreAddNum } this.addHP(addNum, role) } if ( skill.skillCfg.type == SKILL_TYPE.addShieldHPByHP || skill.skillCfg.type == SKILL_TYPE.addShieldHPBySpAttack ) { addNum = (skill.skillCfg.hurtRate / Data.game.rateNum) * (skill.skillCfg.type == SKILL_TYPE.addShieldHPByHP ? fightData.HP : fightData.spellAttack) if (changeHPRole.shieldHP < addNum) changeHPRole.shieldHP = addNum if (skill.skillCfg.type == SKILL_TYPE.addShieldHPBySpAttack) { for (let i = 0; i < skill.skillCfg.effectType.length; i++) { if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addRateShieldHP) { addNum += (skill.skillCfg.effectParm[i][0] / Data.game.rateNum) * changeHPRole.HP } } } } changeHPRole.HPDirty = true } changeHpByRebound(role: EntityIndex, enemy: EntityIndex) { let comRoleEnemy: ComRole = this.getComponent(enemy, ComRole) let comRole: ComRole = this.getComponent(enemy, ComRole) if (this.isDie(comRoleEnemy)) return comRoleEnemy.buffs.forEach(buff => { let buffType = buff.buffCfg.buffType if (buffType == BUFF_TYPE.reboundAttack || buffType == BUFF_TYPE.reboundReal) { //真实伤害 let defenseRate = 1 if (buffType == BUFF_TYPE.reboundAttack) { //物理伤害 defenseRate = this.getDefenseRate(comRole, comRoleEnemy) } let hurt = (comRoleEnemy.attack * defenseRate * buff.buffCfg.attrRate[0]) / Data.game.rateNum this.changeHpByHurt(role, hurt, false, 0) } }) if (comRoleEnemy.entryMap.get(ENTRY.hurtRebound)?.num) { let defenseRate = this.getDefenseRate(comRole, comRoleEnemy) let hurt = (comRoleEnemy.attack * defenseRate * comRoleEnemy.entryMap.get(ENTRY.hurtRebound)?.num) / Data.game.rateNum this.changeHpByHurt(role, hurt, false, 0) } } moveToMeleeAttackPos( selfEntity: EntityIndex, comTrans: ComTransform, targetComTrans: ComTransform, targetComMovable: ComMovable, isBack?: boolean, ) { let targetPos = cc.v2(targetComTrans.x, targetComTrans.y) // 近战前往目标敌人没被锁定的某一个近战范围攻击点 let isLeft = comTrans.x - targetComTrans.x < 0 if (isBack) isLeft = !isLeft if (targetComTrans.x >= Data.game.fightSizeMaxX) { isLeft = true } if (targetComTrans.x <= Data.game.fightSizeMinX) { isLeft = false } let isDown = comTrans.y - targetComTrans.y < 0 let attackArrayPos = isLeft ? Data.game.attackLeftRadiusPoints : Data.game.attackRightRadiusPoints let curAttackArrayPos = isLeft ? targetComMovable.leftMeleeEnemiesPosDirty : targetComMovable.rightMeleeEnemiesPosDirty let posIndex = curAttackArrayPos.indexOf(-1) let secondPosIndex = curAttackArrayPos.indexOf(-1, posIndex + 1) let targetIndex //因为leftMeleeEnemiesPosDirty数组是上下位置交替插入的,所以找出离自己近的点 if (posIndex >= 0 && secondPosIndex > 0) { if (isDown) { targetIndex = attackArrayPos[posIndex].y < 0 ? posIndex : secondPosIndex } else { targetIndex = attackArrayPos[posIndex].y >= 0 ? posIndex : secondPosIndex } } else if (posIndex >= 0 && secondPosIndex <= 0) { targetIndex = posIndex } else { targetIndex = Math.randomRangeInt(0, attackArrayPos.length - 1) } curAttackArrayPos[targetIndex] = selfEntity targetPos.addSelf(attackArrayPos[targetIndex]) if (targetPos.y <= Data.game.fightSizeMinY) targetPos.y = Data.game.fightSizeMinY if (targetPos.y >= Data.game.fightSizeMaxY) targetPos.y = Data.game.fightSizeMaxY return targetPos } //加血吸血 addHP(addHPNum: number, role: EntityIndex) { let comRole = this.getComponent(role, ComRole) let comCocosNode = this.getComponent(role, ComCocosNode) if (!this.isDie(role)) { if (addHPNum >= 1) { comCocosNode.events.push(new EventRoleTip(GAME_ROLE_TIP.hpTip, addHPNum, `+${Math.toKMBNum(addHPNum)}`)) } let target = comRole.nowHP + addHPNum if (target > comRole.HP) { addHPNum = comRole.HP - comRole.nowHP } comRole.nowHP += addHPNum } } //-------------------------------子弹----------------------------------------- public createBulletEntity(role: EntityIndex, isCrit: boolean): EntityIndex[] { let comRole = this.getComponent(role, ComRole) let comTransform = this.getComponent(role, ComTransform) let comFindEnemy = this.getComponent(role, ComFindEnemy) let comAttackable = this.getComponent(role, ComAttackable) let entities = [] if (this.isDie(comRole)) { //Log.warn('创建子弹失败') return entities } let bulletID = comRole.roleCfg.bullet if (!bulletID) { return entities } let bulletCfg = BulletConfig[bulletID] let enemies = [comAttackable.curAttack] let endPosArr: cc.Vec2[] = [] //跟踪敌人改成固定角度 if (bulletCfg.splitNum > 1) { // let otherEnemies = comFindEnemy.attackCObject.containsBody.keysArr() // otherEnemies = otherEnemies.filter( // v => // Math.sign(comTransform.dir.x) != Math.sign(this.getComponent(v, ComTransform)?.dir.x) && // v != comAttackable.curAttack, // ) // // otherEnemies.sort((a, b) => { // let at = this.getComponent(a, ComTransform) // let bt = this.getComponent(b, ComTransform) // return at.x ** 2 + at.y ** 2 - (bt.x ** 2 + bt.y ** 2) // }) // enemies = enemies.concat(otherEnemies) let enemyComTransform = this.getComponent(enemies[0], ComTransform) let startPos = cc.v2(comTransform.x, comTransform.y + comTransform.halfHeight) let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight) for (let i = 1; i < bulletCfg.splitNum; i++) { endPosArr.push(this.rotatePoint(startPos, hitPos, 10 * i * (i % 2 == 0 ? -1 : 1))) } } for (let i = 0; i < bulletCfg.splitNum; i++) { //if (i < enemies.length) { let enemyComTransform = this.getComponent(enemies[i], ComTransform) if (!enemyComTransform) { enemyComTransform = new ComTransform() enemyComTransform.x = endPosArr[i - 1].x enemyComTransform.y = endPosArr[i - 1].y } let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[GAME_LAYER.bullet] comMap.prefabName = GAME_PREFAB_TYPE.bullet //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) let bulletPosScaleX = comTransform.dir.x >= 0 ? 1 : -1 let spineScale = comRole.roleCfg.gameScale[GAME_SCALE_TYPE.spine] / 100 comTrans.x = comTransform.x + comRole.roleCfg.bulletPos[0] * bulletPosScaleX * spineScale comTrans.y = comTransform.y + comRole.roleCfg.bulletPos[1] * spineScale let comMovable = this.addComponent(entity, ComMovable) comMovable.speed = 0 let comBullet = this.addComponent(entity, ComBullet) comBullet.group = comRole.group == Data.game.gFriend ? Data.game.gFriendBullet : Data.game.gEnemyBullet comBullet.fightData = {...comRole, roleEntity: role} comBullet.fightData.buffs = ccUtils.deepCopy(comRole.buffs) comBullet.bulletCfg = bulletCfg comBullet.ejectionEnemies.length = 0 comBullet.ejectionEnemy = enemies[i] ? enemies[i] : 0 comBullet.hitEnemies.length = 0 comBullet.isCrit = isCrit this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet) entities.push(entity) // } } return entities } public createRoleSkillBulletEntity( bulletID: number, createEntity: EntityIndex, enemy: EntityIndex, randomPos: boolean = false, pos?: cc.Vec2, ): EntityIndex[] { let bulletCfg = BulletConfig[bulletID] let roleComTransform = this.getComponent(createEntity, ComTransform) let enemyComTransform = this.getComponent(enemy, ComTransform) if (pos) { enemyComTransform = new ComTransform() enemyComTransform.x = pos.x enemyComTransform.y = pos.y } if (!enemyComTransform || !bulletCfg) { return } let endPosArr: cc.Vec2[] = [] //跟踪敌人改成固定角度 if (bulletCfg.splitNum > 1) { let startPos = cc.v2(roleComTransform.x, roleComTransform.y + roleComTransform.halfHeight) let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight) for (let i = 1; i < bulletCfg.splitNum; i++) { endPosArr.push(this.rotatePoint(startPos, hitPos, 10 * i * (i % 2 == 0 ? -1 : 1))) } } let entityArr = [] for (let i = 0; i < bulletCfg.splitNum; i++) { let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[GAME_LAYER.bullet] comMap.prefabName = GAME_PREFAB_TYPE.bullet //移除cocosNode this.removeComponent(entity, ComCocosNode) let comRole = this.getComponent(createEntity, ComRole) // 添加transform let comTrans = this.addComponent(entity, ComTransform) let bulletPosScaleX = roleComTransform.dir.x >= 0 ? 1 : -1 let spineScale = comRole.roleCfg.gameScale[GAME_SCALE_TYPE.spine] / 100 comTrans.x = roleComTransform.x + comRole.roleCfg.bulletPos[0] * bulletPosScaleX * spineScale comTrans.y = roleComTransform.y + (comRole.roleCfg.bulletPos[1] ? comRole.roleCfg.bulletPos[1] * spineScale : roleComTransform.halfHeight) let comMovable = this.addComponent(entity, ComMovable) comMovable.speed = 0 let comBullet = this.addComponent(entity, ComBullet) comBullet.group = comRole.group == Data.game.gFriend ? Data.game.gFriendBullet : Data.game.gEnemyBullet comBullet.fightData = {...comRole, roleEntity: createEntity} comBullet.bulletCfg = bulletCfg comBullet.ejectionEnemies.length = 0 comBullet.ejectionEnemy = enemy comBullet.hitEnemies.length = 0 comBullet.isCrit = false //特效子弹位置随机 if (randomPos && SkillConfig[bulletCfg.skill]) { let randomWidth = SkillConfig[bulletCfg.skill].attackRangeX let randomHeight = SkillConfig[bulletCfg.skill].attackRangeY let randomX = enemyComTransform.x + Math.randomRangeFloat(-randomWidth / 2, randomWidth / 2) let randomY = enemyComTransform.y + Math.randomRangeFloat(-randomHeight / 2, randomHeight / 2) enemyComTransform = new ComTransform() enemyComTransform.x = randomX enemyComTransform.y = randomY } if (bulletCfg.born == START_POS.straightFall || bulletCfg.born == START_POS.obliqueFall) { comTrans.x = enemyComTransform.x - (bulletCfg.born == START_POS.obliqueFall ? 200 : 0) comTrans.y = ConstValue.CANVAS_HEIGHT / 2 } if (i > 0) { enemyComTransform = new ComTransform() enemyComTransform.x = endPosArr[i - 1].x enemyComTransform.y = endPosArr[i - 1].y } this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet) entityArr.push(entity) } return entityArr } public createCardBulletEntity( iCard: ICard, startPos: cc.Vec2, endPos: cc.Vec2, enemy: EntityIndex = 0, ): EntityIndex { let cardSkillCfg = iCard.cfg let bulletCfg = BulletConfig[cardSkillCfg.bullet] let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[GAME_LAYER.bullet] comMap.prefabName = GAME_PREFAB_TYPE.bullet //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) comTrans.x = startPos.x comTrans.y = startPos.y let comMovable = this.addComponent(entity, ComMovable) comMovable.speed = 0 let comBullet = this.addComponent(entity, ComBullet) comBullet.group = Data.game.gFriendBullet comBullet.fightData = {buffs: [], entryMap: new Map(), ...iCard} comBullet.bulletCfg = bulletCfg comBullet.ejectionEnemies.length = 0 comBullet.ejectionEnemy = enemy comBullet.hitEnemies.length = 0 comBullet.isCrit = false let enemyComTransform = new ComTransform() enemyComTransform.x = endPos.x enemyComTransform.y = endPos.y this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet) return entity } public createBaseBulletEntity(posOrTrans: ComTransform | cc.Vec2) { let sysCastleSkill = this.getSystem(SysCastleSkill) if (sysCastleSkill.rechargeTime > 0) { Mgr.ui.tip(LANGUAGE_TYPE.inRecharge) return } if (!Data.user.useCastleSkillID) return sysCastleSkill.reduceLeftNum() let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[GAME_LAYER.bullet] comMap.prefabName = GAME_PREFAB_TYPE.bullet //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) comTrans.x = -10000 comTrans.y = 10000 let comMovable = this.addComponent(entity, ComMovable) comMovable.speed = 0 let comBullet = this.addComponent(entity, ComBullet) comBullet.group = Data.game.gFriendBullet let baseBulletCfg = CastleSkillConfig[Data.user.useCastleSkillID] comBullet.fightData = {buffs: [], entryMap: new Map(), ...baseBulletCfg} comBullet.bulletCfg = BulletConfig[baseBulletCfg.bullet] comBullet.ejectionEnemies.length = 0 comBullet.ejectionEnemy = 0 comBullet.hitEnemies.length = 0 comBullet.ejectionAnis.length = 0 comBullet.isCrit = false let enemyComTransform if (posOrTrans instanceof ComTransform) { enemyComTransform = posOrTrans } else { let startPos = cc.v2(comTrans.x, comTrans.y) let direction = posOrTrans.sub(startPos).normalize() let endPos = startPos.add(direction.mul(baseBulletCfg.attackRange)) enemyComTransform = new ComTransform() enemyComTransform.x = endPos.x enemyComTransform.y = endPos.y } this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet) return entity } public initBulletDir( comTrans: ComTransform, enemyComTransform: ComTransform, comMovable: ComMovable, comBullet: ComBullet, comCocosNode?: ComCocosNode, ) { let startPos = cc.v2(comTrans.x, comTrans.y) let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight) // 计算子弹的飞行方向向量 let direction = hitPos.sub(startPos).normalize() let bulletCfg = comBullet.bulletCfg if ( !bulletCfg.isEjection && bulletCfg.type == BULLET_TYPE.normal && !bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.attackRange) && !bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.boomerangRange) ) { //如果是直线子弹,将子弹终点设置为边界外的某个点,子弹到达边界点,移除子弹 hitPos = this.findIntersection(startPos, direction) //当子弹从区域外进入,直接让子弹结束 if (!hitPos) hitPos = startPos } let hitPosArr = [hitPos] if (bulletCfg.flyType == BULLET_FLY_TYPE.parabolic) { hitPosArr = this.getParabolaPoints(startPos, hitPos, 50) if (hitPosArr.length >= 2) direction = hitPosArr[1].sub(hitPosArr[0]).normalize() } else if (bulletCfg.flyType == BULLET_FLY_TYPE.bezier) { hitPosArr.length = 0 hitPosArr.push(...this.getEquidistantPoints(startPos, hitPos, 10, comBullet.group)) hitPosArr.push(hitPos) } else if (bulletCfg.flyType == BULLET_FLY_TYPE.boomerang) { hitPosArr.length = 0 let parms = bulletCfg.effectParm[bulletCfg.effectType.indexOf(BULLET_EFFECT_TYPE.boomerangRange)] let halfPoints = this.getEquidistantPoints(startPos, hitPos, 10, comBullet.group, parms[1]) let leftPoints = this.getEquidistantPoints(hitPos, startPos, 10, comBullet.group, parms[1]) hitPosArr.push(...halfPoints) hitPosArr.push(hitPos) hitPosArr.push(...leftPoints) hitPosArr.push(startPos) } else if (bulletCfg.flyType == BULLET_FLY_TYPE.horizon) { hitPosArr.length = 0 hitPosArr.push(cc.v2(comTrans.x + (direction.x >= 0 ? 1000 : -1000), comTrans.y)) } comTrans.dir.x = direction.x comTrans.dir.y = direction.y comMovable.pointIdx = 0 comMovable.points.length = 0 comMovable.points.push(...hitPosArr) if (comCocosNode) { //计算发射角度 let angle = Math.atan2(comTrans.dir.y, comTrans.dir.x) comCocosNode.node.angle = cc.misc.radiansToDegrees(angle) } } getParabolaPoints(a: cc.Vec2, b: cc.Vec2, interval: number): cc.Vec2[] { let xA = a.x, yA = a.y let xB = b.x, yB = b.y let yMax = Data.game.fightSizeMaxY - Math.randomRangeInt(0, Data.game.fightSizeMaxY - Math.max(yA, yB)) // 最高点的高度 let xC = (xA + xB) / 2 // 假设C是A和B的中点(水平方向) let xD = xA + (xC - xA) / 2 // 控制点D的x坐标是A和C的x坐标的平均值 let yD = yA + (yMax - yA) / 2 // 控制点D的y坐标是A和最高点之间的某个值(这里取中点) let points = [] let step = 1 / (interval - 1) for (let t = 0; t <= 1; t += step) { let x = Math.pow(1 - t, 3) * xA + 3 * Math.pow(1 - t, 2) * t * xD + 3 * (1 - t) * Math.pow(t, 2) * xC + Math.pow(t, 3) * xB let y = Math.pow(1 - t, 3) * yA + 3 * Math.pow(1 - t, 2) * t * yD + 3 * (1 - t) * Math.pow(t, 2) * yMax + Math.pow(t, 3) * yB points.push(cc.v2(x, y)) } return points } boundaries = [ {dir: 'right', eq: Data.game.fightAreaMaxX, var: 'x'}, // 右边界 {dir: 'left', eq: Data.game.fightAreaMinX, var: 'x'}, // 左边界 {dir: 'top', eq: Data.game.fightAreaMaxY, var: 'y'}, // 上边界 {dir: 'bottom', eq: Data.game.fightAreaMinY, var: 'y'}, // 下边界 ] findIntersection(a, v) { // 将矩形边界转换为线性方程组 // 例如,对于矩形的上边界(y-centerY = height/2),转换为 y = centerY + height/2 // 并以此类推其他三个边界 // 定义四个边界线性方程 let intersection = null //起点Y位置加上了人物身高,这里做个限制,让子弹起始点在屏幕内 this.boundaries.forEach(boundary => { let t if (boundary.var === 'x') { // 解 x = a.x + t*v.x t = (boundary.eq - a.x) / v.x } else { // 解 y = a.y + t*v.y t = (boundary.eq - a.y) / v.y } // 检查t是否在[0, +∞)范围内,确保交点在射线方向上且不过原点 if (t >= 0) { let intersectPoint = cc.v2(a.x + t * v.x, a.y + t * v.y) // 判断交点是否在矩形内或边上 if ( (boundary.dir === 'right' || boundary.dir === 'left') && intersectPoint.y >= Data.game.fightAreaMinY && intersectPoint.y <= Data.game.fightAreaMaxY ) { if (!intersection || intersection.sub(a).mag() < intersectPoint.sub(a).mag()) intersection = intersectPoint } else if ( (boundary.dir === 'top' || boundary.dir === 'bottom') && intersectPoint.x >= Data.game.fightAreaMinX && intersectPoint.x <= Data.game.fightAreaMaxX ) { if (!intersection || intersection.sub(a).mag() < intersectPoint.sub(a).mag()) intersection = intersectPoint } } }) return intersection } public removeBulletEntity(entity: EntityIndex) { let comCocosNode = this.getComponent(entity, ComCocosNode) let comBullet = this.getComponent(entity, ComBullet) if (!comBullet) { return //console.log('子弹已经移除') } //1秒后移除弹射特效 comBullet.ejectionAnis.forEach(aniEntity => { let aniEntityCom = this.getComponent(aniEntity, ComFrameAni) if (aniEntityCom && aniEntityCom.countDown > 1) aniEntityCom.countDown = 1 }) if (comBullet.cObject) { cCollider.inst.remove(comBullet.cObject.body) comCocosNode.node.removeComponent(comBullet.cObject) comBullet.cObject = null } this.removeNodeEntity(entity) } rotatePoint(a: cc.Vec2, b: cc.Vec2, angleDegrees: number): cc.Vec2 { // 将角度转换为弧度 const angleRadians = (angleDegrees * Math.PI) / 180 // 计算cos和sin值 const cosAngle = Math.cos(angleRadians) const sinAngle = Math.sin(angleRadians) // 计算新的坐标 const x_new = (b.x - a.x) * cosAngle - (b.y - a.y) * sinAngle + a.x const y_new = (b.x - a.x) * sinAngle + (b.y - a.y) * cosAngle + a.y return cc.v2(x_new, y_new) } bezierPoint(t, a, c, d, b) { let x = Math.pow(1 - t, 3) * a.x + 3 * Math.pow(1 - t, 2) * t * c.x + 3 * (1 - t) * Math.pow(t, 2) * d.x + Math.pow(t, 3) * b.x let y = Math.pow(1 - t, 3) * a.y + 3 * Math.pow(1 - t, 2) * t * c.y + 3 * (1 - t) * Math.pow(t, 2) * d.y + Math.pow(t, 3) * b.y return cc.v2(x, y) } getBezierLength(a, c, d, b, numPoints) { let length = 0 let previousPoint = a for (let i = 1; i <= numPoints; i++) { let t = i / numPoints let currentPoint = this.bezierPoint(t, a, c, d, b) length += previousPoint.sub(currentPoint).mag() previousPoint = currentPoint } return length } getEquidistantPoints(a, b, numPoints, group, height?) { let {c, d} = this.calculatePointCD(a.x, a.y, b.x, b.y, group, height) let points = [] let totalLength = this.getBezierLength(a, c, d, b, numPoints) let segmentLength = totalLength / (numPoints - 1) let previousPoint = a points.push(previousPoint) for (let i = 1; i < numPoints; i++) { let targetLength = segmentLength * i let low = (i - 1) / numPoints let high = i / numPoints while (high - low > 1e-5) { let mid = (low + high) / 2 let point = this.bezierPoint(mid, a, c, d, b) let length = previousPoint.sub(point).mag() if (length < targetLength) { low = mid } else { high = mid } } let point = this.bezierPoint((low + high) / 2, a, c, d, b) points.push(point) previousPoint = point } return points } calculatePointCD(x1, y1, x2, y2, group, height?) { let a = cc.v2(x1, y1) let b = cc.v2(x2, y2) let dir = b.sub(a).normalize() let length = a.sub(b).mag() let k = Math.max(100000 / length, 50) k = Math.min(k, 100) if (height) k = height // 垂直方向向量 let vDir = dir.rotate(90 * (Math.PI / 180)).mul(group == Data.game.gFriendBullet ? 1 : -1) let c = a.add(vDir.mul(k)).add(dir.mul(length / 3)) let d = a.add(vDir.mul(k)).add(dir.mul((length * 2) / 3)) return {c, d} } //-------------------------------技能----------------------------------------- public createSkill( fightData: IFightData, skillCfg: ISkillConfig, role: EntityIndex, pos?: cc.Vec3, group?: number, ) { let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[skillCfg.layer ? skillCfg.layer : GAME_LAYER.skill] comMap.prefabName = GAME_PREFAB_TYPE.skill //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) //提升自己数值技能 let comSkill = this.addComponent(entity, ComSkill) comSkill.skillCfg = skillCfg comSkill.fightData = fightData comSkill.countDown = skillCfg.duration comSkill.role = role comSkill.group = group comSkill.hurtFrameCompleted = false comSkill.dirty = false if (role > 0) { let comRoleTrans = this.getComponent(role, ComTransform) let comRole = this.getComponent(role, ComRole) comTrans.x = comRoleTrans.x comTrans.y = comRoleTrans.y + comRoleTrans.halfHeight * (skillCfg.offsetPos[0] - 1) comSkill.group = comRole.group == Data.game.gFriend ? skillCfg.isHurt ? skillCfg.dirType == SKILL_DIR_TYPE.selfNormal ? Data.game.gFriendHurtSkill : Data.game.gEnemyHurtSkill : Data.game.gFriendGainSkill : skillCfg.isHurt ? skillCfg.dirType == SKILL_DIR_TYPE.selfNormal ? Data.game.gEnemyHurtSkill : Data.game.gFriendHurtSkill : Data.game.gEnemyGainSkill } else { if (!pos || !group) Log.error('技能创建失败') comTrans.x = pos.x comTrans.y = pos.y } comTrans.x += skillCfg.offsetPos[1] comTrans.y += skillCfg.offsetPos[2] if (skillCfg.type == SKILL_TYPE.attackBack && skillCfg.effectType.indexOf(SKILL_EFFECT_TYPE.move) >= 0) { let comMovable = this.addComponent(entity, ComMovable) comMovable.pointIdx = 0 comMovable.points.length = 0 comMovable.speed = skillCfg.effectParm[skillCfg.effectType.indexOf(SKILL_EFFECT_TYPE.move)][0] comMovable.points.push( cc.v2( comSkill.group == Data.game.gFriendHurtSkill || comSkill.group == Data.game.gFriendGainSkill ? Data.game.fightAreaMaxX : Data.game.fightAreaMinX, comTrans.y, ), ) } return entity } public createSkillByFightData(fightData: IFightData, skillCfg: ISkillConfig, roles: EntityIndex[]) { let isSuccess = false roles.forEach((role: EntityIndex) => { let comRole = this.getComponent(role, ComRole) if (this.isDie(comRole)) return this.createSkill(fightData, skillCfg, role) isSuccess = true }) return isSuccess } public createCardBulletSkill(comBullet: ComBullet, role: EntityIndex, pos?: cc.Vec3) { //卡牌弹射子弹每次命中目标放技能 let skillCfg = SkillConfig[comBullet.bulletCfg.skill] for (let i = 0; i < skillCfg.effectType.length; i++) { let type = skillCfg.effectType[i] if (type == SKILL_EFFECT_TYPE.reduce) { comBullet.fightData.attack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum comBullet.fightData.spellAttack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum comBullet.fightData.realAttack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum } } if (role) { this.createSkillByFightData(comBullet.fightData, skillCfg, [role]) } else { let skillEntity = this.createSkill( comBullet.fightData, skillCfg, 0, pos, comBullet.group == Data.game.gEnemyBullet ? skillCfg.isHurt ? Data.game.gEnemyHurtSkill : Data.game.gEnemyGainSkill : skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill, ) let tmp = this.getComponent(skillEntity, ComSkill) } //地板受击 if (skillCfg.hitID[HIT_ANI_TYPE.floor]) { this.createAni(skillCfg.hitID[HIT_ANI_TYPE.floor], role, role ? null : cc.v2(pos)) } } public isOneRoleSkill(skillCfg: ISkillConfig): boolean { return ( skillCfg.dirType == SKILL_DIR_TYPE.selfRole || skillCfg.dirType == SKILL_DIR_TYPE.anyRole || skillCfg.dirType == SKILL_DIR_TYPE.minHpRole || skillCfg.dirType == SKILL_DIR_TYPE.baby ) } removeSkillEntity(entity) { let comSkill = this.getComponent(entity, ComSkill) let comCocosNode = this.getComponent(entity, ComCocosNode) if (!comSkill || !comCocosNode) return cCollider.inst.remove(comSkill.cObject.body) comCocosNode.node.removeComponent(comSkill.cObject) comSkill.cObject = null this.removeNodeEntity(entity) } //-------------------------------BUFF----------------------------------------- public createBuff(buffID, fightData: IFightData) { if (!BuffConfig[buffID]) return let buff = {buffCfg: BuffConfig[buffID]} as IBuff buff.countDown = buff.buffCfg.duration == Data.game.cdMax ? Infinity : buff.buffCfg.duration buff.countUp = 0 buff.hurtFrameCompleted = false buff.hurtTimes = 0 buff.immuneTimes = 0 buff.curAttrChangeNum = [] buff.createBaseAttr = Mgr.global.buildIBaseAttr(fightData, !fightData) buff.aniEntityArr = [] return buff } public addBuff(skillEntity: EntityIndex, buff: IBuff, fightData: IFightData) { if (!buff) return let comRoleSkill = this.getComponent(skillEntity, ComRole) let comRoleTrans = this.getComponent(skillEntity, ComTransform) let comCocosNodeSkill = this.getComponent(skillEntity, ComCocosNode) let comHasSkillSkill = this.getComponent(skillEntity, ComHasSkill) let comSpineNode = this.getComponent(comRoleSkill.spineEntity, ComCocosNode) if (!comCocosNodeSkill || !comCocosNodeSkill.loaded || this.isDie(comRoleSkill) || this.isBase(comRoleSkill)) { return } //图腾对象不施加BUFF if (comRoleSkill.roleCfg.type == ROLE_TYPE.totem) return let sameIDBuffs = comRoleSkill.buffs.filter(buffTmp => buffTmp.buffCfg.ID == buff.buffCfg.ID) let buffCfg = buff.buffCfg let sameArrIDBuffs = comRoleSkill.buffs.filter( buffTmp => buffCfg.arrID > 0 && buffTmp.buffCfg.arrID == buffCfg.arrID, ) let addBuffFuc = (isReplace: boolean = false) => { let hasImmune = false comRoleSkill.buffs.forEach(buffTmp => { let buffCfg = buffTmp.buffCfg if (buffCfg.buffType == BUFF_TYPE.negativeImmune) { let negativeArr = buffCfg.effectParm[buffCfg.effectType.indexOf(BUFF_EFFECT_TYPE.immuneNegative)] if (negativeArr) { hasImmune ||= negativeArr.includes(NEGATIVE_TYPE.delay) && buff.buffCfg.buffType == BUFF_TYPE.dizzy hasImmune ||= negativeArr.includes(NEGATIVE_TYPE.slow) && buff.buffCfg.attrRate[buff.buffCfg.attr.indexOf(ATTR_NAME.moveSpeed)] < 0 } } }) if (hasImmune) return //光环buff不施放,在处理hasSkill处理 comRoleSkill.buffs.push(buff) //comCocosNodeSkill.events.push(new EventBuffChange(comRoleSkill.buffs, [buff], [])) for (let aniID of buff.buffCfg.buffUrl) { if (!aniID || isReplace) continue if (aniID == BUFF_ANI_TYPE.slow) { comSpineNode?.events.push(new EventSlowDown(true)) } buff.aniEntityArr.push(this.createAni(aniID, skillEntity)) } buffCfg.buffIcon.forEach(value => { comCocosNodeSkill.events.push(new EventRoleTip(GAME_ROLE_TIP.buffTip, buffCfg.hurtEffect, value)) }) if (buff.buffCfg.buffType == BUFF_TYPE.dizzy) { let comDizzy = this.getComponent(skillEntity, ComDizzy) if (comDizzy && !this.isDie(comRoleSkill)) { comDizzy.countDown = buff.buffCfg.attrNum[0] for (let i = 0; i < buff.buffCfg.effectType.length; i++) { let type = buff.buffCfg.effectType[i] if (type == BUFF_EFFECT_TYPE.boss && comRoleSkill.roleCfg.type == MONSTER_TYPE.boss) { comDizzy.countDown *= 1 - buff.buffCfg.effectParm[i][0] / Data.game.rateNum } } if (comRoleSkill.entryMap.get(ENTRY.delayReduce)?.num) { comDizzy.countDown *= 1 - comRoleSkill.entryMap.get(ENTRY.delayReduce).num / Data.game.rateNum } if (fightData && fightData.entryMap.get(ENTRY.delayAdd)?.num) { comDizzy.countDown *= 1 + fightData.entryMap.get(ENTRY.delayAdd).num / Data.game.rateNum } //将顶盾的buff去掉 let findIndex = comRoleSkill.buffs.findIndex( value => value.buffCfg.buffType == BUFF_TYPE.shieldReduceHurt, ) if (findIndex != -1) comRoleSkill.buffs.splice(findIndex, 1) let comDizzySkillAbel = this.getComponent(skillEntity, ComSkillAbel) comDizzySkillAbel.isInShield = false //将顶盾的罩子,友军免疫远程攻击buff去掉 this.removeNodeEntity(comDizzySkillAbel.ani) let skillIndex = comRoleSkill.skills.findIndex(v => v.type == SKILL_TYPE.holo) if (skillIndex >= 0) { let allEntity = Array.from(comHasSkillSkill.skillCObjects[skillIndex].containsBody.keys()) allEntity = allEntity.filter(entityTmp => !this.isDie(entityTmp)) allEntity.forEach(v => { let tmpComRole = this.getComponent(v, ComRole) let findIndex = tmpComRole.buffs.findIndex( value => value.buffCfg.buffType == BUFF_TYPE.rangedImmune, ) if (findIndex != -1) { console.warn('去掉免疫buff') tmpComRole.buffs.splice(findIndex, 1) } }) } //将技能弹射子弹去除 if (comDizzySkillAbel.bullets) { comDizzySkillAbel.bullets.forEach(v => { this.removeBulletEntity(v) }) comDizzySkillAbel.bullets.length = 0 } } } } let replaceBuffFuc = (replaceBuff: IBuff) => { //addType==0直接替换,==1替换效果最好的 if ( buffCfg.addType == 0 || (buffCfg.addType == 1 && buffCfg.attrRate[0] >= replaceBuff.buffCfg.attrRate[0]) ) { let removeBuffs = comRoleSkill.buffs.splice(comRoleSkill.buffs.indexOf(replaceBuff), 1) this.removeBuffAttr(skillEntity, removeBuffs[0]) addBuffFuc(true) //特效继承,时间重置 buff.aniEntityArr.push(...removeBuffs[0].aniEntityArr) for (let aniEntity of buff.aniEntityArr) { let comFrameAni = this.getComponent(aniEntity, ComFrameAni) if (comFrameAni) comFrameAni.countDown = comFrameAni.aniConfig.duration } } } if (buffCfg.arrID > 0) { //有buff组,根据叠加和替换规则确定是否叠加和替换 if (buffCfg.isAdd && (!buffCfg.addNum || (buffCfg.addNum > 0 && sameArrIDBuffs.length < buffCfg.addNum))) { //叠加 addBuffFuc() } else if (!buffCfg.isAdd) { //不叠加 if (sameArrIDBuffs.length == 0) { addBuffFuc() } else { replaceBuffFuc(sameArrIDBuffs[0]) } } } else { //不叠加 if (sameIDBuffs.length == 0) { addBuffFuc() } else { replaceBuffFuc(sameIDBuffs[0]) } } } public removeBuffAttr(role: EntityIndex, buff: IBuff) { let comRole = this.getComponent(role, ComRole) if (this.isDie(comRole)) return let buffConfig = buff.buffCfg for (let j = 0; j < buffConfig.attr.length; j++) { if (buff.curAttrChangeNum[j]) { comRole[buffConfig.attr[j]] -= buff.curAttrChangeNum[j] if (buffConfig.attr[j] == ATTR_NAME.attackRange) { let comFindEnemy = this.getComponent(role, ComFindEnemy) if (comFindEnemy.attackCObject.radius != comRole.attackRange) { comFindEnemy.attackCObject.updateSphereShape(comRole.attackRange) } } } } } //-------------------------------特效----------------------------------------- public createAni(aniID: number, role: EntityIndex, pos?: cc.Vec2) { let frameAniConfig = FrameAniConfig[aniID] if (!frameAniConfig) { console.error('frameAniID不存在', aniID) return } if (frameAniConfig.type == ANI_TYPE.shader) return let entity = this.createEntity() // 添加nodeconfig let comMap = this.addComponent(entity, ComNodeConfig) comMap.id = 1 comMap.layer = GAME_LAYER[frameAniConfig.layer ? frameAniConfig.layer : GAME_LAYER.skill] comMap.prefabName = GAME_PREFAB_TYPE.frameAni //移除cocosNode this.removeComponent(entity, ComCocosNode) // 添加transform let comTrans = this.addComponent(entity, ComTransform) let comFrameAni = this.addComponent(entity, ComFrameAni) comFrameAni.countDown = frameAniConfig.duration comFrameAni.dirty = false comFrameAni.aniConfig = frameAniConfig comFrameAni.role = role comFrameAni.lineStartPos = null comFrameAni.lineStartEntity = 0 comFrameAni.lineEndEntity = 0 let comRoleTrans = this.getComponent(role, ComTransform) if (pos) { comTrans.x = pos.x comTrans.y = pos.y } else if (comRoleTrans) { comTrans.x = comRoleTrans.x comTrans.y = comRoleTrans.y + (frameAniConfig.offsetPos[0] ? comRoleTrans.halfHeight * (frameAniConfig.offsetPos[0] - 1) : 0) } comTrans.x += frameAniConfig.offsetPos[1] comTrans.y += frameAniConfig.offsetPos[2] return entity } //--------------------------------词条------------------------------------------------- isGameEntry(type: ENTRY) { return type >= ENTRY.ignoreDefense && type <= 100 } initEntry() { if (Data.game.gameType != GAME_TYPE.relic) { for (let id of Data.user.talents) { let talentCfg = TalentConfig[id] let type = EntryConfig[talentCfg.entryID].type switch (type) { case ENTRY.startCostAdd: break } } } } convertEntry2Obj(entryID: number): EntryObj { let entryCfg = EntryConfig[entryID] let num = 0 if (entryCfg.parmArr[0] && entryCfg.parmArr.length == 1) num = entryCfg.parmArr[0] if (entryCfg.rateArr[0] && entryCfg.rateArr.length == 1) num = entryCfg.rateArr[0] let numArrTmp = [] if (entryCfg.parmArr.length > 1) numArrTmp.push(entryCfg.parmArr) if (entryCfg.rateArr.length > 1) numArrTmp.push(entryCfg.rateArr) return {num, numArr: numArrTmp, type: entryCfg.type, profession: entryCfg.profession} } putEntry2Map(comRole: ComRole, entryObj: EntryObj) { let map = comRole.entryMap if (!this.isGameEntry(entryObj.type) || !entryObj.profession.includes(comRole.roleCfg.profession)) return let obj = map.get(entryObj.type) if (obj) { //叠加规则 if (entryObj.num > 0) { //默认数值相加 obj.num += entryObj.num } else if (entryObj.numArr.length > 0) { //数组默认覆盖最好的效果 let lastNum = obj.numArr[0][obj.numArr[0].length - 1] let newLastNum = entryObj.numArr[0][entryObj.numArr[0].length - 1] if (newLastNum > lastNum) { obj.numArr[0][obj.numArr[0].length - 1] = newLastNum } } } else { map.set(entryObj.type, entryObj) } } //--------------------------------改变无敌状态------------------------------------------------- changeInvincible(role: EntityIndex, invincible: boolean) { let comRole = this.getComponent(role, ComRole) if (this.isDie(comRole)) return comRole.invincible = invincible } //--------------------------------绘制碰撞体------------------------------------------------- drawDebug(entity: EntityIndex, cObject) { let comCocosNode = this.getComponent(entity, ComCocosNode) let comTrans = this.getComponent(entity, ComTransform) if (!comCocosNode || !comTrans || !cObject || !CC_DEV || !cc.debug.isDisplayStats()) return //绘制碰撞体 let localPoints let offset = cc.v2(comTrans.x, comTrans.y).add(cc.v2(cObject.center)) if (cObject.type == ShapeType.Box) { localPoints = [] localPoints.push(cc.v2(offset.x - cObject.size.x / 2, offset.y + cObject.size.y / 2)) // 左上角 localPoints.push(cc.v2(offset.x + cObject.size.x / 2, offset.y + cObject.size.y / 2)) // 右上角 localPoints.push(cc.v2(offset.x + cObject.size.x / 2, offset.y - cObject.size.y / 2)) // 右下角 localPoints.push(cc.v2(offset.x - cObject.size.x / 2, offset.y - cObject.size.y / 2)) // 左下角 } if (cObject.type == ShapeType.Sphere) { localPoints = [cc.v2(comTrans.x, comTrans.y).add(cc.v2(cObject.center))] } if (localPoints) { let color let comRole = this.getComponent(entity, ComRole) if (comRole) { color = comRole.group == Data.game.gFriend ? cc.Color.GREEN : cc.Color.RED } let comSkill = this.getComponent(entity, ComSkill) if (comSkill) { color = comSkill.group == Data.game.gFriendGainSkill || comSkill.group == Data.game.gFriendHurtSkill ? cc.Color.GREEN : cc.Color.RED } comCocosNode.events.push( new EventGraphicsDraw(localPoints, cObject.type == ShapeType.Box ? 0 : cObject.radius, color), ) } } //--------------------------------移除战场上的实体------------------------------------------------- removeNodeEntity(entity: EntityIndex) { this.putNode(entity) this.removeAllComponents(entity) this.removeEntity(entity) } putNode(entity: EntityIndex) { let comCocosNode = this.getComponent(entity, ComCocosNode) if (comCocosNode) { let node = comCocosNode.node if (node) { let eventProcess = node.getComponent(EventProcess) eventProcess.onDetach() node.removeFromParent() if (this.fightCore) { let pool = this.fightCore.gamePool.get(node.name) if (pool) { this.resetGameNode(node) pool.put(node) } } } } } resetGameNode(node) { ccUtils.stopAni(node) node.stopAllActions() node.opacity = 255 node.angle = 0 node.scale = 1 node.position = cc.v2(-10000, -10000) let sprite = node.getComponent(cc.Sprite) if (sprite) sprite.spriteFrame = null let spine = node.getComponent(sp.Skeleton) if (spine) spine.skeletonData = null let frameAnimation = node.getComponent(FrameAnimation) if (frameAnimation) { frameAnimation.stop() //frameAnimation.spriteAtlas = null } if (node.name != GAME_PREFAB_TYPE.role) node.children.forEach(v => this.resetGameNode(v)) } }