import { _decorator, BoxCollider2D, Button, CircleCollider2D, Collider2D, Component, find, instantiate, Node, NodeEventType, tween, view, Vec3, mat4, UITransform, Label } from 'cc'; import { CupHeight, TakeGobletGlobalInstance, WaterColorLog, WaterColors } from './TakeGobletGlobalInstance'; import { OutArea } from './Component/OutArea'; import { WaitArea } from './Component/WaitArea'; import { CocktailCup } from './Component/CocktailCup'; import { OriginCup, OriginCupState } from './Component/OriginCup'; import { Water } from './Component/Water'; import { EventDispatcher } from '../../core_tgx/easy_ui_framework/EventDispatcher'; import { GameEvent } from './Enum/GameEvent'; import { TempCup } from './Component/TempCup'; import { TempCups } from './Component/TempCups'; import { tgxUIMgr, tgxUITips } from '../../core_tgx/tgx'; import { LevelManager } from './Manager/LevelMgr'; import { UI_BattleResult } from '../../scripts/UIDef'; import { GameUtil } from './GameUtil'; import { OriginArea } from './Component/OriginArea'; import { GtagMgr, GtagType } from '../../core_tgx/base/GtagMgr'; import { GlobalConfig } from '../../start/Config/GlobalConfig'; import { AdvertMgr } from '../../core_tgx/base/ad/AdvertMgr'; const { ccclass, property } = _decorator; //动画时长 export const ANIMATION_DURATION = 0.3; @ccclass('LevelAction') export class LevelAction extends Component { @property(OutArea) outArea: OutArea = null!; // 直接引用OutArea组件 @property(WaitArea) waitArea: WaitArea = null!; // 直接引用WaitArea组件 @property(Node) tempCups: Node = null!; //临时杯 @property(Node) originArea: Node = null!; //原浆区 originCupPositions = new Map(); // 改用唯一ID记录 private isProcessing = false; // 添加状态锁 static instance: LevelAction; // 添加静态实例 onLoad() { LevelAction.instance = this; } start() { this.generateInitialCups(); this.registerListener(); this.reportInformation(); } //上报信息 reportInformation() { const { level } = LevelManager.instance.levelModel; console.log(`上报信息 level:${level}`); GtagMgr.inst.doGameDot(GtagType.level_start, { level }); if (!GlobalConfig.isDebug) { AdvertMgr.instance.showInterstitial(); } } onDestroy() { this.unregisterListener(); } registerListener() { EventDispatcher.instance.on(GameEvent.EVENT_REFRESH_COLOR, this.generateOriginCups, this); EventDispatcher.instance.on(GameEvent.EVENT_CLICK_ORIGIN_CUP, this.handlePourOriginCup, this); EventDispatcher.instance.on(GameEvent.EVENT_ORIGIN_CUP_DESTROYED, (uuid: string) => { if (!this.originCupPositions) return const targetPos = this.originCupPositions.get(uuid); if (targetPos) { this.spawnNewOriginCup(targetPos); } }, this); EventDispatcher.instance.on(GameEvent.EVENT_COCKTAIL_CUP_DESTROYED, this.handleCupDestroyed, this); EventDispatcher.instance.on(GameEvent.EVENT_RIGHT_CUP_FULL, this.addWaitCupToOutArea, this); } unregisterListener() { EventDispatcher.instance.off(GameEvent.EVENT_REFRESH_COLOR, this.generateOriginCups, this); EventDispatcher.instance.off(GameEvent.EVENT_CLICK_ORIGIN_CUP, this.handlePourOriginCup, this); EventDispatcher.instance.off(GameEvent.EVENT_ORIGIN_CUP_DESTROYED, this.spawnNewOriginCup, this); EventDispatcher.instance.off(GameEvent.EVENT_COCKTAIL_CUP_DESTROYED, this.handleCupDestroyed, this); EventDispatcher.instance.off(GameEvent.EVENT_RIGHT_CUP_FULL, this.addWaitCupToOutArea, this); } private async generateInitialCups() { const instance = TakeGobletGlobalInstance.instance; const configs = instance.getInitialCupsConfig(); const allCups: Node[] = []; for (const config of configs) { for (let i = 0; i < config.count; i++) { const prefab = await instance.loadAsyncCocktail(config.height); const cupNode = instantiate(prefab); const cup = cupNode.getComponent(CocktailCup)!; cup.reset(); allCups.push(cupNode); } } const levelColors = LevelManager.instance.levelModel.levelColors; const rule = instance.cocktailCupRule(); const [x, y] = rule; const colorPool = levelColors.slice(0, y); console.log(`colorPool:`, colorPool); // 为所有杯子分配颜色 // 确保所有颜色至少出现一次 const shuffledCups = [...allCups]; const shuffledColors = [...levelColors]; let currentIndex = 0; // 先为每个颜色分配一个杯子 for (let i = 0; i < shuffledColors.length && i < shuffledCups.length; i++) { const cup = shuffledCups[i]; const cupComp = cup.getComponent(CocktailCup)!; cupComp.cupColor = shuffledColors[i]; currentIndex = i + 1; } // 为剩余杯子分配颜色,确保不超过x个相同颜色相邻 for (let i = currentIndex; i < shuffledCups.length; i++) { const cup = shuffledCups[i]; const cupComp = cup.getComponent(CocktailCup)!; // 获取前x-1个杯子的颜色 const previousColors = new Set(); for (let j = Math.max(0, i - (x - 1)); j < i; j++) { const prevCup = shuffledCups[j].getComponent(CocktailCup)!; previousColors.add(prevCup.cupColor); } // 从可用颜色中筛选出合适的颜色 const availableColors = shuffledColors.filter(color => !previousColors.has(color)); // 如果没有合适的颜色,就从所有颜色中随机选择 const colorPool = availableColors.length > 0 ? availableColors : shuffledColors; cupComp.cupColor = colorPool[Math.floor(Math.random() * colorPool.length)]; } // 随机打乱杯子顺序 for (let i = shuffledCups.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffledCups[i], shuffledCups[j]] = [shuffledCups[j], shuffledCups[i]]; } allCups.length = 0; allCups.push(...shuffledCups); // allCups.forEach(cup => { // const cupComp = cup.getComponent(CocktailCup)!; // // 从颜色池随机选择一个颜色 // const randomColor = colorPool[Math.floor(Math.random() * colorPool.length)]; // cupComp.cupColor = randomColor; // }); console.log('allCups: ', allCups.length); // 分配初始位置 allCups.slice(0, 2).forEach(cup => this.outArea.addCup(cup)); allCups.slice(2).forEach(cup => this.waitArea.addCup(cup)); // 在分配完调酒杯后添加 this.generateOriginCups(); // 初始化暂存区 this.tempCups.children.forEach(tempCupNode => { const tempCup = tempCupNode.getComponent(TempCup)!; tempCup.reset(); // 重置所有暂存杯 }); EventDispatcher.instance.emit(GameEvent.EVENT_REFRESH_REMAIN_CUP); } // 当调酒区杯子被消除时调用 public async handleCupsRemoved(count: number) { for (let i = 0; i < count; i++) { const cup = this.waitArea.takeCup(); if (cup) { this.outArea.addCup(cup); } } } private async generateOriginCups() { if (this.isProcessing) { tgxUITips.show('Please wait for the \n current process to complete!'); return; } const levelModel = LevelManager.instance.levelModel; const outCups = this.outArea.getCups() as Node[]; const waitCups = this.waitArea.getCups() as Node[]; const measuringcup_number = levelModel.levelConfig.measuringcup_number; const allCups = [...outCups, ...waitCups].slice(0, measuringcup_number); const colors = allCups.map(cup => { const comp = cup.getComponent(CocktailCup); return comp ? comp.cupColor : WaterColors.Blue; }); this.originArea.children.forEach(originCupNode => { const originCup = originCupNode.getComponent(OriginCup)!; const waters = originCup.waters.children; for (let i = 0; i < originCup.cupHeight; i++) { const waterNode = waters[i]; const water = waterNode.getComponent(Water); if (water) { water.initColor(colors[Math.floor(Math.random() * colors.length)]); waterNode.active = true; } } // 在生成初始原浆杯时记录位置 const id = originCupNode.uuid; // 使用节点唯一ID this.originCupPositions.set(id, originCupNode.position.clone()); // console.log('在生成初始原浆杯时记录id : ', id, originCupNode.position); }); } private findTargetCupInOutArea(color: WaterColors): { node: Node, comp: CocktailCup } | null { const validCups = this.outArea.getCups() .map(node => ({ node, comp: node.getComponent(CocktailCup)! })) .filter(({ comp }) => comp && comp.cupColor === color && !comp.isFull ); if (validCups.length === 0) return null; const sorted = validCups.sort((a, b) => (a.comp.remainingCapacity ?? 0) - (b.comp.remainingCapacity ?? 0)); return sorted[0]; } public async handlePourOriginCup(originCup: OriginCup) { if (this.isProcessing) { tgxUITips.show('Please wait for the \n current process to complete!'); return; } this.isProcessing = true; try { // 如果子节点0是底层,需要反转顺序 const watersNode: Node[] = []; for (let i = originCup.waters.children.length - 1; i >= 0; i--) { const waterNode = originCup.waters.children[i]; if (waterNode.active) { watersNode.push(waterNode); } } let hasUnprocessed = false; // 标记是否有未处理的水层 originCup.setMark(false); for (const waterNode of watersNode) { const color = waterNode.getComponent(Water)!.color; console.log(`当前处理的颜色:${WaterColorLog[color]}}`); let targetNode: Node | null = this.findTargetCupInOutArea(color)?.node || null; let targetIsTemp = false; // 调酒区未找到,查找暂存区 if (!targetNode) { const tempCupsComp = this.tempCups.getComponent(TempCups); if (!tempCupsComp) { console.error('TempCups component not found!'); continue; } const tempCup = tempCupsComp.findAvailableTempCup(); if (tempCup) { targetNode = tempCup.node; targetIsTemp = true; } } if (!targetNode) { hasUnprocessed = true; console.log(`颜色${WaterColors[color]}未找到可用杯子`); continue; // 继续尝试处理后续颜色 } await this.pourAnimation( originCup.node, targetNode, undefined, targetIsTemp ); originCup.pourWater(); // 更新目标杯 if (targetIsTemp) { const tempCupComp = targetNode.getComponent(TempCup)!; await tempCupComp.fill(color); } else { const cocktailCup = targetNode.getComponent(CocktailCup)!; await cocktailCup.addLayer(); // 等待添加水层流程完成 } originCup.hideCurrentWaterLayer(); } // 处理完所有颜色后检查剩余水层 if (!originCup.waters) return const remaining = originCup.waters.children.filter(n => n.active).length; if (hasUnprocessed || remaining > 0) { // console.log("游戏结束:仍有未处理的水层"); this.isProcessing = true; const waitLength = this.waitArea!.getCups().length; const outLength = this.outArea!.getCups().length; let remain = waitLength + outLength; console.log(`waitLength:${waitLength} + outLenght:${outLength} = remain:${remain}`); LevelManager.instance.levelModel.remainCupCount = remain; LevelManager.instance.levelModel.isWin = false; tgxUIMgr.inst.showUI(UI_BattleResult); } else { // 所有水层处理完毕,销毁原浆杯 await originCup.destroyOriginCup(); this.addWaitCupToOutArea(); } } finally { this.isProcessing = false; } } //处理暂存区倒水到调酒区 private async handlePourTempCupToOutArea() { if (this.isProcessing) return; this.isProcessing = true; try { const tempCupsComp = this.tempCups!.getComponent(TempCups)!; const filledCups = tempCupsComp.getFilledCups(); for (const tempCup of filledCups) { const originalPos = tempCup.node.position.clone(); const colors = tempCup.getColors(); for (const color of colors) { const targetCup = this.findTargetCupInOutArea(color); if (!targetCup) { // console.log(`颜色${WaterColors[color]}未找到可用调酒杯`); continue; } await this.pourAnimation( tempCup.node, targetCup.node, originalPos, true ); tempCup.pour(); const cocktailCup = targetCup.comp; await cocktailCup.addLayer(); await GameUtil.delay(0.2); // 返回到暂存区初始位置 if (originalPos) { await new Promise(resolve => { tween(tempCup.node) .to(ANIMATION_DURATION, { position: originalPos }) .call(() => { tempCup.reset(); resolve(true); }) .start(); }); } } } } finally { this.isProcessing = false; } } // 添加新杯子后触发暂存区倒水 private async addWaitCupToOutArea() { const waitCups = this.waitArea.cups; const outCups = this.outArea.getCups(); const needAddCount = outCups.length === 0 ? 2 : 1; const byX = outCups.length === 0 ? 220 : 110; const movingCups: Node[] = []; for (let i = 0; i < needAddCount; i++) { if (waitCups.length === 0) break; movingCups.push(waitCups.pop()!); } const newCups: Node[] = []; for (const cup of movingCups) { const comp = cup.getComponent(CocktailCup)!; const prefab = await TakeGobletGlobalInstance.instance.loadAsyncCocktail(comp.cupHeight); const newCup = instantiate(prefab); const newComp = newCup.getComponent(CocktailCup)!; newComp.cupColor = comp.cupColor; newComp.reset(); const targetX = outCups.length === 0 ? (newCups.length === 0 ? -160 : -50) : -50; newCup.setPosition(new Vec3(targetX, 0, 0)); newCups.push(newCup); cup.destroy(); } const outNodes = this.outArea.node.getChildByName('OutNodes')!; newCups.forEach(cup => cup.setParent(outNodes)); // 执行统一平移 if (this.waitArea.getCups().length > 0) { this.outArea.getCups().concat(this.waitArea.getCups()).forEach(cup => { tween(cup) .by(ANIMATION_DURATION, { position: new Vec3(byX, 0, 0) }, { easing: 'sineOut' }) .start(); }); } await GameUtil.delay(0.2); // 在添加完成后处理暂存区倒水 await this.handlePourTempCupToOutArea(); // 胜利条件检测:当两个区域都没有杯子时触发胜利 if (this.outArea.getCups().length === 0 && this.waitArea.cups.length === 0) { this.isProcessing = true; LevelManager.instance.levelModel.isWin = true; tgxUIMgr.inst.showUI(UI_BattleResult); } } /** 倒水移动动画 * @param origin 原杯子 * @param target 目标杯子 * @param originalPos 原始位置 * @param isTempCup 是否是暂存区杯子 */ private async pourAnimation( origin: Node, target: Node, originalPos?: Vec3, isTempCup: boolean = false ) { const targetWorldPos = target.getWorldPosition().clone(); const tempRegex = /TempCup/.test(origin.name); let targetPosY: number = 135; if (origin.getComponent(OriginCup)) { const targetCup = origin.getComponent(OriginCup)!; if (targetCup.cupHeight == CupHeight.Two) { targetPosY = 165; } else if (targetCup.cupHeight == CupHeight.Four) { targetPosY = 105; } } // 调整偏移量 targetWorldPos.x -= !tempRegex ? 55 : 40; targetWorldPos.y += !tempRegex ? targetPosY : 205; // 移动动画到目标位置 await new Promise(resolve => { tween(origin) .to(ANIMATION_DURATION, { worldPosition: targetWorldPos }) .call(resolve) .start(); }); } private async spawnNewOriginCup(targetPos: Vec3) { const levelModel = LevelManager.instance.levelModel; const measuringcup_number = levelModel.levelConfig.measuringcup_number;//获取调酒和等待区前面数量 const colors = this.getAvailableColors(measuringcup_number); if (colors.length <= 0) return; // 创建新原浆杯 const height = TakeGobletGlobalInstance.instance.generateOriginCupHeight(); const prefab = await TakeGobletGlobalInstance.instance.loadAsyncOriginCup(height); const newCup = instantiate(prefab); this.originArea.addChild(newCup); await newCup.getComponent(OriginCup)?.spawnNewOriginCup(height, targetPos, colors); } // 获取可用颜色 private getAvailableColors(count: number): WaterColors[] { const outCups = this.outArea.getCups(); const waitCups = this.waitArea.getCups(); const allCups = [...outCups, ...waitCups].slice(0, count); return allCups.map(cup => { const comp = cup.getComponent(CocktailCup); return comp ? comp.cupColor : WaterColors.Blue; }); } private handleCupDestroyed(destroyedCup: Node) { // 从outArea移除被销毁的杯子 this.outArea.removeCup(destroyedCup); } }