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 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() { console.log('[GameBlockSelection] onEnable() 节点被激活'); // 如果还未初始化,则进行初始化 if (!this.isInitialized) { this.initializeComponent(); } else { // 如果已经初始化,重新设置事件监听器(因为onDisable时会移除) this.setupEventListeners(); } this.initDebugDraw(); } start() { console.log('[GameBlockSelection] start() 被调用'); // 如果还未初始化,则进行初始化 if (!this.isInitialized) { this.initializeComponent(); } } private initializeComponent() { console.log('[GameBlockSelection] initializeComponent() 开始初始化'); console.log('[GameBlockSelection] 组件节点名称:', this.node.name); console.log('[GameBlockSelection] 组件节点激活状态:', this.node.active); // 获取管理器实例 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) { console.log('[GameBlockSelection] 武器配置已预加载,直接传递给BlockManager'); // 通过公共方法将预加载的配置传递给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; console.log('GameBlockSelection.initializeComponent() 初始化完成'); } // 设置事件监听器 private setupEventListeners() { console.log('[GameBlockSelection] 开始设置事件监听器'); const eventBus = EventBus.getInstance(); console.log('[GameBlockSelection] EventBus实例获取结果:', !!eventBus); // 监听重置方块选择事件 eventBus.on(GameEvents.RESET_BLOCK_SELECTION, this.onResetBlockSelectionEvent, this); console.log('[GameBlockSelection] RESET_BLOCK_SELECTION事件监听器已设置'); // 监听显示方块选择事件 // 监听游戏开始事件,用于标记可以开始生成方块 eventBus.on(GameEvents.GAME_START, this.onGameStartEvent, this); console.log('[GameBlockSelection] GAME_START事件监听器已设置'); // 监听方块拖拽事件设置请求 eventBus.on(GameEvents.SETUP_BLOCK_DRAG_EVENTS, this.onSetupBlockDragEventsEvent, this); console.log('[GameBlockSelection] SETUP_BLOCK_DRAG_EVENTS事件监听器已设置'); console.log('[GameBlockSelection] 事件监听器设置完成,组件节点:', this.node.name); console.log('[GameBlockSelection] 当前节点状态:', this.node.active); } // 处理重置方块选择事件 private onResetBlockSelectionEvent() { console.log('[GameBlockSelection] 接收到重置方块选择事件'); this.resetSelection(); } // 处理游戏开始事件 private onGameStartEvent() { console.log('[GameBlockSelection] 接收到游戏开始事件,允许生成方块'); this.shouldGenerateBlocks = true; } // 处理方块拖拽事件设置请求 private onSetupBlockDragEventsEvent(blocks: Node[]) { console.log('[GameBlockSelection] 接收到方块拖拽事件设置请求,方块数量:', blocks.length); // 确保组件仍然有效 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); console.log(`[GameBlockSelection] 为方块 ${block.name} 重新设置拖拽事件`); } else { console.warn('[GameBlockSelection] 跳过无效方块的拖拽事件设置'); } } } // 绑定按钮事件 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() { // 应用便宜技能效果计算实际费用 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); console.log(`新增小球成功,扣除${actualCost}金币`); } } // 增加金币按钮点击 private onAddCoinClicked() { // 免费增加金币(模拟看广告获得奖励) const coinsToAdd = 80; // 免费获得的金币数量 this.session.addCoins(coinsToAdd); console.log(`通过观看广告免费获得${coinsToAdd}金币`); // 更新显示 this.updateCoinDisplay(); } // 刷新方块按钮点击 private onRefreshClicked() { console.log('[GameBlockSelection] 刷新方块按钮被点击'); // 应用便宜技能效果计算实际费用 const actualCost = this.getActualCost(this.REFRESH_COST); console.log(`[GameBlockSelection] 计算实际费用: ${actualCost}`); if (!this.canSpendCoins(actualCost)) { console.log('[GameBlockSelection] 金币不足,无法刷新方块'); this.showInsufficientCoinsUI(); return; } // 扣除金币 if (this.session.spendCoins(actualCost)) { console.log(`[GameBlockSelection] 成功扣除 ${actualCost} 金币`); this.updateCoinDisplay(); // 刷新方块 if (this.blockManager) { console.log('[GameBlockSelection] 开始刷新方块流程'); // 找到PlacedBlocks容器 const placedBlocksContainer = find('Canvas/GameLevelUI/PlacedBlocks'); if (placedBlocksContainer) { console.log('[GameBlockSelection] 移除已放置方块的标签'); // 移除已放置方块的标签 BlockTag.removeTagsInContainer(placedBlocksContainer); } // 刷新方块 console.log('[GameBlockSelection] 调用 blockManager.refreshBlocks()'); this.blockManager.refreshBlocks(); // 等待一帧确保方块生成完成 this.scheduleOnce(() => { console.log('[GameBlockSelection] 刷新方块延迟检查完成'); }, 0.1); console.log(`[GameBlockSelection] 刷新方块成功,扣除${actualCost}金币`); } else { console.error('[GameBlockSelection] 找不到BlockManager,无法刷新方块'); } } else { console.error('[GameBlockSelection] 扣除金币失败'); } } // 确认按钮点击 public onConfirmButtonClicked() { // 检查是否有上阵方块 const hasBlocks = this.hasPlacedBlocks(); console.log(`[GameBlockSelection] 检查上阵方块: ${hasBlocks ? '有' : '无'}`); if (!hasBlocks) { this.showNoPlacedBlocksToast(); return; } // 保存已放置的方块 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() { console.log('[GameBlockSelection] 开始播放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); console.log('[GameBlockSelection] 已调用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(); console.log(`[GameBlockSelection] 更新金币显示: ${coins}`); } else { console.warn('[GameBlockSelection] coinLabelNode缺少Label组件'); } } else { console.warn('[GameBlockSelection] coinLabelNode未找到'); } } // 显示金币不足UI private showInsufficientCoinsUI() { // 使用事件机制显示Toast EventBus.getInstance().emit(GameEvents.SHOW_TOAST, { message: '金币不足!', duration: 3.0 }); console.log('金币不足!'); } // === 公共方法:供GameManager调用 === // 生成方块选择(不再控制UI显示,只负责生成方块) public generateBlockSelection() { console.log('[GameBlockSelection] generateBlockSelection开始执行'); // 直接生成方块,不再依赖shouldGenerateBlocks标志 if (this.blockManager) { this.blockManager.refreshBlocks(); console.log('[GameBlockSelection] 生成新的随机方块'); } else { console.warn('[GameBlockSelection] BlockManager未找到,无法生成随机方块'); } // 触发进入备战状态事件 EventBus.getInstance().emit(GameEvents.ENTER_BATTLE_PREPARATION); console.log('[GameBlockSelection] 方块生成完成'); } // 设置确认回调 public setConfirmCallback(callback: () => void) { this.onConfirmCallback = callback; } // 统一的方块占用情况刷新方法 public refreshGridOccupation() { console.log('[GameBlockSelection] 刷新方块占用情况'); if (this.blockManager) { this.blockManager.resetGridOccupation(); // 重新计算所有已放置方块的占用情况 const placedBlocksContainer = find('Canvas/GameLevelUI/PlacedBlocks'); if (placedBlocksContainer) { for (let i = 0; i < placedBlocksContainer.children.length; i++) { const block = placedBlocksContainer.children[i]; console.log(`[GameBlockSelection] 刷新方块占用情况,方块${i}`, block); // 按照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); console.log(`[GameBlockSelection] B1世界坐标:`, b1WorldPos); console.log(`[GameBlockSelection] 网格本地坐标:`, gridPos); // 重新标记方块占用的网格位置 const gridNode = this.blockManager.findNearestGridNode(gridPos); if (gridNode) { this.blockManager.markOccupiedPositions(block, gridNode); console.log(`[GameBlockSelection] 方块 ${block.name} 重新标记到网格 ${gridNode.name}`); } else { console.warn(`[GameBlockSelection] 方块 ${block.name} 未找到对应的网格节点`); } } } console.log('[GameBlockSelection] 方块占用情况刷新完成'); } else { console.warn('[GameBlockSelection] BlockManager未找到,无法刷新占用情况'); } this.blockManager.printGridOccupationMatrix(); } // 重置方块选择状态 public resetSelection() { console.log('[GameBlockSelection] 重置方块选择状态'); // 重置方块生成标志,等待下次onBattle触发 this.shouldGenerateBlocks = false; console.log('[GameBlockSelection] 重置方块生成标志'); // 注意:不再直接调用blockManager.onGameReset(),因为StartGame.clearGameStates() // 已经通过RESET_BLOCK_MANAGER事件触发了BlockManager的重置,避免重复生成方块 console.log('[GameBlockSelection] BlockManager将通过事件系统自动重置'); // 清理所有方块标签 BlockTag.clearAllTags(); console.log('[GameBlockSelection] 方块标签已清理'); // 更新金币显示 this.updateCoinDisplay(); console.log('[GameBlockSelection] 金币显示已更新'); } // 检查是否有上阵方块 private hasPlacedBlocks(): boolean { // 优先使用BlockManager的方法检查 if (this.blockManager) { return this.blockManager.hasPlacedBlocks(); } // 备用方案:直接检查PlacedBlocks容器 const placedBlocksContainer = find('Canvas/GameLevelUI/PlacedBlocks'); if (!placedBlocksContainer) { console.warn('找不到PlacedBlocks容器'); return false; } // 检查容器中是否有子节点(方块) return placedBlocksContainer.children.length > 0; } // 显示没有上阵方块的Toast提示 private showNoPlacedBlocksToast() { console.log('[GameBlockSelection] 显示未上阵植物提示'); // 使用事件机制显示Toast EventBus.getInstance().emit(GameEvents.SHOW_TOAST, { message: '请至少上阵一个植物!', duration: 3.0 }); console.log('[GameBlockSelection] 请至少上阵一个植物!'); } // 设置方块拖拽事件 public setupBlockDragEvents(block: Node) { block.on(Node.EventType.TOUCH_START, (event: EventTouch) => { console.log('[GameBlockSelection] TOUCH_START - gameStarted:', this.blockManager.gameStarted); // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { console.log('[GameBlockSelection] 游戏未开始,拒绝拖拽'); return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); console.log('[GameBlockSelection] 方块位置:', blockLocation, '可移动检查:', blockLocation === 'grid' ? this.canMoveBlock(block) : true); if (blockLocation === 'grid' && !this.canMoveBlock(block)) { console.log('[GameBlockSelection] grid区域方块移动被限制'); return; } console.log('[GameBlockSelection] 开始拖拽方块,位置:', blockLocation); this.currentDragBlock = block; this.startPos = event.getUILocation(); this.blockStartPos.set(block.position); this.currentDragBlock['startLocation'] = blockLocation; // 设置拖动状态,隐藏价格标签 block['isDragging'] = true; block.setSiblingIndex(block.parent.children.length - 1); // 拖拽开始时禁用碰撞体 const collider = block.getComponent(Collider2D); if (collider) collider.enabled = false; }, this); block.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => { // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); if (blockLocation === 'grid' && !this.canMoveBlock(block)) { return; } 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.updateDebugDraw(); }, this); block.on(Node.EventType.TOUCH_END, async (event: EventTouch) => { // 检查游戏是否已开始 if (!this.blockManager.gameStarted) { return; } // 只对grid区域的方块检查移动限制,kuang区域的方块可以自由拖拽 const blockLocation = this.blockManager.blockLocations.get(block); if (blockLocation === 'grid' && !this.canMoveBlock(block)) { return; } 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; // 更新调试绘制 this.updateDebugDraw(); } }, 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; // 更新调试绘制 this.updateDebugDraw(); } }, this); } // 检查方块是否可以移动 private canMoveBlock(block: Node): boolean { return true; } // 处理方块放下 private async handleBlockDrop(event: EventTouch) { console.log("事件:处理方块放下"); 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,返回原位置 console.log(`[GameBlockSelection] 方块 ${this.currentDragBlock.name} 没有标签,不能放回kuang区域`); this.returnBlockToOriginalPosition(); } } else if (this.blockManager.tryPlaceBlockToGrid(this.currentDragBlock)) { await this.handleSuccessfulPlacement(startLocation); } else { console.log(`[GameBlockSelection] 方块 ${this.currentDragBlock.name} 放置到网格失败`); console.log(`[GameBlockSelection] 方块标签状态:`, BlockTag.hasTag(this.currentDragBlock)); console.log(`[GameBlockSelection] 方块UUID:`, this.currentDragBlock.uuid); // 放置失败,尝试直接与重叠方块合成 if (this.blockManager.tryMergeOnOverlap(this.currentDragBlock)) { // 合成成功时,若来自 kuang 则扣费 if (startLocation !== 'grid') { const price = this.blockManager.getBlockPrice(this.currentDragBlock); this.blockManager.deductPlayerCoins(price); } // 当前拖拽块已被销毁(合并时),无需复位 } else { console.log(`[GameBlockSelection] 方块 ${this.currentDragBlock.name} 合成也失败,返回原位置`); this.returnBlockToOriginalPosition(); } } } catch (error) { console.error('[GameBlockSelection] handleBlockDrop 发生错误:', error); // 发生错误时,将方块返回原位置 this.returnBlockToOriginalPosition(); throw error; // 重新抛出错误,让上层处理 } // 刷新方块占用情况 this.refreshGridOccupation(); } // 检查是否在kuang区域内 private isInKuangArea(touchPos: Vec2): boolean { if (!this.blockManager.kuangContainer) return false; const kuangTransform = this.blockManager.kuangContainer.getComponent(UITransform); if (!kuangTransform) return false; 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)); } // 返回方块到kuang区域 private returnBlockToKuang(startLocation: string) { const originalPos = this.blockManager.originalPositions.get(this.currentDragBlock); if (originalPos) { const kuangNode = this.blockManager.kuangContainer; if (kuangNode && this.currentDragBlock.parent !== kuangNode) { this.currentDragBlock.removeFromParent(); kuangNode.addChild(this.currentDragBlock); } this.currentDragBlock.position = originalPos.clone(); } this.blockManager.blockLocations.set(this.currentDragBlock, 'kuang'); this.blockManager.showPriceLabel(this.currentDragBlock); // 当方块返回kuang区域时,重新设置植物图标缩放至0.45倍 const b1Node = this.currentDragBlock.getChildByName('B1'); if (b1Node) { const weaponNode = b1Node.getChildByName('Weapon'); if (weaponNode) { weaponNode.setScale(0.45, 0.45, 1); console.log(`[GameBlockSelection] 方块返回kuang区域,设置植物图标缩放: 0.45倍`); } } if (startLocation === 'grid') { const price = this.blockManager.getBlockPrice(this.currentDragBlock); this.blockManager.refundPlayerCoins(price); this.currentDragBlock['placedBefore'] = false; } const dbNode = this.currentDragBlock['dbNode']; if (dbNode) { dbNode.active = true; this.currentDragBlock.emit(Node.EventType.TRANSFORM_CHANGED); } } /** * 为方块的武器节点添加武器信息组件 * @param block 方块节点 */ private attachWeaponInfoToBlock(block: Node): void { console.log(`[GameBlockSelection] 添加武器信息`); try { // 查找方块中的Weapon节点 const weaponNode = this.findWeaponNodeInBlock(block); if (!weaponNode) { console.warn(`[GameBlockSelection] 方块 ${block.name} 中未找到Weapon节点,无法添加武器信息组件`); return; } // 检查是否已经有WeaponInfo组件 let weaponInfo = weaponNode.getComponent(WeaponInfo); if (weaponInfo) { console.log(`[GameBlockSelection] 武器节点 ${weaponNode.name} 已有WeaponInfo组件,跳过添加`); return; } // 添加WeaponInfo组件 weaponInfo = weaponNode.addComponent(WeaponInfo); // 获取方块的武器配置 const weaponConfig = this.blockManager.getBlockWeaponConfig(block); if (weaponConfig) { // 设置武器配置到WeaponInfo组件 weaponInfo.setWeaponConfig(weaponConfig); console.log(`[GameBlockSelection] 成功为武器节点 ${weaponNode.name} 添加武器信息组件,武器: ${weaponConfig.name}`); } 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; } // 递归查找名为"Weapon"的子节点 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); } // 处理成功放置 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'); this.blockManager.hidePriceLabel(this.currentDragBlock); const dbNode = this.currentDragBlock['dbNode']; if (dbNode) { dbNode.active = false; } // 立即将方块移动到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 { if (this.blockManager.deductPlayerCoins(price)) { this.blockManager.clearTempStoredOccupiedGrids(this.currentDragBlock); this.blockManager.blockLocations.set(this.currentDragBlock, 'grid'); this.blockManager.hidePriceLabel(this.currentDragBlock); const dbNode = this.currentDragBlock['dbNode']; if (dbNode) { dbNode.active = false; } 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); 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(); } // 清除拖动状态,恢复价格标签显示 this.currentDragBlock['isDragging'] = false; this.blockManager.showPriceLabel(this.currentDragBlock); const dbNode = this.currentDragBlock['dbNode']; if (dbNode) { dbNode.active = true; this.currentDragBlock.emit(Node.EventType.TRANSFORM_CHANGED); } } // === 调试绘制相关方法 === // 初始化调试绘制 private initDebugDraw() { if (!this.debugDrawSnapRange) return; // 创建调试绘制节点 this.debugDrawNode = new Node('DebugDraw'); this.debugGraphics = this.debugDrawNode.addComponent(Graphics); // 将调试绘制节点添加到场景中 if (this.gridContainer && this.gridContainer.parent) { this.gridContainer.parent.addChild(this.debugDrawNode); } console.log('[GameBlockSelection] 调试绘制初始化完成'); } // 绘制网格吸附范围 private drawGridSnapRanges() { if (!this.debugDrawSnapRange || !this.debugGraphics || !this.blockManager) return; this.debugGraphics.strokeColor = Color.GREEN; this.debugGraphics.lineWidth = 2; // 通过BlockManager获取网格信息来绘制吸附范围 const gridSpacing = this.blockManager.getGridSpacing(); // 动态获取网格间距 const snapRange = gridSpacing * 0.8; // 吸附范围 // 遍历所有网格位置,绘制吸附范围 for (let row = 0; row < 6; row++) { for (let col = 0; col < 11; col++) { // 计算网格世界坐标 const gridWorldPos = this.blockManager.getGridWorldPosition(row, col); if (!gridWorldPos) continue; // 转换为调试绘制节点的本地坐标 const localPos = new Vec3(); this.debugDrawNode.getComponent(UITransform).convertToNodeSpaceAR(gridWorldPos, localPos); // 绘制网格吸附范围圆圈 this.debugGraphics.circle(localPos.x, localPos.y, snapRange); this.debugGraphics.stroke(); } } } // 绘制方块吸附范围 private drawBlockSnapRange(block: Node) { if (!this.debugDrawSnapRange || !this.debugGraphics || !block || !this.blockManager) return; // 绘制方块吸附点 this.debugGraphics.strokeColor = Color.RED; this.debugGraphics.fillColor = Color.RED; this.debugGraphics.lineWidth = 3; const blockParts = this.blockManager.getBlockParts(block); const gridSpacing = this.blockManager.getGridSpacing(); // 动态获取网格间距 const snapRange = gridSpacing * 0.6; // 吸附范围 blockParts.forEach(part => { const worldPos = part.node.getWorldPosition(); const localPos = new Vec3(); this.debugDrawNode.getComponent(UITransform).convertToNodeSpaceAR(worldPos, localPos); // 绘制红色十字标记吸附点 const crossSize = 10; this.debugGraphics.moveTo(localPos.x - crossSize, localPos.y); this.debugGraphics.lineTo(localPos.x + crossSize, localPos.y); this.debugGraphics.moveTo(localPos.x, localPos.y - crossSize); this.debugGraphics.lineTo(localPos.x, localPos.y + crossSize); this.debugGraphics.stroke(); // 绘制吸附范围圆圈 this.debugGraphics.circle(localPos.x, localPos.y, snapRange); this.debugGraphics.stroke(); }); } // 更新调试绘制 private updateDebugDraw() { if (!this.debugDrawSnapRange || !this.debugGraphics) return; this.debugGraphics.clear(); // 绘制网格吸附范围 this.drawGridSnapRanges(); // 如果有正在拖拽的方块,绘制其吸附范围 if (this.currentDragBlock) { this.drawBlockSnapRange(this.currentDragBlock); } } // 清理调试绘制 private cleanupDebugDraw() { if (this.debugDrawNode && this.debugDrawNode.isValid) { this.debugDrawNode.destroy(); this.debugDrawNode = null; this.debugGraphics = null; } } // 设置调试绘制开关 public setDebugDrawSnapRange(enabled: boolean) { this.debugDrawSnapRange = enabled; if (enabled) { this.initDebugDraw(); } else { this.cleanupDebugDraw(); } console.log(`[GameBlockSelection] 调试绘制已${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); } }