FightWorld.ts 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883
  1. /** @format */
  2. import {ECSWorld} from '../lib/ECSWorld'
  3. import {IRoleConfig, RoleConfig} from '../../config/RoleConfig'
  4. import {Data, Mgr} from '../../GameControl'
  5. import {cCollider} from '../../collision/Collider'
  6. import {ComRole} from '../components/ComRole'
  7. import {ComAttackable} from '../components/ComAttackable'
  8. import {ComType, EntityIndex} from '../lib/Const'
  9. import {ComCocosNode} from '../components/ComCocosNode'
  10. import {
  11. EventGraphicsDraw,
  12. EventHurtOrAdd,
  13. EventRoleTip,
  14. EventRun,
  15. EventSlowDown,
  16. EventStand,
  17. EventType,
  18. } from '../core/NodeEvent'
  19. import {ComTransform} from '../components/ComTransform'
  20. import {ComMovable} from '../components/ComMovable'
  21. import {ComNodeConfig} from '../components/ComNodeConfig'
  22. import {IStageRolePosConfig, StageRolePosConfig} from '../../config/StageRolePosConfig'
  23. import {ComEnemy} from '../components/ComEnemy'
  24. import {ComFriend} from '../components/ComFriend'
  25. import {ISkillConfig, SkillConfig} from '../../config/SkillConfig'
  26. import {ComFindEnemy} from '../components/ComFindEnemy'
  27. import {BulletConfig} from '../../config/BulletConfig'
  28. import {ComBullet} from '../components/ComBullet'
  29. import {ComBehaviorTree} from '../components/ComBehaviorTree'
  30. import {BT} from '../../behaviorTree/BehaviorTree'
  31. import {Log} from '../../utils/LogUtils'
  32. import {
  33. ANI_TYPE,
  34. ATTR_NAME,
  35. BUFF_ANI_TYPE,
  36. BUFF_EFFECT_TYPE,
  37. BUFF_TYPE,
  38. BULLET_EFFECT_TYPE,
  39. BULLET_FLY_TYPE,
  40. BULLET_TYPE,
  41. ENTRY,
  42. GAME_LAYER,
  43. GAME_PREFAB_TYPE,
  44. GAME_ROLE_TIP,
  45. GAME_SCALE_TYPE,
  46. GAME_TYPE,
  47. GAME_WIN_TYPE,
  48. HIT_ANI_TYPE,
  49. LANGUAGE_TYPE,
  50. MONSTER_TYPE,
  51. NEGATIVE_TYPE,
  52. ROLE_TYPE,
  53. SKILL_DIR_TYPE,
  54. SKILL_EFFECT_TYPE,
  55. SKILL_TYPE,
  56. START_POS,
  57. } from '../../enums/Enum'
  58. import {BuffConfig} from '../../config/BuffConfig'
  59. import {ccUtils} from '../../utils/ccUtils'
  60. import {ComRoleSpine} from '../components/ComRoleSpine'
  61. import {EntryObj, IAttackEffect, IBuff, IFightData} from '../core/GameInterface'
  62. import {ComSkill} from '../components/ComSkill'
  63. import {ComDizzy} from '../components/ComDizzy'
  64. import {ComSkillAbel} from '../components/ComSkillAbel'
  65. import {FrameAniConfig} from '../../config/FrameAniConfig'
  66. import {ComFrameAni} from '../components/ComFrameAni'
  67. import {EntryConfig} from '../../config/EntryConfig'
  68. import {TalentConfig} from '../../config/TalentConfig'
  69. import {IBaseAttr, ICard, IRole} from '../../interface/GlobalInterface'
  70. import {ComEnter} from '../components/ComEnter'
  71. import {ArmorConfig} from '../../config/ArmorConfig'
  72. import {ConstValue} from '../../data/ConstValue'
  73. import {SysHasSkill} from '../systems/SysHasSkill'
  74. import {SysFindEnemy} from '../systems/SysFindEnemy'
  75. import {SysBullet} from '../systems/SysBullet'
  76. import {SysBehaviorTree} from '../systems/SysBehaviorTree'
  77. import {SysBuff} from '../systems/SysBuff'
  78. import {SysSkillAbel} from '../systems/SysSkillAbel'
  79. import {SysSkill} from '../systems/SysSkill'
  80. import {SysMovable} from '../systems/SysMovable'
  81. import {SysAttack} from '../systems/SysAttack'
  82. import {SysDizzy} from '../systems/SysDizzy'
  83. import {SysDie} from '../systems/SysDie'
  84. import {SysLifeTime} from '../systems/SysLifeTime'
  85. import {SysFrameAni} from '../systems/SysFrameAni'
  86. import {SysRoleState} from '../systems/SysRoleState'
  87. import {SysCocosView} from '../systems/SysCocosView'
  88. import {SysEnter} from '../systems/SysEnter'
  89. import GameUI from '../../zuma/FightCore'
  90. import {CastleSkillConfig} from '../../config/CastleSkillConfig'
  91. import {idNum} from '../../proto/typedef'
  92. import {SysCastleSkill} from '../systems/SysCastleSkill'
  93. import {ShapeType} from '../../collision/Shape'
  94. import {ComHasSkill} from '../components/ComHasSkill'
  95. import FrameAnimation from '../../uiutils/FrameAnimation'
  96. import {EventProcess} from '../core/EventProcess'
  97. import FightCore from '../../zuma/FightCore'
  98. import {ZumabuffConfig} from '../../config/ZumabuffConfig'
  99. import {RoleSpineProcess} from '../core/RoleSpineProcess'
  100. export class FightWorld extends ECSWorld {
  101. //创建单例
  102. static instance: FightWorld
  103. static getInstance() {
  104. if (!FightWorld.instance) {
  105. FightWorld.instance = new FightWorld()
  106. FightWorld.instance.createWorldCocosView()
  107. }
  108. return FightWorld.instance
  109. }
  110. fightCore: FightCore
  111. rolePosMap: Map<number, IStageRolePosConfig[]>
  112. init() {
  113. this.rolePosMap = new Map<number, IStageRolePosConfig[]>()
  114. this.rolePosMap.set(Data.game.gFriend, [])
  115. this.rolePosMap.set(Data.game.gEnemy, [])
  116. for (let key in StageRolePosConfig) {
  117. if (+key <= 100) {
  118. this.rolePosMap.get(Data.game.gEnemy).push(StageRolePosConfig[key])
  119. } else if (+key > 100 && +key <= 200) {
  120. this.rolePosMap.get(Data.game.gFriend).push(StageRolePosConfig[key])
  121. }
  122. }
  123. this.initEntry()
  124. this.fightCore.registerTouchHandler(this.getSystem(SysCocosView))
  125. }
  126. createWorldCocosView() {
  127. //添加系统顺序不能错,保证行为树的判断能正常执行
  128. this.createEntity() // 创建0号实体
  129. this.addSystem(new SysHasSkill()) // 是否有技能施放
  130. this.addSystem(new SysFindEnemy()) // 寻敌锁定
  131. this.addSystem(new SysBullet()) // 子弹系统(在移动系统之前判断)
  132. this.addSystem(new SysBehaviorTree()) // 行为树
  133. this.addSystem(new SysBuff()) // buff光环系统
  134. this.addSystem(new SysSkillAbel()) // 技能吟唱
  135. this.addSystem(new SysSkill()) // 技能持续生效
  136. this.addSystem(new SysMovable()) // 移动
  137. this.addSystem(new SysAttack()) // 攻击动作
  138. this.addSystem(new SysDizzy()) // 晕眩
  139. this.addSystem(new SysDie()) // 死亡
  140. this.addSystem(new SysLifeTime()) // 生命时间倒计时
  141. this.addSystem(new SysFrameAni()) // 特效
  142. this.addSystem(new SysRoleState()) // role state
  143. this.addSystem(new SysCocosView()) // cocos view
  144. this.addSystem(new SysEnter()) // 角色入场
  145. }
  146. //-------------------------------角色-----------------------------------------
  147. public createRoleEntity(
  148. IDOrCfg: number | IRoleConfig,
  149. isEnemy?: boolean,
  150. posCfgID?: number,
  151. iRole?: IRole,
  152. dropOutGoods?: idNum,
  153. isExtraEnemy?: boolean,
  154. ): EntityIndex {
  155. let roleCfg: IRoleConfig
  156. if (typeof IDOrCfg == 'number') {
  157. roleCfg = RoleConfig[IDOrCfg]
  158. } else {
  159. roleCfg = IDOrCfg
  160. }
  161. if (!roleCfg) {
  162. console.error('没有这个角色配置----------->', IDOrCfg)
  163. }
  164. let entity = this.createEntity()
  165. // 添加nodeconfig
  166. let comMap = this.addComponent(entity, ComNodeConfig)
  167. comMap.id = 1
  168. comMap.layer = GAME_LAYER[GAME_LAYER.role]
  169. comMap.prefabName = GAME_PREFAB_TYPE.role
  170. let entitySpine = this.createEntity()
  171. // 添加spineNode
  172. let comSpineMap = this.addComponent(entitySpine, ComNodeConfig)
  173. comSpineMap.id = 1
  174. comSpineMap.layer = GAME_LAYER[GAME_LAYER.roleSpine]
  175. comSpineMap.prefabName = GAME_PREFAB_TYPE.roleSpine
  176. //移除cocosNode
  177. this.removeComponent(entity, ComCocosNode)
  178. // 添加transform
  179. let comTrans = this.addComponent(entity, ComTransform)
  180. comTrans.x = isEnemy ? Data.game.fightSizeMaxX : Data.game.fightSizeMinX
  181. if (posCfgID > 0 && roleCfg.type != ROLE_TYPE.base) {
  182. comTrans.x = StageRolePosConfig[posCfgID].posX
  183. }
  184. let posArr = this.rolePosMap.get(isEnemy ? Data.game.gEnemy : Data.game.gFriend)
  185. //id为1的是基地
  186. comTrans.y =
  187. posCfgID > 0
  188. ? StageRolePosConfig[posCfgID].posY
  189. : roleCfg.type == ROLE_TYPE.base
  190. ? StageRolePosConfig[1].posY
  191. : posArr[Math.randomRangeInt(0, posArr.length - 1)].posY
  192. if (isEnemy) {
  193. this.addComponent(entity, ComEnemy)
  194. } else {
  195. this.addComponent(entity, ComFriend)
  196. }
  197. // 添加spineNode transform
  198. let comSpineTrans = this.addComponent(entitySpine, ComTransform)
  199. comSpineTrans.x = comTrans.x
  200. comSpineTrans.y = comTrans.y
  201. let comRoleSpine = this.addComponent(entitySpine, ComRoleSpine)
  202. comRoleSpine.roleCfg = roleCfg
  203. comRoleSpine.group = isEnemy ? Data.game.gEnemy : Data.game.gFriend
  204. let comRole = this.addComponent(entity, ComRole)
  205. comRole.roleCfg = roleCfg
  206. comRole.drop = dropOutGoods
  207. let spineData: sp.spine.SkeletonData = Data.main.roleSpineMap.get(roleCfg.url)?.getRuntimeData()
  208. comRole.width = spineData ? (spineData.width * roleCfg.gameScale[GAME_SCALE_TYPE.spine]) / 100 : 60
  209. comRole.height = spineData ? (spineData.height * roleCfg.gameScale[GAME_SCALE_TYPE.spine]) / 100 : 100
  210. comRole.spineEntity = entitySpine
  211. comTrans.halfHeight = comRole.height / 2
  212. let baseAttr: IBaseAttr = iRole ? iRole : roleCfg
  213. Mgr.global.changeBaseAttr(comRole, baseAttr)
  214. comRole.attackRange = roleCfg.attackRange
  215. comRole.attackCD = roleCfg.attackCD == Data.game.cdMax ? Infinity : roleCfg.attackCD
  216. comRole.killNum = 0
  217. comRole.attackNum = 0
  218. comRole.group = isEnemy ? Data.game.gEnemy : Data.game.gFriend
  219. comRole.skills.length = 0
  220. comRole.skillCDs.length = 0
  221. comRole.enterCDs.length = 0
  222. comRole.skillCountDowns.length = 0
  223. comRole.babys.length = 0
  224. comRole.parent = 0
  225. comRole.parentRoleID = 0
  226. comRole.HPDirty = true
  227. comRole.transDirty = false
  228. comRole.transID = 0
  229. comRole.buffs.length = 0
  230. comRole.entryMap.clear()
  231. comRole.equips = null
  232. //所有技能
  233. let allSkill = []
  234. let allSkillCDs = []
  235. let allEnterCDs = []
  236. //人物技能
  237. roleCfg.skills.forEach((skill, index) => {
  238. if (skill) {
  239. allSkill.push(skill)
  240. allSkillCDs.push(roleCfg.skillCDs[index])
  241. allEnterCDs.push(roleCfg.enterCDs[index])
  242. }
  243. })
  244. //天赋词条
  245. for (let id of Data.user.talents) {
  246. this.putEntry2Map(comRole, this.convertEntry2Obj(TalentConfig[id].entryID))
  247. }
  248. //装备词条
  249. if (iRole) {
  250. comRole.equips = iRole.equips
  251. for (let iEquip of iRole.equips) {
  252. if (iEquip) {
  253. if (iEquip.cfg.entry && iEquip.cfg.entry < ENTRY.textShow) {
  254. for (let i = 1; i <= iEquip.cfg.quality; i++) {
  255. let ID = Math.floor(iEquip.cfg.ID / 100) * 100 + i
  256. if (ArmorConfig[ID.toString()].entry)
  257. this.putEntry2Map(comRole, this.convertEntry2Obj(ArmorConfig[ID.toString()].entry))
  258. }
  259. }
  260. //装备技能
  261. iEquip.cfg.skills?.forEach((skill, index) => {
  262. if (skill) {
  263. allSkill.push(skill)
  264. allSkillCDs.push(iEquip.cfg.skillCDs[index])
  265. allEnterCDs.push(iEquip.cfg.enterCDs[index])
  266. }
  267. })
  268. }
  269. }
  270. }
  271. //遗迹词条
  272. if (Data.game.gameType == GAME_TYPE.relic) {
  273. //基础属性
  274. if (Data.main.relicAdd[roleCfg.profession]) {
  275. let keys = Object.keys(ATTR_NAME)
  276. for (let attrKey of keys) {
  277. if (Data.main.relicAdd[roleCfg.profession][attrKey]) {
  278. comRole[attrKey] *= 1 + Data.main.relicAdd[roleCfg.profession][attrKey] / Data.game.rateNum
  279. }
  280. }
  281. }
  282. for (let entry of Data.game.relicEntryArr) {
  283. this.putEntry2Map(comRole, this.convertEntry2Obj(entry))
  284. }
  285. }
  286. if (comRole.entryMap.get(ENTRY.startShieldHP)?.num) {
  287. comRole.shieldHP = comRole.entryMap.get(ENTRY.startShieldHP).num
  288. }
  289. allSkill.forEach((skill, index) => {
  290. if (skill && SkillConfig[skill]) {
  291. comRole.skills.push(SkillConfig[skill])
  292. comRole.skillCDs.push(allSkillCDs[index])
  293. comRole.enterCDs.push(allEnterCDs[index])
  294. let cd = allSkillCDs[index]
  295. if (cd == Data.game.cdMax) cd = Infinity
  296. if (cd > 0 && cd != Infinity && comRole.entryMap.get(ENTRY.skillCD)?.num) {
  297. cd *= 1 - comRole.entryMap.get(ENTRY.skillCD).num / Data.game.rateNum
  298. if (cd < 0) cd = 0
  299. }
  300. //入场CD
  301. let enterCD = allEnterCDs[index]
  302. comRole.skillCountDowns.push(enterCD > 0 && cd != Infinity ? enterCD : cd)
  303. } else {
  304. console.error('没有这个技能配置----------->', allSkill[index])
  305. }
  306. })
  307. let attackTime = Infinity
  308. let castTime = new Array(allSkill.length).fill(0) //spine没有技能动作
  309. let enterTime = 0
  310. let dieTime = 0
  311. if (spineData) {
  312. if (spineData.findAnimation('skill') && castTime.length > 0) {
  313. castTime[0] = spineData.findAnimation('skill').duration
  314. }
  315. for (let i = 1; i <= roleCfg.skills.length; i++) {
  316. if (spineData.findAnimation(`skill${i}`)) {
  317. castTime[i - 1] = spineData.findAnimation(`skill${i}`).duration
  318. } else {
  319. castTime[i - 1] = castTime[0]
  320. }
  321. }
  322. if (spineData.findAnimation('enter')) {
  323. enterTime = spineData.findAnimation('enter').duration
  324. }
  325. if (spineData.findAnimation('attack')) {
  326. attackTime = spineData.findAnimation('attack').duration
  327. }
  328. if (spineData.findAnimation('die')) {
  329. dieTime = spineData.findAnimation('die').duration
  330. }
  331. }
  332. comRole.attackTime = attackTime
  333. comRole.castTime = castTime
  334. comRole.enterTime = enterTime
  335. comRole.dieTime = dieTime
  336. //血量等词条装备处理完后处理
  337. comRole.nowHP = comRole.HP
  338. comRole.lastHP = comRole.HP
  339. comRole.shieldHP = 0
  340. comRole.lastShieldHP = 0
  341. comRole.isExtraEnemy = isExtraEnemy
  342. //处理gameUI显示
  343. if (this.fightCore) {
  344. let entities = this.fightCore.roleEntityMap.get(roleCfg.ID)
  345. if (!entities) {
  346. entities = []
  347. this.fightCore.roleEntityMap.set(roleCfg.ID, entities)
  348. }
  349. entities.push(entity)
  350. if (roleCfg.type == MONSTER_TYPE.boss) {
  351. if (this.fightCore.stageInfo.type == GAME_WIN_TYPE.boss) {
  352. }
  353. this.fightCore.showBossHP(comRole)
  354. }
  355. }
  356. return entity
  357. }
  358. setRoleHP(entity, HP) {
  359. if (!HP) return
  360. let comRole = this.getComponent(entity, ComRole)
  361. if (!comRole) return
  362. comRole.HP = HP
  363. comRole.lastHP = HP
  364. comRole.nowHP = HP
  365. }
  366. public initRoleBehavior(comBehavior: ComBehaviorTree, roleConfig: IRoleConfig) {
  367. let findEnemyNode = new BT.FindEnemyNode()
  368. let meleeMonitorNode = new BT.MeleeMonitorNode()
  369. let meleeXMonitorNode = new BT.MeleeXMonitorNode()
  370. let attackMonitorNode = new BT.AttackMonitorNode()
  371. let attackNode = new BT.AttackNode()
  372. let meleeWalkToTargetNode = new BT.MeleeWalkToTargetNode(roleConfig.moveSpeed * 1.5)
  373. let stopNode = new BT.StopNode()
  374. let hasAttackEnemy = new BT.HasAttackEnemyNode()
  375. let hasBeAttackNode = new BT.HasBeAttackNode()
  376. let willAttackNode = new BT.WillAttackNode()
  377. let willBeAttackNode = new BT.WillBeAttackNode()
  378. let willAttackNotWillAttackNode = new BT.WillAttackNotWillAttackNode()
  379. let stopAttackNode = new BT.StopAttackNode()
  380. let beDizzyNode = new BT.BeDizzyNode()
  381. let notBeDizzyNode = new BT.InverterNode(new BT.BeDizzyNode())
  382. let dizzyNode = new BT.DizzyNode()
  383. let skillNode = new BT.SkillNode()
  384. let hasSkillNode = new BT.HasSkillNode()
  385. let walkToCloseXTargetNode = new BT.WalkToCloseTargetNode(roleConfig.moveSpeed, true)
  386. let walkToCloseTargetNode = new BT.WalkToCloseTargetNode(roleConfig.moveSpeed, false)
  387. let notFindEnemyNode = new BT.InverterNode(findEnemyNode)
  388. let notMeleeMonitorNode = new BT.InverterNode(meleeMonitorNode)
  389. let notMeleeXMonitorNode = new BT.InverterNode(meleeXMonitorNode)
  390. let notAttackMonitorNode = new BT.InverterNode(attackMonitorNode)
  391. let notHasAttackEnemy = new BT.InverterNode(hasAttackEnemy)
  392. let notWillBeAttackNode = new BT.InverterNode(willBeAttackNode)
  393. let notWillAttackNode = new BT.InverterNode(willAttackNode)
  394. let notHasBeAttackNode = new BT.InverterNode(hasBeAttackNode)
  395. let notHasSkillNode = new BT.InverterNode(hasSkillNode)
  396. let notCastSkillNode = new BT.InverterNode(new BT.CastSkillNode())
  397. let stopSkillNode = new BT.StopSkillNode()
  398. let shootRoot = new BT.RootSelectorNode(
  399. [
  400. // 晕眩
  401. new BT.SequenceNode([beDizzyNode, stopNode, stopSkillNode, stopAttackNode, dizzyNode]),
  402. // 放技能
  403. new BT.SequenceNode([notBeDizzyNode, hasSkillNode, stopNode, stopAttackNode, skillNode]),
  404. // 远程攻击范围有敌人,攻击最近的敌人
  405. new BT.SequenceNode([notBeDizzyNode, attackMonitorNode, stopNode, attackNode]),
  406. // 远程攻击范围没有敌人,场上有敌军, 往最近敌方X轴方向移动
  407. new BT.SequenceNode([
  408. notBeDizzyNode,
  409. notHasSkillNode,
  410. findEnemyNode,
  411. notAttackMonitorNode,
  412. walkToCloseTargetNode,
  413. ]),
  414. // 没有敌人停止移动
  415. new BT.SequenceNode([notFindEnemyNode, stopNode]),
  416. ],
  417. false,
  418. )
  419. let meleeRoot = new BT.RootSelectorNode([
  420. // 晕眩
  421. new BT.SequenceNode([beDizzyNode, stopNode, stopSkillNode, stopAttackNode, dizzyNode]),
  422. // 放技能
  423. new BT.SequenceNode([notBeDizzyNode, hasSkillNode, stopNode, stopAttackNode, skillNode]),
  424. // X轴Y轴近战探测范围没有敌人,场上有敌军, 往最近敌方X轴方向移动
  425. new BT.SequenceNode([
  426. notBeDizzyNode,
  427. notHasSkillNode,
  428. findEnemyNode,
  429. notHasAttackEnemy,
  430. notWillBeAttackNode,
  431. notWillAttackNode,
  432. notMeleeXMonitorNode,
  433. notMeleeMonitorNode,
  434. walkToCloseXTargetNode,
  435. ]),
  436. // X轴近战探测范围有敌人,往最近敌方X轴方向移动,直到进入攻击范围
  437. new BT.SequenceNode([
  438. notBeDizzyNode,
  439. notHasSkillNode,
  440. findEnemyNode,
  441. notHasAttackEnemy,
  442. notWillBeAttackNode,
  443. notWillAttackNode,
  444. meleeXMonitorNode,
  445. walkToCloseXTargetNode,
  446. ]),
  447. // X轴近战攻击范围没有敌人,没有被近战即将攻击, 往最近Y轴的敌方方向移动
  448. new BT.SequenceNode([
  449. notBeDizzyNode,
  450. notHasSkillNode,
  451. findEnemyNode,
  452. notHasAttackEnemy,
  453. notWillBeAttackNode,
  454. notWillAttackNode,
  455. notMeleeXMonitorNode,
  456. meleeMonitorNode,
  457. walkToCloseTargetNode,
  458. ]),
  459. // 自己即将被攻击,停止
  460. new BT.SequenceNode([notBeDizzyNode, notHasSkillNode, notHasAttackEnemy, willBeAttackNode, stopNode]),
  461. // 自己即将攻击敌人,跑到攻击点
  462. new BT.SequenceNode([
  463. notBeDizzyNode,
  464. notHasAttackEnemy,
  465. // notHasBeAttackNode,
  466. willAttackNode,
  467. willAttackNotWillAttackNode,
  468. meleeWalkToTargetNode,
  469. ]),
  470. // 到达了攻击地点,继续攻击
  471. new BT.SequenceNode([notBeDizzyNode, hasAttackEnemy, stopNode, attackNode]),
  472. // 停止移动
  473. new BT.SequenceNode([notFindEnemyNode, stopNode]),
  474. ])
  475. comBehavior.root = roleConfig.attackRange > Data.game.meleeRange ? shootRoot : meleeRoot
  476. if (roleConfig.attackRange == 0) comBehavior.root = null
  477. }
  478. public changeMoveSpeed(entity: EntityIndex, speed: number) {
  479. let comMovable = this.getComponent(entity, ComMovable)
  480. let comCocosNode = this.getComponent(entity, ComCocosNode)
  481. let comRole = this.getComponent(entity, ComRole)
  482. let comFriend = this.getComponent(entity, ComFriend)
  483. if (!comMovable || !comCocosNode) return
  484. let isChange = comMovable.speed != speed || comFriend
  485. comMovable.speed = speed
  486. //同步spine战立和移动
  487. let comSpineNode = this.getComponent(comRole?.spineEntity, ComCocosNode)
  488. if (comMovable.speed > 0) {
  489. isChange && comCocosNode.events.push(new EventRun()) && comSpineNode?.events.push(new EventRun())
  490. } else {
  491. comMovable.points.length = 0
  492. comMovable.pointIdx = 0
  493. isChange && comCocosNode.events.push(new EventStand()) && comSpineNode?.events.push(new EventStand())
  494. }
  495. }
  496. public changeRoleRun(entity: EntityIndex, isRun: boolean) {
  497. let comRole = this.getComponent(entity, ComRole)
  498. if (!comRole) return
  499. let comSpineNode = this.getComponent(comRole.spineEntity, ComCocosNode)
  500. comSpineNode?.node.getComponent(RoleSpineProcess).processEvent(isRun ? new EventRun() : new EventStand())
  501. }
  502. isDie(idOrCom: EntityIndex | ComRole) {
  503. let comRole: ComRole
  504. if (typeof idOrCom == 'number') {
  505. if (!idOrCom) return true
  506. comRole = this.getComponent(idOrCom, ComRole)
  507. } else {
  508. comRole = idOrCom
  509. }
  510. return !comRole || comRole.nowHP + comRole.shieldHP <= 0
  511. }
  512. isEnter(id: EntityIndex) {
  513. let comEnter = this.getComponent(id, ComEnter)
  514. return comEnter != null
  515. }
  516. isBase(idOrCom: EntityIndex | ComRole) {
  517. return this.isRoleType(idOrCom, ROLE_TYPE.base)
  518. }
  519. isBoss(idOrCom: EntityIndex | ComRole) {
  520. return this.isRoleType(idOrCom, MONSTER_TYPE.boss)
  521. }
  522. isRoleType(idOrCom: EntityIndex | ComRole, type: ROLE_TYPE | MONSTER_TYPE) {
  523. let comRole: ComRole
  524. if (typeof idOrCom == 'number') {
  525. if (!idOrCom) return false
  526. comRole = this.getComponent(idOrCom, ComRole)
  527. } else {
  528. comRole = idOrCom
  529. }
  530. return !comRole || comRole.roleCfg.type === type
  531. }
  532. //-------------------------战斗扣血加血-----------------------------------------------
  533. //扣血
  534. changeHpByHurt(role: EntityIndex, hurtHP: number, isCrit: boolean, HitAniID: number) {
  535. if (!hurtHP) return
  536. let changeHPRole = this.getComponent(role, ComRole)
  537. if (changeHPRole.invincible) return
  538. let changeHPComCocosNode = this.getComponent(role, ComCocosNode)
  539. changeHPRole.lastHP = changeHPRole.nowHP
  540. changeHPRole.lastShieldHP = changeHPRole.shieldHP
  541. changeHPComCocosNode.events.push(
  542. new EventRoleTip(
  543. isCrit ? GAME_ROLE_TIP.critTip : GAME_ROLE_TIP.damageTip,
  544. -hurtHP,
  545. `-${Math.toKMBNum(hurtHP)}`,
  546. ),
  547. )
  548. let comSpineNode = this.getComponent(changeHPRole.spineEntity, ComCocosNode)
  549. comSpineNode?.events.push(new EventHurtOrAdd(-hurtHP, isCrit))
  550. if (changeHPRole.shieldHP > 0) {
  551. changeHPRole.shieldHP -= hurtHP
  552. if (changeHPRole.shieldHP < 0) {
  553. changeHPRole.nowHP += changeHPRole.shieldHP
  554. changeHPRole.shieldHP = 0
  555. }
  556. } else {
  557. changeHPRole.nowHP -= hurtHP
  558. }
  559. changeHPRole.HPDirty = true
  560. if (!this.isBase(changeHPRole) && changeHPRole.roleCfg.type != ROLE_TYPE.totem && HitAniID > 0) {
  561. this.createAni(HitAniID, role)
  562. }
  563. }
  564. getDefenseRate(defenseObj: IFightData, attackObj?: IFightData) {
  565. let ignoreDefenseE = attackObj?.entryMap.get(ENTRY.ignoreDefense)?.num || 0
  566. return (
  567. 1 -
  568. (defenseObj.defense * (1 - ignoreDefenseE / Data.game.rateNum)) /
  569. (defenseObj.defense + Data.game.defenseConst)
  570. )
  571. }
  572. getSpellDefenseRate(fightData: IFightData, attackObj?: IFightData) {
  573. let ignoreDefenseE = attackObj?.entryMap.get(ENTRY.ignoreDefense)?.num || 0
  574. return (
  575. 1 -
  576. (fightData.spellDefense * (1 - ignoreDefenseE / Data.game.rateNum)) /
  577. (fightData.spellDefense + Data.game.defenseConst)
  578. )
  579. }
  580. //攻击扣血值
  581. getHurtByAttackRole(attackObj: IFightData, role: EntityIndex, attackEffect: IAttackEffect): number {
  582. let hurtHP = 0
  583. let changeHPRole = this.getComponent(role, ComRole)
  584. let changeHPComCocosNode = this.getComponent(role, ComCocosNode)
  585. if (this.isDie(changeHPRole) || !changeHPComCocosNode || !changeHPComCocosNode.loaded) return hurtHP
  586. let critAddAttack = 0
  587. let rateNum = Data.game.rateNum
  588. let attack = attackObj.attack
  589. let spellAttack = attackObj.spellAttack
  590. let realAttack = attackObj.realAttack
  591. // 所有的比例加伤
  592. let hurtAddRate = 0
  593. let realHurtAdd: number = 0
  594. attackObj.buffs.forEach(buff => {
  595. let buffConfig = buff.buffCfg
  596. if (buffConfig.buffType == BUFF_TYPE.backAddHurt && attackEffect.isBack) {
  597. //后背加伤(万分比)
  598. hurtAddRate += buffConfig.attrRate[0]
  599. } else if (buffConfig.buffType == BUFF_TYPE.realByHp) {
  600. //血量比例加真实攻击(万分比)
  601. realHurtAdd += attackObj.nowHP * (buffConfig.attrRate[0] / rateNum)
  602. } else if (
  603. buffConfig.buffType == BUFF_TYPE.attackNumAddHurt &&
  604. attackObj.attackNum % buffConfig.attrNum[0] == 0
  605. ) {
  606. //N弹加伤(万分比)
  607. hurtAddRate += buffConfig.attrRate[0]
  608. }
  609. })
  610. //普攻对boss加伤
  611. if (attackObj.entryMap.get(ENTRY.boosHurt)?.num && changeHPRole.roleCfg.type == MONSTER_TYPE.boss) {
  612. hurtAddRate += attackObj.entryMap.get(ENTRY.boosHurt).num
  613. }
  614. changeHPRole.buffs.forEach(buff => {
  615. let buffConfig = buff.buffCfg
  616. if (buffConfig.buffType == BUFF_TYPE.shieldReduceHurt) {
  617. //顶盾减伤(万分比)
  618. hurtAddRate += buffConfig.attrRate[0]
  619. } else if (buffConfig.buffType == BUFF_TYPE.hurtRateChange) {
  620. //伤害减免(万分比)
  621. hurtAddRate += buffConfig.attrRate[0]
  622. }
  623. })
  624. //暴击
  625. if (attackEffect.isCrit) {
  626. attack *= attackObj.critNum / rateNum
  627. spellAttack *= attackObj.critNum / rateNum
  628. realAttack *= attackObj.critNum / rateNum
  629. }
  630. //溅射
  631. if (attackEffect.sputter) {
  632. attack *= attackEffect.sputter / rateNum
  633. spellAttack *= attackEffect.sputter / rateNum
  634. realAttack *= attackEffect.sputter / rateNum
  635. }
  636. if (attack || spellAttack || realAttack) {
  637. //物理伤害 物理攻击*(1-物理防御/(物理防御+防御常数))
  638. let hurt = attack * this.getDefenseRate(changeHPRole, attackObj)
  639. //魔法伤害 魔法攻击*(1-魔法防御/(魔法防御+防御常数))
  640. let spellHurt = spellAttack * this.getSpellDefenseRate(changeHPRole, attackObj)
  641. //真实伤害 真实攻击
  642. let realHurt = realAttack
  643. realHurt += realHurtAdd
  644. let endHurtRate = 1 + hurtAddRate / rateNum
  645. if (endHurtRate < 0) endHurtRate = 0
  646. hurtHP = (hurt + spellHurt + realHurt) * (1 + Data.game.curHurtRate / rateNum) * endHurtRate
  647. }
  648. //普攻减伤
  649. if (changeHPRole.entryMap.get(ENTRY.hurtReduce)?.num > 0) {
  650. hurtHP -= changeHPRole.entryMap.get(ENTRY.hurtReduce).num
  651. }
  652. if (hurtHP < 0) hurtHP = 0
  653. return hurtHP
  654. }
  655. //技能加减血
  656. changeHpBySkill(skill: ComSkill, role: EntityIndex) {
  657. let changeHPRole = this.getComponent(role, ComRole)
  658. let changeHPComCocosNode = this.getComponent(role, ComCocosNode)
  659. if (
  660. this.isDie(changeHPRole) ||
  661. (this.isBase(changeHPRole) && !skill.skillCfg.effectType.includes(SKILL_EFFECT_TYPE.hurtBase)) ||
  662. changeHPRole.invincible ||
  663. !changeHPComCocosNode ||
  664. !changeHPComCocosNode.loaded
  665. )
  666. return
  667. let fightData = skill.fightData
  668. if (
  669. (skill.skillCfg.type == SKILL_TYPE.normal || skill.skillCfg.type == SKILL_TYPE.attackBack) &&
  670. skill.skillCfg.hurtRate
  671. ) {
  672. let rateNum = Data.game.rateNum
  673. let hurtHP = 0
  674. let attack = fightData.attack
  675. let spellAttack = fightData.spellAttack
  676. let realAttack = fightData.realAttack
  677. let hurtAddRate = skill.skillCfg.hurtRate
  678. //技能加伤
  679. if (fightData.entryMap.get(ENTRY.skillHurtRate)?.num) {
  680. hurtAddRate += fightData.entryMap.get(ENTRY.skillHurtRate).num
  681. }
  682. //技能对boss加伤
  683. if (fightData.entryMap.get(ENTRY.boosHurt)?.num && changeHPRole.roleCfg.type == MONSTER_TYPE.boss) {
  684. hurtAddRate += fightData.entryMap.get(ENTRY.boosHurt).num
  685. }
  686. //自身buff加伤
  687. for (let j = 0; j < fightData.buffs.length; j++) {
  688. let buffCfg = fightData.buffs[j].buffCfg
  689. if (buffCfg.buffType == BUFF_TYPE.skillHurt && buffCfg.attrRate[skill.skillIndex]) {
  690. hurtAddRate += buffCfg.attrRate[skill.skillIndex]
  691. }
  692. }
  693. //受击者buff减伤
  694. changeHPRole.buffs.forEach(buff => {
  695. let buffConfig = buff.buffCfg
  696. if (buffConfig.buffType == BUFF_TYPE.hurtRateChange) {
  697. //伤害减免(万分比)
  698. hurtAddRate += buffConfig.attrRate[0]
  699. }
  700. })
  701. if (attack || spellAttack || realAttack) {
  702. //物理伤害 物理攻击*(1-物理防御/(物理防御+防御常数))
  703. let hurt = attack * this.getDefenseRate(changeHPRole)
  704. //魔法伤害 魔法攻击*(1-魔法防御/(魔法防御+防御常数))
  705. let spellHurt = spellAttack * this.getSpellDefenseRate(changeHPRole)
  706. //真实伤害 真实攻击
  707. let realHurt = realAttack
  708. hurtHP = (hurt + spellHurt + realHurt) * (1 + Data.game.curHurtRate / rateNum) * (hurtAddRate / rateNum)
  709. }
  710. //技能减伤
  711. if (changeHPRole.entryMap.get(ENTRY.hurtReduce)?.num > 0) {
  712. hurtHP -= changeHPRole.entryMap.get(ENTRY.hurtReduce).num
  713. }
  714. if (hurtHP < 0) hurtHP = 0
  715. //受击特效统一处理,这里是0
  716. this.changeHpByHurt(role, hurtHP, false, 0)
  717. }
  718. let addNum = 0
  719. if (skill.skillCfg.type == SKILL_TYPE.addHP) {
  720. addNum = (skill.skillCfg.hurtRate / Data.game.rateNum) * fightData.spellAttack
  721. let moreAddNum = 0
  722. if (addNum + changeHPRole.nowHP > changeHPRole.HP) {
  723. moreAddNum = addNum + changeHPRole.nowHP - changeHPRole.HP
  724. addNum = changeHPRole.HP - changeHPRole.nowHP
  725. }
  726. for (let i = 0; i < skill.skillCfg.effectType.length; i++) {
  727. if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addExtraHP) {
  728. if (changeHPRole.nowHP / changeHPRole.HP < skill.skillCfg.effectParm[i][0] / Data.game.rateNum) {
  729. addNum += skill.skillCfg.effectParm[i][1]
  730. }
  731. } else if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addRateHP) {
  732. addNum += (skill.skillCfg.effectParm[i][0] / Data.game.rateNum) * changeHPRole.HP
  733. }
  734. }
  735. //增加治疗量
  736. if (fightData.entryMap.get(ENTRY.addHealing)?.num) {
  737. addNum *= 1 + fightData.entryMap.get(ENTRY.addHealing).num / Data.game.rateNum
  738. }
  739. //受治疗增加量
  740. if (changeHPRole.entryMap.get(ENTRY.healingMore)?.num) {
  741. addNum *= 1 + changeHPRole.entryMap.get(ENTRY.healingMore).num / Data.game.rateNum
  742. }
  743. //多的治疗量转为白血盾
  744. if (changeHPRole.entryMap.get(ENTRY.healing2Shield)?.num && moreAddNum) {
  745. changeHPRole.shieldHP +=
  746. (changeHPRole.entryMap.get(ENTRY.healing2Shield).num / Data.game.rateNum) * moreAddNum
  747. }
  748. this.addHP(addNum, role)
  749. }
  750. if (
  751. skill.skillCfg.type == SKILL_TYPE.addShieldHPByHP ||
  752. skill.skillCfg.type == SKILL_TYPE.addShieldHPBySpAttack
  753. ) {
  754. addNum =
  755. (skill.skillCfg.hurtRate / Data.game.rateNum) *
  756. (skill.skillCfg.type == SKILL_TYPE.addShieldHPByHP ? fightData.HP : fightData.spellAttack)
  757. if (changeHPRole.shieldHP < addNum) changeHPRole.shieldHP = addNum
  758. if (skill.skillCfg.type == SKILL_TYPE.addShieldHPBySpAttack) {
  759. for (let i = 0; i < skill.skillCfg.effectType.length; i++) {
  760. if (skill.skillCfg.effectType[i] == SKILL_EFFECT_TYPE.addRateShieldHP) {
  761. addNum += (skill.skillCfg.effectParm[i][0] / Data.game.rateNum) * changeHPRole.HP
  762. }
  763. }
  764. }
  765. }
  766. changeHPRole.HPDirty = true
  767. }
  768. changeHpByRebound(role: EntityIndex, enemy: EntityIndex) {
  769. let comRoleEnemy: ComRole = this.getComponent(enemy, ComRole)
  770. let comRole: ComRole = this.getComponent(enemy, ComRole)
  771. if (this.isDie(comRoleEnemy)) return
  772. comRoleEnemy.buffs.forEach(buff => {
  773. let buffType = buff.buffCfg.buffType
  774. if (buffType == BUFF_TYPE.reboundAttack || buffType == BUFF_TYPE.reboundReal) {
  775. //真实伤害
  776. let defenseRate = 1
  777. if (buffType == BUFF_TYPE.reboundAttack) {
  778. //物理伤害
  779. defenseRate = this.getDefenseRate(comRole, comRoleEnemy)
  780. }
  781. let hurt = (comRoleEnemy.attack * defenseRate * buff.buffCfg.attrRate[0]) / Data.game.rateNum
  782. this.changeHpByHurt(role, hurt, false, 0)
  783. }
  784. })
  785. if (comRoleEnemy.entryMap.get(ENTRY.hurtRebound)?.num) {
  786. let defenseRate = this.getDefenseRate(comRole, comRoleEnemy)
  787. let hurt =
  788. (comRoleEnemy.attack * defenseRate * comRoleEnemy.entryMap.get(ENTRY.hurtRebound)?.num) /
  789. Data.game.rateNum
  790. this.changeHpByHurt(role, hurt, false, 0)
  791. }
  792. }
  793. moveToMeleeAttackPos(
  794. selfEntity: EntityIndex,
  795. comTrans: ComTransform,
  796. targetComTrans: ComTransform,
  797. targetComMovable: ComMovable,
  798. isBack?: boolean,
  799. ) {
  800. let targetPos = cc.v2(targetComTrans.x, targetComTrans.y)
  801. // 近战前往目标敌人没被锁定的某一个近战范围攻击点
  802. let isLeft = comTrans.x - targetComTrans.x < 0
  803. if (isBack) isLeft = !isLeft
  804. if (targetComTrans.x >= Data.game.fightSizeMaxX) {
  805. isLeft = true
  806. }
  807. if (targetComTrans.x <= Data.game.fightSizeMinX) {
  808. isLeft = false
  809. }
  810. let isDown = comTrans.y - targetComTrans.y < 0
  811. let attackArrayPos = isLeft ? Data.game.attackLeftRadiusPoints : Data.game.attackRightRadiusPoints
  812. let curAttackArrayPos = isLeft
  813. ? targetComMovable.leftMeleeEnemiesPosDirty
  814. : targetComMovable.rightMeleeEnemiesPosDirty
  815. let posIndex = curAttackArrayPos.indexOf(-1)
  816. let secondPosIndex = curAttackArrayPos.indexOf(-1, posIndex + 1)
  817. let targetIndex
  818. //因为leftMeleeEnemiesPosDirty数组是上下位置交替插入的,所以找出离自己近的点
  819. if (posIndex >= 0 && secondPosIndex > 0) {
  820. if (isDown) {
  821. targetIndex = attackArrayPos[posIndex].y < 0 ? posIndex : secondPosIndex
  822. } else {
  823. targetIndex = attackArrayPos[posIndex].y >= 0 ? posIndex : secondPosIndex
  824. }
  825. } else if (posIndex >= 0 && secondPosIndex <= 0) {
  826. targetIndex = posIndex
  827. } else {
  828. targetIndex = Math.randomRangeInt(0, attackArrayPos.length - 1)
  829. }
  830. curAttackArrayPos[targetIndex] = selfEntity
  831. targetPos.addSelf(attackArrayPos[targetIndex])
  832. if (targetPos.y <= Data.game.fightSizeMinY) targetPos.y = Data.game.fightSizeMinY
  833. if (targetPos.y >= Data.game.fightSizeMaxY) targetPos.y = Data.game.fightSizeMaxY
  834. return targetPos
  835. }
  836. //加血吸血
  837. addHP(addHPNum: number, role: EntityIndex) {
  838. let comRole = this.getComponent(role, ComRole)
  839. let comCocosNode = this.getComponent(role, ComCocosNode)
  840. if (!this.isDie(role)) {
  841. if (addHPNum >= 1) {
  842. comCocosNode.events.push(new EventRoleTip(GAME_ROLE_TIP.hpTip, addHPNum, `+${Math.toKMBNum(addHPNum)}`))
  843. }
  844. let target = comRole.nowHP + addHPNum
  845. if (target > comRole.HP) {
  846. addHPNum = comRole.HP - comRole.nowHP
  847. }
  848. comRole.nowHP += addHPNum
  849. }
  850. }
  851. //-------------------------------子弹-----------------------------------------
  852. public createBulletEntity(role: EntityIndex, isCrit: boolean): EntityIndex[] {
  853. let comRole = this.getComponent(role, ComRole)
  854. let comTransform = this.getComponent(role, ComTransform)
  855. let comFindEnemy = this.getComponent(role, ComFindEnemy)
  856. let comAttackable = this.getComponent(role, ComAttackable)
  857. let entities = []
  858. if (this.isDie(comRole)) {
  859. //Log.warn('创建子弹失败')
  860. return entities
  861. }
  862. let bulletID = comRole.roleCfg.bullet
  863. if (!bulletID) {
  864. return entities
  865. }
  866. let bulletCfg = BulletConfig[bulletID]
  867. let enemies = [comAttackable.curAttack]
  868. let endPosArr: cc.Vec2[] = []
  869. //跟踪敌人改成固定角度
  870. if (bulletCfg.splitNum > 1) {
  871. // let otherEnemies = comFindEnemy.attackCObject.containsBody.keysArr()
  872. // otherEnemies = otherEnemies.filter(
  873. // v =>
  874. // Math.sign(comTransform.dir.x) != Math.sign(this.getComponent(v, ComTransform)?.dir.x) &&
  875. // v != comAttackable.curAttack,
  876. // )
  877. //
  878. // otherEnemies.sort((a, b) => {
  879. // let at = this.getComponent(a, ComTransform)
  880. // let bt = this.getComponent(b, ComTransform)
  881. // return at.x ** 2 + at.y ** 2 - (bt.x ** 2 + bt.y ** 2)
  882. // })
  883. // enemies = enemies.concat(otherEnemies)
  884. let enemyComTransform = this.getComponent(enemies[0], ComTransform)
  885. let startPos = cc.v2(comTransform.x, comTransform.y + comTransform.halfHeight)
  886. let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight)
  887. for (let i = 1; i < bulletCfg.splitNum; i++) {
  888. endPosArr.push(this.rotatePoint(startPos, hitPos, 10 * i * (i % 2 == 0 ? -1 : 1)))
  889. }
  890. }
  891. for (let i = 0; i < bulletCfg.splitNum; i++) {
  892. //if (i < enemies.length) {
  893. let enemyComTransform = this.getComponent(enemies[i], ComTransform)
  894. if (!enemyComTransform) {
  895. enemyComTransform = new ComTransform()
  896. enemyComTransform.x = endPosArr[i - 1].x
  897. enemyComTransform.y = endPosArr[i - 1].y
  898. }
  899. let entity = this.createEntity()
  900. // 添加nodeconfig
  901. let comMap = this.addComponent(entity, ComNodeConfig)
  902. comMap.id = 1
  903. comMap.layer = GAME_LAYER[GAME_LAYER.bullet]
  904. comMap.prefabName = GAME_PREFAB_TYPE.bullet
  905. //移除cocosNode
  906. this.removeComponent(entity, ComCocosNode)
  907. // 添加transform
  908. let comTrans = this.addComponent(entity, ComTransform)
  909. let bulletPosScaleX = comTransform.dir.x >= 0 ? 1 : -1
  910. let spineScale = comRole.roleCfg.gameScale[GAME_SCALE_TYPE.spine] / 100
  911. comTrans.x = comTransform.x + comRole.roleCfg.bulletPos[0] * bulletPosScaleX * spineScale
  912. comTrans.y = comTransform.y + comRole.roleCfg.bulletPos[1] * spineScale
  913. let comMovable = this.addComponent(entity, ComMovable)
  914. comMovable.speed = 0
  915. let comBullet = this.addComponent(entity, ComBullet)
  916. comBullet.group = comRole.group == Data.game.gFriend ? Data.game.gFriendBullet : Data.game.gEnemyBullet
  917. comBullet.fightData = {...comRole, roleEntity: role}
  918. comBullet.fightData.buffs = ccUtils.deepCopy(comRole.buffs)
  919. comBullet.bulletCfg = bulletCfg
  920. comBullet.ejectionEnemies.length = 0
  921. comBullet.ejectionEnemy = enemies[i] ? enemies[i] : 0
  922. comBullet.hitEnemies.length = 0
  923. comBullet.isCrit = isCrit
  924. this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet)
  925. entities.push(entity)
  926. // }
  927. }
  928. return entities
  929. }
  930. public createRoleSkillBulletEntity(
  931. skillConfig: ISkillConfig,
  932. bulletID: number,
  933. createEntity: EntityIndex,
  934. enemy: EntityIndex,
  935. randomPos: boolean = false,
  936. pos?: cc.Vec2,
  937. ): EntityIndex[] {
  938. let bulletCfg = BulletConfig[bulletID]
  939. let roleComTransform = this.getComponent(createEntity, ComTransform)
  940. let enemyComTransform = this.getComponent(enemy, ComTransform)
  941. if (pos) {
  942. enemyComTransform = new ComTransform()
  943. enemyComTransform.x = pos.x
  944. enemyComTransform.y = pos.y
  945. }
  946. if (!enemyComTransform || !bulletCfg) {
  947. return
  948. }
  949. let endPosArr: cc.Vec2[] = []
  950. //跟踪敌人改成固定角度
  951. if (bulletCfg.splitNum > 1) {
  952. let startPos = cc.v2(roleComTransform.x, roleComTransform.y + roleComTransform.halfHeight)
  953. let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight)
  954. for (let i = 1; i < bulletCfg.splitNum; i++) {
  955. endPosArr.push(this.rotatePoint(startPos, hitPos, 10 * i * (i % 2 == 0 ? -1 : 1)))
  956. }
  957. }
  958. let entityArr = []
  959. for (let i = 0; i < bulletCfg.splitNum; i++) {
  960. let entity = this.createEntity()
  961. // 添加nodeconfig
  962. let comMap = this.addComponent(entity, ComNodeConfig)
  963. comMap.id = 1
  964. comMap.layer = GAME_LAYER[GAME_LAYER.bullet]
  965. comMap.prefabName = GAME_PREFAB_TYPE.bullet
  966. //移除cocosNode
  967. this.removeComponent(entity, ComCocosNode)
  968. let comRole = this.getComponent(createEntity, ComRole)
  969. // 添加transform
  970. let comTrans = this.addComponent(entity, ComTransform)
  971. let bulletPosScaleX = roleComTransform.dir.x >= 0 ? 1 : -1
  972. let spineScale = comRole.roleCfg.gameScale[GAME_SCALE_TYPE.spine] / 100
  973. comTrans.x = roleComTransform.x + comRole.roleCfg.bulletPos[0] * bulletPosScaleX * spineScale
  974. comTrans.y =
  975. roleComTransform.y +
  976. (comRole.roleCfg.bulletPos[1] ? comRole.roleCfg.bulletPos[1] * spineScale : roleComTransform.halfHeight)
  977. let comMovable = this.addComponent(entity, ComMovable)
  978. comMovable.speed = 0
  979. let comBullet = this.addComponent(entity, ComBullet)
  980. comBullet.group = comRole.group == Data.game.gFriend ? Data.game.gFriendBullet : Data.game.gEnemyBullet
  981. comBullet.fightData = {...comRole, roleEntity: createEntity}
  982. comBullet.bulletCfg = bulletCfg
  983. comBullet.ejectionEnemies.length = 0
  984. comBullet.ejectionEnemy = enemy
  985. comBullet.hitEnemies.length = 0
  986. comBullet.isCrit = false
  987. //特效子弹位置随机
  988. if (randomPos) {
  989. let randomWidth = SkillConfig[bulletCfg.skill]
  990. ? SkillConfig[bulletCfg.skill].attackRangeX
  991. : skillConfig.attackRangeX
  992. let randomHeight = SkillConfig[bulletCfg.skill]
  993. ? SkillConfig[bulletCfg.skill].attackRangeY
  994. : skillConfig.attackRangeY
  995. let randomX = enemyComTransform.x + Math.randomRangeFloat(-randomWidth / 2, randomWidth / 2)
  996. let randomY = enemyComTransform.y + Math.randomRangeFloat(-randomHeight / 2, randomHeight / 2)
  997. enemyComTransform = new ComTransform()
  998. enemyComTransform.x = randomX
  999. enemyComTransform.y = randomY
  1000. }
  1001. if (bulletCfg.born == START_POS.straightFall || bulletCfg.born == START_POS.obliqueFall) {
  1002. comTrans.x = enemyComTransform.x - (bulletCfg.born == START_POS.obliqueFall ? 200 : 0)
  1003. comTrans.y = ConstValue.CANVAS_HEIGHT / 2
  1004. }
  1005. if (i > 0) {
  1006. enemyComTransform = new ComTransform()
  1007. enemyComTransform.x = endPosArr[i - 1].x
  1008. enemyComTransform.y = endPosArr[i - 1].y
  1009. }
  1010. this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet)
  1011. entityArr.push(entity)
  1012. }
  1013. return entityArr
  1014. }
  1015. public createCardBulletEntity(
  1016. iCard: ICard,
  1017. startPos: cc.Vec2,
  1018. endPos: cc.Vec2,
  1019. enemy: EntityIndex = 0,
  1020. ): EntityIndex {
  1021. let cardSkillCfg = iCard.cfg
  1022. let bulletCfg = BulletConfig[cardSkillCfg.bullet]
  1023. let entity = this.createEntity()
  1024. // 添加nodeconfig
  1025. let comMap = this.addComponent(entity, ComNodeConfig)
  1026. comMap.id = 1
  1027. comMap.layer = GAME_LAYER[GAME_LAYER.bullet]
  1028. comMap.prefabName = GAME_PREFAB_TYPE.bullet
  1029. //移除cocosNode
  1030. this.removeComponent(entity, ComCocosNode)
  1031. // 添加transform
  1032. let comTrans = this.addComponent(entity, ComTransform)
  1033. comTrans.x = startPos.x
  1034. comTrans.y = startPos.y
  1035. let comMovable = this.addComponent(entity, ComMovable)
  1036. comMovable.speed = 0
  1037. let comBullet = this.addComponent(entity, ComBullet)
  1038. comBullet.group = Data.game.gFriendBullet
  1039. comBullet.fightData = {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...iCard}
  1040. comBullet.bulletCfg = bulletCfg
  1041. comBullet.ejectionEnemies.length = 0
  1042. comBullet.ejectionEnemy = enemy
  1043. comBullet.hitEnemies.length = 0
  1044. comBullet.isCrit = false
  1045. let enemyComTransform = new ComTransform()
  1046. enemyComTransform.x = endPos.x
  1047. enemyComTransform.y = endPos.y
  1048. this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet)
  1049. return entity
  1050. }
  1051. public createBaseBulletEntity(posOrTrans: ComTransform | cc.Vec2) {
  1052. let sysCastleSkill = this.getSystem(SysCastleSkill)
  1053. if (sysCastleSkill.rechargeTime > 0) {
  1054. Mgr.ui.tip(LANGUAGE_TYPE.inRecharge)
  1055. return
  1056. }
  1057. if (!Data.user.useCastleSkillID) return
  1058. sysCastleSkill.reduceLeftNum()
  1059. let entity = this.createEntity()
  1060. // 添加nodeconfig
  1061. let comMap = this.addComponent(entity, ComNodeConfig)
  1062. comMap.id = 1
  1063. comMap.layer = GAME_LAYER[GAME_LAYER.bullet]
  1064. comMap.prefabName = GAME_PREFAB_TYPE.bullet
  1065. //移除cocosNode
  1066. this.removeComponent(entity, ComCocosNode)
  1067. // 添加transform
  1068. let comTrans = this.addComponent(entity, ComTransform)
  1069. comTrans.x = -10000
  1070. comTrans.y = 10000
  1071. let comMovable = this.addComponent(entity, ComMovable)
  1072. comMovable.speed = 0
  1073. let comBullet = this.addComponent(entity, ComBullet)
  1074. comBullet.group = Data.game.gFriendBullet
  1075. let baseBulletCfg = CastleSkillConfig[Data.user.useCastleSkillID]
  1076. comBullet.fightData = {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...baseBulletCfg}
  1077. comBullet.bulletCfg = BulletConfig[baseBulletCfg.bullet]
  1078. comBullet.ejectionEnemies.length = 0
  1079. comBullet.ejectionEnemy = 0
  1080. comBullet.hitEnemies.length = 0
  1081. comBullet.ejectionAnis.length = 0
  1082. comBullet.isCrit = false
  1083. let enemyComTransform
  1084. if (posOrTrans instanceof ComTransform) {
  1085. enemyComTransform = posOrTrans
  1086. } else {
  1087. let startPos = cc.v2(comTrans.x, comTrans.y)
  1088. let direction = posOrTrans.sub(startPos).normalize()
  1089. let endPos = startPos.add(direction.mul(baseBulletCfg.attackRange))
  1090. enemyComTransform = new ComTransform()
  1091. enemyComTransform.x = endPos.x
  1092. enemyComTransform.y = endPos.y
  1093. }
  1094. this.initBulletDir(comTrans, enemyComTransform, comMovable, comBullet)
  1095. return entity
  1096. }
  1097. public initBulletDir(
  1098. comTrans: ComTransform,
  1099. enemyComTransform: ComTransform,
  1100. comMovable: ComMovable,
  1101. comBullet: ComBullet,
  1102. comCocosNode?: ComCocosNode,
  1103. ) {
  1104. let startPos = cc.v2(comTrans.x, comTrans.y)
  1105. let hitPos = cc.v2(enemyComTransform.x, enemyComTransform.y + enemyComTransform.halfHeight)
  1106. // 计算子弹的飞行方向向量
  1107. let direction = hitPos.sub(startPos).normalize()
  1108. let bulletCfg = comBullet.bulletCfg
  1109. if (
  1110. !bulletCfg.isEjection &&
  1111. bulletCfg.type == BULLET_TYPE.normal &&
  1112. !bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.attackRange) &&
  1113. !bulletCfg.effectType.includes(BULLET_EFFECT_TYPE.boomerangRange)
  1114. ) {
  1115. //如果是直线子弹,将子弹终点设置为边界外的某个点,子弹到达边界点,移除子弹
  1116. hitPos = this.findIntersection(startPos, direction)
  1117. //当子弹从区域外进入,直接让子弹结束
  1118. if (!hitPos) hitPos = startPos
  1119. }
  1120. let hitPosArr = [hitPos]
  1121. if (bulletCfg.flyType == BULLET_FLY_TYPE.parabolic) {
  1122. hitPosArr = this.getParabolaPoints(startPos, hitPos, 50)
  1123. if (hitPosArr.length >= 2) direction = hitPosArr[1].sub(hitPosArr[0]).normalize()
  1124. } else if (bulletCfg.flyType == BULLET_FLY_TYPE.bezier) {
  1125. hitPosArr.length = 0
  1126. hitPosArr.push(...this.getEquidistantPoints(startPos, hitPos, 10, comBullet.group))
  1127. hitPosArr.push(hitPos)
  1128. } else if (bulletCfg.flyType == BULLET_FLY_TYPE.boomerang) {
  1129. hitPosArr.length = 0
  1130. let parms = bulletCfg.effectParm[bulletCfg.effectType.indexOf(BULLET_EFFECT_TYPE.boomerangRange)]
  1131. let halfPoints = this.getEquidistantPoints(startPos, hitPos, 10, comBullet.group, parms[1])
  1132. let leftPoints = this.getEquidistantPoints(hitPos, startPos, 10, comBullet.group, parms[1])
  1133. hitPosArr.push(...halfPoints)
  1134. hitPosArr.push(hitPos)
  1135. hitPosArr.push(...leftPoints)
  1136. hitPosArr.push(startPos)
  1137. } else if (bulletCfg.flyType == BULLET_FLY_TYPE.horizon) {
  1138. hitPosArr.length = 0
  1139. hitPosArr.push(cc.v2(comTrans.x + (direction.x >= 0 ? 1000 : -1000), comTrans.y))
  1140. }
  1141. comTrans.dir.x = direction.x
  1142. comTrans.dir.y = direction.y
  1143. comMovable.pointIdx = 0
  1144. comMovable.points.length = 0
  1145. comMovable.points.push(...hitPosArr)
  1146. if (comCocosNode) {
  1147. //计算发射角度
  1148. let angle = Math.atan2(comTrans.dir.y, comTrans.dir.x)
  1149. comCocosNode.node.angle = cc.misc.radiansToDegrees(angle)
  1150. }
  1151. }
  1152. getParabolaPoints(a: cc.Vec2, b: cc.Vec2, interval: number): cc.Vec2[] {
  1153. let xA = a.x,
  1154. yA = a.y
  1155. let xB = b.x,
  1156. yB = b.y
  1157. let yMax = Data.game.fightSizeMaxY - Math.randomRangeInt(0, Data.game.fightSizeMaxY - Math.max(yA, yB)) // 最高点的高度
  1158. let xC = (xA + xB) / 2 // 假设C是A和B的中点(水平方向)
  1159. let xD = xA + (xC - xA) / 2 // 控制点D的x坐标是A和C的x坐标的平均值
  1160. let yD = yA + (yMax - yA) / 2 // 控制点D的y坐标是A和最高点之间的某个值(这里取中点)
  1161. let points = []
  1162. let step = 1 / (interval - 1)
  1163. for (let t = 0; t <= 1; t += step) {
  1164. let x =
  1165. Math.pow(1 - t, 3) * xA +
  1166. 3 * Math.pow(1 - t, 2) * t * xD +
  1167. 3 * (1 - t) * Math.pow(t, 2) * xC +
  1168. Math.pow(t, 3) * xB
  1169. let y =
  1170. Math.pow(1 - t, 3) * yA +
  1171. 3 * Math.pow(1 - t, 2) * t * yD +
  1172. 3 * (1 - t) * Math.pow(t, 2) * yMax +
  1173. Math.pow(t, 3) * yB
  1174. points.push(cc.v2(x, y))
  1175. }
  1176. return points
  1177. }
  1178. boundaries = [
  1179. {dir: 'right', eq: Data.game.fightAreaMaxX, var: 'x'}, // 右边界
  1180. {dir: 'left', eq: Data.game.fightAreaMinX, var: 'x'}, // 左边界
  1181. {dir: 'top', eq: Data.game.fightAreaMaxY, var: 'y'}, // 上边界
  1182. {dir: 'bottom', eq: Data.game.fightAreaMinY, var: 'y'}, // 下边界
  1183. ]
  1184. findIntersection(a, v) {
  1185. // 将矩形边界转换为线性方程组
  1186. // 例如,对于矩形的上边界(y-centerY = height/2),转换为 y = centerY + height/2
  1187. // 并以此类推其他三个边界
  1188. // 定义四个边界线性方程
  1189. let intersection = null
  1190. //起点Y位置加上了人物身高,这里做个限制,让子弹起始点在屏幕内
  1191. this.boundaries.forEach(boundary => {
  1192. let t
  1193. if (boundary.var === 'x') {
  1194. // 解 x = a.x + t*v.x
  1195. t = (boundary.eq - a.x) / v.x
  1196. } else {
  1197. // 解 y = a.y + t*v.y
  1198. t = (boundary.eq - a.y) / v.y
  1199. }
  1200. // 检查t是否在[0, +∞)范围内,确保交点在射线方向上且不过原点
  1201. if (t >= 0) {
  1202. let intersectPoint = cc.v2(a.x + t * v.x, a.y + t * v.y)
  1203. // 判断交点是否在矩形内或边上
  1204. if (
  1205. (boundary.dir === 'right' || boundary.dir === 'left') &&
  1206. intersectPoint.y >= Data.game.fightAreaMinY &&
  1207. intersectPoint.y <= Data.game.fightAreaMaxY
  1208. ) {
  1209. if (!intersection || intersection.sub(a).mag() < intersectPoint.sub(a).mag())
  1210. intersection = intersectPoint
  1211. } else if (
  1212. (boundary.dir === 'top' || boundary.dir === 'bottom') &&
  1213. intersectPoint.x >= Data.game.fightAreaMinX &&
  1214. intersectPoint.x <= Data.game.fightAreaMaxX
  1215. ) {
  1216. if (!intersection || intersection.sub(a).mag() < intersectPoint.sub(a).mag())
  1217. intersection = intersectPoint
  1218. }
  1219. }
  1220. })
  1221. return intersection
  1222. }
  1223. public removeBulletEntity(entity: EntityIndex) {
  1224. let comCocosNode = this.getComponent(entity, ComCocosNode)
  1225. let comBullet = this.getComponent(entity, ComBullet)
  1226. if (!comBullet) {
  1227. return
  1228. //console.log('子弹已经移除')
  1229. }
  1230. //1秒后移除弹射特效
  1231. comBullet.ejectionAnis.forEach(aniEntity => {
  1232. let aniEntityCom = this.getComponent(aniEntity, ComFrameAni)
  1233. if (aniEntityCom && aniEntityCom.countDown > 1) aniEntityCom.countDown = 1
  1234. })
  1235. if (comBullet.cObject) {
  1236. cCollider.inst.remove(comBullet.cObject.body)
  1237. comCocosNode.node.removeComponent(comBullet.cObject)
  1238. comBullet.cObject = null
  1239. }
  1240. this.removeNodeEntity(entity)
  1241. }
  1242. rotatePoint(a: cc.Vec2, b: cc.Vec2, angleDegrees: number): cc.Vec2 {
  1243. // 将角度转换为弧度
  1244. const angleRadians = (angleDegrees * Math.PI) / 180
  1245. // 计算cos和sin值
  1246. const cosAngle = Math.cos(angleRadians)
  1247. const sinAngle = Math.sin(angleRadians)
  1248. // 计算新的坐标
  1249. const x_new = (b.x - a.x) * cosAngle - (b.y - a.y) * sinAngle + a.x
  1250. const y_new = (b.x - a.x) * sinAngle + (b.y - a.y) * cosAngle + a.y
  1251. return cc.v2(x_new, y_new)
  1252. }
  1253. bezierPoint(t, a, c, d, b) {
  1254. let x =
  1255. Math.pow(1 - t, 3) * a.x +
  1256. 3 * Math.pow(1 - t, 2) * t * c.x +
  1257. 3 * (1 - t) * Math.pow(t, 2) * d.x +
  1258. Math.pow(t, 3) * b.x
  1259. let y =
  1260. Math.pow(1 - t, 3) * a.y +
  1261. 3 * Math.pow(1 - t, 2) * t * c.y +
  1262. 3 * (1 - t) * Math.pow(t, 2) * d.y +
  1263. Math.pow(t, 3) * b.y
  1264. return cc.v2(x, y)
  1265. }
  1266. getBezierLength(a, c, d, b, numPoints) {
  1267. let length = 0
  1268. let previousPoint = a
  1269. for (let i = 1; i <= numPoints; i++) {
  1270. let t = i / numPoints
  1271. let currentPoint = this.bezierPoint(t, a, c, d, b)
  1272. length += previousPoint.sub(currentPoint).mag()
  1273. previousPoint = currentPoint
  1274. }
  1275. return length
  1276. }
  1277. getEquidistantPoints(a, b, numPoints, group, height?) {
  1278. let {c, d} = this.calculatePointCD(a.x, a.y, b.x, b.y, group, height)
  1279. let points = []
  1280. let totalLength = this.getBezierLength(a, c, d, b, numPoints)
  1281. let segmentLength = totalLength / (numPoints - 1)
  1282. let previousPoint = a
  1283. points.push(previousPoint)
  1284. for (let i = 1; i < numPoints; i++) {
  1285. let targetLength = segmentLength * i
  1286. let low = (i - 1) / numPoints
  1287. let high = i / numPoints
  1288. while (high - low > 1e-5) {
  1289. let mid = (low + high) / 2
  1290. let point = this.bezierPoint(mid, a, c, d, b)
  1291. let length = previousPoint.sub(point).mag()
  1292. if (length < targetLength) {
  1293. low = mid
  1294. } else {
  1295. high = mid
  1296. }
  1297. }
  1298. let point = this.bezierPoint((low + high) / 2, a, c, d, b)
  1299. points.push(point)
  1300. previousPoint = point
  1301. }
  1302. return points
  1303. }
  1304. calculatePointCD(x1, y1, x2, y2, group, height?) {
  1305. let a = cc.v2(x1, y1)
  1306. let b = cc.v2(x2, y2)
  1307. let dir = b.sub(a).normalize()
  1308. let length = a.sub(b).mag()
  1309. let k = Math.max(100000 / length, 50)
  1310. k = Math.min(k, 100)
  1311. if (height) k = height
  1312. // 垂直方向向量
  1313. let vDir = dir.rotate(90 * (Math.PI / 180)).mul(group == Data.game.gFriendBullet ? 1 : -1)
  1314. let c = a.add(vDir.mul(k)).add(dir.mul(length / 3))
  1315. let d = a.add(vDir.mul(k)).add(dir.mul((length * 2) / 3))
  1316. return {c, d}
  1317. }
  1318. //-------------------------------技能-----------------------------------------
  1319. public createSkill(
  1320. fightData: IFightData,
  1321. skillCfg: ISkillConfig,
  1322. skillIndex: number,
  1323. role: EntityIndex,
  1324. pos?: cc.Vec3,
  1325. group?: number,
  1326. ) {
  1327. let entity = this.createEntity()
  1328. // 添加nodeconfig
  1329. let comMap = this.addComponent(entity, ComNodeConfig)
  1330. comMap.id = 1
  1331. comMap.layer = GAME_LAYER[skillCfg.layer ? skillCfg.layer : GAME_LAYER.skill]
  1332. comMap.prefabName = GAME_PREFAB_TYPE.skill
  1333. //移除cocosNode
  1334. this.removeComponent(entity, ComCocosNode)
  1335. // 添加transform
  1336. let comTrans = this.addComponent(entity, ComTransform)
  1337. //提升自己数值技能
  1338. let comSkill = this.addComponent(entity, ComSkill)
  1339. comSkill.skillCfg = skillCfg
  1340. comSkill.skillIndex = skillIndex
  1341. comSkill.fightData = fightData
  1342. comSkill.countDown = skillCfg.duration
  1343. comSkill.role = role
  1344. comSkill.group = group
  1345. comSkill.hurtFrameCompleted = false
  1346. comSkill.dirty = false
  1347. if (role > 0) {
  1348. let comRoleTrans = this.getComponent(role, ComTransform)
  1349. let comRole = this.getComponent(role, ComRole)
  1350. comTrans.x = comRoleTrans.x
  1351. comTrans.y = comRoleTrans.y + comRoleTrans.halfHeight * (skillCfg.offsetPos[0] - 1)
  1352. comSkill.group =
  1353. comRole.group == Data.game.gFriend
  1354. ? skillCfg.isHurt
  1355. ? skillCfg.dirType == SKILL_DIR_TYPE.selfNormal
  1356. ? Data.game.gFriendHurtSkill
  1357. : Data.game.gEnemyHurtSkill
  1358. : Data.game.gFriendGainSkill
  1359. : skillCfg.isHurt
  1360. ? skillCfg.dirType == SKILL_DIR_TYPE.selfNormal
  1361. ? Data.game.gEnemyHurtSkill
  1362. : Data.game.gFriendHurtSkill
  1363. : Data.game.gEnemyGainSkill
  1364. } else {
  1365. if (!pos || !group) Log.error('技能创建失败')
  1366. comTrans.x = pos.x
  1367. comTrans.y = pos.y
  1368. }
  1369. comTrans.x += skillCfg.offsetPos[1]
  1370. comTrans.y += skillCfg.offsetPos[2]
  1371. if (skillCfg.type == SKILL_TYPE.attackBack && skillCfg.effectType.indexOf(SKILL_EFFECT_TYPE.move) >= 0) {
  1372. let comMovable = this.addComponent(entity, ComMovable)
  1373. comMovable.pointIdx = 0
  1374. comMovable.points.length = 0
  1375. comMovable.speed = skillCfg.effectParm[skillCfg.effectType.indexOf(SKILL_EFFECT_TYPE.move)][0]
  1376. comMovable.points.push(
  1377. cc.v2(
  1378. comSkill.group == Data.game.gFriendHurtSkill || comSkill.group == Data.game.gFriendGainSkill
  1379. ? Data.game.fightAreaMaxX
  1380. : Data.game.fightAreaMinX,
  1381. comTrans.y,
  1382. ),
  1383. )
  1384. }
  1385. return entity
  1386. }
  1387. public createSkillByFightData(
  1388. fightData: IFightData,
  1389. skillCfg: ISkillConfig,
  1390. skillIndex: number,
  1391. roles: EntityIndex[],
  1392. ) {
  1393. let isSuccess = false
  1394. roles.forEach((role: EntityIndex) => {
  1395. let comRole = this.getComponent(role, ComRole)
  1396. if (this.isDie(comRole)) return
  1397. this.createSkill(fightData, skillCfg, skillIndex, role)
  1398. isSuccess = true
  1399. })
  1400. return isSuccess
  1401. }
  1402. public createCardBulletSkill(comBullet: ComBullet, role: EntityIndex, pos?: cc.Vec3) {
  1403. //卡牌弹射子弹每次命中目标放技能
  1404. let skillCfg = SkillConfig[comBullet.bulletCfg.skill]
  1405. for (let i = 0; i < skillCfg.effectType.length; i++) {
  1406. let type = skillCfg.effectType[i]
  1407. if (type == SKILL_EFFECT_TYPE.reduce) {
  1408. comBullet.fightData.attack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum
  1409. comBullet.fightData.spellAttack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum
  1410. comBullet.fightData.realAttack *= 1 - skillCfg.effectParm[i][0] / Data.game.rateNum
  1411. }
  1412. }
  1413. if (role) {
  1414. this.createSkillByFightData(comBullet.fightData, skillCfg, -1, [role])
  1415. } else {
  1416. let skillEntity = this.createSkill(
  1417. comBullet.fightData,
  1418. skillCfg,
  1419. -1,
  1420. 0,
  1421. pos,
  1422. comBullet.group == Data.game.gEnemyBullet
  1423. ? skillCfg.isHurt
  1424. ? Data.game.gEnemyHurtSkill
  1425. : Data.game.gEnemyGainSkill
  1426. : skillCfg.isHurt
  1427. ? Data.game.gFriendHurtSkill
  1428. : Data.game.gFriendGainSkill,
  1429. )
  1430. let tmp = this.getComponent(skillEntity, ComSkill)
  1431. }
  1432. //地板受击
  1433. if (skillCfg.hitID[HIT_ANI_TYPE.floor]) {
  1434. this.createAni(skillCfg.hitID[HIT_ANI_TYPE.floor], role, role ? null : cc.v2(pos))
  1435. }
  1436. }
  1437. public isOneRoleSkill(skillCfg: ISkillConfig): boolean {
  1438. return (
  1439. skillCfg.dirType == SKILL_DIR_TYPE.selfRole ||
  1440. skillCfg.dirType == SKILL_DIR_TYPE.anyRole ||
  1441. skillCfg.dirType == SKILL_DIR_TYPE.minHpRole ||
  1442. skillCfg.dirType == SKILL_DIR_TYPE.baby
  1443. )
  1444. }
  1445. removeSkillEntity(entity) {
  1446. let comSkill = this.getComponent(entity, ComSkill)
  1447. let comCocosNode = this.getComponent(entity, ComCocosNode)
  1448. if (!comSkill || !comCocosNode) return
  1449. cCollider.inst.remove(comSkill.cObject.body)
  1450. comCocosNode.node.removeComponent(comSkill.cObject)
  1451. comSkill.cObject = null
  1452. this.removeNodeEntity(entity)
  1453. }
  1454. //-------------------------------BUFF-----------------------------------------
  1455. public createBuff(buffID, fightData: IFightData) {
  1456. if (!BuffConfig[buffID]) return
  1457. let buff = {buffCfg: BuffConfig[buffID]} as IBuff
  1458. buff.countDown = buff.buffCfg.duration == Data.game.cdMax ? Infinity : buff.buffCfg.duration
  1459. buff.countUp = 0
  1460. buff.hurtFrameCompleted = false
  1461. buff.hurtTimes = 0
  1462. buff.immuneTimes = 0
  1463. buff.curAttrChangeNum = []
  1464. buff.createBaseAttr = Mgr.global.buildIBaseAttr(fightData, !fightData)
  1465. buff.aniEntityArr = []
  1466. return buff
  1467. }
  1468. public addBuff(skillEntity: EntityIndex, buff: IBuff, fightData: IFightData) {
  1469. if (!buff) return
  1470. let comRoleSkill = this.getComponent(skillEntity, ComRole)
  1471. let comRoleTrans = this.getComponent(skillEntity, ComTransform)
  1472. let comCocosNodeSkill = this.getComponent(skillEntity, ComCocosNode)
  1473. let comHasSkillSkill = this.getComponent(skillEntity, ComHasSkill)
  1474. let comSpineNode = this.getComponent(comRoleSkill.spineEntity, ComCocosNode)
  1475. if (!comCocosNodeSkill || !comCocosNodeSkill.loaded || this.isDie(comRoleSkill) || this.isBase(comRoleSkill)) {
  1476. return
  1477. }
  1478. //图腾对象不施加BUFF
  1479. if (comRoleSkill.roleCfg.type == ROLE_TYPE.totem) return
  1480. let sameIDBuffs = comRoleSkill.buffs.filter(buffTmp => buffTmp.buffCfg.ID == buff.buffCfg.ID)
  1481. let buffCfg = buff.buffCfg
  1482. let sameArrIDBuffs = comRoleSkill.buffs.filter(
  1483. buffTmp => buffCfg.arrID > 0 && buffTmp.buffCfg.arrID == buffCfg.arrID,
  1484. )
  1485. let addBuffFuc = (isReplace: boolean = false) => {
  1486. let hasImmune = false
  1487. comRoleSkill.buffs.forEach(buffTmp => {
  1488. let buffCfg = buffTmp.buffCfg
  1489. if (buffCfg.buffType == BUFF_TYPE.negativeImmune) {
  1490. let negativeArr = buffCfg.effectParm[buffCfg.effectType.indexOf(BUFF_EFFECT_TYPE.immuneNegative)]
  1491. if (negativeArr) {
  1492. hasImmune ||=
  1493. negativeArr.includes(NEGATIVE_TYPE.delay) && buff.buffCfg.buffType == BUFF_TYPE.dizzy
  1494. hasImmune ||=
  1495. negativeArr.includes(NEGATIVE_TYPE.slow) &&
  1496. buff.buffCfg.attrRate[buff.buffCfg.attr.indexOf(ATTR_NAME.moveSpeed)] < 0
  1497. }
  1498. }
  1499. })
  1500. if (hasImmune) return
  1501. //光环buff不施放,在处理hasSkill处理
  1502. comRoleSkill.buffs.push(buff)
  1503. //comCocosNodeSkill.events.push(new EventBuffChange(comRoleSkill.buffs, [buff], []))
  1504. for (let aniID of buff.buffCfg.buffUrl) {
  1505. if (!aniID || isReplace) continue
  1506. if (aniID == BUFF_ANI_TYPE.slow) {
  1507. comSpineNode?.events.push(new EventSlowDown(true))
  1508. }
  1509. buff.aniEntityArr.push(this.createAni(aniID, skillEntity))
  1510. }
  1511. buffCfg.buffIcon.forEach(value => {
  1512. console.log('推入buff', value)
  1513. comCocosNodeSkill.events.push(new EventRoleTip(GAME_ROLE_TIP.buffTip, buffCfg.hurtEffect, value))
  1514. })
  1515. if (buff.buffCfg.buffType == BUFF_TYPE.dizzy) {
  1516. let comDizzy = this.getComponent(skillEntity, ComDizzy)
  1517. if (comDizzy && !this.isDie(comRoleSkill)) {
  1518. comDizzy.countDown = buff.buffCfg.attrNum[0]
  1519. for (let i = 0; i < buff.buffCfg.effectType.length; i++) {
  1520. let type = buff.buffCfg.effectType[i]
  1521. if (type == BUFF_EFFECT_TYPE.boss && comRoleSkill.roleCfg.type == MONSTER_TYPE.boss) {
  1522. comDizzy.countDown *= 1 - buff.buffCfg.effectParm[i][0] / Data.game.rateNum
  1523. }
  1524. }
  1525. if (comRoleSkill.entryMap.get(ENTRY.delayReduce)?.num) {
  1526. comDizzy.countDown *= 1 - comRoleSkill.entryMap.get(ENTRY.delayReduce).num / Data.game.rateNum
  1527. }
  1528. if (fightData && fightData.entryMap.get(ENTRY.delayAdd)?.num) {
  1529. comDizzy.countDown *= 1 + fightData.entryMap.get(ENTRY.delayAdd).num / Data.game.rateNum
  1530. }
  1531. //将顶盾的buff去掉
  1532. let findIndex = comRoleSkill.buffs.findIndex(
  1533. value => value.buffCfg.buffType == BUFF_TYPE.shieldReduceHurt,
  1534. )
  1535. if (findIndex != -1) comRoleSkill.buffs.splice(findIndex, 1)
  1536. let comDizzySkillAbel = this.getComponent(skillEntity, ComSkillAbel)
  1537. comDizzySkillAbel.isInShield = false
  1538. //将顶盾的罩子,友军免疫远程攻击buff去掉
  1539. this.removeNodeEntity(comDizzySkillAbel.ani)
  1540. let skillIndex = comRoleSkill.skills.findIndex(v => v.type == SKILL_TYPE.holo)
  1541. if (skillIndex >= 0) {
  1542. let allEntity = Array.from(comHasSkillSkill.skillCObjects[skillIndex].containsBody.keys())
  1543. allEntity = allEntity.filter(entityTmp => !this.isDie(entityTmp))
  1544. allEntity.forEach(v => {
  1545. let tmpComRole = this.getComponent(v, ComRole)
  1546. let findIndex = tmpComRole.buffs.findIndex(
  1547. value => value.buffCfg.buffType == BUFF_TYPE.rangedImmune,
  1548. )
  1549. if (findIndex != -1) {
  1550. console.warn('去掉免疫buff')
  1551. tmpComRole.buffs.splice(findIndex, 1)
  1552. }
  1553. })
  1554. }
  1555. //将技能弹射子弹去除
  1556. if (comDizzySkillAbel.bullets) {
  1557. comDizzySkillAbel.bullets.forEach(v => {
  1558. this.removeBulletEntity(v)
  1559. })
  1560. comDizzySkillAbel.bullets.length = 0
  1561. }
  1562. }
  1563. }
  1564. }
  1565. let replaceBuffFuc = (replaceBuff: IBuff) => {
  1566. //addType==0直接替换,==1替换效果最好的
  1567. if (
  1568. buffCfg.addType == 0 ||
  1569. (buffCfg.addType == 1 && buffCfg.attrRate[0] >= replaceBuff.buffCfg.attrRate[0])
  1570. ) {
  1571. let removeBuffs = comRoleSkill.buffs.splice(comRoleSkill.buffs.indexOf(replaceBuff), 1)
  1572. this.removeBuffAttr(skillEntity, removeBuffs[0])
  1573. addBuffFuc(true)
  1574. //特效继承,时间重置
  1575. buff.aniEntityArr.push(...removeBuffs[0].aniEntityArr)
  1576. for (let aniEntity of buff.aniEntityArr) {
  1577. let comFrameAni = this.getComponent(aniEntity, ComFrameAni)
  1578. if (comFrameAni) comFrameAni.countDown = comFrameAni.aniConfig.duration
  1579. }
  1580. }
  1581. }
  1582. if (buffCfg.arrID > 0) {
  1583. //有buff组,根据叠加和替换规则确定是否叠加和替换
  1584. if (buffCfg.isAdd && (!buffCfg.addNum || (buffCfg.addNum > 0 && sameArrIDBuffs.length < buffCfg.addNum))) {
  1585. //叠加
  1586. addBuffFuc()
  1587. } else if (!buffCfg.isAdd) {
  1588. //不叠加
  1589. if (sameArrIDBuffs.length == 0) {
  1590. addBuffFuc()
  1591. } else {
  1592. replaceBuffFuc(sameArrIDBuffs[0])
  1593. }
  1594. }
  1595. } else {
  1596. //不叠加
  1597. if (sameIDBuffs.length == 0) {
  1598. addBuffFuc()
  1599. } else {
  1600. replaceBuffFuc(sameIDBuffs[0])
  1601. }
  1602. }
  1603. }
  1604. public removeBuffAttr(role: EntityIndex, buff: IBuff) {
  1605. let comRole = this.getComponent(role, ComRole)
  1606. if (this.isDie(comRole)) return
  1607. let buffConfig = buff.buffCfg
  1608. for (let j = 0; j < buffConfig.attr.length; j++) {
  1609. if (buff.curAttrChangeNum[j]) {
  1610. comRole[buffConfig.attr[j]] -= buff.curAttrChangeNum[j]
  1611. if (buffConfig.attr[j] == ATTR_NAME.attackRange) {
  1612. let comFindEnemy = this.getComponent(role, ComFindEnemy)
  1613. if (comFindEnemy.attackCObject.radius != comRole.attackRange) {
  1614. comFindEnemy.attackCObject.updateSphereShape(comRole.attackRange)
  1615. }
  1616. }
  1617. }
  1618. }
  1619. }
  1620. //-------------------------------特效-----------------------------------------
  1621. public createAni(aniID: number, role: EntityIndex, pos?: cc.Vec2) {
  1622. let frameAniConfig = FrameAniConfig[aniID]
  1623. if (!frameAniConfig) {
  1624. console.error('frameAniID不存在', aniID)
  1625. return
  1626. }
  1627. if (frameAniConfig.type == ANI_TYPE.shader) return
  1628. let entity = this.createEntity()
  1629. // 添加nodeconfig
  1630. let comMap = this.addComponent(entity, ComNodeConfig)
  1631. comMap.id = 1
  1632. comMap.layer = GAME_LAYER[frameAniConfig.layer ? frameAniConfig.layer : GAME_LAYER.skill]
  1633. comMap.prefabName = GAME_PREFAB_TYPE.frameAni
  1634. //移除cocosNode
  1635. this.removeComponent(entity, ComCocosNode)
  1636. // 添加transform
  1637. let comTrans = this.addComponent(entity, ComTransform)
  1638. let comFrameAni = this.addComponent(entity, ComFrameAni)
  1639. comFrameAni.countDown = frameAniConfig.duration
  1640. comFrameAni.dirty = false
  1641. comFrameAni.aniConfig = frameAniConfig
  1642. comFrameAni.role = role
  1643. comFrameAni.lineStartPos = null
  1644. comFrameAni.lineStartEntity = 0
  1645. comFrameAni.lineEndEntity = 0
  1646. let comRoleTrans = this.getComponent(role, ComTransform)
  1647. if (pos) {
  1648. comTrans.x = pos.x
  1649. comTrans.y = pos.y
  1650. } else if (comRoleTrans) {
  1651. comTrans.x = comRoleTrans.x
  1652. comTrans.y =
  1653. comRoleTrans.y +
  1654. (frameAniConfig.offsetPos[0] ? comRoleTrans.halfHeight * (frameAniConfig.offsetPos[0] - 1) : 0)
  1655. }
  1656. comTrans.x += frameAniConfig.offsetPos[1]
  1657. comTrans.y += frameAniConfig.offsetPos[2]
  1658. return entity
  1659. }
  1660. //--------------------------------词条-------------------------------------------------
  1661. isGameEntry(type: ENTRY) {
  1662. return type >= ENTRY.ignoreDefense && type <= 100
  1663. }
  1664. initEntry() {
  1665. if (Data.game.gameType != GAME_TYPE.relic) {
  1666. for (let id of Data.user.talents) {
  1667. let talentCfg = TalentConfig[id]
  1668. let type = EntryConfig[talentCfg.entryID].type
  1669. switch (type) {
  1670. case ENTRY.startCostAdd:
  1671. break
  1672. }
  1673. }
  1674. }
  1675. }
  1676. convertEntry2Obj(entryID: number): EntryObj {
  1677. let entryCfg = EntryConfig[entryID]
  1678. let num = 0
  1679. if (entryCfg.parmArr[0] && entryCfg.parmArr.length == 1) num = entryCfg.parmArr[0]
  1680. if (entryCfg.rateArr[0] && entryCfg.rateArr.length == 1) num = entryCfg.rateArr[0]
  1681. let numArrTmp = []
  1682. if (entryCfg.parmArr.length > 1) numArrTmp.push(entryCfg.parmArr)
  1683. if (entryCfg.rateArr.length > 1) numArrTmp.push(entryCfg.rateArr)
  1684. return {num, numArr: numArrTmp, type: entryCfg.type, profession: entryCfg.profession}
  1685. }
  1686. putEntry2Map(comRole: ComRole, entryObj: EntryObj) {
  1687. let map = comRole.entryMap
  1688. if (!this.isGameEntry(entryObj.type) || !entryObj.profession.includes(comRole.roleCfg.profession)) return
  1689. let obj = map.get(entryObj.type)
  1690. if (obj) {
  1691. //叠加规则
  1692. if (entryObj.num > 0) {
  1693. //默认数值相加
  1694. obj.num += entryObj.num
  1695. } else if (entryObj.numArr.length > 0) {
  1696. //数组默认覆盖最好的效果
  1697. let lastNum = obj.numArr[0][obj.numArr[0].length - 1]
  1698. let newLastNum = entryObj.numArr[0][entryObj.numArr[0].length - 1]
  1699. if (newLastNum > lastNum) {
  1700. obj.numArr[0][obj.numArr[0].length - 1] = newLastNum
  1701. }
  1702. }
  1703. } else {
  1704. map.set(entryObj.type, entryObj)
  1705. }
  1706. }
  1707. //--------------------------------改变无敌状态-------------------------------------------------
  1708. changeInvincible(role: EntityIndex, invincible: boolean) {
  1709. let comRole = this.getComponent(role, ComRole)
  1710. if (this.isDie(comRole)) return
  1711. comRole.invincible = invincible
  1712. }
  1713. //--------------------------------绘制碰撞体-------------------------------------------------
  1714. drawDebug(entity: EntityIndex, cObject) {
  1715. let comCocosNode = this.getComponent(entity, ComCocosNode)
  1716. let comTrans = this.getComponent(entity, ComTransform)
  1717. if (!comCocosNode || !comTrans || !cObject || !CC_DEV || !cc.debug.isDisplayStats()) return
  1718. //绘制碰撞体
  1719. let localPoints
  1720. let offset = cc.v2(comTrans.x, comTrans.y).add(cc.v2(cObject.center))
  1721. if (cObject.type == ShapeType.Box) {
  1722. localPoints = []
  1723. localPoints.push(cc.v2(offset.x - cObject.size.x / 2, offset.y + cObject.size.y / 2)) // 左上角
  1724. localPoints.push(cc.v2(offset.x + cObject.size.x / 2, offset.y + cObject.size.y / 2)) // 右上角
  1725. localPoints.push(cc.v2(offset.x + cObject.size.x / 2, offset.y - cObject.size.y / 2)) // 右下角
  1726. localPoints.push(cc.v2(offset.x - cObject.size.x / 2, offset.y - cObject.size.y / 2)) // 左下角
  1727. }
  1728. if (cObject.type == ShapeType.Sphere) {
  1729. localPoints = [cc.v2(comTrans.x, comTrans.y).add(cc.v2(cObject.center))]
  1730. }
  1731. if (localPoints) {
  1732. let color
  1733. let comRole = this.getComponent(entity, ComRole)
  1734. if (comRole) {
  1735. color = comRole.group == Data.game.gFriend ? cc.Color.GREEN : cc.Color.RED
  1736. }
  1737. let comSkill = this.getComponent(entity, ComSkill)
  1738. if (comSkill) {
  1739. color =
  1740. comSkill.group == Data.game.gFriendGainSkill || comSkill.group == Data.game.gFriendHurtSkill
  1741. ? cc.Color.GREEN
  1742. : cc.Color.RED
  1743. }
  1744. comCocosNode.events.push(
  1745. new EventGraphicsDraw(localPoints, cObject.type == ShapeType.Box ? 0 : cObject.radius, color),
  1746. )
  1747. }
  1748. }
  1749. //--------------------------------移除战场上的实体-------------------------------------------------
  1750. removeNodeEntity(entity: EntityIndex) {
  1751. this.putNode(entity)
  1752. this.removeAllComponents(entity)
  1753. this.removeEntity(entity)
  1754. }
  1755. putNode(entity: EntityIndex) {
  1756. let comCocosNode = this.getComponent(entity, ComCocosNode)
  1757. if (comCocosNode) {
  1758. let node = comCocosNode.node
  1759. if (node) {
  1760. let eventProcess = node.getComponent(EventProcess)
  1761. eventProcess.onDetach()
  1762. node.removeFromParent()
  1763. if (this.fightCore) {
  1764. let pool = this.fightCore.gamePool.get(node.name)
  1765. if (pool) {
  1766. this.resetGameNode(node)
  1767. pool.put(node)
  1768. }
  1769. }
  1770. }
  1771. }
  1772. }
  1773. resetGameNode(node) {
  1774. ccUtils.stopAni(node)
  1775. node.stopAllActions()
  1776. node.opacity = 255
  1777. node.angle = 0
  1778. node.scale = 1
  1779. node.position = cc.v2(-10000, -10000)
  1780. let sprite = node.getComponent(cc.Sprite)
  1781. if (sprite) sprite.spriteFrame = null
  1782. let spine = node.getComponent(sp.Skeleton)
  1783. if (spine) spine.skeletonData = null
  1784. let frameAnimation = node.getComponent(FrameAnimation)
  1785. if (frameAnimation) {
  1786. frameAnimation.stop()
  1787. //frameAnimation.spriteAtlas = null
  1788. }
  1789. if (node.name != GAME_PREFAB_TYPE.role) node.children.forEach(v => this.resetGameNode(v))
  1790. }
  1791. }