SysSkillAbel.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /** @format */
  2. import {ECSSystem} from '../lib/ECSSystem'
  3. import {GenFilterKey} from '../lib/ECSComponent'
  4. import {FightWorld} from '../worlds/FightWorld'
  5. import {ComSkillAbel} from '../components/ComSkillAbel'
  6. import {ComTransform} from '../components/ComTransform'
  7. import {ComRole} from '../components/ComRole'
  8. import {ComCocosNode} from '../components/ComCocosNode'
  9. import {Data} from '../../GameControl'
  10. import {ccUtils} from '../../utils/ccUtils'
  11. import {ComMovable} from '../components/ComMovable'
  12. import {ComAttackable} from '../components/ComAttackable'
  13. import {ComDie} from '../components/ComDie'
  14. import {
  15. BUFF_TYPE,
  16. BULLET_EFFECT_TYPE,
  17. BULLET_FLY_TYPE,
  18. BULLET_TYPE,
  19. ENTRY,
  20. FRAME_ANI_NAME,
  21. GAME_ROLE_TIP,
  22. HIT_ANI_TYPE,
  23. SKILL_DIR_TYPE,
  24. SKILL_EFFECT_TYPE,
  25. SKILL_TYPE,
  26. } from '../../enums/Enum'
  27. import {ComFindEnemy} from '../components/ComFindEnemy'
  28. import {ComDizzy} from '../components/ComDizzy'
  29. import {cObject} from '../../collision/Object'
  30. import {EventRoleTip} from '../core/NodeEvent'
  31. import {ComBehaviorTree} from '../components/ComBehaviorTree'
  32. import {RoleConfig} from '../../config/RoleConfig'
  33. import {BulletConfig} from '../../config/BulletConfig'
  34. import {ComBullet} from '../components/ComBullet'
  35. import {cCollider} from '../../collision/Collider'
  36. import {EntryObj} from '../core/GameInterface'
  37. const FILTER_SKILLABEL = GenFilterKey([ComSkillAbel, ComTransform, ComRole, ComCocosNode, ComBehaviorTree], [ComDie])
  38. export class SysSkillAbel extends ECSSystem {
  39. /** 连接 */
  40. public onAdd(world: FightWorld): void {}
  41. /** 断开连接 */
  42. public onRemove(world: FightWorld): void {}
  43. /** 添加实体 */
  44. public onEntityEnter(world: FightWorld, entity: number): void {}
  45. /** */
  46. public onEntityLeave(world: FightWorld, entity: number): void {}
  47. /** 更新 */
  48. public onUpdate(world: FightWorld, dt: number): void {
  49. let filter = world.getFilter(FILTER_SKILLABEL)
  50. filter.walk((entity: number) => {
  51. let comRole = world.getComponent(entity, ComRole)
  52. let comCocosNode = world.getComponent(entity, ComCocosNode)
  53. let comSkillAbel = world.getComponent(entity, ComSkillAbel)
  54. let comTransform = world.getComponent(entity, ComTransform)
  55. if (!comSkillAbel.dirty) return
  56. let curSkillIndex = comRole.skills.findIndex(value => value.ID == comSkillAbel.skillConfig.ID)
  57. let fightData
  58. if (curSkillIndex > comRole.roleCfg.skills.length - 1) {
  59. fightData = {
  60. buffs: [],
  61. entryMap: new Map<ENTRY, EntryObj>(),
  62. ...comRole.equips[curSkillIndex - comRole.roleCfg.skills.length],
  63. }
  64. }
  65. let addBuff = () => {
  66. let buffs = []
  67. for (let buffID of comSkillAbel.skillConfig.buffs) {
  68. buffs.push(world.createBuff(buffID, comRole))
  69. }
  70. comSkillAbel.roles.forEach(skillEntity => {
  71. //除开光环以外的buff技能
  72. if (comSkillAbel.skillConfig.type != SKILL_TYPE.holo && buffs.length > 0) {
  73. for (let buff of buffs) {
  74. world.addBuff(skillEntity, buff, comRole)
  75. }
  76. }
  77. })
  78. }
  79. if (comSkillAbel.startDirty) {
  80. //顶盾技能在吟唱开始的时候加buff 其他除了光环技能在技能伤害帧加BUFF
  81. if (comSkillAbel.skillConfig.type == SKILL_TYPE.shield && !comSkillAbel.isInShield) {
  82. comSkillAbel.isInShield = true
  83. addBuff()
  84. //顶盾特效
  85. if (comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role]) {
  86. comSkillAbel.ani = world.createAni(comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role], entity)
  87. }
  88. }
  89. if (comSkillAbel.skillConfig.type == SKILL_TYPE.skillBullet) {
  90. let comTrans = world.getComponent(comSkillAbel.roles[0], ComTransform)
  91. if (comTrans) {
  92. comSkillAbel.skillBulletPos = cc.v2(comTrans.x, comTrans.y)
  93. //瞄准特效
  94. if (comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role]) {
  95. world.createAni(
  96. comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role],
  97. undefined,
  98. comSkillAbel.skillBulletPos,
  99. )
  100. }
  101. } else {
  102. //让技能可以重新被施放
  103. let curSkillIndex = comRole.skills.findIndex(value => value.ID == comSkillAbel.skillConfig.ID)
  104. if (curSkillIndex >= 0) {
  105. comRole.skillCountDowns[curSkillIndex] = comRole.castTime[curSkillIndex]
  106. }
  107. }
  108. }
  109. comSkillAbel.bullets = []
  110. comSkillAbel.skillBulletTime = this.getSkillBulletInverter(comSkillAbel)
  111. comSkillAbel.skillBulletNum = 0
  112. comSkillAbel.startDirty = false
  113. }
  114. //发射多枚技能子弹
  115. if (
  116. comSkillAbel.skillConfig.type == SKILL_TYPE.skillBullet ||
  117. comSkillAbel.skillConfig.type == SKILL_TYPE.ejectionSkillBullet
  118. ) {
  119. let skillBulletParams =
  120. comSkillAbel.skillConfig.effectParm[
  121. comSkillAbel.skillConfig.effectType.indexOf(SKILL_EFFECT_TYPE.skillBullet)
  122. ]
  123. let bulletCfg = BulletConfig[skillBulletParams[0]]
  124. let bulletNum = skillBulletParams[1]
  125. comSkillAbel.skillBulletTime -= dt
  126. if (comSkillAbel.skillBulletTime <= 0 && comSkillAbel.skillBulletNum < bulletNum) {
  127. comSkillAbel.skillBulletNum += 1
  128. if (bulletCfg.flyType == BULLET_FLY_TYPE.boomerang) {
  129. let durRange =
  130. bulletCfg.effectParm[bulletCfg.effectType.indexOf(BULLET_EFFECT_TYPE.boomerangRange)][0]
  131. comSkillAbel.skillBulletPos = cc.v2(
  132. comTransform.x + durRange * (comTransform.dir.x > 0 ? 1 : -1),
  133. comTransform.y + comTransform.halfHeight,
  134. )
  135. }
  136. //0是吟唱时间平均值
  137. comSkillAbel.skillBulletTime = this.getSkillBulletInverter(comSkillAbel)
  138. if (comSkillAbel.skillConfig.type == SKILL_TYPE.skillBullet) {
  139. let tmp = world.createRoleSkillBulletEntity(
  140. comSkillAbel.skillConfig,
  141. skillBulletParams[0],
  142. entity,
  143. BulletConfig[skillBulletParams[0]]?.type == BULLET_TYPE.normal ||
  144. BulletConfig[skillBulletParams[0]]?.isEjection
  145. ? comSkillAbel.roles[0]
  146. : 0,
  147. Boolean(skillBulletParams[3]),
  148. comSkillAbel.skillBulletPos,
  149. )
  150. if (tmp.length > 0) {
  151. if (bulletCfg.flyType == BULLET_FLY_TYPE.boomerang) comSkillAbel.bullets.push(tmp[0])
  152. let comBullet = world.getComponent(tmp[0], ComBullet)
  153. if (fightData && comBullet) comBullet.fightData = fightData
  154. }
  155. } else if (comSkillAbel.skillConfig.type == SKILL_TYPE.ejectionSkillBullet) {
  156. let tmp = world.createRoleSkillBulletEntity(
  157. comSkillAbel.skillConfig,
  158. skillBulletParams[0],
  159. entity,
  160. 0,
  161. false,
  162. cc.v2(
  163. Math.randomRangeFloat(
  164. comRole.group == Data.game.gFriend ? comTransform.x : Data.game.fightSizeMinX,
  165. comRole.group == Data.game.gFriend ? Data.game.fightSizeMaxX : comTransform.x,
  166. ),
  167. Math.randomRangeFloat(Data.game.fightSizeMinY, Data.game.fightSizeMaxY),
  168. ),
  169. )
  170. if (tmp.length > 0) {
  171. comSkillAbel.bullets.push(tmp[0])
  172. }
  173. }
  174. }
  175. }
  176. comSkillAbel.countDown -= dt
  177. if (comSkillAbel.countDown <= comSkillAbel.castSkillTime && comSkillAbel.skillDirty) {
  178. comSkillAbel.skillDirty = false
  179. if (CC_DEV) ccUtils.setLabel('', comCocosNode?.node, 'skill')
  180. let comAttackable = world.getComponent(entity, ComAttackable)
  181. let comFindEnemy = world.getComponent(entity, ComFindEnemy)
  182. if (comSkillAbel.skillConfig.type == SKILL_TYPE.moveBack) {
  183. if (!world.isDie(comSkillAbel.roles[0])) {
  184. let targetComTrans = world.getComponent(comSkillAbel.roles[0], ComTransform)
  185. let targetComMovable = world.getComponent(comSkillAbel.roles[0], ComMovable)
  186. let targetComAttackable = world.getComponent(comSkillAbel.roles[0], ComAttackable)
  187. let comEnemyFindEnemy = world.getComponent(comSkillAbel.roles[0], ComFindEnemy)
  188. if (
  189. comAttackable.curAttack ||
  190. comFindEnemy.willBeAttackMelee ||
  191. comFindEnemy.willAttackMelee ||
  192. comAttackable.beAttacks.length > 0 ||
  193. comEnemyFindEnemy.willAttackMelee ||
  194. comEnemyFindEnemy.willBeAttackMelee ||
  195. targetComAttackable.beAttacks.length == 0
  196. ) {
  197. return
  198. }
  199. let targetPos = world.moveToMeleeAttackPos(
  200. entity,
  201. comTransform,
  202. targetComTrans,
  203. targetComMovable,
  204. true,
  205. )
  206. comTransform.x = targetPos.x
  207. comTransform.y = targetPos.y
  208. let comSpineTransform = world.getComponent(comRole.spineEntity, ComTransform)
  209. if (comSpineTransform) {
  210. comSpineTransform.x = targetPos.x
  211. comSpineTransform.y = targetPos.y
  212. }
  213. world.changeMoveSpeed(entity, 0)
  214. // 此处必须让所有的cObject位置更新
  215. comCocosNode.node?.getComponents(cObject).forEach(cObject => {
  216. cObject.setPosition(cc.v3(comTransform.x, comTransform.y, 0))
  217. })
  218. comAttackable.curAttack = comSkillAbel.roles[0]
  219. //背刺比较特殊,这次要处理被攻击数组
  220. if (!targetComAttackable.beAttacks.includes(entity)) {
  221. targetComAttackable.beAttacks.push(entity)
  222. }
  223. //把刺客完成背刺后提升暴击率的技能CD改成0秒
  224. comRole.skills.forEach((skill, index) => {
  225. if (
  226. skill.effectType.includes(SKILL_EFFECT_TYPE.castBySkill) &&
  227. skill.effectParm[0][0] == comSkillAbel.skillConfig.ID
  228. ) {
  229. comRole.skillCountDowns[index] = 0
  230. }
  231. })
  232. }
  233. } else if (
  234. comSkillAbel.skillConfig.type == SKILL_TYPE.normal ||
  235. comSkillAbel.skillConfig.type == SKILL_TYPE.addHP ||
  236. comSkillAbel.skillConfig.type == SKILL_TYPE.addShieldHPByHP ||
  237. comSkillAbel.skillConfig.type == SKILL_TYPE.attackBack
  238. ) {
  239. let isSuccess = world.createSkillByFightData(
  240. fightData ? fightData : comRole,
  241. comSkillAbel.skillConfig,
  242. comSkillAbel.roles,
  243. )
  244. //让没放成功的技能可以再次施放
  245. if (!isSuccess) {
  246. if (curSkillIndex >= 0) {
  247. //让技能可以重新被施放
  248. comRole.skillCountDowns[curSkillIndex] = comRole.castTime[curSkillIndex]
  249. }
  250. } else {
  251. //地板受击
  252. if (comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.floor]) {
  253. world.createAni(comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.floor], comSkillAbel.roles[0])
  254. }
  255. //自杀
  256. if (comSkillAbel.skillConfig.effectType.includes(SKILL_EFFECT_TYPE.killSelf)) {
  257. comRole.nowHP = 0
  258. comRole.HPDirty = true
  259. }
  260. }
  261. } else if (comSkillAbel.skillConfig.type == SKILL_TYPE.createRole) {
  262. comSkillAbel.skillConfig.createRole.forEach((role, index) => {
  263. if (role < 10000) {
  264. role = role * 100 + (comRole.roleCfg.ID % 100)
  265. }
  266. let cfg = RoleConfig[role]
  267. if (!cfg && comRole.group == Data.game.gEnemy) {
  268. cfg = world.fightCore.getRoleCfgByCfgID(role)
  269. }
  270. let baby = world.createRoleEntity(cfg, comRole.group == Data.game.gEnemy)
  271. //图腾特效
  272. if (comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role])
  273. world.createAni(comSkillAbel.skillConfig.hitID[HIT_ANI_TYPE.role], baby)
  274. comRole.babys.push(baby)
  275. let babyComRole = world.getComponent(baby, ComRole)
  276. babyComRole.parent = entity
  277. babyComRole.parentRoleID = comRole.roleCfg.ID
  278. let babyComTransform = world.getComponent(baby, ComTransform)
  279. let babySpComTransform = world.getComponent(babyComRole.spineEntity, ComTransform)
  280. let pos = comSkillAbel.skillConfig.createRolePos[index]
  281. babyComTransform.x = comTransform.x + (comRole.group == Data.game.gEnemy ? -pos[0] : pos[0])
  282. babyComTransform.y = comTransform.y + pos[1]
  283. babySpComTransform.x = babyComTransform.x
  284. babySpComTransform.y = babyComTransform.y
  285. //角色表创建的宝宝,继承父角色的属性,怪物表遗迹表等没有养成,直接用固定值
  286. if (RoleConfig[role]) {
  287. let parentCfg = comRole.roleCfg
  288. babyComRole.nowHP = parentCfg.HP * (babyComRole.roleCfg.HP / Data.game.rateNum)
  289. babyComRole.lastHP = parentCfg.HP * (babyComRole.roleCfg.HP / Data.game.rateNum)
  290. babyComRole.HP = parentCfg.HP * (babyComRole.roleCfg.HP / Data.game.rateNum)
  291. babyComRole.attack = parentCfg.attack * (babyComRole.roleCfg.attack / Data.game.rateNum)
  292. babyComRole.spellAttack =
  293. parentCfg.spellAttack * (babyComRole.roleCfg.spellAttack / Data.game.rateNum)
  294. babyComRole.realAttack =
  295. parentCfg.realAttack * (babyComRole.roleCfg.realAttack / Data.game.rateNum)
  296. babyComRole.defense = parentCfg.defense * (babyComRole.roleCfg.defense / Data.game.rateNum)
  297. babyComRole.spellDefense =
  298. parentCfg.spellDefense * (babyComRole.roleCfg.spellDefense / Data.game.rateNum)
  299. }
  300. if (comRole.entryMap.get(ENTRY.addBabyHP)?.num) {
  301. babyComRole.HP *= 1 + comRole.entryMap.get(ENTRY.addBabyHP).num / Data.game.rateNum
  302. babyComRole.nowHP = babyComRole.HP
  303. babyComRole.lastHP = babyComRole.HP
  304. }
  305. if (comRole.entryMap.get(ENTRY.addBabyAttack)?.num) {
  306. babyComRole.attack *= 1 + comRole.entryMap.get(ENTRY.addBabyAttack).num / Data.game.rateNum
  307. babyComRole.spellAttack *=
  308. 1 + comRole.entryMap.get(ENTRY.addBabyAttack).num / Data.game.rateNum
  309. }
  310. })
  311. } else if (comSkillAbel.skillConfig.type == SKILL_TYPE.transRole) {
  312. let transID = comSkillAbel.skillConfig.createRole[0]
  313. if (transID < 10000) {
  314. transID = comSkillAbel.skillConfig.createRole[0] * 100 + (comRole.roleCfg.ID % 100)
  315. }
  316. let transRole = world.createRoleEntity(transID, comRole.group == Data.game.gEnemy)
  317. let comTransRole = world.getComponent(transRole, ComRole)
  318. let comTransTransform = world.getComponent(transRole, ComTransform)
  319. let comTransCocosNode = world.getComponent(transRole, ComCocosNode)
  320. let comSpineTransTransform = world.getComponent(comTransRole.spineEntity, ComTransform)
  321. comTransRole.lastHP = (comRole.nowHP / comRole.HP) * comTransRole.roleCfg.HP
  322. comTransRole.nowHP = comTransRole.lastHP
  323. comTransTransform.x = comTransform.x
  324. comTransTransform.y = comTransform.y
  325. comTransTransform.dir.x = comTransform.dir.x
  326. comTransTransform.dir.y = comTransform.dir.y
  327. if (comSpineTransTransform) {
  328. comSpineTransTransform.x = comTransform.x
  329. comSpineTransTransform.y = comTransform.y
  330. comSpineTransTransform.dir.x = comTransform.dir.x
  331. comSpineTransTransform.dir.y = comTransform.dir.y
  332. }
  333. //继承词条
  334. comRole.entryMap.forEach((entry, key) => {
  335. comTransRole.entryMap.set(key, entry)
  336. })
  337. //继承buff
  338. comTransRole.buffs = [...comRole.buffs]
  339. comRole.nowHP = 0
  340. comRole.shieldHP = 0
  341. comRole.HPDirty = true
  342. comRole.transDirty = true
  343. comTransRole.transID = comRole.roleCfg.ID
  344. }
  345. //放技能加血
  346. if (comRole.entryMap.get(ENTRY.skillRestoreHP)?.num > 0) {
  347. let addHPNum = comRole.entryMap.get(ENTRY.skillRestoreHP).num
  348. world.addHP(addHPNum, entity)
  349. comRole.HPDirty = true
  350. }
  351. }
  352. if (comSkillAbel.countDown <= 0) {
  353. if (comSkillAbel.bullets) {
  354. comSkillAbel.bullets.forEach(v => {
  355. world.removeBulletEntity(v)
  356. })
  357. comSkillAbel.bullets.length = 0
  358. }
  359. comSkillAbel.isInShield = false
  360. comSkillAbel.skillConfig = null
  361. comSkillAbel.roles.length = 0
  362. comSkillAbel.dirty = false
  363. }
  364. return false
  365. })
  366. }
  367. getSkillBulletInverter(comSkillAbel: ComSkillAbel): number {
  368. let cfg =
  369. comSkillAbel.skillConfig.effectParm[
  370. comSkillAbel.skillConfig.effectType.indexOf(SKILL_EFFECT_TYPE.skillBullet)
  371. ]
  372. if (!cfg) return 0
  373. let time = cfg[2] ? cfg[2] : +(comSkillAbel.castSkillTime / cfg[1]).toFixed(1)
  374. return Math.min(time, comSkillAbel.countDown)
  375. }
  376. }