import { _decorator, Component, Node, Button, Label, find, EventTouch, Vec2, Vec3, UITransform, Rect, Collider2D, Graphics, Color, JsonAsset } from 'cc'; import { LevelSessionManager } from '../../Core/LevelSessionManager'; import { BallController } from '../BallController'; import { BlockManager } from '../BlockManager'; import { ConfigManager } from '../../Core/ConfigManager'; import { BlockTag } from './BlockTag'; import { WeaponInfo } from './WeaponInfo'; import { SkillManager } from '../SkillSelection/SkillManager'; import { Audio } from '../../AudioManager/AudioManager'; import EventBus, { GameEvents } from '../../Core/EventBus'; const { ccclass, property } = _decorator; @ccclass('GameBlockSelection') export class GameBlockSelection extends Component { @property({ type: Node, tooltip: '拖拽diban/ann001按钮节点到这里' }) public addBallButton: Node = null; @property({ type: Node, tooltip: '拖拽diban/ann002按钮节点到这里' }) public addCoinButton: Node = null; @property({ type: Node, tooltip: '拖拽diban/ann003按钮节点到这里' }) public refreshButton: Node = null; @property({ type: Node, tooltip: '拖拽Canvas-001/TopArea/CoinNode/CoinLabel节点到这里' }) public coinLabelNode: Node = null; @property({ type: Node, tooltip: '拖拽Canvas/GameLevelUI/BallController节点到这里' }) public ballControllerNode: Node = null; @property({ type: Node, tooltip: '拖拽Canvas/GameLevelUI/BlockController节点到这里' }) public blockManagerNode: Node = null; @property({ type: Node, tooltip: '拖拽Canvas/GameLevelUI/GameArea/GridContainer节点到这里' }) public gridContainer: Node = null; @property({ type: Node, tooltip: '拖拽confirm按钮节点到这里' }) public confirmButton: Node = null; @property({ type: Node, tooltip: '拖拽Canvas/GameLevelUI/InGameManager节点到这里' }) public inGameManagerNode: Node = null; @property({ type: Node, tooltip: '拖拽Canvas/Camera节点到这里' }) public cameraNode: Node = null; // 武器配置JsonAsset - 通过装饰器预加载 @property({ type: JsonAsset, tooltip: '拖拽weapons.json文件到这里,实现配置预加载' }) public weaponsConfig: JsonAsset = null; // 常量定义 private readonly ADD_BALL_COST = 80; private readonly ADD_COIN_AMOUNT = 80; private readonly REFRESH_COST = 5; private session: LevelSessionManager = null; private ballController: BallController = null; private blockManager: BlockManager = null; // 回调函数,用于通知GameManager public onConfirmCallback: () => void = null; // 标记是否已初始化 private isInitialized: boolean = false; // 标记是否应该生成方块(只有在onBattle触发后才为true) private shouldGenerateBlocks: boolean = false; // 用户操作方块相关属性 private currentDragBlock: Node | null = null; private startPos = new Vec2(); private blockStartPos: Vec3 = new Vec3(); // 调试绘制相关属性 @property({ tooltip: '是否启用吸附检测范围调试绘制' }) public debugDrawSnapRange: boolean = false; private debugDrawNode: Node = null; private debugGraphics: Graphics = null; onEnable() { // 如果还未初始化,则进行初始化 if (!this.isInitialized) { this.initializeComponent(); } else { // 如果已经初始化,重新设置事件监听器(因为onDisable时会移除) this.setupEventListeners(); } // this.initDebugDraw(); } start() { // 如果还未初始化,则进行初始化 if (!this.isInitialized) { this.initializeComponent(); } } private initializeComponent() { // 获取管理器实例 this.session = LevelSessionManager.inst; // 获取BallController if (this.ballControllerNode) { this.ballController = this.ballControllerNode.getComponent(BallController); } else { console.warn('BallController节点未绑定,请在Inspector中拖拽Canvas/GameLevelUI/BallController节点'); } // 获取BlockManager if (this.blockManagerNode) { this.blockManager = this.blockManagerNode.getComponent(BlockManager); // 如果武器配置已通过装饰器预加载,直接传递给BlockManager if (this.weaponsConfig && this.weaponsConfig.json) { // 通过公共方法将预加载的配置传递给BlockManager if (this.blockManager && typeof this.blockManager.setPreloadedWeaponsConfig === 'function') { this.blockManager.setPreloadedWeaponsConfig(this.weaponsConfig.json); } else { console.warn('[GameBlockSelection] BlockManager不支持setPreloadedWeaponsConfig方法'); } } else { console.warn('[GameBlockSelection] 武器配置未预加载,请在Inspector中拖拽weapons.json文件到weaponsConfig属性'); } } else { console.warn('BlockManager节点未绑定,请在Inspector中拖拽Canvas/GameLevelUI/BlockController节点'); } // 如果没有指定coinLabelNode,尝试找到它 if (!this.coinLabelNode) { this.coinLabelNode = find('Canvas-001/TopArea/CoinNode/CoinLabel'); } // 初始化金币显示 this.updateCoinDisplay(); // 绑定按钮事件 this.bindButtonEvents(); // 设置事件监听器 this.setupEventListeners(); // 标记为已初始化 this.isInitialized = true; // 初始化完成 } // 设置事件监听器 private setupEventListeners() { const eventBus = EventBus.getInstance(); // 监听重置方块选择事件 eventBus.on(GameEvents.RESET_BLOCK_SELECTION, this.onResetBlockSelectionEvent, this); // 监听游戏开始事件,用于标记可以开始生成方块 eventBus.on(GameEvents.GAME_START, this.onGameStartEvent, this); // 监听方块拖拽事件设置请求 eventBus.on(GameEvents.SETUP_BLOCK_DRAG_EVENTS, this.onSetupBlockDragEventsEvent, this); } // 处理重置方块选择事件 private onResetBlockSelectionEvent() { this.resetSelection(); } // 处理游戏开始事件 private onGameStartEvent() { // 接收到游戏开始事件,允许生成方块 this.shouldGenerateBlocks = true; } // 处理方块拖拽事件设置请求 private onSetupBlockDragEventsEvent(blocks: Node[]) { // 确保组件仍然有效 if (!this.node || !this.node.isValid) { console.warn('[GameBlockSelection] 组件节点无效,跳过拖拽事件设置'); return; } for (const block of blocks) { if (block && block.isValid) { // 先移除可能存在的旧事件监听器 block.off(Node.EventType.TOUCH_START); block.off(Node.EventType.TOUCH_MOVE); block.off(Node.EventType.TOUCH_END); block.off(Node.EventType.TOUCH_CANCEL); // 重新设置拖拽事件 this.setupBlockDragEvents(block); } else { // 跳过无效方块的拖拽事件设置 } } } // 绑定按钮事件 private bindButtonEvents() { // 绑定新增小球按钮 if (this.addBallButton) { const btn = this.addBallButton.getComponent(Button); if (btn) { this.addBallButton.on(Button.EventType.CLICK, this.onAddBallClicked, this); } else { this.addBallButton.on(Node.EventType.TOUCH_END, this.onAddBallClicked, this); } } // 绑定增加金币按钮 if (this.addCoinButton) { const btn = this.addCoinButton.getComponent(Button); if (btn) { this.addCoinButton.on(Button.EventType.CLICK, this.onAddCoinClicked, this); } else { this.addCoinButton.on(Node.EventType.TOUCH_END, this.onAddCoinClicked, this); } } // 绑定刷新方块按钮 if (this.refreshButton) { const btn = this.refreshButton.getComponent(Button); if (btn) { this.refreshButton.on(Button.EventType.CLICK, this.onRefreshClicked, this); } else { this.refreshButton.on(Node.EventType.TOUCH_END, this.onRefreshClicked, this); } } // 绑定确认按钮 if (this.confirmButton) { const btn = this.confirmButton.getComponent(Button); if (btn) { this.confirmButton.on(Button.EventType.CLICK, this.onConfirmButtonClicked, this); } else { this.confirmButton.on(Node.EventType.TOUCH_END, this.onConfirmButtonClicked, this); } } } // 新增小球按钮点击 private onAddBallClicked() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); // 应用便宜技能效果计算实际费用 const actualCost = this.getActualCost(this.ADD_BALL_COST); if (!this.canSpendCoins(actualCost)) { this.showInsufficientCoinsUI(); return; } // 扣除金币 if (this.session.spendCoins(actualCost)) { this.updateCoinDisplay(); // 通过事件系统创建新的小球 const eventBus = EventBus.getInstance(); eventBus.emit(GameEvents.BALL_CREATE_ADDITIONAL); // 新增小球成功 } } // 增加金币按钮点击 private onAddCoinClicked() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); // 免费增加金币(模拟看广告获得奖励) const coinsToAdd = 80; // 免费获得的金币数量 this.session.addCoins(coinsToAdd); // 更新显示 this.updateCoinDisplay(); } // 刷新方块按钮点击 private onRefreshClicked() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); // 应用便宜技能效果计算实际费用 const actualCost = this.getActualCost(this.REFRESH_COST); if (!this.canSpendCoins(actualCost)) { this.showInsufficientCoinsUI(); return; } // 扣除金币 if (this.session.spendCoins(actualCost)) { // 成功扣除金币 this.updateCoinDisplay(); // 刷新方块 if (this.blockManager) { console.log('[GameBlockSelection] 开始刷新方块流程'); // 找到PlacedBlocks容器 const placedBlocksContainer = find('Canvas/GameLevelUI/GameArea/PlacedBlocks'); if (placedBlocksContainer) { // 移除已放置方块的标签 // 移除已放置方块的标签 BlockTag.removeTagsInContainer(placedBlocksContainer); } // 刷新方块 // 调用 blockManager.refreshBlocks() this.blockManager.refreshBlocks(); // 等待一帧确保方块生成完成 this.scheduleOnce(() => { }, 0.1); } else { console.error('[GameBlockSelection] 找不到BlockManager,无法刷新方块'); } } else { console.error('[GameBlockSelection] 扣除金币失败'); } } // 确认按钮点击 public onConfirmButtonClicked() { // 检查是否有上阵方块 const hasBlocks = this.hasPlacedBlocks(); if (!hasBlocks) { this.showNoPlacedBlocksToast(); return; } // 播放UI音效 Audio.playUISound('data/弹球音效/ui play'); // 保存已放置的方块 this.preservePlacedBlocks(); // 清理kuang区域的方块(用户期望的行为) if (this.blockManager) { this.blockManager.clearBlocks(); console.log('[GameBlockSelection] 已清理kuang区域的方块'); } // 先回调通知GameManager,让它处理波次逻辑 if (this.onConfirmCallback) { this.onConfirmCallback(); } // 播放下滑diban动画,结束备战进入playing状态 this.playDibanSlideDownAnimation(); } // 播放diban下滑动画 private playDibanSlideDownAnimation() { // 开始播放diban下滑动画 // 使用装饰器属性获取Camera节点上的GameStartMove组件 if (!this.cameraNode) { console.warn('[GameBlockSelection] Camera节点未设置,请在Inspector中拖拽Canvas/Camera节点'); return; } const gameStartMove = this.cameraNode.getComponent('GameStartMove'); if (!gameStartMove) { console.warn('[GameBlockSelection] GameStartMove组件未找到'); return; } // 调用GameStartMove的下滑动画方法 (gameStartMove as any).slideDibanDownAndHide(0.3); // 已调用GameStartMove的diban下滑动画 } // 保存已放置的方块(从GameManager迁移) private preservePlacedBlocks() { if (this.blockManager) { this.blockManager.onGameStart(); } } // 检查是否有足够金币 private canSpendCoins(amount: number): boolean { return this.session.getCoins() >= amount; } // 计算应用便宜技能效果后的实际费用 private getActualCost(baseCost: number): number { const skillManager = SkillManager.getInstance(); if (skillManager) { const cheaperSkillLevel = skillManager.getSkillLevel('cheaper_units'); return Math.ceil(SkillManager.calculateCheaperUnitsPrice(baseCost, cheaperSkillLevel)); } return baseCost; } // 更新金币显示 private updateCoinDisplay() { if (this.coinLabelNode) { const label = this.coinLabelNode.getComponent(Label); if (label) { const coins = this.session.getCoins(); label.string = coins.toString(); // 更新金币显示 } else { console.warn('[GameBlockSelection] coinLabelNode缺少Label组件'); } } else { console.warn('[GameBlockSelection] coinLabelNode未找到'); } } // 显示金币不足UI private showInsufficientCoinsUI() { // 使用事件机制显示资源不足Toast EventBus.getInstance().emit(GameEvents.SHOW_RESOURCE_TOAST, { message: '金币不足!', duration: 3.0 }); // 金币不足 } // === 公共方法:供GameManager调用 === // 生成方块选择(不再控制UI显示,只负责生成方块) public generateBlockSelection() { // 直接生成方块,不再依赖shouldGenerateBlocks标志 if (this.blockManager) { this.blockManager.refreshBlocks(); } else { console.warn('[GameBlockSelection] BlockManager未找到,无法生成随机方块'); } // 触发进入备战状态事件 EventBus.getInstance().emit(GameEvents.ENTER_BATTLE_PREPARATION); } // 设置确认回调 public setConfirmCallback(callback: () => void) { this.onConfirmCallback = callback; } // 统一的方块占用情况刷新方法 public refreshGridOccupation() { if (this.blockManager) { this.blockManager.resetGridOccupation(); // 重新计算所有已放置方块的占用情况 const placedBlocksContainer = find('Canvas/GameLevelUI/GameArea/PlacedBlocks'); if (placedBlocksContainer) { for (let i = 0; i < placedBlocksContainer.children.length; i++) { const block = placedBlocksContainer.children[i]; // 按照BlockManager.tryPlaceBlockToGrid的正确方法获取位置 let b1Node = block; if (block.name !== 'B1') { b1Node = block.getChildByName('B1'); if (!b1Node) { console.warn(`[GameBlockSelection] 方块 ${block.name} 没有B1子节点`); continue; } } // 获取B1节点的世界坐标,然后转换为网格本地坐标 const b1WorldPos = b1Node.parent.getComponent(UITransform).convertToWorldSpaceAR(b1Node.position); const gridPos = this.blockManager.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos); // 重新标记方块占用的网格位置 const gridNode = this.blockManager.findNearestGridNode(gridPos); if (gridNode) { this.blockManager.markOccupiedPositions(block, gridNode); } else { console.warn(`[GameBlockSelection] 方块 ${block.name} 未找到对应的网格节点`); } } } } else { console.warn('[GameBlockSelection] BlockManager未找到,无法刷新占用情况'); } this.blockManager.printGridOccupationMatrix(); } // 重置方块选择状态 public resetSelection() { // 重置方块生成标志,等待下次onBattle触发 this.shouldGenerateBlocks = false; // 注意:不再直接调用blockManager.onGameReset(),因为StartGame.clearGameStates() // 已经通过RESET_BLOCK_MANAGER事件触发了BlockManager的重置,避免重复生成方块 // 清理所有方块标签 BlockTag.clearAllTags(); // 更新金币显示 this.updateCoinDisplay(); } // 检查是否有上阵方块 private hasPlacedBlocks(): boolean { // 优先使用BlockManager的方法检查 if (this.blockManager) { return this.blockManager.hasPlacedBlocks(); } // 备用方案:直接检查PlacedBlocks容器 const placedBlocksContainer = find('Canvas/GameLevelUI/GameArea/PlacedBlocks'); if (!placedBlocksContainer) { console.warn('找不到PlacedBlocks容器'); return false; } // 检查容器中是否有子节点(方块) return placedBlocksContainer.children.length > 0; } // 显示没有上阵方块的Toast提示 private showNoPlacedBlocksToast() { // 使用事件机制显示Toast EventBus.getInstance().emit(GameEvents.SHOW_RESOURCE_TOAST, { message: '请至少上阵一个植物!', duration: 3.0 }); } // 设置方块拖拽事件 public setupBlockDragEvents(block: Node) { block.on(Node.EventType.TOUCH_START, (event: EventTouch) => { // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); // grid区域的方块目前允许自由移动 this.currentDragBlock = block; this.startPos = event.getUILocation(); this.blockStartPos.set(block.position); this.currentDragBlock['startLocation'] = blockLocation; // 如果方块在grid区域,拿起时清除其占用状态 if (blockLocation === 'grid') { this.blockManager.clearOccupiedPositions(block); // 输出更新后的占用情况 this.blockManager.printGridOccupationMatrix(); } // 设置拖动状态,隐藏价格标签 block['isDragging'] = true; block.setSiblingIndex(block.parent.children.length - 1); // 拖拽开始时禁用碰撞体 const collider = block.getComponent(Collider2D); if (collider) collider.enabled = false; // 通知BallController有方块开始拖拽 EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_START, { block: block }); }, this); block.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => { // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); // grid区域的方块目前允许自由移动 if (!this.currentDragBlock) return; const location = event.getUILocation(); const deltaX = location.x - this.startPos.x; const deltaY = location.y - this.startPos.y; this.currentDragBlock.position = new Vec3( this.blockStartPos.x + deltaX, this.blockStartPos.y + deltaY, this.blockStartPos.z ); }, this); block.on(Node.EventType.TOUCH_END, async (event: EventTouch) => { // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); // grid区域的方块目前允许自由移动 if (this.currentDragBlock) { try { await this.handleBlockDrop(event); } catch (error) { console.error('[GameBlockSelection] 处理方块拖拽放置时发生错误:', error); // 发生错误时,将方块返回原位置 this.returnBlockToOriginalPosition(); } // 清除拖动状态,恢复价格标签显示 block['isDragging'] = false; this.currentDragBlock = null; // 拖拽结束时恢复碰撞体 const collider = block.getComponent(Collider2D); if (collider) collider.enabled = true; // 通知BallController方块拖拽结束 EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_END, { block: block }); } }, this); block.on(Node.EventType.TOUCH_CANCEL, () => { if (this.currentDragBlock) { this.returnBlockToOriginalPosition(); // 清除拖动状态,恢复价格标签显示 block['isDragging'] = false; this.currentDragBlock = null; // 拖拽取消时恢复碰撞体 const collider = block.getComponent(Collider2D); if (collider) collider.enabled = true; // 通知BallController方块拖拽结束 EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_END, { block: block }); } }, this); } // 处理方块放下 private async handleBlockDrop(event: EventTouch) { try { const touchPos = event.getLocation(); const startLocation = this.currentDragBlock['startLocation']; if (this.isInKuangArea(touchPos)) { // 检查是否有标签,只有有标签的方块才能放回kuang if (BlockTag.hasTag(this.currentDragBlock)) { this.returnBlockToKuang(startLocation); } else { // 没有标签的方块不能放回kuang,返回原位置 this.returnBlockToOriginalPosition(); } } else if (this.blockManager.tryPlaceBlockToGrid(this.currentDragBlock)) { await this.handleSuccessfulPlacement(startLocation); } else { // 放置失败,尝试直接与重叠方块合成 if (this.blockManager.tryMergeOnOverlap(this.currentDragBlock)) { // 合成成功时,若来自 kuang 则扣费 if (startLocation !== 'grid') { const price = this.blockManager.getBlockPrice(this.currentDragBlock); this.blockManager.deductPlayerCoins(price); } // 当前拖拽块已被销毁(合并时),无需复位 } else { this.returnBlockToOriginalPosition(); } } } catch (error) { console.error('[GameBlockSelection] handleBlockDrop 发生错误:', error); // 发生错误时,将方块返回原位置 this.returnBlockToOriginalPosition(); throw error; // 重新抛出错误,让上层处理 } finally { // 无论成功还是失败,都要清理拖拽状态 if (this.currentDragBlock && this.currentDragBlock.isValid) { // 重新启用碰撞器 const collider = this.currentDragBlock.getComponent(Collider2D); if (collider) { collider.enabled = true; console.log('[GameBlockSelection] 拖拽结束,重新启用碰撞器:', this.currentDragBlock.name); } // 发射拖拽结束事件 console.log('[GameBlockSelection] 发射 BLOCK_DRAG_END 事件:', this.currentDragBlock.name); EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_END, { block: this.currentDragBlock }); } // 清理拖拽状态 this.currentDragBlock = null; } // 刷新方块占用情况 this.refreshGridOccupation(); } // 检查是否在kuang区域内 private isInKuangArea(touchPos: Vec2): boolean { // 检查是否在任何一个Block容器区域内 const blockContainers = [ this.blockManager.block1Container, this.blockManager.block2Container, this.blockManager.block3Container ]; for (const container of blockContainers) { if (container) { const transform = container.getComponent(UITransform); if (transform) { const boundingBox = new Rect( container.worldPosition.x - transform.width * transform.anchorX, container.worldPosition.y - transform.height * transform.anchorY, transform.width, transform.height ); if (boundingBox.contains(new Vec2(touchPos.x, touchPos.y))) { return true; } } } } // 如果Block容器都不可用,回退到检查kuang容器 if (this.blockManager.kuangContainer) { const kuangTransform = this.blockManager.kuangContainer.getComponent(UITransform); if (kuangTransform) { const kuangBoundingBox = new Rect( this.blockManager.kuangContainer.worldPosition.x - kuangTransform.width * kuangTransform.anchorX, this.blockManager.kuangContainer.worldPosition.y - kuangTransform.height * kuangTransform.anchorY, kuangTransform.width, kuangTransform.height ); return kuangBoundingBox.contains(new Vec2(touchPos.x, touchPos.y)); } } return false; } // 返回方块到对应的Block容器区域 private returnBlockToKuang(startLocation: string) { const originalPos = this.blockManager.originalPositions.get(this.currentDragBlock); const blockLocation = this.blockManager.blockLocations.get(this.currentDragBlock); if (originalPos) { // 根据方块的原始位置确定应该返回到哪个Block容器 let targetContainer: Node = null; let targetLocation = 'kuang'; // 默认位置 if (blockLocation && blockLocation.startsWith('block')) { // 如果方块原本在Block容器中,返回到对应的容器 if (blockLocation === 'block1') { targetContainer = this.blockManager.block1Container; targetLocation = 'block1'; } else if (blockLocation === 'block2') { targetContainer = this.blockManager.block2Container; targetLocation = 'block2'; } else if (blockLocation === 'block3') { targetContainer = this.blockManager.block3Container; targetLocation = 'block3'; } } // 如果没有找到对应的Block容器,回退到kuang容器 if (!targetContainer) { targetContainer = this.blockManager.kuangContainer; targetLocation = 'kuang'; } if (targetContainer && this.currentDragBlock.parent !== targetContainer) { this.currentDragBlock.removeFromParent(); targetContainer.addChild(this.currentDragBlock); } this.currentDragBlock.position = originalPos.clone(); this.blockManager.blockLocations.set(this.currentDragBlock, targetLocation); } this.blockManager.showPriceLabel(this.currentDragBlock); // 当方块返回kuang区域时,重新设置植物图标缩放至0.4倍 const weaponNode = this.findWeaponNodeInBlock(this.currentDragBlock); if (weaponNode) { weaponNode.setScale(0.4, 0.4, 1); // 方块返回kuang区域,设置植物图标缩放: 0.4倍 } if (startLocation === 'grid') { const price = this.blockManager.getBlockPrice(this.currentDragBlock); this.blockManager.refundPlayerCoins(price); this.currentDragBlock['placedBefore'] = false; } // 显示对应的db标签节点 this.showDbNodeByBlockLocation(this.currentDragBlock); } /** * 为方块的武器节点添加武器信息组件 * @param block 方块节点 */ private attachWeaponInfoToBlock(block: Node): void { try { // 查找方块中的Weapon节点 const weaponNode = this.findWeaponNodeInBlock(block); if (!weaponNode) { console.warn(`[GameBlockSelection] 方块 ${block.name} 中未找到Weapon节点,无法添加武器信息组件`); return; } // 检查是否已经有WeaponInfo组件 let weaponInfo = weaponNode.getComponent(WeaponInfo); if (weaponInfo) { return; } // 添加WeaponInfo组件 weaponInfo = weaponNode.addComponent(WeaponInfo); // 获取方块的武器配置 const weaponConfig = this.blockManager.getBlockWeaponConfig(block); if (weaponConfig) { // 设置武器配置到WeaponInfo组件 weaponInfo.setWeaponConfig(weaponConfig); } else { console.warn(`[GameBlockSelection] 方块 ${block.name} 没有武器配置,无法设置武器信息`); // 移除刚添加的组件 weaponNode.removeComponent(WeaponInfo); } } catch (error) { console.error(`[GameBlockSelection] 为方块 ${block.name} 添加武器信息组件时发生错误:`, error); } } /** * 在方块中查找Weapon节点 * @param block 方块节点 * @returns Weapon节点,如果未找到返回null */ private findWeaponNodeInBlock(block: Node): Node | null { if (!block || !block.isValid) { return null; } // 根据新的预制体结构,武器节点直接位于方块根节点下 const weaponNode = block.getChildByName('Weapon'); if (weaponNode) { return weaponNode; } // 兼容旧结构:如果直接查找失败,尝试B1/Weapon路径 const b1Node = block.getChildByName('B1'); if (b1Node) { const b1WeaponNode = b1Node.getChildByName('Weapon'); if (b1WeaponNode) { return b1WeaponNode; } } // 最后使用递归方式查找(兼容其他可能的结构) const findWeaponRecursive = (node: Node): Node | null => { if (node.name === 'Weapon') { return node; } for (let i = 0; i < node.children.length; i++) { const result = findWeaponRecursive(node.children[i]); if (result) { return result; } } return null; }; return findWeaponRecursive(block); } // 根据方块位置隐藏对应的db标签节点 private hideDbNodeByBlockLocation(block: Node) { const originalLocation = this.getBlockOriginalLocation(block); if (originalLocation === 'block1' && this.blockManager.block1DbNode) { this.blockManager.block1DbNode.active = false; } else if (originalLocation === 'block2' && this.blockManager.block2DbNode) { this.blockManager.block2DbNode.active = false; } else if (originalLocation === 'block3' && this.blockManager.block3DbNode) { this.blockManager.block3DbNode.active = false; } } // 根据方块位置显示对应的db标签节点 private showDbNodeByBlockLocation(block: Node) { const originalLocation = this.getBlockOriginalLocation(block); if (originalLocation === 'block1' && this.blockManager.block1DbNode) { this.blockManager.block1DbNode.active = true; } else if (originalLocation === 'block2' && this.blockManager.block2DbNode) { this.blockManager.block2DbNode.active = true; } else if (originalLocation === 'block3' && this.blockManager.block3DbNode) { this.blockManager.block3DbNode.active = true; } } // 处理成功放置 private async handleSuccessfulPlacement(startLocation: string) { try { const price = this.blockManager.getBlockPrice(this.currentDragBlock); if (startLocation === 'grid') { this.blockManager.clearTempStoredOccupiedGrids(this.currentDragBlock); this.blockManager.blockLocations.set(this.currentDragBlock, 'grid'); // 隐藏对应的db标签节点 this.hideDbNodeByBlockLocation(this.currentDragBlock); // 立即将方块移动到PlacedBlocks节点下,不等游戏开始 this.blockManager.moveBlockToPlacedBlocks(this.currentDragBlock); // 为武器节点添加武器信息组件 this.attachWeaponInfoToBlock(this.currentDragBlock); // 如果游戏已开始,添加锁定视觉提示 if (this.blockManager.gameStarted) { this.blockManager.addLockedVisualHint(this.currentDragBlock); BlockTag.removeTag(this.currentDragBlock); } // 检查并执行合成 try { await this.blockManager.tryMergeBlock(this.currentDragBlock); } catch (mergeError) { console.error('[GameBlockSelection] 方块合成时发生错误:', mergeError); } } else { if (this.blockManager.deductPlayerCoins(price)) { this.blockManager.clearTempStoredOccupiedGrids(this.currentDragBlock); this.blockManager.blockLocations.set(this.currentDragBlock, 'grid'); // 隐藏对应的db标签节点 this.hideDbNodeByBlockLocation(this.currentDragBlock); this.currentDragBlock['placedBefore'] = true; // 立即将方块移动到PlacedBlocks节点下,不等游戏开始 this.blockManager.moveBlockToPlacedBlocks(this.currentDragBlock); // 为武器节点添加武器信息组件 this.attachWeaponInfoToBlock(this.currentDragBlock); // 如果游戏已开始,添加锁定视觉提示 if (this.blockManager.gameStarted) { this.blockManager.addLockedVisualHint(this.currentDragBlock); // 游戏开始后放置的方块移除标签,不能再放回kuang BlockTag.removeTag(this.currentDragBlock); } // 检查并执行合成 try { await this.blockManager.tryMergeBlock(this.currentDragBlock); } catch (mergeError) { console.error('[GameBlockSelection] 方块合成时发生错误:', mergeError); // 合成失败不影响方块放置,只记录错误 } } else { // 金币不足时显示价格标签闪烁效果和Toast提示 this.blockManager.showInsufficientCoinsEffect(this.currentDragBlock); this.returnBlockToOriginalPosition(); } } } catch (error) { console.error('[GameBlockSelection] handleSuccessfulPlacement 发生错误:', error); // 发生错误时,将方块返回原位置 this.returnBlockToOriginalPosition(); throw error; // 重新抛出错误,让上层处理 } } // 返回方块到原位置 private returnBlockToOriginalPosition() { const currentLocation = this.blockManager.blockLocations.get(this.currentDragBlock); const startLocation = this.currentDragBlock['startLocation']; if (currentLocation === 'kuang') { const originalPos = this.blockManager.originalPositions.get(this.currentDragBlock); if (originalPos) { this.currentDragBlock.position = originalPos.clone(); } } else { this.currentDragBlock.position = this.blockStartPos.clone(); // 如果方块原本在grid区域,返回原位置后需要重新标记占用状态 if (startLocation === 'grid') { // 获取方块当前位置对应的网格节点 let b1Node = this.currentDragBlock; if (this.currentDragBlock.name !== 'B1') { b1Node = this.currentDragBlock.getChildByName('B1'); } if (b1Node) { const b1WorldPos = b1Node.parent.getComponent(UITransform).convertToWorldSpaceAR(b1Node.position); const gridPos = this.blockManager.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos); const gridNode = this.blockManager.findNearestGridNode(gridPos); if (gridNode) { this.blockManager.markOccupiedPositions(this.currentDragBlock, gridNode); // 输出更新后的占用情况 this.blockManager.printGridOccupationMatrix(); } } } } // 清除拖动状态,恢复db节点显示 this.currentDragBlock['isDragging'] = false; this.showDbNodeByBlockLocation(this.currentDragBlock); this.currentDragBlock.emit(Node.EventType.TRANSFORM_CHANGED); } // === 调试绘制相关方法 === private initDebugDraw() { // 调试绘制功能已禁用 } private drawGridSnapRanges() { // 调试绘制功能已禁用 } private drawBlockSnapRange(block: Node) { // 调试绘制功能已禁用 } private updateDebugDraw() { // 调试绘制功能已禁用 } // 清理调试绘制 private cleanupDebugDraw() { if (this.debugDrawNode && this.debugDrawNode.isValid) { this.debugDrawNode.destroy(); this.debugDrawNode = null; this.debugGraphics = null; } } public setDebugDrawSnapRange(enabled: boolean) { this.debugDrawSnapRange = enabled; // 调试绘制功能已禁用 } onDisable() { this.removeEventListeners(); this.cleanupDebugDraw(); } onDestroy() { this.removeEventListeners(); this.cleanupDebugDraw(); } // 移除事件监听器 private removeEventListeners() { const eventBus = EventBus.getInstance(); eventBus.off(GameEvents.RESET_BLOCK_SELECTION, this.onResetBlockSelectionEvent, this); eventBus.off(GameEvents.GAME_START, this.onGameStartEvent, this); eventBus.off(GameEvents.SETUP_BLOCK_DRAG_EVENTS, this.onSetupBlockDragEventsEvent, this); } /** * 获取方块的原始位置 * @param block 方块节点 * @returns 原始位置标识符 */ private getBlockOriginalLocation(block: Node): string | null { // 检查方块是否在block1Container中 if (this.blockManager.block1Container && this.isBlockInContainer(block, this.blockManager.block1Container)) { return 'block1'; } // 检查方块是否在block2Container中 if (this.blockManager.block2Container && this.isBlockInContainer(block, this.blockManager.block2Container)) { return 'block2'; } // 检查方块是否在block3Container中 if (this.blockManager.block3Container && this.isBlockInContainer(block, this.blockManager.block3Container)) { return 'block3'; } return null; } /** * 检查方块是否在指定容器中 * @param block 方块节点 * @param container 容器节点 * @returns 是否在容器中 */ private isBlockInContainer(block: Node, container: Node): boolean { let parent = block.parent; while (parent) { if (parent === container) { return true; } parent = parent.parent; } return false; } }