DragBlockToGridStep.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { find, Node } from 'cc';
  2. import { GuideStep } from '../../NewbieGuidePlugin-v1.0.0/NewbieGuidePlugin-v1.0.0/scripts/GuideStep';
  3. import { BlockManager } from '../CombatSystem/BlockManager';
  4. import EventBus, { GameEvents } from '../Core/EventBus';
  5. /**
  6. * 新手引导步骤:提示并等待玩家将任意方块拖到网格
  7. * 触发条件:场景中存在方块选择区域,且尚未放置任何方块
  8. * 完成条件:BlockManager 检测到至少一个方块已移动到 PlacedBlocks
  9. */
  10. export class DragBlockToGridStep extends GuideStep {
  11. private _blockManager: BlockManager | null = null;
  12. private _pollTimer: any = null;
  13. private _dragEventsReady = false;
  14. private _unsubscribers: Array<() => void> = [];
  15. constructor() {
  16. super('drag_block_to_grid');
  17. }
  18. public canTrigger(): boolean {
  19. // 查找 BlockManager(位于方块选择系统下)
  20. const root = find('Canvas');
  21. if (!root) return false;
  22. // 在整棵树中查找 BlockManager 组件
  23. const nodes: Node[] = [];
  24. const stack: Node[] = [root];
  25. while (stack.length) {
  26. const n = stack.pop()!;
  27. nodes.push(n);
  28. for (const child of n.children) stack.push(child);
  29. }
  30. for (const n of nodes) {
  31. const bm = n.getComponent(BlockManager as any) as BlockManager | null;
  32. if (bm) {
  33. this._blockManager = bm;
  34. break;
  35. }
  36. }
  37. if (!this._blockManager) return false;
  38. // 如果已经有方块被放置则不触发
  39. const hasPlaced = typeof (this._blockManager as any).hasPlacedBlocks === 'function'
  40. ? (this._blockManager as any).hasPlacedBlocks()
  41. : false;
  42. if (hasPlaced) return false;
  43. // 确认方块选择 UI 存在(避免在战斗中或加载前触发)
  44. const selectionUI = find('Canvas/GameLevelUI/BlockSelectionUI');
  45. return !!selectionUI;
  46. }
  47. public doExecute(): void {
  48. // 监听拖拽相关事件,便于在拖拽区域就绪时给出提示或开始轮询
  49. const bus = EventBus.getInstance();
  50. const onSetup = () => {
  51. this._dragEventsReady = true;
  52. };
  53. bus.on(GameEvents.SETUP_BLOCK_DRAG_EVENTS, onSetup, this);
  54. this._unsubscribers.push(() => bus.off(GameEvents.SETUP_BLOCK_DRAG_EVENTS, onSetup, this));
  55. const onDragEnd = () => {
  56. // 尝试立即检测一次是否已经放置成功
  57. this.checkPlacedAndComplete();
  58. };
  59. bus.on(GameEvents.BLOCK_DRAG_END, onDragEnd, this);
  60. this._unsubscribers.push(() => bus.off(GameEvents.BLOCK_DRAG_END, onDragEnd, this));
  61. // 启动轮询,容错检测放置完成(避免事件遗漏)
  62. this._pollTimer = setInterval(() => this.checkPlacedAndComplete(), 500);
  63. }
  64. private checkPlacedAndComplete() {
  65. if (!this._blockManager) return;
  66. try {
  67. const hasPlaced = typeof (this._blockManager as any).hasPlacedBlocks === 'function'
  68. ? (this._blockManager as any).hasPlacedBlocks()
  69. : false;
  70. if (hasPlaced) {
  71. this.complete();
  72. }
  73. } catch (e) {
  74. console.error('[DragBlockToGridStep] 检测放置状态失败:', e);
  75. }
  76. }
  77. protected onComplete(): void {
  78. // 清理事件与轮询
  79. for (const unsub of this._unsubscribers) {
  80. try { unsub(); } catch {}
  81. }
  82. this._unsubscribers = [];
  83. if (this._pollTimer) {
  84. clearInterval(this._pollTimer);
  85. this._pollTimer = null;
  86. }
  87. // 记录由基类完成 complete() 统一处理
  88. }
  89. }
  90. export default DragBlockToGridStep;