BehaviorTree.ts 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  1. /** @format */
  2. import {ComAttackable} from '../ECS/components/ComAttackable'
  3. import {ComCocosNode} from '../ECS/components/ComCocosNode'
  4. import {ComMovable} from '../ECS/components/ComMovable'
  5. import {ComTransform} from '../ECS/components/ComTransform'
  6. import {SysBehaviorTree} from '../ECS/systems/SysBehaviorTree'
  7. import {EventAttack, EventDie, EventSkill, EventStopSkill} from '../ECS/core/NodeEvent'
  8. import {ComFindEnemy} from '../ECS/components/ComFindEnemy'
  9. import {ComRole} from '../ECS/components/ComRole'
  10. import {ComDizzy} from '../ECS/components/ComDizzy'
  11. import {ComSkillAbel} from '../ECS/components/ComSkillAbel'
  12. import {ccUtils} from '../utils/ccUtils'
  13. import {FightWorld} from '../ECS/worlds/FightWorld'
  14. import {Data} from '../GameControl'
  15. import {FILTER_CAN_ATTACK_ENEMY, FILTER_CAN_ATTACK_FRIEND} from '../ECS/systems/SysFindEnemy'
  16. import {Log} from '../utils/LogUtils'
  17. import {BUFF_EFFECT_TYPE, BUFF_TYPE, ENTRY, ROLE_TYPE, SKILL_TYPE} from '../enums/Enum'
  18. import {EventProcess} from '../ECS/core/EventProcess'
  19. export namespace BT {
  20. export class BlackBoard {}
  21. export class ExecuteContext {
  22. executor: SysBehaviorTree
  23. world: FightWorld
  24. bb: BlackBoard
  25. entity: number
  26. dt: number
  27. public init(executor: SysBehaviorTree, world: FightWorld) {
  28. this.executor = executor
  29. this.world = world
  30. }
  31. public set(entity: number, dt: number, bb: BlackBoard) {
  32. this.entity = entity
  33. this.dt = dt
  34. this.bb = bb
  35. }
  36. }
  37. /** 节点状态 */
  38. export enum NodeState {
  39. Executing, // 执行中
  40. Success, // 成功
  41. Fail, // 失败
  42. }
  43. /** 节点类型 */
  44. export enum NodeType {
  45. // 组合节点
  46. LockedSequence, // 锁状态顺序节点
  47. Sequence, //
  48. Selector, // 选择节点
  49. RandomSelector, // 随机选择节点
  50. Parallel, // 并行节点
  51. RootSelector, //行为树根选择节点,每帧会循环进入所有子节点
  52. // 修饰节点
  53. Inverter, // 逆变节点
  54. Success, // 成功节点
  55. Fail, // 失败节点
  56. Repeater, // 重复节点
  57. RetryTillSuccess, // 重复直到成功
  58. // 叶子结点
  59. Wait, // 等待
  60. Action,
  61. WalkToCloseTarget, // 往最近的敌人移动 往敌方X方向移动,到达条件会往敌方X,Y方向一起移动
  62. MeleeWalkToTarget, // 近战移动到即将攻击目标的攻击点
  63. MeleeMonitor, // 近战监测目标敌人是否进入近战接触范围,进入近战接触范围,会往敌方X,Y方向一起移动
  64. MeleeXMonitor, // 当X轴没有敌人再去判断近战监测范围
  65. AttackMonitor, // 监测目标敌人是否进入攻击范围
  66. Attack, // 攻击
  67. WillAttackNotWillAttack, // 将要攻击的敌人将要攻击
  68. WillAttack, //将要攻击敌人
  69. WillBeAttack, //将要被攻击
  70. HasAttackEnemy, //有正在攻击的敌人
  71. FindEnemy, // 有没有最近的敌人
  72. HasBeAttack, // 有没有最近的敌人
  73. BeDizzy, // 被晕眩
  74. Dizzy, // 晕眩中
  75. HasSkill, // 是否有技能能施放
  76. CastSkill, // 技能施放中
  77. Skill, // 技能施放
  78. Stop, //停止移动
  79. StopAttack, //停止攻击
  80. StopSkill, //停止吟唱技能
  81. }
  82. export class NodeBase {
  83. public type: NodeType
  84. public state: NodeState = NodeState.Success
  85. public failLog: string
  86. public successLog: string
  87. constructor(type: NodeType) {
  88. this.type = type
  89. }
  90. }
  91. let debug = CC_DEV
  92. /** 组合节点 */
  93. class CombineNode extends NodeBase {
  94. public children: NodeBase[] = []
  95. public constructor(type: NodeType, children: NodeBase[]) {
  96. super(type)
  97. this.children = children
  98. }
  99. }
  100. export class SequenceNode extends CombineNode {
  101. public currIdx = 0
  102. public ignoreFailure = false
  103. constructor(children: NodeBase[], ignoreFailture = false) {
  104. super(NodeType.Sequence, children)
  105. this.ignoreFailure = ignoreFailture
  106. }
  107. }
  108. /** 依次执行子节点, 遇到执行失败的则退出并返回失败, 全部执行成功则返回成功 */
  109. export class LockedSequenceNode extends CombineNode {
  110. public currIdx = 0
  111. public ignoreFailure = false
  112. constructor(children: NodeBase[], ignoreFailture = false) {
  113. super(NodeType.LockedSequence, children)
  114. this.ignoreFailure = ignoreFailture
  115. }
  116. }
  117. /** 依次执行子节点, 遇到执行成功的则退出并返回成功, 全部执行失败则返回失败 */
  118. export class SelectorNode extends CombineNode {
  119. public currIdx: number = -1
  120. constructor(children: NodeBase[]) {
  121. super(NodeType.Selector, children)
  122. }
  123. }
  124. /** 行为树根节点,类似SelectorNode,但是会比SelectorNode多一些逻辑,进入节点后会直接update子节点 */
  125. export class RootSelectorNode extends CombineNode {
  126. public currIdx: number = -1
  127. public isMelee = true
  128. constructor(children: NodeBase[], isMelee = true) {
  129. super(NodeType.RootSelector, children)
  130. this.isMelee = isMelee
  131. }
  132. }
  133. /** 根据权重随机选择执行某个子节点 */
  134. export class RandomSelectorNode extends CombineNode {
  135. public weights: number[] // 权重
  136. public currIdx = -1 // 选中的节点
  137. constructor(children: NodeBase[], weigets?: number[]) {
  138. super(NodeType.RandomSelector, children)
  139. this.weights = weigets ? weigets : new Array(children.length).fill(1)
  140. }
  141. }
  142. /** 并行执行所有子节点, 全部执行完毕后返回 */
  143. export class ParallelNode extends CombineNode {
  144. public ignoreFailture = true
  145. constructor(children: NodeBase[], ignoreFailture?: boolean) {
  146. super(NodeType.Parallel, children)
  147. this.ignoreFailture = ignoreFailture
  148. }
  149. }
  150. /** 修饰节点 */
  151. class DecoratorNode extends NodeBase {
  152. public child: NodeBase = null
  153. public constructor(type: NodeType, child: NodeBase) {
  154. super(type)
  155. this.child = child
  156. }
  157. }
  158. /** 返回子节点执行结果的取反值 */
  159. export class InverterNode extends DecoratorNode {
  160. constructor(child: NodeBase) {
  161. super(NodeType.Inverter, child)
  162. }
  163. }
  164. /** 子节点执行完毕后, 必定返回成功 */
  165. export class SuccessNode extends DecoratorNode {
  166. constructor(child: NodeBase) {
  167. super(NodeType.Success, child)
  168. }
  169. }
  170. /** 子节点执行完毕后, 必定返回失败 */
  171. export class FailNode extends DecoratorNode {
  172. constructor(child: NodeBase) {
  173. super(NodeType.Fail, child)
  174. }
  175. }
  176. /** 子节点执行重复repeatCount次后返回成功 */
  177. export class RepeaterNode extends DecoratorNode {
  178. public repeatCount = 1
  179. public currRepeatCount = 0
  180. public mustSuccess = false // 子节点必须支持成功才增加重复次数
  181. constructor(child: NodeBase, repeatCount: number, mustSuccess = false) {
  182. super(NodeType.Repeater, child)
  183. this.repeatCount = repeatCount
  184. this.mustSuccess = mustSuccess
  185. }
  186. }
  187. /** 子节点重复执行直到返回成功 */
  188. export class RetryTillSuccess extends DecoratorNode {
  189. timeout: number // 超时时间
  190. countDown: number // 剩余时间
  191. constructor(child: NodeBase, timeout: number) {
  192. super(NodeType.RetryTillSuccess, child)
  193. this.timeout = timeout
  194. }
  195. }
  196. /** 叶子结点 */
  197. export class WaitNode extends NodeBase {
  198. public waitSeconds: number
  199. public countDown: number
  200. constructor(seconds: number) {
  201. super(NodeType.Wait)
  202. this.waitSeconds = seconds
  203. }
  204. }
  205. export class WalkToCloseTargetNode extends NodeBase {
  206. public speed: number
  207. public isCloseX: boolean
  208. constructor(speed: number, isCloseX: boolean) {
  209. super(NodeType.WalkToCloseTarget)
  210. this.speed = speed
  211. this.isCloseX = isCloseX
  212. }
  213. }
  214. /** 移动到目标攻击位置后 返回成功 */
  215. export class MeleeWalkToTargetNode extends NodeBase {
  216. public speed: number
  217. constructor(speed: number) {
  218. super(NodeType.MeleeWalkToTarget)
  219. this.speed = speed
  220. }
  221. }
  222. export class MeleeMonitorNode extends NodeBase {
  223. constructor() {
  224. super(NodeType.MeleeMonitor)
  225. }
  226. }
  227. export class MeleeXMonitorNode extends NodeBase {
  228. constructor() {
  229. super(NodeType.MeleeXMonitor)
  230. }
  231. }
  232. export class AttackMonitorNode extends NodeBase {
  233. constructor() {
  234. super(NodeType.AttackMonitor)
  235. }
  236. }
  237. export class AttackNode extends NodeBase {
  238. constructor() {
  239. super(NodeType.Attack)
  240. }
  241. }
  242. /** 将要攻击的目标 */
  243. export class WillAttackNode extends NodeBase {
  244. constructor() {
  245. super(NodeType.WillAttack)
  246. }
  247. }
  248. /** 将要被攻击的目标 */
  249. export class WillBeAttackNode extends NodeBase {
  250. constructor() {
  251. super(NodeType.WillBeAttack)
  252. }
  253. }
  254. /** 有正在攻击的目标 */
  255. export class HasAttackEnemyNode extends NodeBase {
  256. constructor() {
  257. super(NodeType.HasAttackEnemy)
  258. }
  259. }
  260. export class WillAttackNotWillAttackNode extends NodeBase {
  261. constructor() {
  262. super(NodeType.WillAttackNotWillAttack)
  263. }
  264. }
  265. export class BeDizzyNode extends NodeBase {
  266. constructor() {
  267. super(NodeType.BeDizzy)
  268. }
  269. }
  270. export class DizzyNode extends NodeBase {
  271. constructor() {
  272. super(NodeType.Dizzy)
  273. }
  274. }
  275. export class HasSkillNode extends NodeBase {
  276. constructor() {
  277. super(NodeType.HasSkill)
  278. }
  279. }
  280. export class SkillNode extends NodeBase {
  281. constructor() {
  282. super(NodeType.Skill)
  283. }
  284. }
  285. export class CastSkillNode extends NodeBase {
  286. constructor() {
  287. super(NodeType.CastSkill)
  288. }
  289. }
  290. export class FindEnemyNode extends NodeBase {
  291. constructor() {
  292. super(NodeType.FindEnemy)
  293. }
  294. }
  295. export class HasBeAttackNode extends NodeBase {
  296. constructor() {
  297. super(NodeType.HasBeAttack)
  298. }
  299. }
  300. export class StopNode extends NodeBase {
  301. constructor() {
  302. super(NodeType.Stop)
  303. }
  304. }
  305. export class StopAttackNode extends NodeBase {
  306. constructor() {
  307. super(NodeType.StopAttack)
  308. }
  309. }
  310. export class StopSkillNode extends NodeBase {
  311. constructor() {
  312. super(NodeType.StopSkill)
  313. }
  314. }
  315. class NodeHandler {
  316. onEnter: (node: NodeBase, context: ExecuteContext) => void
  317. onUpdate: (node: NodeBase, context: ExecuteContext) => void
  318. }
  319. export const NodeHandlers: NodeHandler[] = []
  320. /** Sequence node */
  321. NodeHandlers[NodeType.Sequence] = {
  322. onEnter(node: SequenceNode, context: ExecuteContext): void {
  323. node.currIdx = 0
  324. context.executor.onEnterBTNode(node.children[node.currIdx], context)
  325. node.state = NodeState.Executing
  326. },
  327. onUpdate(node: SequenceNode, context: ExecuteContext): void {
  328. if (node.currIdx < 0 || node.currIdx >= node.children.length) {
  329. // 越界了, 不应该发生, 直接认为是失败了
  330. node.state = NodeState.Fail
  331. if (debug) node.failLog = '越界了, 不应该发生, 直接认为是失败了'
  332. return
  333. }
  334. // 检查前置条件是否满足
  335. for (let i = 0; i < node.currIdx; i++) {
  336. context.executor.updateBTNode(node.children[i], context)
  337. if (node.children[i].state !== NodeState.Success) {
  338. //当前置条件不满足,节点应该失败
  339. node.state = NodeState.Fail
  340. if (debug) node.failLog = '队列行为被前置打断===Sequence Fail==>' + node.children[i].failLog
  341. return
  342. }
  343. }
  344. context.executor.updateBTNode(node.children[node.currIdx], context)
  345. const state = node.children[node.currIdx].state
  346. if (node.currIdx == 4 && context.entity == debugEntity)
  347. console.log('state', state, state == NodeState.Executing)
  348. if (state == NodeState.Executing) return
  349. if (state == NodeState.Fail && !node.ignoreFailure) {
  350. node.state = NodeState.Fail
  351. if (debug) node.failLog = '队列中断==>' + node.children[node.currIdx].failLog
  352. return
  353. }
  354. if (state == NodeState.Success && node.currIdx == node.children.length - 1) {
  355. node.state = NodeState.Success
  356. if (debug) node.successLog = '队列成功==>' + node.children[node.currIdx].successLog
  357. return
  358. }
  359. context.executor.onEnterBTNode(node.children[++node.currIdx], context)
  360. },
  361. }
  362. // 子节点某个节点在中途失败,不影响后续节点执行,后续节点执行完结束队列,举个例子 攻击动作1秒 --》 等待2秒,如果攻击动作在0.5秒被打断,这个队列节点也要等到2秒后结束
  363. /** LockedSequence node */
  364. NodeHandlers[NodeType.LockedSequence] = {
  365. onEnter(node: LockedSequenceNode, context: ExecuteContext): void {
  366. node.currIdx = 0
  367. context.executor.onEnterBTNode(node.children[node.currIdx], context)
  368. node.state = NodeState.Executing
  369. },
  370. onUpdate(node: LockedSequenceNode, context: ExecuteContext): void {
  371. if (node.state !== NodeState.Executing) return
  372. if (node.currIdx < 0 || node.currIdx >= node.children.length) {
  373. // 越界了, 不应该发生, 直接认为是失败了
  374. node.state = NodeState.Fail
  375. return
  376. }
  377. context.executor.updateBTNode(node.children[node.currIdx], context)
  378. let state = node.children[node.currIdx].state
  379. if (state == NodeState.Executing) return
  380. if (state === NodeState.Fail && !node.ignoreFailure) {
  381. node.state = NodeState.Fail
  382. return
  383. }
  384. if (state === NodeState.Success && node.currIdx == node.children.length - 1) {
  385. node.state = NodeState.Success
  386. return
  387. }
  388. context.executor.onEnterBTNode(node.children[++node.currIdx], context)
  389. },
  390. }
  391. /** Selector node */
  392. NodeHandlers[NodeType.Selector] = {
  393. onEnter(node: SelectorNode, context: ExecuteContext): void {
  394. node.currIdx = 0
  395. context.executor.onEnterBTNode(node.children[node.currIdx], context)
  396. node.state = NodeState.Executing
  397. },
  398. onUpdate(node: SelectorNode, context: ExecuteContext): void {
  399. if (node.state !== NodeState.Executing) return
  400. if (node.currIdx < 0 || node.currIdx >= node.children.length) {
  401. // 越界了, 认为是失败了
  402. node.state = NodeState.Fail
  403. return
  404. }
  405. context.executor.updateBTNode(node.children[node.currIdx], context)
  406. let state = node.children[node.currIdx].state
  407. if (state == NodeState.Executing) return
  408. // 执行到最后一个都失败了, 那边selector失败了
  409. if (state === NodeState.Fail && node.currIdx == node.children.length - 1) {
  410. node.state = NodeState.Fail
  411. return
  412. }
  413. if (state == NodeState.Success) {
  414. node.state = NodeState.Success
  415. return
  416. }
  417. context.executor.onEnterBTNode(node.children[++node.currIdx], context)
  418. },
  419. }
  420. export let debugEntity: number = -1
  421. let debugEntityCurIdx: number = -1
  422. let rootSelectorLog = ['晕眩', '放技能', '攻击', '往X轴敌人移动', '停止']
  423. let meleeRootSelectorLog = [
  424. '晕眩',
  425. '放技能',
  426. '寻敌',
  427. '往X轴敌人移动',
  428. '往敌人移动',
  429. '将被攻击',
  430. '将攻击敌人',
  431. '攻击',
  432. '停止',
  433. ]
  434. /** UpdateSelector node */
  435. NodeHandlers[NodeType.RootSelector] = {
  436. onEnter(node: RootSelectorNode, context: ExecuteContext): void {
  437. node.currIdx = 0
  438. context.executor.onEnterBTNode(node.children[node.currIdx], context)
  439. node.state = NodeState.Executing
  440. this.onUpdate(node, context)
  441. },
  442. onUpdate(node: RootSelectorNode, context: ExecuteContext): void {
  443. if (node.state !== NodeState.Executing) return
  444. if (node.currIdx < 0 || node.currIdx >= node.children.length) {
  445. // 越界了, 认为是失败了
  446. node.state = NodeState.Fail
  447. return
  448. }
  449. while (node.currIdx < node.children.length) {
  450. context.executor.updateBTNode(node.children[node.currIdx], context)
  451. let state = node.children[node.currIdx].state
  452. if (state == NodeState.Executing) break
  453. // 执行到最后一个都失败了, 那边selector失败了
  454. if (state === NodeState.Fail && node.currIdx == node.children.length - 1) {
  455. node.state = NodeState.Fail
  456. break
  457. }
  458. if (state == NodeState.Success) {
  459. if (context.entity == debugEntity && node.currIdx != debugEntityCurIdx) {
  460. let failStr = ''
  461. let debugRootLog = node.isMelee ? meleeRootSelectorLog : rootSelectorLog
  462. for (let i = 0; i < node.currIdx; i++) {
  463. failStr += `[${debugRootLog[i]}]` + '(' + node.children[i].failLog + ')'
  464. }
  465. console.log('--------', context.entity, '--------', 'RootSelector Fail ', failStr)
  466. console.log(
  467. 'RootSelector Success ',
  468. debugRootLog[node.currIdx],
  469. node.children[node.currIdx].successLog,
  470. '--------',
  471. context.entity,
  472. '--------',
  473. )
  474. node.currIdx = debugEntityCurIdx
  475. }
  476. node.state = NodeState.Success
  477. break
  478. }
  479. context.executor.onEnterBTNode(node.children[++node.currIdx], context)
  480. }
  481. },
  482. }
  483. /** Selector node */
  484. NodeHandlers[NodeType.RandomSelector] = {
  485. onEnter(node: RandomSelectorNode, context: ExecuteContext): void {
  486. // 根据权重随机获取idx
  487. let totalWeight = 0
  488. for (const weight of node.weights) {
  489. totalWeight += weight
  490. }
  491. let randomWeight = Math.random() * totalWeight
  492. for (let i = 0; i < node.weights.length; i++) {
  493. randomWeight -= node.weights[i]
  494. if (randomWeight <= 0) {
  495. node.currIdx = i
  496. break
  497. }
  498. }
  499. context.executor.onEnterBTNode(node.children[node.currIdx], context)
  500. node.state = NodeState.Executing
  501. },
  502. onUpdate(node: RandomSelectorNode, context: ExecuteContext): void {
  503. if (node.state !== NodeState.Executing) return
  504. let n = node.children[node.currIdx]
  505. context.executor.updateBTNode(n, context)
  506. node.state = n.state
  507. },
  508. }
  509. /** Parallel node */
  510. NodeHandlers[NodeType.Parallel] = {
  511. onEnter(node: ParallelNode, context: ExecuteContext): void {
  512. for (const n of node.children) {
  513. context.executor.onEnterBTNode(n, context)
  514. }
  515. node.state = NodeState.Executing
  516. },
  517. onUpdate(node: ParallelNode, context: ExecuteContext): void {
  518. if (node.state !== NodeState.Executing) return
  519. let end = true
  520. for (const child of node.children) {
  521. context.executor.updateBTNode(child, context)
  522. if (child.state === NodeState.Executing) {
  523. end = false
  524. continue
  525. }
  526. if (child.state == NodeState.Fail) {
  527. node.state = NodeState.Fail
  528. return
  529. }
  530. }
  531. if (end) {
  532. node.state = NodeState.Success
  533. }
  534. },
  535. }
  536. /** Inverter node */
  537. NodeHandlers[NodeType.Inverter] = {
  538. onEnter(node: InverterNode, context: ExecuteContext): void {
  539. context.executor.onEnterBTNode(node.child, context)
  540. node.state = NodeState.Executing
  541. },
  542. onUpdate(node: InverterNode, context: ExecuteContext): void {
  543. context.executor.updateBTNode(node.child, context)
  544. if (node.child.state === NodeState.Executing) return
  545. if (node.child.state == NodeState.Success) {
  546. node.state = NodeState.Fail
  547. if (debug) node.failLog = node.child.successLog
  548. }
  549. if (node.child.state == NodeState.Fail) {
  550. node.state = NodeState.Success
  551. if (debug) node.successLog = node.child.failLog
  552. }
  553. },
  554. }
  555. /** Success node */
  556. NodeHandlers[NodeType.Success] = {
  557. onEnter(node: SuccessNode, context: ExecuteContext): void {
  558. context.executor.onEnterBTNode(node.child, context)
  559. node.state = NodeState.Executing
  560. },
  561. onUpdate(node: SuccessNode, context: ExecuteContext): void {
  562. if (node.state !== NodeState.Executing) return
  563. context.executor.updateBTNode(node.child, context)
  564. if (node.child.state === NodeState.Executing) return
  565. node.state = NodeState.Success
  566. },
  567. }
  568. /** Fail node */
  569. NodeHandlers[NodeType.Fail] = {
  570. onEnter(node: FailNode, context: ExecuteContext): void {
  571. context.executor.onEnterBTNode(node.child, context)
  572. node.state = NodeState.Executing
  573. },
  574. onUpdate(node: FailNode, context: ExecuteContext): void {
  575. if (node.state !== NodeState.Executing) return
  576. context.executor.updateBTNode(node.child, context)
  577. if (node.child.state === NodeState.Executing) return
  578. node.state = NodeState.Fail
  579. },
  580. }
  581. /** Repeater node */
  582. NodeHandlers[NodeType.Repeater] = {
  583. onEnter(node: RepeaterNode, context: ExecuteContext): void {
  584. node.currRepeatCount = 0
  585. context.executor.onEnterBTNode(node.child, context)
  586. node.state = NodeState.Executing
  587. },
  588. onUpdate(node: RepeaterNode, context: ExecuteContext): void {
  589. if (node.state !== NodeState.Executing) return
  590. context.executor.updateBTNode(node.child, context)
  591. if (node.child.state === NodeState.Executing) return
  592. if (!node.mustSuccess || node.child.state == NodeState.Success) node.currRepeatCount++
  593. if (node.currRepeatCount >= node.repeatCount) {
  594. node.state = NodeState.Success
  595. return
  596. }
  597. context.executor.onEnterBTNode(node.child, context)
  598. },
  599. }
  600. /** RetryTillSuccess node */
  601. NodeHandlers[NodeType.RetryTillSuccess] = {
  602. onEnter(node: RetryTillSuccess, context: ExecuteContext): void {
  603. node.countDown = node.timeout
  604. context.executor.onEnterBTNode(node.child, context)
  605. node.state = NodeState.Executing
  606. },
  607. onUpdate(node: RetryTillSuccess, context: ExecuteContext): void {
  608. if (node.state !== NodeState.Executing) return
  609. node.countDown -= context.dt
  610. context.executor.updateBTNode(node.child, context)
  611. if (node.child.state === NodeState.Executing) return
  612. if (node.child.state == NodeState.Success) {
  613. node.state = NodeState.Success
  614. return
  615. }
  616. if (node.countDown > 0) {
  617. context.executor.onEnterBTNode(node.child, context)
  618. return
  619. }
  620. node.state = NodeState.Fail
  621. },
  622. }
  623. /** Wait node */
  624. NodeHandlers[NodeType.Wait] = {
  625. onEnter(node: WaitNode, context: ExecuteContext): void {
  626. node.countDown = node.waitSeconds
  627. node.state = NodeState.Executing
  628. },
  629. onUpdate(node: WaitNode, context: ExecuteContext): void {
  630. if (node.state !== NodeState.Executing) return
  631. node.countDown -= context.dt
  632. if (node.countDown <= 0) {
  633. node.state = NodeState.Success
  634. }
  635. },
  636. }
  637. //-------------------------------------行为能执行的条件,每次行为update要执行条件--------------------------------------------------
  638. /** FindEnemy node 战场上有没有敌人 */
  639. NodeHandlers[NodeType.FindEnemy] = {
  640. onEnter(node: FindEnemyNode, context: ExecuteContext): void {
  641. node.state = NodeState.Executing
  642. },
  643. onUpdate(node: FindEnemyNode, context: ExecuteContext): void {
  644. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  645. node.state = !context.world.isDie(comFindEnemy?.enemy) ? NodeState.Success : NodeState.Fail
  646. if (debug) {
  647. if (node.state == NodeState.Success) {
  648. node.successLog = '找到敌人==>' + comFindEnemy.enemy.toString()
  649. } else {
  650. node.failLog = '战场上没有敌人'
  651. }
  652. }
  653. },
  654. }
  655. /** MeleeMonitor node 是否进入Y轴近战监视区域 */
  656. NodeHandlers[NodeType.MeleeMonitor] = {
  657. onEnter(node: MeleeMonitorNode, context: ExecuteContext): void {
  658. node.state = NodeState.Executing
  659. },
  660. onUpdate(node: MeleeMonitorNode, context: ExecuteContext): void {
  661. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  662. node.state =
  663. comFindEnemy && comFindEnemy.cObject && comFindEnemy.cObject.containsBody.size > 0
  664. ? BT.NodeState.Success
  665. : BT.NodeState.Fail
  666. if (debug) {
  667. if (node.state == NodeState.Success) {
  668. node.successLog =
  669. '敌人进入Y轴近战监视区域==>' + comFindEnemy.cObject.containsBody.keysArr().toString()
  670. } else {
  671. node.failLog = 'Y轴近战监视区域没有敌人'
  672. }
  673. }
  674. },
  675. }
  676. /** MeleeMonitor node 是否进入X轴近战监视区域 */
  677. NodeHandlers[NodeType.MeleeXMonitor] = {
  678. onEnter(node: MeleeXMonitorNode, context: ExecuteContext): void {
  679. node.state = NodeState.Executing
  680. },
  681. onUpdate(node: MeleeXMonitorNode, context: ExecuteContext): void {
  682. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  683. node.state =
  684. comFindEnemy && comFindEnemy.cObjectMeleeX && comFindEnemy.cObjectMeleeX.containsBody.size > 0
  685. ? BT.NodeState.Success
  686. : BT.NodeState.Fail
  687. if (debug) {
  688. if (node.state == NodeState.Success) {
  689. node.successLog =
  690. '敌人进入X轴近战监视区域==>' + comFindEnemy.cObjectMeleeX.containsBody.keysArr().toString()
  691. } else {
  692. node.failLog = 'X轴近战监视区域没有敌人'
  693. }
  694. }
  695. },
  696. }
  697. /** AttackMonitor node 是否进入攻击范围*/
  698. NodeHandlers[NodeType.AttackMonitor] = {
  699. onEnter(node: AttackMonitorNode, context: ExecuteContext): void {
  700. node.state = NodeState.Executing
  701. },
  702. onUpdate(node: AttackMonitorNode, context: ExecuteContext): void {
  703. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  704. node.state =
  705. comFindEnemy && comFindEnemy.attackCObject && comFindEnemy.attackCObject.containsBody.size > 0
  706. ? BT.NodeState.Success
  707. : BT.NodeState.Fail
  708. if (debug) {
  709. if (node.state == NodeState.Success) {
  710. node.successLog =
  711. '敌人进入攻击范围==>' + comFindEnemy.attackCObject.containsBody.keysArr().toString()
  712. } else {
  713. node.failLog = '没有敌人进入攻击范围'
  714. }
  715. }
  716. },
  717. }
  718. /** WillAttackNotWillAttack node 近战即将攻击的目标有没有即将攻击的目标*/
  719. NodeHandlers[NodeType.WillAttackNotWillAttack] = {
  720. onEnter(node: WillAttackNotWillAttackNode, context: ExecuteContext): void {
  721. node.state = NodeState.Executing
  722. },
  723. onUpdate(node: WillAttackNotWillAttackNode, context: ExecuteContext): void {
  724. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  725. let comMovable = context.world.getComponent(comFindEnemy?.willAttackMelee, ComMovable)
  726. node.state = comMovable.speed ? NodeState.Fail : NodeState.Success
  727. if (debug) {
  728. if (node.state == NodeState.Success) {
  729. node.successLog = '近战即将攻击的目标正在走路==>' + comFindEnemy?.willAttackMelee
  730. } else {
  731. node.failLog = '近战即将攻击的目标停止了==>' + comFindEnemy?.willAttackMelee
  732. }
  733. }
  734. },
  735. }
  736. /** WillAttackNode node 近战即将攻击敌人*/
  737. NodeHandlers[NodeType.WillAttack] = {
  738. onEnter(node: WillAttackNode, context: ExecuteContext): void {
  739. node.state = NodeState.Executing
  740. },
  741. onUpdate(node: WillAttackNode, context: ExecuteContext): void {
  742. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  743. node.state = !context.world.isDie(comFindEnemy?.willAttackMelee) ? BT.NodeState.Success : BT.NodeState.Fail
  744. if (debug) {
  745. if (node.state == NodeState.Success) {
  746. node.successLog = '近战有即将攻击的敌人==>' + comFindEnemy?.willAttackMelee
  747. } else {
  748. node.failLog = '近战没有即将攻击敌人'
  749. }
  750. }
  751. },
  752. }
  753. /** WillAttackNode node 近战即将被敌人攻击*/
  754. NodeHandlers[NodeType.WillBeAttack] = {
  755. onEnter(node: WillBeAttackNode, context: ExecuteContext): void {
  756. node.state = NodeState.Executing
  757. },
  758. onUpdate(node: WillBeAttackNode, context: ExecuteContext): void {
  759. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  760. node.state = !context.world.isDie(comFindEnemy?.willBeAttackMelee)
  761. ? BT.NodeState.Success
  762. : BT.NodeState.Fail
  763. if (debug) {
  764. if (node.state == NodeState.Success) {
  765. node.successLog = '近战即将被敌人攻击==>' + comFindEnemy?.willBeAttackMelee
  766. } else {
  767. node.failLog = '近战没有近战即将被敌人攻击'
  768. }
  769. }
  770. },
  771. }
  772. /** HasAttackEnemy node 近战有没有正在攻击的敌人*/
  773. NodeHandlers[NodeType.HasAttackEnemy] = {
  774. onEnter(node: HasAttackEnemyNode, context: ExecuteContext): void {
  775. node.state = NodeState.Executing
  776. },
  777. onUpdate(node: HasAttackEnemyNode, context: ExecuteContext): void {
  778. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  779. node.state = !context.world.isDie(comAttackable?.curAttack) ? BT.NodeState.Success : BT.NodeState.Fail
  780. if (debug) {
  781. if (node.state == NodeState.Success) {
  782. node.successLog = '近战正在攻击的敌==>' + comAttackable?.curAttack
  783. } else {
  784. node.failLog = '近战没有正在攻击的敌人'
  785. }
  786. }
  787. },
  788. }
  789. /** BeDizzy node 是否被晕眩*/
  790. NodeHandlers[NodeType.BeDizzy] = {
  791. onEnter(node: BeDizzyNode, context: ExecuteContext): void {
  792. node.state = NodeState.Executing
  793. },
  794. onUpdate(node: BeDizzyNode, context: ExecuteContext): void {
  795. let comDizzy = context.world.getComponent(context.entity, ComDizzy)
  796. node.state = comDizzy && comDizzy.countDown > 0 ? NodeState.Success : NodeState.Fail
  797. if (debug) {
  798. if (node.state == NodeState.Success) {
  799. node.successLog = '被晕眩='
  800. } else {
  801. node.failLog = '没被晕眩'
  802. }
  803. }
  804. },
  805. }
  806. /** HasSkill node 有没有技能可以施放*/
  807. // 所有的判断条件每次都要判断
  808. NodeHandlers[NodeType.HasSkill] = {
  809. onEnter(node: HasSkillNode, context: ExecuteContext): void {
  810. node.state = NodeState.Executing
  811. },
  812. onUpdate(node: HasSkillNode, context: ExecuteContext): void {
  813. let comSkillAbel = context.world.getComponent(context.entity, ComSkillAbel)
  814. if (!comSkillAbel) {
  815. //console.log('HasSkill onUpdate', '目标没有ComSkillAbel', context.entity)
  816. node.state = NodeState.Fail
  817. return
  818. }
  819. node.state =
  820. comSkillAbel &&
  821. comSkillAbel.skillConfig &&
  822. comSkillAbel.roles.length >= comSkillAbel.skillConfig.minRole
  823. ? NodeState.Success
  824. : NodeState.Fail
  825. if (debug) {
  826. if (node.state == NodeState.Success) {
  827. node.successLog = `有技能可以施放===>${
  828. comSkillAbel.skillConfig.name
  829. }==>技能目标${comSkillAbel.roles.toString()}`
  830. } else {
  831. node.failLog = `没有技能可以施放===>技能目标人数:${comSkillAbel.roles.length}技能:${comSkillAbel.skillConfig?.name}正在施放:${comSkillAbel.dirty}`
  832. }
  833. }
  834. },
  835. }
  836. /** CastSkill node 正在施放技能*/
  837. // 所有的判断条件每次都要判断
  838. NodeHandlers[NodeType.CastSkill] = {
  839. onEnter(node: HasSkillNode, context: ExecuteContext): void {
  840. node.state = NodeState.Executing
  841. },
  842. onUpdate(node: HasSkillNode, context: ExecuteContext): void {
  843. let comSkillAbel = context.world.getComponent(context.entity, ComSkillAbel)
  844. if (!comSkillAbel) {
  845. //console.log('HasSkill onUpdate', '目标没有ComSkillAbel', context.entity)
  846. node.state = NodeState.Fail
  847. return
  848. }
  849. node.state = comSkillAbel.dirty ? NodeState.Success : NodeState.Fail
  850. if (debug) {
  851. if (node.state == NodeState.Success) {
  852. node.successLog = '正在施放技能'
  853. } else {
  854. node.failLog = '没有正在施放技能'
  855. }
  856. }
  857. },
  858. }
  859. /** BeDizzy node 是否即将被攻击*/
  860. NodeHandlers[NodeType.HasBeAttack] = {
  861. onEnter(node: HasBeAttackNode, context: ExecuteContext): void {
  862. node.state = NodeState.Executing
  863. },
  864. onUpdate(node: HasBeAttackNode, context: ExecuteContext): void {
  865. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  866. node.state = comAttackable && comAttackable.beAttacks.length > 0 ? BT.NodeState.Success : BT.NodeState.Fail
  867. if (debug) {
  868. if (node.state == NodeState.Success) {
  869. node.successLog = '被近战包围==>' + comAttackable.beAttacks.toString()
  870. } else {
  871. node.failLog = '没有被近战包围'
  872. }
  873. }
  874. },
  875. }
  876. //-------------------------------------行为--------------------------------------------------
  877. /** MeleeWalkToTarget node */
  878. NodeHandlers[NodeType.MeleeWalkToTarget] = {
  879. onEnter(node: MeleeWalkToTargetNode, context: ExecuteContext): void {
  880. let comTrans = context.world.getComponent(context.entity, ComTransform)
  881. let comMovable = context.world.getComponent(context.entity, ComMovable)
  882. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  883. let targetComTrans = context.world.getComponent(comFindEnemy.willAttackMelee, ComTransform)
  884. let targetComMovable = context.world.getComponent(comFindEnemy.willAttackMelee, ComMovable)
  885. let targetPos = context.world.moveToMeleeAttackPos(
  886. context.entity,
  887. comTrans,
  888. targetComTrans,
  889. targetComMovable,
  890. )
  891. comMovable.pointIdx = 0
  892. comMovable.points.length = 0
  893. comMovable.points.push(targetPos)
  894. //加速前往近战攻击点
  895. context.world.changeMoveSpeed(context.entity, node.speed)
  896. node.state = NodeState.Executing
  897. //console.log(' onEnter comFindEnemy.willAttackMelee', context.entity, comFindEnemy.willAttackMelee)
  898. },
  899. onUpdate(node: MeleeWalkToTargetNode, context: ExecuteContext): void {
  900. if (node.state !== NodeState.Executing) return
  901. let comMovable = context.world.getComponent(context.entity, ComMovable)
  902. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  903. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  904. //在进入行为之前满足条件,这时候运行到下一帧,可能在SysFindEnemy系统中修改了死亡的敌人comFindEnemy.willAttackMelee=0
  905. if (context.world.isDie(comFindEnemy.willAttackMelee)) {
  906. Log.error('MeleeWalkToTarget onUpdate', '将要攻击的敌人不存在', comFindEnemy.willAttackMelee)
  907. node.state = BT.NodeState.Fail
  908. return
  909. }
  910. if (
  911. comMovable.points.length == 0 ||
  912. comMovable.pointIdx < 0 ||
  913. comMovable.pointIdx >= comMovable.points.length
  914. ) {
  915. // 把将要击打变成击打
  916. comAttackable.curAttack = comFindEnemy.willAttackMelee
  917. let enemyComFindEnemy = context.world.getComponent(comAttackable.curAttack, ComFindEnemy)
  918. let enemyComAttackable = context.world.getComponent(comAttackable.curAttack, ComAttackable)
  919. // 敌人击打数组加入自己
  920. enemyComAttackable.beAttacks.push(context.entity)
  921. //如果敌人等待着自己将敌人攻击赋值
  922. if (enemyComFindEnemy && enemyComFindEnemy.willBeAttackMelee == context.entity) {
  923. enemyComFindEnemy.willBeAttackMelee = 0
  924. enemyComAttackable.curAttack = context.entity
  925. comAttackable.beAttacks.push(comAttackable.curAttack)
  926. }
  927. comFindEnemy.willAttackMelee = 0
  928. node.state = BT.NodeState.Success
  929. if (debug) {
  930. if (node.state == NodeState.Success) {
  931. node.successLog = '走到了近战攻击点==>' + comAttackable.curAttack.toString()
  932. }
  933. }
  934. }
  935. },
  936. }
  937. /** WalkToClosedTarget node */
  938. NodeHandlers[NodeType.WalkToCloseTarget] = {
  939. onEnter(node: WalkToCloseTargetNode, context: ExecuteContext): void {
  940. let comTrans = context.world.getComponent(context.entity, ComTransform)
  941. let comMovable = context.world.getComponent(context.entity, ComMovable)
  942. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  943. let comCocosNode = context.world.getComponent(context.entity, ComCocosNode)
  944. let comRole = context.world.getComponent(context.entity, ComRole)
  945. let comSpComCocosNode = context.world.getComponent(comRole.spineEntity, ComCocosNode)
  946. let targetComTrans = context.world.getComponent(comFindEnemy.enemy, ComTransform)
  947. comMovable.pointIdx = 0
  948. comMovable.points.length = 0
  949. comMovable.points.push(
  950. cc.v2(comTrans.x, comTrans.y),
  951. cc.v2(targetComTrans.x, node.isCloseX ? comTrans.y : targetComTrans.y),
  952. )
  953. context.world.changeMoveSpeed(context.entity, node.speed)
  954. comMovable.closeTarget = comFindEnemy.enemy
  955. comTrans.dir.x = targetComTrans.x > comTrans.x ? 1 : -1
  956. comCocosNode.node?.getComponent(EventProcess)?.syncDir(comTrans.dir)
  957. comSpComCocosNode?.node?.getComponent(EventProcess)?.syncDir(comTrans.dir)
  958. node.state = NodeState.Executing
  959. },
  960. onUpdate(node: WalkToCloseTargetNode, context: ExecuteContext): void {
  961. if (node.state !== NodeState.Executing) return
  962. let comTrans = context.world.getComponent(context.entity, ComTransform)
  963. let comMovable = context.world.getComponent(context.entity, ComMovable)
  964. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  965. let targetComTrans = context.world.getComponent(comFindEnemy.enemy, ComTransform)
  966. if (comMovable.points[1]) {
  967. comMovable.points[1].x = targetComTrans.x
  968. comMovable.points[1].y = node.isCloseX ? comTrans.y : targetComTrans.y
  969. }
  970. if (
  971. comMovable.points.length == 0 ||
  972. comMovable.pointIdx < 0 ||
  973. comMovable.pointIdx >= comMovable.points.length
  974. ) {
  975. node.state = BT.NodeState.Success
  976. }
  977. },
  978. }
  979. /** Attack node */
  980. NodeHandlers[NodeType.Attack] = {
  981. onEnter(node: AttackNode, context: ExecuteContext): void {
  982. //当攻击目标死亡,前置条件被打断,被再次执行攻击行为,这个时候要return
  983. if (node.state == NodeState.Executing) {
  984. return
  985. }
  986. let comCocosNode = context.world.getComponent(context.entity, ComCocosNode)
  987. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  988. let comRole = context.world.getComponent(context.entity, ComRole)
  989. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  990. //远程每次切换最近的目标
  991. if (!comAttackable.isMelee) {
  992. comAttackable.curAttack = comFindEnemy.enemy
  993. }
  994. let enemyComTransform = context.world.getComponent(comAttackable.curAttack, ComTransform)
  995. let comTransform = context.world.getComponent(context.entity, ComTransform)
  996. //console.log('攻击节点 ------------------->', context.entity)
  997. comTransform.dir.x = comTransform?.x - enemyComTransform?.x < 0 ? 1 : -1
  998. let comSpineTransform = context.world.getComponent(comRole.spineEntity, ComTransform)
  999. if (comSpineTransform) {
  1000. comSpineTransform.dir.x = comTransform.dir.x
  1001. }
  1002. let attackSpeed = Math.clampValue(comRole.attackSpeed, Data.game.minAttackSpeed, Data.game.maxAttackSpeed)
  1003. let attackScale = Data.game.rateNum / attackSpeed
  1004. let buffs = comRole.buffs
  1005. let attackIndex = 0
  1006. for (let i = 0; i < buffs.length; i++) {
  1007. let tmpIndex = buffs[i].buffCfg.effectType.indexOf(BUFF_EFFECT_TYPE.changeSpineAttack)
  1008. if (tmpIndex >= 0) {
  1009. attackIndex = buffs[i].buffCfg.effectParm[tmpIndex][0]
  1010. }
  1011. }
  1012. comCocosNode.events.push(
  1013. new EventAttack(comTransform.dir, !comAttackable.isMelee, attackScale, attackIndex),
  1014. )
  1015. //同步spine攻击
  1016. let comSpineNode = context.world.getComponent(comRole.spineEntity, ComCocosNode)
  1017. comSpineNode?.events.push(
  1018. new EventAttack(comTransform.dir, !comAttackable.isMelee, attackScale, attackIndex),
  1019. )
  1020. comAttackable.countDown = (comRole.attackTime + comRole.attackCD) * attackScale * Data.game.gameSpeed
  1021. comAttackable.dirty = true
  1022. comAttackable.hurtFrame =
  1023. comAttackable.countDown - comRole.roleCfg.hurtFrame * attackScale * comRole.attackTime
  1024. comAttackable.hurtFrameCompleted = false
  1025. node.state = NodeState.Executing
  1026. },
  1027. onUpdate(node: AttackNode, context: ExecuteContext): void {
  1028. if (node.state != NodeState.Executing) return
  1029. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  1030. let comFindEnemy = context.world.getComponent(context.entity, ComFindEnemy)
  1031. let comRole = context.world.getComponent(context.entity, ComRole)
  1032. //可能当前攻击敌人死亡
  1033. // if (context.world.isDie(comAttackable?.curAttack)) {
  1034. // //console.log('Attack onUpdate', '当前攻击敌人死亡', context.entity, comAttackable?.curAttack)
  1035. // comAttackable.dirty = false
  1036. // comAttackable.countDown = 0
  1037. // node.state = NodeState.Fail
  1038. // }
  1039. if (comAttackable && comAttackable.countDown <= 0) {
  1040. node.state = NodeState.Success
  1041. if (debug) {
  1042. if (node.state == NodeState.Success) {
  1043. node.successLog = '攻击行为成功==>' + comAttackable?.curAttack
  1044. }
  1045. }
  1046. let comBeAttackRole: ComRole = context.world.getComponent(comAttackable.curAttack, ComRole)
  1047. //当正在攻击对面基地的时候,敌军有别的单位,不在打基地了--》修改为Y轴探测范围内有人不再攻击基地
  1048. if (context.world.isBase(comBeAttackRole)) {
  1049. let filter = context.world.getFilter(
  1050. comRole.group == Data.game.gFriend ? FILTER_CAN_ATTACK_ENEMY : FILTER_CAN_ATTACK_FRIEND,
  1051. )
  1052. if (filter.entities.size > 1 && comFindEnemy.cObject.containsBody.size > 1) {
  1053. comAttackable.curAttack = 0
  1054. }
  1055. }
  1056. }
  1057. },
  1058. }
  1059. /** Skill node */
  1060. NodeHandlers[NodeType.Skill] = {
  1061. onEnter(node: SkillNode, context: ExecuteContext): void {
  1062. let comSkillAbel = context.world.getComponent(context.entity, ComSkillAbel)
  1063. let comCocosNode = context.world.getComponent(context.entity, ComCocosNode)
  1064. let comRole = context.world.getComponent(context.entity, ComRole)
  1065. if (!comSkillAbel || !comCocosNode || !comRole) {
  1066. !comSkillAbel && console.log('Skill onEnter', '目标没有ComSkillAbel', context.entity)
  1067. !comCocosNode && console.log('Skill onEnter', '目标没有ComCocosNode', context.entity)
  1068. return
  1069. }
  1070. //console.log('施放技能', comSkillAbel.skillConfig.name)
  1071. if (CC_DEV) ccUtils.setLabel(comSkillAbel.skillConfig.name, comCocosNode.node, 'skill')
  1072. //技能无CD的buff只放一次
  1073. let curSkillIndex = 0
  1074. for (let i = 0; i < comRole.skills.length; i++) {
  1075. if (comRole.skills[i].ID == comSkillAbel.skillConfig.ID) {
  1076. curSkillIndex = i
  1077. let cd = comRole.skillCDs[i]
  1078. if (cd > 0 && cd != Data.game.cdMax) {
  1079. //词条减CD
  1080. if (comRole.entryMap.get(ENTRY.skillCD)?.num) {
  1081. cd *= 1 - comRole.entryMap.get(ENTRY.skillCD).num / Data.game.rateNum
  1082. }
  1083. //buff减CD
  1084. for (let j = 0; j < comRole.buffs.length; j++) {
  1085. let buffCfg = comRole.buffs[j].buffCfg
  1086. if (buffCfg.buffType == BUFF_TYPE.skillCD && buffCfg.attrRate[curSkillIndex]) {
  1087. cd *= 1 - buffCfg.attrRate[curSkillIndex] / Data.game.rateNum
  1088. }
  1089. }
  1090. if (cd < 0) cd = 0
  1091. }
  1092. comRole.skillCountDowns[i] =
  1093. (cd == 0 && comSkillAbel.skillConfig.type != SKILL_TYPE.holo) || cd == Data.game.cdMax
  1094. ? Infinity
  1095. : cd
  1096. }
  1097. }
  1098. comSkillAbel.dirty = true
  1099. comSkillAbel.startDirty = true
  1100. comSkillAbel.skillDirty = true
  1101. //吟唱时间
  1102. comSkillAbel.countDown =
  1103. comSkillAbel.skillConfig.castDuration > comRole.castTime[curSkillIndex]
  1104. ? comSkillAbel.skillConfig.castDuration
  1105. : comRole.castTime[curSkillIndex]
  1106. let timeScale = 1 - comSkillAbel.skillConfig.castFrame
  1107. if (timeScale > 1) timeScale = 1
  1108. if (timeScale < 0) timeScale = 0
  1109. comSkillAbel.castSkillTime = timeScale * comSkillAbel.countDown
  1110. comCocosNode.events.push(
  1111. new EventSkill(comSkillAbel.countDown, comRole.skills.indexOf(comSkillAbel.skillConfig)),
  1112. )
  1113. //同步spine吟唱
  1114. let comSpineNode = context.world.getComponent(comRole.spineEntity, ComCocosNode)
  1115. comSpineNode?.events.push(
  1116. new EventSkill(comSkillAbel.countDown, comRole.skills.indexOf(comSkillAbel.skillConfig)),
  1117. )
  1118. node.state = NodeState.Executing
  1119. },
  1120. onUpdate(node: SkillNode, context: ExecuteContext): void {
  1121. if (node.state !== NodeState.Executing) return
  1122. let comSkillAbel = context.world.getComponent(context.entity, ComSkillAbel)
  1123. let comCocosNode = context.world.getComponent(context.entity, ComCocosNode)
  1124. // 技能开始的时候没有技能施放目标停止施放技能
  1125. if (comSkillAbel.skillConfig && comSkillAbel.roles.length == 0 && comSkillAbel.skillConfig.minRole > 0) {
  1126. Log.error('Skill onUpdate', '没有技能施放目标停止施放技能', context.entity, comSkillAbel.skillConfig)
  1127. let comRole = context.world.getComponent(context.entity, ComRole)
  1128. let curSkillIndex = comRole.skills.findIndex(value => value.ID == comSkillAbel.skillConfig.ID)
  1129. if (curSkillIndex >= 0) {
  1130. //让技能可以重新被施放
  1131. comRole.skillCountDowns[curSkillIndex] = 0
  1132. }
  1133. comSkillAbel.dirty = false
  1134. node.state = NodeState.Fail
  1135. }
  1136. if (comSkillAbel && comSkillAbel.countDown <= 0) {
  1137. comSkillAbel.dirty = false
  1138. node.state = NodeState.Success
  1139. if (debug) {
  1140. if (node.state == NodeState.Success) {
  1141. node.successLog = '技能行为成功==>' + context.entity
  1142. }
  1143. }
  1144. if (debug) ccUtils.setLabel('', comCocosNode.node, 'skill')
  1145. }
  1146. },
  1147. }
  1148. /** Dizzy node */
  1149. NodeHandlers[NodeType.Dizzy] = {
  1150. onEnter(node: DizzyNode, context: ExecuteContext): void {
  1151. let comDizzy = context.world.getComponent(context.entity, ComDizzy)
  1152. if (!comDizzy) {
  1153. //console.log('Dizzy onEnter', '目标没有ComDizzy', context.entity)
  1154. return
  1155. }
  1156. comDizzy.dirty = true
  1157. node.state = NodeState.Executing
  1158. },
  1159. onUpdate(node: DizzyNode, context: ExecuteContext): void {
  1160. if (node.state !== NodeState.Executing) return
  1161. },
  1162. }
  1163. /** StopNode node */
  1164. NodeHandlers[NodeType.Stop] = {
  1165. onEnter(node: StopNode, context: ExecuteContext): void {
  1166. node.state = NodeState.Executing
  1167. },
  1168. onUpdate(node: StopNode, context: ExecuteContext): void {
  1169. if (node.state !== NodeState.Executing) return
  1170. context.world.changeMoveSpeed(context.entity, 0)
  1171. node.state = NodeState.Success
  1172. if (debug) {
  1173. if (node.state == NodeState.Success) {
  1174. node.successLog = '停止行为成功==>' + context.entity
  1175. }
  1176. }
  1177. },
  1178. }
  1179. /** StopAttack node */
  1180. NodeHandlers[NodeType.StopAttack] = {
  1181. onEnter(node: StopAttackNode, context: ExecuteContext): void {
  1182. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  1183. if (!comAttackable) {
  1184. Log.error('StopAttack onEnter', '目标没有ComAttackable', context.entity)
  1185. return
  1186. }
  1187. node.state = NodeState.Executing
  1188. },
  1189. onUpdate(node: StopAttackNode, context: ExecuteContext): void {
  1190. if (node.state !== NodeState.Executing) return
  1191. let comAttackable = context.world.getComponent(context.entity, ComAttackable)
  1192. comAttackable.dirty = false
  1193. comAttackable.countDown = 0
  1194. node.state = NodeState.Success
  1195. if (debug) {
  1196. if (node.state == NodeState.Success) {
  1197. node.successLog = '停止攻击行为成功==>' + context.entity
  1198. }
  1199. }
  1200. },
  1201. }
  1202. /** StopAttack node */
  1203. NodeHandlers[NodeType.StopSkill] = {
  1204. onEnter(node: StopAttackNode, context: ExecuteContext): void {
  1205. let comSkill = context.world.getComponent(context.entity, ComSkillAbel)
  1206. if (!comSkill) {
  1207. Log.error('StopSkill onEnter', '目标没有ComSkill', context.entity)
  1208. return
  1209. }
  1210. node.state = NodeState.Executing
  1211. },
  1212. onUpdate(node: StopAttackNode, context: ExecuteContext): void {
  1213. if (node.state !== NodeState.Executing) return
  1214. let comSkill = context.world.getComponent(context.entity, ComSkillAbel)
  1215. let comRole = context.world.getComponent(context.entity, ComRole)
  1216. let comSpineCocosNode = context.world.getComponent(comRole?.spineEntity, ComCocosNode)
  1217. comSpineCocosNode.events.push(new EventStopSkill())
  1218. comSkill.dirty = false
  1219. comSkill.countDown = Infinity
  1220. comSkill.skillConfig = null
  1221. comSkill.isInShield = false
  1222. node.state = NodeState.Success
  1223. if (debug) {
  1224. if (node.state == NodeState.Success) {
  1225. node.successLog = '停止技能行为成功==>' + context.entity
  1226. }
  1227. }
  1228. },
  1229. }
  1230. }