Selaa lähdekoodia

【功能】拆分功能,暂存 还有问题

mojunshou 1 vuosi sitten
vanhempi
commit
896446500e

+ 9 - 0
assets/script/game/view/eliminate.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "ac280510-ba1f-47b6-be0f-a0b3c72c6209",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 352 - 0
assets/script/game/view/eliminate/EliminateAnimationManager.ts

@@ -0,0 +1,352 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-19 18:41:36
+ * @Description: 消除游戏动画管理器
+ */
+import { Label, Node, Prefab, Vec3, instantiate, tween } from "cc";
+import { LabelChange } from "db://oops-framework/libs/gui/label/LabelChange";
+import { Format } from "../../utils/Format";
+
+export class EliminateAnimationManager {
+    private coinPrefab: Prefab | null = null;
+    private redPacketPrefab: Prefab | null = null;
+    private lab_addScore: Label | null = null;
+    private lab_wxCoin: LabelChange | null = null;
+    private lab_hbCoin: LabelChange | null = null;
+    private tweenWechatNode: Node | null = null;
+    private tweenRedNode: Node | null = null;
+    private comboNode: Node | null = null;
+    private rootNode: Node | null = null;
+
+    // 动画速度相关
+    private isDoubleSpeed: boolean = false;
+    private doubleNum: number = 1;
+
+    constructor(
+        rootNode: Node,
+        coinPrefab: Prefab,
+        redPacketPrefab: Prefab,
+        lab_addScore: Label,
+        lab_wxCoin: LabelChange,
+        lab_hbCoin: LabelChange,
+        tweenWechatNode: Node,
+        tweenRedNode: Node,
+        comboNode: Node
+    ) {
+        this.rootNode = rootNode;
+        this.coinPrefab = coinPrefab;
+        this.redPacketPrefab = redPacketPrefab;
+        this.lab_addScore = lab_addScore;
+        this.lab_wxCoin = lab_wxCoin;
+        this.lab_hbCoin = lab_hbCoin;
+        this.tweenWechatNode = tweenWechatNode;
+        this.tweenRedNode = tweenRedNode;
+        this.comboNode = comboNode;
+    }
+
+    /**
+     * 设置动画速度
+     */
+    public setDoubleSpeed(isDoubleSpeed: boolean, multiplier: number = 2): void {
+        this.isDoubleSpeed = isDoubleSpeed;
+        this.doubleNum = isDoubleSpeed ? multiplier : 1;
+    }
+
+    /**
+     * 创建金币飞行动画
+     */
+    public createCoinFlyAnimation(
+        prefab: Prefab,
+        startPos: Vec3,
+        endPos: Vec3,
+        count: number,
+        callback?: Function
+    ): void {
+        if (!prefab || !this.rootNode) return;
+
+        let completedCount = 0;
+        const totalCoins = Math.min(count, 5); // 限制最大数量
+
+        for (let i = 0; i < totalCoins; i++) {
+            const coin = instantiate(prefab);
+            this.rootNode.addChild(coin);
+            coin.setWorldPosition(startPos);
+
+            // 随机偏移起始位置
+            const randomOffset = new Vec3(
+                (Math.random() - 0.5) * 50,
+                (Math.random() - 0.5) * 50,
+                0
+            );
+
+            // 创建曲线动画
+            const num = this.isDoubleSpeed ? this.doubleNum : 1;
+            tween(coin)
+                .to(0.2 / num, {
+                    position: new Vec3(
+                        coin.position.x + randomOffset.x,
+                        coin.position.y + randomOffset.y,
+                        0
+                    )
+                })
+                .to(0.5 / num, { worldPosition: endPos })
+                .call(() => {
+                    coin.destroy();
+                    completedCount++;
+
+                    // 所有金币动画完成后执行回调
+                    if (completedCount === totalCoins && callback) {
+                        callback();
+                    }
+                })
+                .start();
+        }
+    }
+
+    /**
+     * 显示微信分数增加动画
+     */
+    public showWechatScoreAnimation(changeValue: number, currentMoney: number): void {
+        if (!this.tweenWechatNode || !this.lab_wxCoin) return;
+
+        const formattedValue = changeValue;
+        console.log("微信币增加数值>>>>>>>>>", changeValue);
+
+        // 获取并设置分数标签
+        const scoreLabel = this.tweenWechatNode.getChildByName("lab_num")?.getComponent(Label);
+        if (scoreLabel) {
+            scoreLabel.string = "+" + Format.formatWxCoinModify(formattedValue);
+        }
+
+        // 保存原始位置
+        const originalPosition = this.lab_wxCoin.node.worldPosition;
+
+        //设置原始位置
+        this.tweenWechatNode.setWorldPosition(originalPosition);
+        // 显示节点
+        this.tweenWechatNode.active = true;
+
+        // 创建向上移动的动画
+        const num = this.isDoubleSpeed ? this.doubleNum : 1;
+        tween(this.tweenWechatNode)
+            .to(0.8 / num, {
+                worldPosition: new Vec3(
+                    originalPosition.x,
+                    originalPosition.y + 50,
+                    originalPosition.z
+                ),
+                opacity: 255
+            })
+            .to(0.2 / num, { opacity: 0 })
+            .call(() => {
+                //设置位置y-100
+                if (this.tweenWechatNode) {
+                    this.tweenWechatNode.setWorldPosition(new Vec3(
+                        originalPosition.x,
+                        originalPosition.y,
+                        originalPosition.z
+                    ));
+                    this.tweenWechatNode.active = false;
+                    // 更新总金额
+                    if (this.lab_wxCoin) {
+                        this.lab_wxCoin.string = Format.formatWxCoin(currentMoney);
+                    }
+                }
+            })
+            .start();
+    }
+
+    /**
+     * 显示红包分数增加动画
+     */
+    public showRedPacketScoreAnimation(changeValue: number, currentCash: number): void {
+        if (!this.tweenRedNode || !this.lab_hbCoin) return;
+
+        console.log("红包分数增加动画", changeValue);
+        if (!changeValue) return;
+
+        const formattedValue = changeValue;
+
+        // 获取并设置分数标签
+        const scoreLabel = this.tweenRedNode.getChildByName("lab_num")?.getComponent(Label);
+        if (scoreLabel) {
+            scoreLabel.string = "+" + Format.formatRedPacketCoin(formattedValue);
+        }
+
+        // 保存原始位置
+        const originalPosition = this.lab_hbCoin.node.worldPosition;
+
+        //设置原始位置
+        this.tweenRedNode.setWorldPosition(originalPosition);
+
+        // 显示节点
+        this.tweenRedNode.active = true;
+
+        // 创建向上移动的动画
+        const num = this.isDoubleSpeed ? this.doubleNum : 1;
+        tween(this.tweenRedNode)
+            .to(0.8 / num, {
+                worldPosition: new Vec3(
+                    originalPosition.x,
+                    originalPosition.y + 50,
+                    originalPosition.z
+                ),
+                opacity: 255
+            })
+            .to(0.2 / num, { opacity: 0 })
+            .call(() => {
+                if (!this.tweenRedNode) {
+                    return
+                }
+
+
+                this.tweenRedNode.setWorldPosition(new Vec3(
+                    originalPosition.x,
+                    originalPosition.y,
+                    originalPosition.z
+                ));
+
+                this.tweenRedNode.active = false;
+                // 更新总红包金额
+                if (this.lab_hbCoin) {
+                    this.lab_hbCoin.string = Format.formatRedPacketCoin(currentCash);
+                }
+            })
+            .start();
+    }
+
+    /**
+     * 显示得分动画
+     */
+    public showScoreAnimation(position: Vec3, score: number, placementBaseScore: number): void {
+        if (!this.lab_addScore || !this.rootNode) return;
+
+        // 计算得分(未消除时的得分)
+        const calculatedScore = score * placementBaseScore;
+
+        // 复制得分Label
+        const scoreLabel = instantiate(this.lab_addScore.node);
+        scoreLabel.active = true;
+
+        // 设置文本和位置
+        const label = scoreLabel.getComponent(Label);
+        if (label) {
+            label.string = `+${calculatedScore}`;
+        }
+
+        // 添加到场景中
+        this.rootNode.addChild(scoreLabel);
+        scoreLabel.setWorldPosition(position);
+
+        const num = this.isDoubleSpeed ? this.doubleNum : 1;
+
+        // 创建动画效果
+        tween(scoreLabel)
+            .to(0.5 / num, {
+                position: new Vec3(scoreLabel.position.x, scoreLabel.position.y + 50, 0),
+                scale: new Vec3(1.2, 1.2, 1.2)
+            })
+            .to(0.3 / num, { opacity: 0 })
+            .call(() => {
+                scoreLabel.destroy();
+            })
+            .start();
+    }
+
+    /**
+     * 显示消除次数动画
+     */
+    public showEliminateCountAnimation(yPosition: number, comboCount: number): void {
+        if (!this.comboNode || !this.rootNode) return;
+
+        // 复制总次数Label
+        const comboNode = instantiate(this.comboNode);
+        comboNode.active = true;
+
+        // 设置文本
+        const label = comboNode.getChildByName("lab_combo");
+        if (label) {
+            const labelComponent = label.getComponent(Label);
+            if (labelComponent) {
+                labelComponent.string = `${comboCount}`;
+            }
+        }
+
+        // 添加到场景中
+        this.rootNode.addChild(comboNode);
+
+        // 计算网格区域的X轴中心位置,Y轴使用传入的消除行位置
+        const centerPos = new Vec3(0, yPosition, 0);
+
+        comboNode.setWorldPosition(centerPos);
+
+        // 创建动画效果
+        const num = this.isDoubleSpeed ? this.doubleNum : 1;
+        tween(comboNode)
+            .to(0.3 / num, {
+                scale: new Vec3(1.5, 1.5, 1.5),
+                opacity: 255
+            })
+            .delay(0.5 / num) // 停留更长时间
+            .to(0.4 / num, {
+                scale: new Vec3(1.2, 1.2, 1.2),
+                position: new Vec3(comboNode.position.x, comboNode.position.y + 50, 0),
+                opacity: 0
+            })
+            .call(() => {
+                comboNode.destroy();
+            })
+            .start();
+    }
+
+    /**
+     * 显示完整金币动画
+     */
+    public showCoinAnimation(lastPos: Vec3, score: number, onlyRedPacket: boolean = false): void {
+        if (!this.rootNode) return;
+
+        if (onlyRedPacket) {
+            // 添加回调函数,在红包动画完成后显示红包分数增加
+            this.createCoinFlyAnimation(
+                this.redPacketPrefab!,
+                lastPos,
+                this.lab_hbCoin!.node.getWorldPosition(),
+                5,
+                () => {
+                    // 显示红包分数增加动画 - 这里需要在主界面中调用显示逻辑
+                }
+            );
+            return;
+        } else {
+            this.createCoinFlyAnimation(
+                this.redPacketPrefab!,
+                lastPos,
+                this.lab_hbCoin!.node.getWorldPosition(),
+                5,
+                () => {
+                    // 显示红包分数增加动画 - 这里需要在主界面中调用显示逻辑
+                }
+            );
+            // 添加回调函数,在金币动画完成后显示微信分数增加
+            this.createCoinFlyAnimation(
+                this.coinPrefab!,
+                lastPos,
+                this.lab_wxCoin!.node.getWorldPosition(),
+                score,
+                () => {
+                    // 显示微信分数增加动画 - 这里需要在主界面中调用显示逻辑
+                }
+            );
+        }
+    }
+
+    public getIsDoubleSpeed(): boolean {
+        return this.isDoubleSpeed;
+    }
+
+    public getDoubleNum(): number {
+        return this.doubleNum;
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateAnimationManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "79f525a0-f174-4d8d-8524-644b49fde3ae",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 264 - 0
assets/script/game/view/eliminate/EliminateAutoPlayManager.ts

@@ -0,0 +1,264 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-19 18:01:14
+ * @Description: 消除游戏自动游戏管理器
+ */
+import { Node, Vec3, tween } from "cc";
+import { BrickData, GridConfigData, GridData, PlacementData } from "./EliminateTypes";
+import { EliminateGridManager } from "./EliminateGridManager";
+import { EliminateBrickManager } from "./EliminateBrickManager";
+
+export class EliminateAutoPlayManager {
+    private autoState: boolean = false; // 自动模式状态
+    private autoMoveTime: number = 0.4; // 自动移动时间
+    private autoPlaceInterval: number = 0.4; // 再次自动放置间隔时间
+    private isDoubleSpeed: boolean = false; // 是否开启二倍速
+    private doubleNum: number = 1; // 速度倍数
+
+    private gridManager: EliminateGridManager;
+    private brickManager: EliminateBrickManager;
+    private moveNode: Node;
+
+    constructor(
+        gridManager: EliminateGridManager,
+        brickManager: EliminateBrickManager,
+        moveNode: Node
+    ) {
+        this.gridManager = gridManager;
+        this.brickManager = brickManager;
+        this.moveNode = moveNode;
+    }
+
+    /**
+     * 设置自动状态
+     */
+    public setAutoState(state: boolean): void {
+        this.autoState = state;
+    }
+
+    /**
+     * 获取自动状态
+     */
+    public getAutoState(): boolean {
+        return this.autoState;
+    }
+
+    /**
+     * 设置双倍速度
+     */
+    public setDoubleSpeed(isDoubleSpeed: boolean): void {
+        this.isDoubleSpeed = isDoubleSpeed;
+        this.doubleNum = isDoubleSpeed ? 2 : 1;
+    }
+
+    /**
+     * 执行自动放置
+     */
+    public executeAutoPlace(callback: (success: boolean) => void): void {
+        if (!this.autoState) {
+            callback(false);
+            return;
+        }
+
+        const bestPlacement = this.findBestPlacement();
+        if (!bestPlacement) {
+            // 所有方块都无法放置,游戏结束
+            callback(false);
+            return;
+        }
+
+        // 执行放置
+        this.placeBrickAtPosition(bestPlacement, callback);
+    }
+
+    /**
+     * 寻找最佳放置位置
+     */
+    private findBestPlacement(): PlacementData | null {
+        const placements: PlacementData[] = [];
+        const bricksList = this.brickManager.getBricksList();
+
+        // 对每个方块计算所有可能的放置位置和分数
+        for (let brickIndex = 0; brickIndex < bricksList.length; brickIndex++) {
+            const brickData = bricksList[brickIndex];
+
+            // 检查不同旋转状态
+            let gridConfigs = [brickData.gridConfig];
+            let degrees = [brickData.deg];
+
+            // 如果可旋转,计算所有旋转状态
+            if (brickData.rotateFlag) {
+                for (let i = 1; i <= 3; i++) {
+                    const next = this.brickManager.nextGridRotate(
+                        i === 1 ? brickData.gridConfig : gridConfigs[i - 1],
+                        i === 1 ? brickData.deg : degrees[i - 1]
+                    );
+                    gridConfigs.push(next.gridConfig);
+                    degrees.push(next.deg);
+                }
+            }
+
+            // 遍历所有网格位置
+            for (let rowIndex = 0; rowIndex < this.gridManager.getRows(); rowIndex++) {
+                for (let columnIndex = 0; columnIndex < this.gridManager.getCols(); columnIndex++) {
+                    // 对每个旋转状态检查
+                    for (let rotateIndex = 0; rotateIndex < gridConfigs.length; rotateIndex++) {
+                        const currentGridConfig = gridConfigs[rotateIndex];
+                        const currentDeg = degrees[rotateIndex];
+
+                        // 检查是否可以放置
+                        if (this.gridManager.moveIf(rowIndex, columnIndex, currentGridConfig)) {
+                            // 复制网格并模拟放置
+                            const gridList = this.gridManager.copyGridList();
+                            currentGridConfig.forEach((gridConfigData) => {
+                                const r = gridConfigData.row + rowIndex;
+                                const c = gridConfigData.column + columnIndex;
+                                gridList[r][c].status = 1; // CellState.FILLED
+                                gridList[r][c].type = brickData.type;
+                            });
+
+                            // 检查是否可以消除,计算分数
+                            const elimination = this.gridManager.gridEliminateCheck(gridList);
+                            let score = 0;
+
+                            if (elimination.gridEliminateList.length > 0) {
+                                // 计算消除得分
+                                for (let i = 1; i <= elimination.eliminateRowNum; i++) {
+                                    score += this.gridManager.getCols() * i;
+                                }
+                                for (let i = 1; i <= elimination.eliminateColumnNum; i++) {
+                                    score += this.gridManager.getRows() * i;
+                                }
+                            }
+
+                            // 记录此放置选项
+                            placements.push({
+                                brickIndex,
+                                brickData,
+                                rowIndex,
+                                columnIndex,
+                                gridConfig: currentGridConfig,
+                                deg: currentDeg,
+                                score,
+                                canEliminate: elimination.gridEliminateList.length > 0
+                            });
+                        }
+                    }
+                }
+            }
+        }
+
+        // 按优先级排序:最高分 > 有分数 > 没有分数但可放置
+        placements.sort((a, b) => {
+            // 首先按分数排序
+            if (a.score !== b.score) {
+                return b.score - a.score;
+            }
+            // 其次按是否可消除排序
+            if (a.canEliminate !== b.canEliminate) {
+                return a.canEliminate ? -1 : 1;
+            }
+            // 最后按照方块优先级排序(底部的方块优先)
+            return a.brickIndex - b.brickIndex;
+        });
+
+        return placements.length > 0 ? placements[0] : null;
+    }
+
+    /**
+     * 在指定位置放置方块
+     */
+    private placeBrickAtPosition(placement: PlacementData, callback: (success: boolean) => void): void {
+        const brickData = placement.brickData;
+
+        // 从方块列表中移除该方块
+        this.brickManager.removeBrick(brickData);
+
+        // 应用旋转
+        if (brickData.deg !== placement.deg) {
+            brickData.gridConfig = placement.gridConfig;
+            brickData.deg = placement.deg;
+            if (brickData.brickNode) {
+                tween(brickData.brickNode).to(0.1, { angle: placement.deg }).start();
+            }
+        }
+
+        // 构建对应网格列表
+        const targetGrids: GridData[] = [];
+        const gridList = this.gridManager.getGridList();
+
+        placement.gridConfig.forEach((gridConfigData: GridConfigData) => {
+            const r = gridConfigData.row + placement.rowIndex;
+            const c = gridConfigData.column + placement.columnIndex;
+            targetGrids.push(gridList[r][c]);
+        });
+
+        // 计算移动位置(中点)
+        let centerPos = new Vec3(0, 0, 0);
+        let count = 0;
+
+        for (const grid of targetGrids) {
+            if (grid.gridNode) {
+                const pos = grid.gridNode.getWorldPosition();
+                centerPos.add(pos);
+                count++;
+            }
+        }
+
+        if (count > 0) {
+            centerPos.x /= count;
+            centerPos.y /= count;
+            centerPos.z /= count;
+        }
+
+        // 设置方块初始位置
+        const originPos = brickData.brickNode?.getWorldPosition() || new Vec3();
+        if (brickData.brickNode) {
+            brickData.brickNode.setParent(this.moveNode);
+            brickData.brickNode.setWorldPosition(originPos);
+        }
+
+        // 动画放置方块
+        const speedMultiplier = this.isDoubleSpeed ? this.doubleNum : 1;
+        if (brickData.brickNode) {
+            tween(brickData.brickNode)
+                .to(this.autoMoveTime / speedMultiplier, { worldPosition: centerPos })
+                .call(() => {
+                    // 更新格子状态
+                    targetGrids.forEach(gridData => {
+                        gridData.status = 1; // CellState.FILLED
+                        gridData.type = brickData.type;
+                        this.gridManager.generateGrid(gridData);
+                    });
+
+                    // 销毁方块节点
+                    if (brickData.brickNode) {
+                        brickData.brickNode.destroy();
+                    }
+
+                    // 添加新方块
+                    this.brickManager.addBrick(brickData.index);
+
+                    // 返回成功
+                    callback(true);
+                })
+                .start();
+        }
+    }
+
+    /**
+     * 获取双倍速状态
+     */
+    public getIsDoubleSpeed(): boolean {
+        return this.isDoubleSpeed;
+    }
+
+    /**
+     * 获取速度倍数
+     */
+    public getDoubleNum(): number {
+        return this.doubleNum;
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateAutoPlayManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "5a80bfe4-9b98-4fb0-8d8b-6fc32046539b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 479 - 0
assets/script/game/view/eliminate/EliminateBrickManager.ts

@@ -0,0 +1,479 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-20 10:00:00
+ * @Description: 消除游戏方块管理器
+ */
+import { EventTouch, JsonAsset, Node, Prefab, UITransform, Vec2, Vec3, tween, instantiate } from "cc";
+import { oops } from "db://oops-framework/core/Oops";
+import { BrickData, GridConfigData, GridData } from "./EliminateTypes";
+
+export class EliminateBrickManager {
+    private brickNode: Node | null = null; // 方块容器
+    private rotateNode: Node | null = null; // 旋转容器
+    private rotatePrefab: Node | null = null; // 旋转预制体
+    private moveNode: Node | null = null; // 移动容器
+    private itemSize: number = 76.25; // 格子大小
+    private itemPrefabs: Prefab[] = []; // 方块预制体列表
+    private rotateFaultTolerant = 10; // 旋转容错
+    private yOffset = 100; // Y轴偏移
+    private aniBrickRotate = 0; // 旋转动画时间
+
+    private bricksList: BrickData[] = []; // 所有可用方块
+    private brickConfig: { bricks?: any } = {}; // 方块配置
+
+    constructor(
+        brickNode: Node,
+        rotateNode: Node,
+        moveNode: Node,
+        itemPrefabs: Prefab[],
+        rotatePrefab: Node,
+        itemSize: number
+    ) {
+        this.brickNode = brickNode;
+        this.rotateNode = rotateNode;
+        this.moveNode = moveNode;
+        this.itemPrefabs = itemPrefabs;
+        this.rotatePrefab = rotatePrefab;
+        this.itemSize = itemSize;
+    }
+
+    /**
+     * 加载方块配置文件
+     */
+    public async loadConfig(): Promise<void> {
+        let json_name: string = "gui/eliminate/config/GridConfig";
+        return new Promise<void>((resolve, reject) => {
+            oops.res.load(json_name, JsonAsset, (err: Error | null, res: any) => {
+                if (res) {
+                    this.brickConfig = res.json;
+                    resolve();
+                } else {
+                    console.log("JSON数据加载失败,请检查文件");
+                    reject(err);
+                }
+            });
+        });
+    }
+
+    /**
+     * 初始化方块列表
+     */
+    public initBricks(count: number): void {
+        if (this.brickNode) {
+            this.brickNode.destroyAllChildren();
+        }
+
+        this.bricksList.length = 0;
+
+        for (let i = 1; i <= count; i++) {
+            this.addBrick(i);
+        }
+    }
+
+    /**
+     * 添加一个砖块
+     */
+    public addBrick(index: number, isGuideMode: boolean = false): BrickData {
+        // 随机选择砖块类型
+        const brickConfigs = Object.keys(this.brickConfig['bricks']);
+        let brickKey;
+
+        if (isGuideMode) {
+            brickKey = "Brick1";
+        } else {
+            const randomIndex = Math.floor(Math.random() * brickConfigs.length);
+            brickKey = brickConfigs[randomIndex];
+        }
+
+        // 随机选择颜色
+        const randomColorIndex = Math.floor(Math.random() * 3) + 1;
+
+        // 创建砖块
+        const brickNode = this.generateBrick(brickKey, randomColorIndex);
+        if (!brickNode || !this.brickNode) {
+            throw new Error("无法生成砖块");
+        }
+
+        this.brickNode.addChild(brickNode);
+
+        // 设置砖块位置
+        const brickConfig = this.brickConfig['bricks'][brickKey];
+        const rotateFlag = brickConfig.rotateFlag || false;
+
+        // 创建砖块数据对象
+        const brickData: BrickData = {
+            index: index,
+            brickKey: brickKey,
+            rotateFlag: rotateFlag,
+            gridConfig: JSON.parse(JSON.stringify(brickConfig.gridConfig)),
+            deg: 0,
+            brickNode: brickNode,
+            brickInitPos: new Vec3(this.calculateInitPosition(index)),
+            type: randomColorIndex,
+            rotateNode: null
+        };
+
+        // 设置初始位置
+        brickNode.setWorldPosition(brickData.brickInitPos);
+        brickNode.scale.set(0.8, 0.8, 0.8);
+
+        // 创建旋转节点
+        if (rotateFlag) {
+            this.createRotateNode(brickData);
+        }
+
+        // 添加到方块列表
+        this.bricksList.push(brickData);
+
+        return brickData;
+    }
+
+    /**
+     * 生成方块节点
+     */
+    public generateBrick(brickKey: string, colorIndex: number): Node {
+        const brickConfig = this.brickConfig['bricks'][brickKey];
+        let rowMin = 0;
+        let rowMax = 0;
+        let columnMin = 0;
+        let columnMax = 0;
+
+        // 计算方块尺寸
+        brickConfig['gridConfig'].forEach((gridConfigData: GridConfigData) => {
+            if (gridConfigData.row < rowMin) {
+                rowMin = gridConfigData.row;
+            }
+            else if (gridConfigData.row > rowMax) {
+                rowMax = gridConfigData.row;
+            }
+            if (gridConfigData.column < columnMin) {
+                columnMin = gridConfigData.column;
+            }
+            else if (gridConfigData.column > columnMax) {
+                columnMax = gridConfigData.column;
+            }
+        });
+
+        const rowNum = (rowMax - rowMin + 1);
+        const columnNum = (columnMax - columnMin + 1);
+
+        // 创建方块节点
+        const brickNode = new Node();
+        brickNode.name = brickKey;
+
+        // 设置方块大小
+        const transformCom: UITransform = brickNode.addComponent(UITransform);
+        transformCom.setContentSize(
+            this.itemSize * columnNum,
+            this.itemSize * rowNum
+        );
+        transformCom.setAnchorPoint(0.5, 0.5);
+
+        // 创建子格子
+        const gridPrefab = this.itemPrefabs[colorIndex];
+
+        brickConfig['gridConfig'].forEach((gridConfigData: GridConfigData) => {
+            const gridNode = new Node();
+            gridNode.name = 'grid';
+            brickNode.addChild(gridNode);
+
+            // 设置子格子大小
+            gridNode.addComponent(UITransform).setContentSize(this.itemSize, this.itemSize);
+
+            // 设置子格子位置
+            const x = this.itemSize * gridConfigData.column - this.itemSize * columnMin;
+            const y = this.itemSize * gridConfigData.row - this.itemSize * rowMin;
+            gridNode.setPosition(x, y);
+
+            // 创建格子显示节点
+            const node = instantiate(gridPrefab);
+            gridNode.addChild(node);
+
+            // 设置格子显示节点大小
+            const uiTransform = node.getComponent(UITransform);
+            if (uiTransform) {
+                uiTransform.setContentSize(
+                    this.itemSize,
+                    this.itemSize,
+                );
+            }
+
+            // 设置位置
+            node.setPosition(Vec3.ZERO);
+
+            // 确保事件冒泡
+            node.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
+                event.preventSwallow = true;
+            }, this);
+            node.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => {
+                event.preventSwallow = true;
+            }, this);
+            node.on(Node.EventType.TOUCH_END, (event: EventTouch) => {
+                event.preventSwallow = true;
+            }, this);
+        });
+
+        return brickNode;
+    }
+
+    /**
+     * 创建引导砖块
+     */
+    public createGuideBrick(
+        gridConfig: GridConfigData[],
+        brickKey: string,
+        colorIndex: number,
+        index: number,
+        rotateFlag = false
+    ): BrickData {
+        const brickData = {
+            index,
+            brickKey: brickKey,
+            rotateFlag,
+            gridConfig,
+            deg: 0,
+            brickNode: new Node(),
+            gridColorKey: "colorKey",
+            brickInitPos: new Vec3(),
+            type: colorIndex,
+            rotateNode: new Node(),
+        };
+
+        const node = this.generateBrick(brickKey, colorIndex);
+        if (this.brickNode) {
+            this.brickNode.addChild(node);
+        }
+
+        const transform = this.brickNode?.getComponent(UITransform);
+        if (transform) {
+            const midX = transform.width / 2;
+            node.setPosition(0, 0);
+            brickData.brickNode = node;
+            brickData.brickInitPos = node.getWorldPosition();
+            this.bricksList.push(brickData);
+            this.brickAddEvent(brickData, () => { });
+        }
+
+        if (brickData.rotateFlag && this.rotatePrefab && this.rotateNode) {
+            brickData.rotateNode = instantiate(this.rotatePrefab);
+            this.rotateNode.addChild(brickData.rotateNode);
+            //先隐藏
+            brickData.rotateNode.active = false;
+            brickData.rotateNode.setWorldPosition(this.brickNode!.getWorldPosition());
+        }
+
+        return brickData;
+    }
+
+    /**
+     * 给砖块添加事件
+     */
+    public brickAddEvent(brickData: BrickData, onDragHandler: (brickData: BrickData, position: Vec3, startPos: Vec2, delta: Vec2) => void): void {
+        const brickNode = brickData.brickNode;
+        if (!brickNode) {
+            console.error("brickNode为空,无法添加事件");
+            return;
+        }
+
+        // 记录触摸开始位置
+        let touchStartPos = new Vec2();
+
+        // 触摸开始事件
+        brickNode.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
+            // 记录触摸起始位置
+            touchStartPos.set(event.getUILocation());
+        }, this);
+
+        // 触摸移动事件
+        brickNode.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => {
+            const currentPos = event.getUILocation();
+            const delta = new Vec2(
+                currentPos.x - touchStartPos.x,
+                currentPos.y - touchStartPos.y
+            );
+
+            // 如果移动距离太小,忽略
+            if (delta.length() <= this.rotateFaultTolerant) {
+                return;
+            }
+
+            // 调用拖动处理回调
+            onDragHandler(brickData, event.getUILocation().toVec3().add3f(0, this.yOffset, 0), touchStartPos, delta);
+        }, this);
+    }
+
+    /**
+     * 旋转方块
+     */
+    public brickGridRotate(brickData: BrickData): Promise<boolean> {
+        return new Promise((resolve) => {
+            const next = this.nextGridRotate(brickData.gridConfig, brickData.deg);
+            brickData.deg = next.deg;
+            brickData.gridConfig = next.gridConfig;
+
+            if (brickData.brickNode) {
+                tween(brickData.brickNode)
+                    .to(this.aniBrickRotate, { angle: next.deg })
+                    .call(() => {
+                        resolve(true);
+                    })
+                    .start();
+            } else {
+                resolve(true);
+            }
+        });
+    }
+
+    /**
+     * 计算下一个旋转状态
+     */
+    public nextGridRotate(gridConfig: GridConfigData[], deg: number): { gridConfig: GridConfigData[], deg: number } {
+        const newGridConfig: GridConfigData[] = [];
+        // 顺时针旋转
+        let newDeg = deg - 90;
+
+        gridConfig.forEach((gridConfigData) => {
+            // 例如(1,2) => (-2,1),可以画图分析
+            newGridConfig.push({
+                row: -gridConfigData.column,
+                column: gridConfigData.row
+            });
+        });
+
+        return { gridConfig: newGridConfig, deg: newDeg };
+    }
+
+    /**
+     * 获取所有方块
+     */
+    public getBricksList(): BrickData[] {
+        return this.bricksList;
+    }
+
+    /**
+     * 设置所有方块
+     */
+    public setBricksList(bricks: BrickData[]): void {
+        this.bricksList = bricks;
+    }
+
+    /**
+     * 移除方块
+     */
+    public removeBrick(brickData: BrickData): void {
+        const index = this.bricksList.findIndex(item => item === brickData);
+        if (index > -1) {
+            this.bricksList.splice(index, 1);
+        }
+    }
+
+    /**
+     * 清理所有方块
+     */
+    public clearAllBricks(): void {
+        if (this.brickNode) {
+            this.brickNode.destroyAllChildren();
+        }
+        this.bricksList = [];
+    }
+
+    /**
+     * 清理旋转节点
+     */
+    public clearAllRotateNodes(): void {
+        if (this.rotateNode) {
+            this.rotateNode.destroyAllChildren();
+        }
+    }
+
+    /**
+     * 给砖块添加拖动结束事件
+     */
+    public brickEndDrag(
+        brickData: BrickData,
+        onEndDragHandler: (brickData: BrickData, canPlace: boolean) => void
+    ): void {
+        const brickNode = brickData.brickNode;
+        if (!brickNode) {
+            console.error("brickNode为空,无法添加拖动结束事件");
+            return;
+        }
+
+        // 添加触摸结束事件
+        const touchEndHandler = (event: EventTouch) => {
+            // 获取当前触摸位置
+            const currentPos = event.getUILocation();
+            // 调用处理函数
+            onEndDragHandler(brickData, true);
+        };
+
+        brickNode.on(Node.EventType.TOUCH_END, touchEndHandler, this);
+        brickNode.on(Node.EventType.TOUCH_CANCEL, touchEndHandler, this);
+    }
+
+    /**
+     * 给砖块添加拖动开始事件
+     */
+    public brickStartDrag(
+        brickData: BrickData,
+        onStartDragHandler: (brickData: BrickData, startPos: Vec3) => void
+    ): void {
+        const brickNode = brickData.brickNode;
+        if (!brickNode) {
+            console.error("brickNode为空,无法添加拖动开始事件");
+            return;
+        }
+
+        // 添加触摸开始事件
+        brickNode.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
+            // 记录触摸起始位置
+            const startPos = brickNode.getWorldPosition().clone();
+            // 调用处理函数
+            onStartDragHandler(brickData, startPos);
+        }, this);
+    }
+
+    /**
+     * 计算初始位置
+     */
+    private calculateInitPosition(index: number): Vec3 {
+        // 计算位置
+        let offset = 220;
+        const brickNum = this.bricksList.length + 1; // +1 因为当前砖块还未添加到列表
+
+        if (brickNum % 2 === 1) {
+            const middleNum = Math.floor(brickNum / 2) + 1;
+            if (index < middleNum) {
+                offset = -offset;
+            }
+            else if (index === middleNum) {
+                offset = 0;
+            }
+        } else {
+            const middleNum = brickNum / 2;
+            if (index <= middleNum) {
+                offset = -offset;
+            }
+        }
+
+        return new Vec3(offset, 0, 0);
+    }
+
+    /**
+     * 创建旋转节点
+     */
+    private createRotateNode(brickData: BrickData): void {
+        if (!this.rotatePrefab || !this.rotateNode || !brickData.brickNode) {
+            return;
+        }
+
+        brickData.rotateNode = instantiate(this.rotatePrefab);
+        this.rotateNode.addChild(brickData.rotateNode);
+
+        // 先隐藏
+        brickData.rotateNode.active = false;
+        brickData.rotateNode.setWorldPosition(brickData.brickNode.getWorldPosition());
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateBrickManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "b1d6ef2c-d270-4693-bb0b-3b49f85cfe75",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 358 - 0
assets/script/game/view/eliminate/EliminateGridManager.ts

@@ -0,0 +1,358 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-20 10:00:00
+ * @Description: 消除游戏网格管理器
+ */
+import { Color, Node, Prefab, Sprite, UITransform, Vec3, instantiate } from "cc";
+import { CellState, GridConfigData, GridData, EliminateCheckResult } from "./EliminateTypes";
+
+export class EliminateGridManager {
+    private rows: number = 8;       // 行数
+    private cols: number = 8;       // 列数
+    private itemSize: number = 76.25;  // 格子大小
+
+    // 颜色定义
+    private notUseColor = new Color(255, 255, 255, 255);
+    private usableColor = new Color(0, 255, 0, 100);
+    private unavailableColor = new Color(255, 0, 0, 100);
+
+    private itemPrefabs: Prefab[] = [];
+    private gridNode: Node | null = null;
+
+    // 网格列表
+    private gridList: GridData[][] = [];
+    // 需要恢复颜色的网格列表
+    private gridColorList: GridData[] = [];
+
+    constructor(gridNode: Node, itemPrefabs: Prefab[], rows: number, cols: number, itemSize: number) {
+        this.gridNode = gridNode;
+        this.itemPrefabs = itemPrefabs;
+        this.rows = rows;
+        this.cols = cols;
+        this.itemSize = itemSize;
+    }
+
+    /**
+     * 初始化网格
+     */
+    public initGrid(): void {
+        this.clearExistingGrids();
+        this.createGridMatrix();
+    }
+
+    /**
+     * 清理现有的网格数据
+     */
+    private clearExistingGrids(): void {
+        this.gridList = [];
+        if (this.gridNode) {
+            this.gridNode.destroyAllChildren();
+        }
+    }
+
+    /**
+     * 创建网格矩阵
+     */
+    private createGridMatrix(): void {
+        for (let rowIndex = 0; rowIndex < this.rows; rowIndex++) {
+            const currentRow: GridData[] = [];
+            this.gridList.push(currentRow);
+            for (let columnIndex = 0; columnIndex < this.cols; columnIndex++) {
+                const gridData = this.createGridData(rowIndex, columnIndex);
+                currentRow.push(gridData);
+                this.createGridNode(gridData);
+            }
+        }
+
+        // 初始化格子状态
+        for (let rowIndex = 0; rowIndex < this.rows; rowIndex++) {
+            for (let columnIndex = 0; columnIndex < this.cols; columnIndex++) {
+                this.gridList[rowIndex][columnIndex].status = CellState.EMPTY;
+                this.generateGrid(this.gridList[rowIndex][columnIndex]);
+            }
+        }
+    }
+
+    /**
+     * 创建格子数据
+     */
+    private createGridData(row: number, column: number): GridData {
+        return {
+            name: `Grid-${row}-${column}`,
+            status: CellState.EMPTY,
+            gridNode: null,
+            row: row,
+            col: column,
+            type: 0
+        };
+    }
+
+    /**
+     * 创建网格节点
+     */
+    private createGridNode(gridData: GridData): void {
+        const gridNode = new Node(gridData.name);
+        if (this.gridNode) {
+            this.gridNode.addChild(gridNode);
+        }
+        gridData.gridNode = gridNode;
+        // 设置网格大小
+        gridNode.addComponent(UITransform).setContentSize(this.itemSize, this.itemSize);
+    }
+
+    /**
+     * 生成或更新网格
+     */
+    public generateGrid(gridData: GridData): void {
+        if (!gridData || !gridData.gridNode) {
+            console.warn('无效的网格数据');
+            return;
+        }
+        // 清理现有子节点
+        this.clearGridChildren(gridData.gridNode);
+
+        // 获取对应的预制体
+        const prefab = this.getGridPrefab(gridData);
+        if (!prefab) {
+            console.warn('无法获取网格预制体');
+            return;
+        }
+        // 创建并配置新节点
+        const node = this.createNewGridNode(prefab, gridData);
+        // 设置节点属性
+        this.setupGridNode(node, gridData);
+    }
+
+    /**
+     * 获取对应状态的预制体
+     */
+    private getGridPrefab(gridData: GridData): Prefab {
+        if (gridData.status === CellState.EMPTY) {
+            if (this.itemPrefabs[0]) {
+                return this.itemPrefabs[0];
+            } else {
+                throw new Error('Grid prefab is not loaded');
+            }
+        }
+
+        if (gridData.status === CellState.FILLED && gridData.type) {
+            const type = gridData.type;
+            return this.itemPrefabs[type];
+        }
+        throw new Error('Invalid grid status or missing gridColorKey');
+    }
+
+    /**
+     * 创建网格节点
+     */
+    private createNewGridNode(prefab: Prefab, gridData: GridData): Node {
+        const node = instantiate(prefab);
+        if (gridData && gridData.gridNode) {
+            gridData.gridNode.addChild(node);
+            return node;
+        }
+        return node;
+    }
+
+    /**
+     * 设置网格节点的属性
+     */
+    private setupGridNode(node: Node, gridData: GridData): void {
+        // 设置未使用状态的颜色
+        if (gridData.status === CellState.EMPTY) {
+            const sprite = node.getComponent(Sprite);
+            if (sprite) {
+                sprite.color = this.notUseColor;
+            }
+        }
+        // 设置节点大小
+        const transform = node.getComponent(UITransform);
+        if (transform) {
+            transform.setContentSize(
+                this.itemSize,
+                this.itemSize
+            );
+        }
+        // 设置位置
+        node.setPosition(Vec3.ZERO);
+    }
+
+    /**
+     * 清理网格的子节点
+     */
+    private clearGridChildren(gridNode: Node): void {
+        const children = gridNode.children.slice(); // 创建副本避免遍历时修改问题
+        children.forEach(node => node.destroy());
+    }
+
+    /**
+     * 检查格子是否可放置
+     */
+    public moveIf(row: number, column: number, gridConfig: GridConfigData[]): boolean {
+        let moveFlag = true;
+        for (let i = 0; i < gridConfig.length; i++) {
+            const gridConfigData = gridConfig[i];
+            const gridI = row + gridConfigData.row;
+            const gridJ = column + gridConfigData.column;
+            // 边界判断
+            if (
+                gridI < 0 ||
+                gridI > this.rows - 1 ||
+                gridJ < 0 ||
+                gridJ > this.cols - 1
+            ) {
+                moveFlag = false;
+                break;
+            }
+            // 已用
+            else if (this.gridList[gridI][gridJ].status === CellState.FILLED) {
+                moveFlag = false;
+                break;
+            }
+        }
+        return moveFlag;
+    }
+
+    /**
+     * 消除检查
+     */
+    public gridEliminateCheck(gridList: GridData[][]): EliminateCheckResult {
+        const gridEliminateList: GridData[] = [];
+        let eliminateRowNum = 0;
+        let eliminateColumnNum = 0;
+
+        // 行检查
+        for (let rowIndex = 0; rowIndex < this.rows; rowIndex++) {
+            const rowData = gridList[rowIndex];
+            if (rowData.every(gridData => gridData.status === CellState.FILLED)) {
+                rowData.forEach(gridData => {
+                    if (gridEliminateList.findIndex(data => data === gridData) < 0) {
+                        gridEliminateList.push(gridData);
+                    }
+                });
+                eliminateRowNum += 1;
+            }
+        }
+
+        // 列检查
+        for (let columnIndex = 0; columnIndex < this.cols; columnIndex++) {
+            if (gridList.every(rowData => rowData[columnIndex].status === CellState.FILLED)) {
+                gridList.forEach(rowData => {
+                    const gridData = rowData[columnIndex];
+                    if (gridEliminateList.findIndex(data => data === gridData) < 0) {
+                        gridEliminateList.push(gridData);
+                    }
+                });
+                eliminateColumnNum += 1;
+            }
+        }
+
+        return {
+            gridEliminateList,
+            eliminateRowNum,
+            eliminateColumnNum,
+        };
+    }
+
+    /**
+     * 复制整体网格
+     */
+    public copyGridList(): GridData[][] {
+        const gridList: GridData[][] = [];
+        for (let rowIndex = 0; rowIndex < this.rows; rowIndex++) {
+            gridList.push([]);
+            for (let columnIndex = 0; columnIndex < this.cols; columnIndex++) {
+                const gridData = this.gridList[rowIndex][columnIndex];
+                gridList[rowIndex].push({
+                    name: gridData.name,
+                    status: gridData.status,
+                    gridNode: null,
+                    row: gridData.row,
+                    col: gridData.col,
+                    type: gridData.type,
+                });
+            }
+        }
+        return gridList;
+    }
+
+    /**
+     * 格子颜色恢复
+     */
+    public gridColorRecovery(): void {
+        while (this.gridColorList.length > 0) {
+            const gridData = this.gridColorList.pop();
+            if (gridData) {
+                if (gridData.status === CellState.EMPTY) {
+                    if (gridData.gridNode && gridData.gridNode.children[0]) {
+                        const sprite = gridData.gridNode.children[0].getComponent(Sprite);
+                        if (sprite) {
+                            sprite.color = this.notUseColor;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 更新网格状态
+     */
+    public updateGridHighlight(grid: GridData, canPlace: boolean): void {
+        if (grid.status === CellState.EMPTY) {
+            if (grid.gridNode && grid.gridNode.children[0]) {
+                const sprite = grid.gridNode.children[0].getComponent(Sprite);
+                if (sprite) {
+                    sprite.color = canPlace ? this.usableColor : this.unavailableColor;
+                }
+            }
+            // 用于后续恢复颜色
+            this.gridColorList.push(grid);
+        }
+    }
+
+    /**
+     * 清除所有引导格子
+     */
+    public clearAllGuideGrids(): void {
+        for (let row = 0; row < this.rows; row++) {
+            for (let col = 0; col < this.cols; col++) {
+                const grid = this.gridList[row][col];
+                grid.status = CellState.EMPTY;
+                grid.type = 0;
+                this.generateGrid(grid);
+            }
+        }
+    }
+
+    // Getters
+    public getGridList(): GridData[][] {
+        return this.gridList;
+    }
+
+    public getRows(): number {
+        return this.rows;
+    }
+
+    public getCols(): number {
+        return this.cols;
+    }
+
+    public getItemSize(): number {
+        return this.itemSize;
+    }
+
+    public getColorLists(): { notUse: Color, usable: Color, unavailable: Color } {
+        return {
+            notUse: this.notUseColor,
+            usable: this.usableColor,
+            unavailable: this.unavailableColor
+        };
+    }
+
+    public addToColorList(grid: GridData): void {
+        this.gridColorList.push(grid);
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateGridManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "ce28289c-f390-4cdc-8fd1-7c6758403a5c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 255 - 0
assets/script/game/view/eliminate/EliminateGuideManager.ts

@@ -0,0 +1,255 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-20 10:00:00
+ * @Description: 消除游戏引导管理器
+ */
+import { Label, Node } from "cc";
+import { BrickData, CellState, GridConfigData } from "./EliminateTypes";
+import { EliminateGridManager } from "./EliminateGridManager";
+import { EliminateBrickManager } from "./EliminateBrickManager";
+
+export class EliminateGuideManager {
+    private isGuideMode: boolean = false;
+    private guideStep: number = 0;
+    private guideNode: Node | null = null;
+
+    private gridManager: EliminateGridManager;
+    private brickManager: EliminateBrickManager;
+
+    // 引导提示文本
+    private guideTips: string[] = [
+        "拖动方块,填满整行可以进行消除",
+        "当行与列被砖块同时填满,砖块会被消除",
+        "点击方块可以旋转90°,不限旋转次数哦",
+        "放置&消除方块得分达成目标获得金砖"
+    ];
+
+    constructor(guideNode: Node, gridManager: EliminateGridManager, brickManager: EliminateBrickManager) {
+        this.guideNode = guideNode;
+        this.gridManager = gridManager;
+        this.brickManager = brickManager;
+    }
+
+    /**
+     * 开始引导模式
+     */
+    public startGuideMode(): void {
+        this.isGuideMode = true;
+        this.guideStep = 1;
+
+        if (this.guideNode) {
+            this.guideNode.active = true;
+        }
+
+        this.setupGuideStep(this.guideStep);
+    }
+
+    /**
+     * 设置引导步骤
+     */
+    public setupGuideStep(step: number): void {
+        this.gridManager.clearAllGuideGrids();
+        this.guideStep = step;
+
+        // 更新引导提示文本
+        const tips_node = this.guideNode?.getChildByPath("tips/lab_tips");
+        if (tips_node) {
+            const tips = tips_node.getComponent(Label);
+            if (tips) {
+                tips.string = this.guideTips[step - 1];
+            }
+        }
+
+        // 根据不同步骤创建不同的引导场景
+        switch (step) {
+            case 1:
+                this.setupStep1();
+                break;
+
+            case 2:
+                this.setupStep2();
+                break;
+
+            case 3:
+                this.setupStep3();
+                break;
+
+            case 4:
+                this.setupStep4();
+                break;
+        }
+    }
+
+    /**
+     * 第1步:引导玩家消除一行
+     */
+    private setupStep1(): void {
+        const cols = this.gridManager.getCols();
+        const emptyIndex = Math.floor(cols / 2);
+
+        // 创建一行只缺一个格子的状态
+        for (let c = 0; c < cols; c++) {
+            if (c !== emptyIndex) {
+                const gridList = this.gridManager.getGridList();
+                const g = gridList[0][c];
+                g.status = CellState.FILLED;
+                g.type = 1;
+                this.gridManager.generateGrid(g);
+            }
+        }
+
+        // 创建一个简单的单格子方块供玩家放置
+        this.brickManager.createGuideBrick(
+            [{ row: 0, column: 0 }],
+            "Brick1",
+            1,
+            1
+        );
+    }
+
+    /**
+     * 第2步:引导玩家消除一列
+     */
+    private setupStep2(): void {
+        const rows = this.gridManager.getRows();
+        const emptyRow = rows - 1;
+
+        // 创建一列只缺一个格子的状态
+        for (let r = 0; r < rows; r++) {
+            if (r !== emptyRow) {
+                const gridList = this.gridManager.getGridList();
+                const g = gridList[r][0];
+                g.status = CellState.FILLED;
+                g.type = 1;
+                this.gridManager.generateGrid(g);
+            }
+        }
+
+        // 创建一个简单的单格子方块供玩家放置
+        this.brickManager.createGuideBrick(
+            [{ row: 0, column: 0 }],
+            "Brick1",
+            1,
+            1
+        );
+    }
+
+    /**
+     * 第3步:引导玩家旋转方块
+     */
+    private setupStep3(): void {
+        // 填满前两列,除去特定位置,制造一个L型缺口
+        for (let r = 0; r < this.gridManager.getRows(); r++) {
+            for (let c = 0; c < 2; c++) {
+                if (r === 2 && c === 0) continue; // 留一个空位用于放置旋转后的L型砖块
+                if (r === 1 && c === 0) continue; // 留一个空位用于放置旋转后的L型砖块
+                if (r === 3 && c === 0) continue; // 留一个空位用于放置旋转后的L型砖块
+                if (r === 2 && c === 1) continue; // 留一个空位用于放置旋转后的L型砖块
+                if (r === 1 && c === 1) continue; // 留一个空位用于放置旋转后的L型砖块
+                if (r === 3 && c === 1) continue; // 留一个空位用于放置旋转后的L型砖块
+                const gridList = this.gridManager.getGridList();
+                const g = gridList[r][c];
+                g.status = CellState.FILLED;
+                g.type = 1;
+                this.gridManager.generateGrid(g);
+            }
+        }
+
+        // 创建一个L型方块,引导玩家旋转后放置
+        this.brickManager.createGuideBrick(
+            [
+                { row: 0, column: 0 },
+                { row: 0, column: 1 },
+                { row: 0, column: 2 },
+                { row: 1, column: 0 },
+                { row: 1, column: 1 },
+                { row: 1, column: 2 }
+            ],
+            "BrickII",
+            1,
+            1,
+            true
+        );
+    }
+
+    /**
+     * 第4步:引导玩家同时消除行和列
+     */
+    private setupStep4(): void {
+        const rows = this.gridManager.getRows();
+        const cols = this.gridManager.getCols();
+        const centerRow = Math.floor(rows / 2);
+        const centerCol = Math.floor(cols / 2);
+
+        // 遍历整个网格
+        for (let r = 0; r < rows; r++) {
+            for (let c = 0; c < cols; c++) {
+                const inCenter =
+                    r >= centerRow && r <= centerRow + 1 &&
+                    c >= centerCol && c <= centerCol + 1;
+
+                const isCross =
+                    r === centerRow || r === centerRow + 1 || // 中间两行
+                    c === centerCol || c === centerCol + 1;   // 中间两列
+
+                if (isCross && !inCenter) {
+                    const gridList = this.gridManager.getGridList();
+                    const g = gridList[r][c];
+                    g.status = CellState.FILLED;
+                    g.type = 1;
+                    this.gridManager.generateGrid(g);
+                }
+            }
+        }
+
+        // 创建一个正方形方块,引导玩家放在中间空位
+        this.brickManager.createGuideBrick(
+            [
+                { row: 0, column: 0 },
+                { row: 0, column: 1 },
+                { row: 1, column: 0 },
+                { row: 1, column: 1 }
+            ],
+            "BrickO",
+            1,
+            1
+        );
+    }
+
+    /**
+     * 结束引导模式
+     */
+    public endGuideMode(): void {
+        this.isGuideMode = false;
+        if (this.guideNode) {
+            this.guideNode.active = false;
+        }
+    }
+
+    /**
+     * 检查是否需要进入下一步引导
+     */
+    public checkNextStep(): void {
+        if (this.isGuideMode && this.guideStep < 4) {
+            this.setupGuideStep(this.guideStep + 1);
+        } else if (this.isGuideMode && this.guideStep >= 4) {
+            this.endGuideMode();
+        }
+    }
+
+    /**
+     * 获取当前是否为引导模式
+     */
+    public getIsGuideMode(): boolean {
+        return this.isGuideMode;
+    }
+
+    /**
+     * 获取当前引导步骤
+     */
+    public getGuideStep(): number {
+        return this.guideStep;
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateGuideManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "e76f7d79-b431-4f23-bbf5-3fb61421709c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 78 - 0
assets/script/game/view/eliminate/EliminateTypes.ts

@@ -0,0 +1,78 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-20 10:00:00
+ * @Description: 消除游戏类型定义
+ */
+import { Node, Vec3 } from "cc";
+
+// 游戏状态枚举
+export enum GameState {
+    READY,      // 准备中
+    PLAYING,    // 游戏中
+    PAUSED,     // 暂停 --进其他界面,广告暂停
+    GAME_OVER,  // 游戏结束
+    GAME_PASS   // 游戏通关
+}
+
+// 格子状态枚举
+export enum CellState {
+    EMPTY,      // 空格子
+    FILLED,     // 有方块
+    HIGHLIGHTED // 高亮(可放置)
+}
+
+// 网格数据接口
+export interface GridData {
+    name: string,       // 名称
+    status: CellState,  // 状态
+    gridNode: Node | null,      // 网格节点
+    row: number,        // 行
+    col: number,        // 列
+    type: number,       // 类型--gridColorKey
+}
+
+// 网格配置接口
+export interface GridConfigData {
+    row: number,
+    column: number,
+}
+
+// 编辑数据接口
+export interface EditingData {
+    brickData: BrickData | null,
+    gridList: GridData[],
+}
+
+// 砖块数据接口
+export interface BrickData {
+    index: number,
+    brickKey: string | null,
+    rotateFlag: boolean,
+    gridConfig: GridConfigData[],
+    deg: number,
+    brickNode: Node | null,
+    brickInitPos: Vec3, // 方块初始位置
+    type: number,   // 方块类型--gridColorKey
+    rotateNode: Node | null,
+}
+
+// 砖块放置位置接口
+export interface PlacementData {
+    brickIndex: number,
+    brickData: BrickData,
+    rowIndex: number,
+    columnIndex: number,
+    gridConfig: GridConfigData[],
+    deg: number,
+    score: number,
+    canEliminate: boolean
+}
+
+// 消除检查结果接口
+export interface EliminateCheckResult {
+    gridEliminateList: GridData[],
+    eliminateRowNum: number,
+    eliminateColumnNum: number,
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateTypes.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "b9a1ccab-cbf2-4105-96ca-db4f87a13801",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 339 - 0
assets/script/game/view/eliminate/EliminateUIManager.ts

@@ -0,0 +1,339 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-04-20 10:00:00
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-19 18:23:18
+ * @Description: 消除游戏UI管理器
+ */
+import { Button, Label, Node } from "cc";
+import { LabelChange } from "db://oops-framework/libs/gui/label/LabelChange";
+import { oops } from "db://oops-framework/core/Oops";
+import { UIID } from "../../common/config/GameUIConfig";
+import { DeviceUtil } from "db://oops-framework/core/utils/DeviceUtil";
+import { ServerHandler } from "../../common/manager/ServerHandler";
+import { Format } from "../../utils/Format";
+import { smc } from "../../common/SingletonModuleComp";
+
+export class EliminateUIManager {
+    // UI元素
+    private lab_wxCoin: LabelChange | null = null;
+    private lab_hbCoin: LabelChange | null = null;
+    private lab_score: Label | null = null;
+    private lab_taget: Label | null = null;
+    private lab_total: Label | null = null;
+    private lab_goldNum: Label | null = null;
+    private lab_doubleTime: Label | null = null;
+    private autoBtn: Button | null = null;
+
+    // 游戏数据
+    private score: number = 0;
+    private money: number = 0;
+    private cash: number = 0;
+    private targetScore: number = 0;
+    private doubleSpeedTime: number = 0;
+    private eliminateTotal: number = 0;
+    private autoState: boolean = false;
+
+    // 福利弹窗类型
+    private popupType: string = "";
+
+    constructor(
+        lab_wxCoin: LabelChange,
+        lab_hbCoin: LabelChange,
+        lab_score: Label,
+        lab_taget: Label,
+        lab_total: Label,
+        lab_goldNum: Label,
+        lab_doubleTime: Label,
+        autoBtn: Button
+    ) {
+        this.lab_wxCoin = lab_wxCoin;
+        this.lab_hbCoin = lab_hbCoin;
+        this.lab_score = lab_score;
+        this.lab_taget = lab_taget;
+        this.lab_total = lab_total;
+        this.lab_goldNum = lab_goldNum;
+        this.lab_doubleTime = lab_doubleTime;
+        this.autoBtn = autoBtn;
+    }
+
+    /**
+     * 初始化数据
+     */
+    public initData(): void {
+        this.score = 0;
+        this.targetScore = 0;
+        this.money = 0;
+        this.cash = 0;
+        this.autoState = false;
+        this.eliminateTotal = 0;
+    }
+
+    /**
+     * 设置数据
+     */
+    public setData(): void {
+        this.score = smc.game.GameModel.curScore;
+        this.money = smc.account.AccountModel.wxCoin;
+        this.cash = smc.account.AccountModel.hbCoin;
+        this.targetScore = smc.game.GameModel.targetScore;
+        this.popupType = smc.game.GameModel.popupType;
+
+        this.updateLabels();
+    }
+
+    /**
+     * 更新标签显示
+     */
+    private updateLabels(): void {
+        if (this.lab_score) {
+            this.lab_score.string = this.score.toString();
+        }
+        if (this.lab_wxCoin) {
+            this.lab_wxCoin.string = Format.formatWxCoin(this.money);
+        }
+        if (this.lab_hbCoin) {
+            this.lab_hbCoin.string = Format.formatRedPacketCoin(this.cash);
+        }
+        if (this.lab_taget) {
+            this.lab_taget.string = this.targetScore.toString();
+        }
+        if (this.lab_goldNum) {
+            this.lab_goldNum.string = smc.account.AccountModel.goldCoin.toString();
+        }
+    }
+
+    /**
+     * 更新游戏分数
+     */
+    public updateGameScore(newScore: number): void {
+        this.score = newScore;
+        if (this.lab_score) {
+            this.lab_score.string = this.score.toString();
+        }
+
+        if (this.score >= this.targetScore) {
+            // 弹出通关奖励界面
+            if (DeviceUtil.isNative && DeviceUtil.isAndroid) {
+                ServerHandler.inst.getGameAwardInfo();
+            } else {
+                console.log("打开通关奖励");
+                oops.gui.open(UIID.GamePass);
+            }
+        }
+    }
+
+    /**
+     * 更新消除总数
+     */
+    public updateEliminateTotal(count: number): void {
+        this.eliminateTotal += count;
+        console.log("消除总数", this.eliminateTotal);
+
+        if (this.lab_total) {
+            this.lab_total.string = this.eliminateTotal.toString();
+        }
+    }
+
+    /**
+     * 更新金币值
+     */
+    public updateCoin(): void {
+        this.money = smc.account.AccountModel.wxCoin;
+        this.cash = smc.account.AccountModel.hbCoin;
+
+        if (this.lab_wxCoin) {
+            this.lab_wxCoin.string = Format.formatWxCoin(this.money);
+        }
+        if (this.lab_hbCoin) {
+            this.lab_hbCoin.string = Format.formatRedPacketCoin(this.cash);
+        }
+    }
+
+    /**
+     * 初始化按钮状态
+     */
+    public initButtonState(state: boolean): void {
+        if (this.autoBtn) {
+            const on = this.autoBtn.node.getChildByName("on");
+            if (on) {
+                on.active = state;
+            }
+
+            const off = this.autoBtn.node.getChildByName("off");
+            if (off) {
+                off.active = !state;
+            }
+
+            this.autoState = state;
+        }
+    }
+
+    /**
+     * 打开特定视图
+     */
+    public openView(viewId: string): void {
+        switch (viewId) {
+            case "openRedBagView":
+                oops.gui.open(UIID.RedPacketWithdraw);
+                break;
+
+            case "openPassView":
+                oops.gui.open(UIID.GamePass);
+                break;
+
+            case "openDoubleSurprise":
+                oops.gui.open(UIID.DoubleRewards);
+                break;
+
+            case "openRebateView":
+                oops.gui.open(UIID.CashRebate);
+                break;
+
+            case "openCashWithdrawalView":
+                oops.gui.open(UIID.WithSussce);  // 提现成功
+                break;
+
+            case "openWechatWithdrawalView":
+                oops.gui.open(UIID.WechatWithdraw);  // 微信提现页
+                break;
+
+            case "openDoubleSpeedView":
+                oops.gui.open(UIID.DoubleSpeed);
+                break;
+
+            case "openRecordView":
+                oops.gui.open(UIID.WithdrawRecord);
+                break;
+        }
+    }
+
+    /**
+     * 更新福利点
+     */
+    public updateWelfarePoint(): void {
+        switch (this.popupType) {
+            case "weal_1":
+                oops.gui.open(UIID.WarmReminder);
+                ServerHandler.inst.GetGuideInfo();
+                break;
+
+            case "weal_2":
+                oops.gui.open(UIID.WelfareTwo);
+                ServerHandler.inst.GetGuideInfo();
+                break;
+
+            case "weal_3":
+                oops.gui.open(UIID.WelfareThree);
+                break;
+        }
+
+        if (smc.game.GameModel.curLevelConfig) {
+            if (smc.game.GameModel.curLevelConfig.eventType && smc.game.GameModel.curLevelConfig.eventType === "SIGN_POINT") {
+                // 展示提现信息
+                oops.gui.open(UIID.ReservePopup);
+            }
+        }
+    }
+
+    /**
+     * 更新二倍速时间
+     */
+    public updateDoubleSpeedTime(time: number): void {
+        if (!this.lab_doubleTime) return;
+
+        if (time <= 0) {
+            this.lab_doubleTime.string = "二倍速";
+            return;
+        }
+
+        const minutes = Math.floor(time / 60);
+        const seconds = time % 60;
+        const formattedTime = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
+        this.lab_doubleTime.string = formattedTime;
+    }
+
+    /**
+     * 获取消除总数
+     */
+    public getEliminateTotal(): number {
+        return this.eliminateTotal;
+    }
+
+    /**
+     * 获取分数
+     */
+    public getScore(): number {
+        return this.score;
+    }
+
+    /**
+     * 设置分数
+     */
+    public setScore(score: number): void {
+        this.score = score;
+        this.updateLabels();
+    }
+
+    /**
+     * 获取目标分数
+     */
+    public getTargetScore(): number {
+        return this.targetScore;
+    }
+
+    /**
+     * 获取自动状态
+     */
+    public getAutoState(): boolean {
+        return this.autoState;
+    }
+
+    /**
+     * 设置自动状态
+     */
+    public setAutoState(state: boolean): void {
+        this.autoState = state;
+        this.initButtonState(state);
+    }
+
+    /**
+     * 游戏设置按钮点击
+     */
+    public onSettingBtnClick(): void {
+        oops.gui.open(UIID.Setting);
+    }
+
+    /**
+     * 微信提现按钮点击
+     */
+    public onWithdrawBtnClick(): void {
+        if (DeviceUtil.isNative && DeviceUtil.isAndroid) {
+            ServerHandler.inst.getWechatTxInfo();
+        } else {
+            oops.gui.open(UIID.WechatWithdraw);
+        }
+    }
+
+    /**
+     * 红包提现按钮点击
+     */
+    public onAwardBtnClick(): void {
+        if (DeviceUtil.isNative && DeviceUtil.isAndroid) {
+            ServerHandler.inst.getHbTxInfo();
+        } else {
+            oops.gui.open(UIID.RedPacketWithdraw);
+        }
+    }
+
+    /**
+     * 二倍速按钮点击
+     */
+    public onDoubleBtnClick(): void {
+        if (DeviceUtil.isNative && DeviceUtil.isAndroid) {
+            ServerHandler.inst.getDoubleSpeedTime();
+        } else {
+            oops.gui.open(UIID.DoubleSpeed);
+        }
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateUIManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "ad208833-0ab4-42c8-8686-956b18dd03f5",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 776 - 0
assets/script/game/view/eliminate/EliminateView.ts

@@ -0,0 +1,776 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-03-20 15:01:09
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-19 18:20:58
+ * @Description: 消除游戏主场景
+ */
+import { _decorator, Button, EventTouch, JsonAsset, Label, Node, Prefab, Vec2, Vec3, tween } from "cc";
+import { oops } from "db://oops-framework/core/Oops";
+import { ecs } from "db://oops-framework/libs/ecs/ECS";
+import { LabelChange } from "db://oops-framework/libs/gui/label/LabelChange";
+import { CCComp } from "db://oops-framework/module/common/CCComp";
+import { GameEvent } from "../../common/config/GameEvent";
+import { UIID } from "../../common/config/GameUIConfig";
+import { smc } from "../../common/SingletonModuleComp";
+import { ServerHandler } from "../../common/manager/ServerHandler";
+import { EliminateGridManager } from "./EliminateGridManager";
+import { EliminateBrickManager } from "./EliminateBrickManager";
+import { EliminateAnimationManager } from "./EliminateAnimationManager";
+import { EliminateGuideManager } from "./EliminateGuideManager";
+import { EliminateAutoPlayManager } from "./EliminateAutoPlayManager";
+import { EliminateUIManager } from "./EliminateUIManager";
+import { BrickData, CellState, EditingData, GameState, GridData } from "./EliminateTypes";
+import { DeviceUtil } from "db://oops-framework/core/utils/DeviceUtil";
+import { Format } from "../../utils/Format";
+
+const { ccclass, property } = _decorator;
+
+/** 视图层对象 */
+@ccclass('EliminateView')
+@ecs.register('Eliminate', false)
+export class EliminateView extends CCComp {
+    @property({ type: LabelChange, displayName: "自动提现金额" })
+    private lab_wxCoin: LabelChange = null!;
+    @property({ type: LabelChange, displayName: "额外奖励" })
+    private lab_hbCoin: LabelChange = null!;
+    @property({ type: Node, displayName: "tween微信钱Node" })
+    private tweenWechatNode: Node = null!;
+    @property({ type: Node, displayName: "tween红包Node" })
+    private tweenRedNode: Node = null!;
+
+    @property({ type: Prefab, displayName: "金币预制体" })
+    private coinPrefab: Prefab = null!
+    @property({ type: Prefab, displayName: "红包预制体" })
+    private redPacketPrefab: Prefab = null!;
+    @property({ type: Label, displayName: "本局分数" })
+    private lab_score: Label = null!;
+    @property({ type: Label, displayName: "目标分数" })
+    private lab_taget: Label = null!;
+
+    @property({ type: Prefab, displayName: "item预制体列表" })
+    private itemPrefabs: Prefab[] = [];
+    @property({ type: Node, displayName: "网格Node" })
+    private gridNode: Node = null!;
+    @property({ type: Node, displayName: "移动Node" })
+    private moveNode: Node = null!;
+    @property({ type: Node, displayName: "旋转Node" })
+    private rotateNode: Node = null!;
+    @property({ type: Node, displayName: "方块Node" })
+    private brickNode: Node = null!;
+
+    @property({ type: Prefab, displayName: "旋转预制体" })
+    private rotatePrefab: Node = null!;
+    @property({ type: Label, displayName: "累计消除次数" })
+    private lab_total: Label = null!;
+    @property({ type: Label, displayName: "每次放置添加的分数" })
+    private lab_addScore: Label = null!;
+
+    @property({ type: Button, displayName: "自动按钮" })
+    private autoBtn: Button = null!;
+
+    @property({ type: Label, displayName: "第几块金砖" })
+    private lab_goldNum: Label = null!;
+
+    @property({ type: Label, displayName: "二倍速时间" })
+    private lab_doubleTime: Label = null!;
+
+    @property({ type: Node, displayName: "引导层" })
+    private guideNode: Node = null!;
+
+    @property({ type: Node, displayName: "ComboNode" })
+    private comboNode: Node = null!;
+
+    // 管理器
+    private gridManager: EliminateGridManager = null!;
+    private brickManager: EliminateBrickManager = null!;
+    private animationManager: EliminateAnimationManager = null!;
+    private guideManager: EliminateGuideManager = null!;
+    private autoPlayManager: EliminateAutoPlayManager = null!;
+    private uiManager: EliminateUIManager = null!;
+
+    // 游戏配置
+    private rows: number = 8;       // 行数
+    private cols: number = 8;       // 列数
+    private itemSize: number = 76.25;  // 格子大小
+    private brickNum: number = 3;   // 砖块数量
+    private yOffset = 100;
+
+    // 游戏状态
+    private gameState: GameState = GameState.READY;
+    private operateFlag: boolean = false;  // 是否可以操作
+    private touchStartPos = new Vec2();
+    private adShowingFlag: boolean = false;  // 广告展示标记
+
+    // 得分设置
+    private eliminateBaseScore: number = 10;  // 每行得多少分
+    private extraGridScore: number = 1;       // 每个格子占用几分
+    private placementBaseScore: number = 1;   // 每个格子占用几分
+
+    // 连击设置
+    private currentCombo: number = 0;            // 当前连击次数
+    private shouldResetEliminateCount: boolean = true; // 是否需要重置消除计数
+
+    // 双倍速设置
+    private isDoubleSpeed: boolean = false;  // 是否开启二倍速
+    private doubleSpeedTime: number = 0;     // 双倍速剩余时间
+    private callback: Function | null = null; // 计时回调函数
+
+    // 编辑中的方块和格子
+    private editingData: EditingData = {
+        brickData: null,
+        gridList: [],
+    };
+
+    // 消除区间数组
+    private eliminateInterval: number[] = [];
+
+    /** 
+     * 初始化
+     */
+    async start() {
+        this.initManagers();
+        this.setButton();
+        this.uiManager.initButtonState(false);
+        await this.brickManager.loadConfig();
+        this.initData();
+        this.uiManager.setData();
+        this.addEventListeners();
+
+        // 初始化网格
+        if (this.guideManager.getGuideStep() === 0 && smc.account.AccountModel.curLevel == 1) {
+            this.guideManager.startGuideMode();
+        } else {
+            this.initGame();
+        }
+
+        // 更新福利点
+        this.uiManager.updateWelfarePoint();
+    }
+
+    /**
+     * 初始化管理器
+     */
+    private initManagers(): void {
+        // 创建网格管理器
+        this.gridManager = new EliminateGridManager(
+            this.gridNode,
+            this.itemPrefabs,
+            this.rows,
+            this.cols,
+            this.itemSize
+        );
+
+        // 创建方块管理器
+        this.brickManager = new EliminateBrickManager(
+            this.brickNode,
+            this.rotateNode,
+            this.moveNode,
+            this.itemPrefabs,
+            this.rotatePrefab,
+            this.itemSize
+        );
+
+        // 创建动画管理器
+        this.animationManager = new EliminateAnimationManager(
+            this.node,
+            this.coinPrefab,
+            this.redPacketPrefab,
+            this.lab_addScore,
+            this.lab_wxCoin,
+            this.lab_hbCoin,
+            this.tweenWechatNode,
+            this.tweenRedNode,
+            this.comboNode
+        );
+
+        // 创建引导管理器
+        this.guideManager = new EliminateGuideManager(
+            this.guideNode,
+            this.gridManager,
+            this.brickManager
+        );
+
+        // 创建自动游戏管理器
+        this.autoPlayManager = new EliminateAutoPlayManager(
+            this.gridManager,
+            this.brickManager,
+            this.moveNode
+        );
+
+        // 创建UI管理器
+        this.uiManager = new EliminateUIManager(
+            this.lab_wxCoin,
+            this.lab_hbCoin,
+            this.lab_score,
+            this.lab_taget,
+            this.lab_total,
+            this.lab_goldNum,
+            this.lab_doubleTime,
+            this.autoBtn
+        );
+    }
+
+    /**
+     * 初始化游戏
+     */
+    private initGame(): void {
+        this.gridManager.initGrid();
+        this.brickManager.initBricks(this.brickNum);
+        this.setupBrickEvents();
+    }
+
+    /**
+     * 设置砖块事件
+     */
+    private setupBrickEvents(): void {
+        const bricksList = this.brickManager.getBricksList();
+        for (const brickData of bricksList) {
+            this.brickManager.brickStartDrag(brickData, this.onBrickStartDrag.bind(this));
+            this.brickManager.brickAddEvent(brickData, this.onBrickDrag.bind(this));
+            this.brickManager.brickEndDrag(brickData, this.onBrickEndDrag.bind(this));
+        }
+    }
+
+    /**
+     * 方块拖动开始事件处理
+     */
+    private onBrickStartDrag(brickData: BrickData, startPos: Vec3): void {
+        // 如果正在编辑其他方块或不允许操作,则忽略
+        if (!this.operateFlag) return;
+
+        // 清空编辑中的数据
+        this.editingData.brickData = null;
+        this.editingData.gridList.length = 0;
+
+        // 将方块移到移动层并设置位置
+        if (brickData.brickNode) {
+            const originalParent = brickData.brickNode.parent;
+            brickData.brickNode.setParent(this.moveNode);
+            brickData.brickNode.setWorldPosition(startPos);
+        }
+
+        // 从方块列表中移除该方块
+        const index = this.brickManager.getBricksList().findIndex(item => item === brickData);
+        if (index > -1) {
+            const bricksList = this.brickManager.getBricksList();
+            this.editingData.brickData = bricksList.splice(index, 1)[0];
+            this.brickManager.setBricksList(bricksList);
+        } else {
+            console.error("未找到方块数据:", brickData);
+        }
+    }
+
+    /**
+     * 方块拖动事件处理
+     */
+    private onBrickDrag(brickData: BrickData, position: Vec3, startPos: Vec2, delta: Vec2): void {
+        // 如果操作标记为false,不处理拖动
+        if (!this.operateFlag) return;
+
+        // 清除旧的编辑数据
+        this.editingData.brickData = brickData;
+        this.editingData.gridList.length = 0;
+
+        // 如果方块可旋转,隐藏旋转节点
+        if (brickData.rotateFlag && brickData.rotateNode) {
+            brickData.rotateNode.active = false;
+        }
+
+        // 恢复所有网格颜色
+        this.gridManager.gridColorRecovery();
+
+        // 移动方块到新位置
+        if (brickData.brickNode) {
+            brickData.brickNode.setWorldPosition(position);
+            brickData.brickNode.scale.set(1, 1, 1);
+        }
+
+        // 检查方块每个子网格是否与游戏网格重叠
+        const tempGridList: GridData[] = [];
+        let allEmptyGrids: boolean = true; // 标记是否所有网格都为空
+
+        if (brickData.brickNode) {
+            brickData.brickNode.children.forEach((childNode) => {
+                const childWorldPos = childNode.getWorldPosition();
+
+                // 查找与子网格重叠的游戏网格
+                let matchedGrid: GridData | null = null;
+                const gridList = this.gridManager.getGridList();
+
+                for (let row = 0; row < this.gridManager.getRows() && !matchedGrid; row++) {
+                    for (let col = 0; col < this.gridManager.getCols() && !matchedGrid; col++) {
+                        const grid = gridList[row][col];
+                        if (!grid || !grid.gridNode) continue;
+
+                        const gridPos = grid.gridNode.getWorldPosition();
+                        if (Vec3.distance(gridPos, childWorldPos) <= (this.gridManager.getItemSize() / 2)) {
+                            matchedGrid = grid;
+                        }
+                    }
+                }
+
+                if (matchedGrid) {
+                    tempGridList.push(matchedGrid);
+                    // 检查是否有非空网格
+                    if (matchedGrid.status !== CellState.EMPTY) {
+                        allEmptyGrids = false;
+                    }
+                }
+            });
+        }
+
+        // 检查是否所有子网格都有对应的游戏网格,且都是空的
+        const canPlace = tempGridList.length === brickData.gridConfig.length && allEmptyGrids;
+
+        // 更新编辑中的网格列表
+        if (canPlace) {
+            this.editingData.gridList = [...tempGridList];
+        }
+
+        // 更新网格颜色提示 - 显示可放置状态
+        tempGridList.forEach(grid => {
+            this.gridManager.updateGridHighlight(grid, canPlace);
+        });
+    }
+
+    /**
+     * 方块拖动结束事件处理
+     */
+    private onBrickEndDrag(brickData: BrickData, canPlace: boolean): void {
+        // 如果操作标记为false,不处理拖动结束
+        if (!this.operateFlag || this.adShowingFlag) return;
+
+        // 临时关闭操作标记,避免重复触发
+        this.operateFlag = false;
+
+        // 恢复所有网格颜色
+        this.gridManager.gridColorRecovery();
+
+        // 检查是否为旋转操作(点击)
+        if (brickData.rotateFlag &&
+            brickData.brickNode &&
+            this.editingData.gridList.length === 0) {
+
+            // 将方块添加回列表
+            this.brickManager.setBricksList([...this.brickManager.getBricksList(), brickData]);
+
+            // 恢复方块到初始位置
+            if (brickData.brickNode) {
+                this.brickNode.addChild(brickData.brickNode);
+                brickData.brickNode.setWorldPosition(brickData.brickInitPos);
+
+                // 显示旋转节点
+                if (brickData.rotateNode) {
+                    brickData.rotateNode.active = true;
+                }
+
+                // 执行旋转
+                this.brickManager.brickGridRotate(brickData).then(() => {
+                    this.operateFlag = true;
+                });
+
+                // 延迟隐藏旋转节点
+                this.scheduleOnce(() => {
+                    if (brickData.rotateNode) {
+                        brickData.rotateNode.active = false;
+                    }
+                }, 0.4);
+            }
+        }
+        // 检查是否可以放置
+        else if (this.editingData.gridList.length > 0) {
+            // 处理引导模式特殊逻辑
+            if (this.guideManager.getIsGuideMode() && this.guideManager.getGuideStep() > 0) {
+                const targetGrids = this.editingData.gridList;
+
+                // 如果格子数量不足,直接视为无效放置
+                if (!targetGrids || targetGrids.length !== brickData.gridConfig.length) {
+                    this.handleInvalidPlacement(brickData);
+                    return;
+                }
+
+                // 模拟砖块落下后的状态
+                const tempGridList = this.gridManager.copyGridList();
+                for (const grid of targetGrids) {
+                    tempGridList[grid.row][grid.col].status = CellState.FILLED;
+                }
+
+                const simulateResult = this.gridManager.gridEliminateCheck(tempGridList);
+                const canEliminate = simulateResult.gridEliminateList.length > 0;
+
+                // 在引导模式下,如果不能消除则视为无效放置
+                if (!canEliminate) {
+                    this.handleInvalidPlacement(brickData);
+                    return;
+                }
+            }
+
+            // 计算放置的格子数量
+            const placedGridCount = this.editingData.gridList.length;
+
+            // 获取中心位置用于显示分数
+            let centerPos = new Vec3(0, 0, 0);
+            if (this.editingData.gridList.length > 0 && this.editingData.gridList[0].gridNode) {
+                centerPos = this.editingData.gridList[0].gridNode.getWorldPosition().clone();
+
+                if (this.editingData.gridList.length > 1) {
+                    // 计算所有格子的平均位置作为中心点
+                    for (let i = 1; i < this.editingData.gridList.length; i++) {
+                        const gridNode = this.editingData.gridList[i].gridNode;
+                        if (gridNode) {
+                            centerPos.add(gridNode.getWorldPosition());
+                        }
+                    }
+                    const validGridCount = this.editingData.gridList.filter(grid => grid.gridNode).length;
+                    centerPos.x /= validGridCount;
+                    centerPos.y /= validGridCount;
+                }
+            }
+
+            // 放置方块到网格
+            this.editingData.gridList.forEach(grid => {
+                grid.status = CellState.FILLED;
+                grid.type = brickData.type;
+                this.gridManager.generateGrid(grid);
+            });
+
+            // 显示放置得分动画
+            this.animationManager.showScoreAnimation(
+                centerPos,
+                placedGridCount,
+                this.placementBaseScore
+            );
+
+            // 标记需要重置消除计数器
+            this.shouldResetEliminateCount = true;
+
+            // 销毁方块节点
+            if (brickData.brickNode) {
+                brickData.brickNode.destroy();
+            }
+
+            // 添加新方块到待选区
+            this.brickManager.addBrick(brickData.index);
+
+            // 检查消除
+            this.scheduleOnce(() => {
+                this.gridEliminate().then((hasElimination) => {
+                    // 如果没有消除,确保下次消除会重置计数
+                    if (!hasElimination) {
+                        this.shouldResetEliminateCount = true;
+                    }
+
+                    this.operateFlag = true;
+
+                    // 处理新手引导
+                    if (this.guideManager.getIsGuideMode()) {
+                        this.scheduleOnce(() => {
+                            this.guideManager.checkNextStep();
+                        }, 0.3);
+                    } else {
+                        // 检查游戏是否结束
+                        this.prompt(false).then(canContinue => {
+                            if (!canContinue) {
+                                this.gameOver();
+                            }
+                        });
+                    }
+                });
+            }, 0.1);
+        } else {
+            // 无法放置,将方块返回原位置
+            this.handleInvalidPlacement(brickData);
+        }
+    }
+
+    /**
+     * 处理无效放置
+     */
+    private handleInvalidPlacement(brickData: BrickData): void {
+        // 将方块添加回列表
+        this.brickManager.setBricksList([...this.brickManager.getBricksList(), brickData]);
+
+        if (brickData.brickNode) {
+            // 添加回弹动画
+            tween(brickData.brickNode)
+                .to(0.2, {
+                    worldPosition: brickData.brickInitPos,
+                    scale: new Vec3(0.6, 0.6, 0.6)
+                })
+                .call(() => {
+                    this.operateFlag = true;
+                    if (brickData.brickNode) {
+                        this.brickNode.addChild(brickData.brickNode);
+                        brickData.brickNode.setWorldPosition(brickData.brickInitPos);
+                    }
+                })
+                .start();
+        } else {
+            this.operateFlag = true;
+        }
+    }
+
+    /**
+     * 添加事件监听
+     */
+    private addEventListeners(): void {
+        oops.message.on(GameEvent.RestartGame, this.restartGame, this);
+        oops.message.on(GameEvent.DoubleSpeedOpenSuccess, this.doubleSpeedOpenSuccess, this);
+        oops.message.on(GameEvent.openView, this.openView, this);
+        oops.message.on(GameEvent.showCoinAnimation, this.showCoinAnimation, this);
+        oops.message.on(GameEvent.Resurrection, this.onResurrection, this);
+        oops.message.on(GameEvent.updateHbAndWxCoin, this.updateCoin, this);
+        oops.message.on(GameEvent.StartAutoGame, this.startAutoGame, this);
+    }
+
+    /**
+     * 初始化数据
+     */
+    private initData(): void {
+        this.operateFlag = true;
+        this.gameState = GameState.READY;
+        this.shouldResetEliminateCount = true;
+        this.currentCombo = 0;
+        this.uiManager.initData();
+    }
+
+    /**
+     * 更新金币
+     */
+    private updateCoin(): void {
+        this.uiManager.updateCoin();
+    }
+
+    /**
+     * 重启游戏
+     */
+    private restartGame(): void {
+        if (this.gameState === GameState.READY) return;
+
+        this.initData();
+        this.uiManager.setData();
+        this.initGame();
+        this.uiManager.initButtonState(this.autoPlayManager.getAutoState());
+        this.uiManager.updateWelfarePoint();
+    }
+
+    /**
+     * 开始自动游戏
+     */
+    private startAutoGame(): void {
+        this.btn_auto();
+    }
+
+    /**
+     * 显示金币动画
+     */
+    private showCoinAnimation(event: string, args: string): void {
+        const lastPos = this.moveNode.getWorldPosition();
+        const score = this.uiManager.getScore();
+
+        // 显示金币动画
+        this.animationManager.showCoinAnimation(lastPos, score, !!args);
+    }
+
+    /**
+     * 打开视图
+     */
+    private openView(event: string, args: string): void {
+        this.uiManager.openView(args);
+    }
+
+    /**
+     * 复活处理
+     */
+    private onResurrection(): void {
+        console.log("复活游戏,分数不清零");
+        // 复活逻辑实现
+    }
+
+    /**
+     * 二倍速开启成功
+     */
+    private doubleSpeedOpenSuccess(): void {
+        if (this.gameState !== GameState.PLAYING) {
+            return;
+        }
+
+        if (this.callback) {
+            this.unschedule(this.callback);
+        }
+
+        this.isDoubleSpeed = true;
+        this.animationManager.setDoubleSpeed(true, 2);
+        this.autoPlayManager.setDoubleSpeed(true);
+
+        // 设置倒计时
+        this.doubleSpeedTime = smc.game.GameModel.doubleSpeedTime || 15;
+
+        if (this.doubleSpeedTime <= 0) {
+            return;
+        }
+
+        // 如果没有开启自动,则开启
+        if (!this.autoPlayManager.getAutoState()) {
+            this.btn_auto();
+        }
+
+        // 设置倒计时回调
+        this.callback = () => {
+            if (!this.adShowingFlag && this.gameState === GameState.PLAYING) {
+                this.doubleSpeedTime--;
+                this.uiManager.updateDoubleSpeedTime(this.doubleSpeedTime);
+
+                // 时间到了
+                if (this.doubleSpeedTime <= 0) {
+                    this.lab_doubleTime.string = "二倍速";
+                    this.isDoubleSpeed = false;
+                    this.animationManager.setDoubleSpeed(false);
+                    this.autoPlayManager.setDoubleSpeed(false);
+
+                    // 再打开继续二倍速页面
+                    oops.gui.open(UIID.KeepSpeed);
+                    this.unschedule(this.callback as Function);
+                }
+            }
+        };
+
+        this.schedule(this.callback, 1);
+    }
+
+    /**
+     * 设置游戏状态
+     */
+    private setGameState(state: GameState): void {
+        this.gameState = state;
+        switch (state) {
+            case GameState.READY:
+                break;
+
+            case GameState.PLAYING:
+                break;
+
+            case GameState.PAUSED:
+                break;
+
+            case GameState.GAME_OVER:
+                // 打开游戏结束界面
+                this.autoPlayManager.setAutoState(false);
+                this.uiManager.setAutoState(false);
+                this.adShowingFlag = false;
+                break;
+
+            case GameState.GAME_PASS:
+                break;
+        }
+    }
+
+    /**
+     * 检查是否可以继续游戏
+     */
+    private prompt(tipFlag = true): Promise<boolean> {
+        // TODO: 实现提示逻辑
+        return Promise.resolve(true);
+    }
+
+    /**
+     * 游戏结束处理
+     */
+    private gameOver(): void {
+        this.setGameState(GameState.GAME_OVER);
+        console.log("游戏结束");
+        oops.gui.open(UIID.GameOver);
+    }
+
+    /**
+     * 消除格子
+     */
+    private gridEliminate(): Promise<boolean> {
+        // TODO: 实现格子消除逻辑
+        return Promise.resolve(false);
+    }
+
+    // =============== 按钮事件处理 ===============
+
+    /**
+     * 设置按钮点击
+     */
+    private btn_setting(): void {
+        this.uiManager.onSettingBtnClick();
+    }
+
+    /**
+     * 提现按钮点击
+     */
+    private btn_withdraw(): void {
+        this.uiManager.onWithdrawBtnClick();
+    }
+
+    /**
+     * 奖励按钮点击
+     */
+    private btn_award(): void {
+        this.uiManager.onAwardBtnClick();
+    }
+
+    /**
+     * 双倍速按钮点击
+     */
+    private btn_double(): void {
+        this.uiManager.onDoubleBtnClick();
+    }
+
+    /**
+     * 自动按钮点击
+     */
+    private btn_auto(): void {
+        const newState = !this.autoPlayManager.getAutoState();
+        this.autoPlayManager.setAutoState(newState);
+        this.uiManager.setAutoState(newState);
+
+        this.gameState = GameState.PLAYING;
+
+        if (newState) {
+            this.executeAutoPlace();
+        }
+    }
+
+    /**
+     * 执行自动放置
+     */
+    private executeAutoPlace(): void {
+        if (!this.autoPlayManager.getAutoState() || this.gameState !== GameState.PLAYING || this.adShowingFlag) {
+            return;
+        }
+
+        this.autoPlayManager.executeAutoPlace((success) => {
+            if (!success) {
+                // 游戏结束
+                this.autoPlayManager.setAutoState(false);
+                this.uiManager.setAutoState(false);
+                this.gameOver();
+                return;
+            }
+
+            // 消除检查
+            this.gridEliminate().then(() => {
+                this.prompt(false).then((canContinue) => {
+                    if (!canContinue) {
+                        this.gameOver();
+                    } else if (this.autoPlayManager.getAutoState()) {
+                        // 继续自动放置
+                        this.scheduleOnce(() => {
+                            this.executeAutoPlace();
+                        }, 0.4);
+                    }
+                });
+            });
+        });
+    }
+
+    /** 视图对象通过 ecs.Entity.remove(eliminateViewComp) 删除组件是触发组件处理自定义释放逻辑 */
+    reset() {
+        this.node.destroy();
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateView.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "cda4467d-aadb-45f0-b48d-a60ca1d293c8",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 776 - 0
assets/script/game/view/eliminate/EliminateViewComp.ts

@@ -0,0 +1,776 @@
+/*
+ * @Author: mojunshou 1637302775@qq.com
+ * @Date: 2025-03-20 15:01:09
+ * @LastEditors: mojunshou 1637302775@qq.com
+ * @LastEditTime: 2025-04-19 18:08:35
+ * @Description: 消除游戏主场景
+ */
+import { _decorator, Button, EventTouch, JsonAsset, Label, Node, Prefab, Vec2, Vec3, tween } from "cc";
+import { oops } from "db://oops-framework/core/Oops";
+import { ecs } from "db://oops-framework/libs/ecs/ECS";
+import { LabelChange } from "db://oops-framework/libs/gui/label/LabelChange";
+import { CCComp } from "db://oops-framework/module/common/CCComp";
+import { GameEvent } from "../../common/config/GameEvent";
+import { UIID } from "../../common/config/GameUIConfig";
+import { smc } from "../../common/SingletonModuleComp";
+import { ServerHandler } from "../../common/manager/ServerHandler";
+import { EliminateGridManager } from "./EliminateGridManager";
+import { EliminateBrickManager } from "./EliminateBrickManager";
+import { EliminateAnimationManager } from "./EliminateAnimationManager";
+import { EliminateGuideManager } from "./EliminateGuideManager";
+import { EliminateAutoPlayManager } from "./EliminateAutoPlayManager";
+import { EliminateUIManager } from "./EliminateUIManager";
+import { BrickData, CellState, EditingData, GameState, GridData } from "./EliminateTypes";
+import { DeviceUtil } from "db://oops-framework/core/utils/DeviceUtil";
+import { Format } from "../../utils/Format";
+
+const { ccclass, property } = _decorator;
+
+/** 视图层对象 */
+@ccclass('EliminateViewComp')
+@ecs.register('EliminateView', false)
+export class EliminateViewComp extends CCComp {
+    @property({ type: LabelChange, displayName: "自动提现金额" })
+    private lab_wxCoin: LabelChange = null!;
+    @property({ type: LabelChange, displayName: "额外奖励" })
+    private lab_hbCoin: LabelChange = null!;
+    @property({ type: Node, displayName: "tween微信钱Node" })
+    private tweenWechatNode: Node = null!;
+    @property({ type: Node, displayName: "tween红包Node" })
+    private tweenRedNode: Node = null!;
+
+    @property({ type: Prefab, displayName: "金币预制体" })
+    private coinPrefab: Prefab = null!
+    @property({ type: Prefab, displayName: "红包预制体" })
+    private redPacketPrefab: Prefab = null!;
+    @property({ type: Label, displayName: "本局分数" })
+    private lab_score: Label = null!;
+    @property({ type: Label, displayName: "目标分数" })
+    private lab_taget: Label = null!;
+
+    @property({ type: Prefab, displayName: "item预制体列表" })
+    private itemPrefabs: Prefab[] = [];
+    @property({ type: Node, displayName: "网格Node" })
+    private gridNode: Node = null!;
+    @property({ type: Node, displayName: "移动Node" })
+    private moveNode: Node = null!;
+    @property({ type: Node, displayName: "旋转Node" })
+    private rotateNode: Node = null!;
+    @property({ type: Node, displayName: "方块Node" })
+    private brickNode: Node = null!;
+
+    @property({ type: Prefab, displayName: "旋转预制体" })
+    private rotatePrefab: Node = null!;
+    @property({ type: Label, displayName: "累计消除次数" })
+    private lab_total: Label = null!;
+    @property({ type: Label, displayName: "每次放置添加的分数" })
+    private lab_addScore: Label = null!;
+
+    @property({ type: Button, displayName: "自动按钮" })
+    private autoBtn: Button = null!;
+
+    @property({ type: Label, displayName: "第几块金砖" })
+    private lab_goldNum: Label = null!;
+
+    @property({ type: Label, displayName: "二倍速时间" })
+    private lab_doubleTime: Label = null!;
+
+    @property({ type: Node, displayName: "引导层" })
+    private guideNode: Node = null!;
+
+    @property({ type: Node, displayName: "ComboNode" })
+    private comboNode: Node = null!;
+
+    // 管理器
+    private gridManager: EliminateGridManager = null!;
+    private brickManager: EliminateBrickManager = null!;
+    private animationManager: EliminateAnimationManager = null!;
+    private guideManager: EliminateGuideManager = null!;
+    private autoPlayManager: EliminateAutoPlayManager = null!;
+    private uiManager: EliminateUIManager = null!;
+
+    // 游戏配置
+    private rows: number = 8;       // 行数
+    private cols: number = 8;       // 列数
+    private itemSize: number = 76.25;  // 格子大小
+    private brickNum: number = 3;   // 砖块数量
+    private yOffset = 100;
+
+    // 游戏状态
+    private gameState: GameState = GameState.READY;
+    private operateFlag: boolean = false;  // 是否可以操作
+    private touchStartPos = new Vec2();
+    private adShowingFlag: boolean = false;  // 广告展示标记
+
+    // 得分设置
+    private eliminateBaseScore: number = 10;  // 每行得多少分
+    private extraGridScore: number = 1;       // 每个格子占用几分
+    private placementBaseScore: number = 1;   // 每个格子占用几分
+
+    // 连击设置
+    private currentCombo: number = 0;            // 当前连击次数
+    private shouldResetEliminateCount: boolean = true; // 是否需要重置消除计数
+
+    // 双倍速设置
+    private isDoubleSpeed: boolean = false;  // 是否开启二倍速
+    private doubleSpeedTime: number = 0;     // 双倍速剩余时间
+    private callback: Function | null = null; // 计时回调函数
+
+    // 编辑中的方块和格子
+    private editingData: EditingData = {
+        brickData: null,
+        gridList: [],
+    };
+
+    // 消除区间数组
+    private eliminateInterval: number[] = [];
+
+    /** 
+     * 初始化
+     */
+    async start() {
+        this.initManagers();
+        this.setButton();
+        this.uiManager.initButtonState(false);
+        await this.brickManager.loadConfig();
+        this.initData();
+        this.uiManager.setData();
+        this.addEventListeners();
+
+        // 初始化网格
+        if (this.guideManager.getGuideStep() === 0 && smc.account.AccountModel.curLevel == 1) {
+            this.guideManager.startGuideMode();
+        } else {
+            this.initGame();
+        }
+
+        // 更新福利点
+        this.uiManager.updateWelfarePoint();
+    }
+
+    /**
+     * 初始化管理器
+     */
+    private initManagers(): void {
+        // 创建网格管理器
+        this.gridManager = new EliminateGridManager(
+            this.gridNode,
+            this.itemPrefabs,
+            this.rows,
+            this.cols,
+            this.itemSize
+        );
+
+        // 创建方块管理器
+        this.brickManager = new EliminateBrickManager(
+            this.brickNode,
+            this.rotateNode,
+            this.moveNode,
+            this.itemPrefabs,
+            this.rotatePrefab,
+            this.itemSize
+        );
+
+        // 创建动画管理器
+        this.animationManager = new EliminateAnimationManager(
+            this.node,
+            this.coinPrefab,
+            this.redPacketPrefab,
+            this.lab_addScore,
+            this.lab_wxCoin,
+            this.lab_hbCoin,
+            this.tweenWechatNode,
+            this.tweenRedNode,
+            this.comboNode
+        );
+
+        // 创建引导管理器
+        this.guideManager = new EliminateGuideManager(
+            this.guideNode,
+            this.gridManager,
+            this.brickManager
+        );
+
+        // 创建自动游戏管理器
+        this.autoPlayManager = new EliminateAutoPlayManager(
+            this.gridManager,
+            this.brickManager,
+            this.moveNode
+        );
+
+        // 创建UI管理器
+        this.uiManager = new EliminateUIManager(
+            this.lab_wxCoin,
+            this.lab_hbCoin,
+            this.lab_score,
+            this.lab_taget,
+            this.lab_total,
+            this.lab_goldNum,
+            this.lab_doubleTime,
+            this.autoBtn
+        );
+    }
+
+    /**
+     * 初始化游戏
+     */
+    private initGame(): void {
+        this.gridManager.initGrid();
+        this.brickManager.initBricks(this.brickNum);
+        this.setupBrickEvents();
+    }
+
+    /**
+     * 设置砖块事件
+     */
+    private setupBrickEvents(): void {
+        const bricksList = this.brickManager.getBricksList();
+        for (const brickData of bricksList) {
+            this.brickManager.brickStartDrag(brickData, this.onBrickStartDrag.bind(this));
+            this.brickManager.brickAddEvent(brickData, this.onBrickDrag.bind(this));
+            this.brickManager.brickEndDrag(brickData, this.onBrickEndDrag.bind(this));
+        }
+    }
+
+    /**
+     * 方块拖动开始事件处理
+     */
+    private onBrickStartDrag(brickData: BrickData, startPos: Vec3): void {
+        // 如果正在编辑其他方块或不允许操作,则忽略
+        if (!this.operateFlag) return;
+
+        // 清空编辑中的数据
+        this.editingData.brickData = null;
+        this.editingData.gridList.length = 0;
+
+        // 将方块移到移动层并设置位置
+        if (brickData.brickNode) {
+            const originalParent = brickData.brickNode.parent;
+            brickData.brickNode.setParent(this.moveNode);
+            brickData.brickNode.setWorldPosition(startPos);
+        }
+
+        // 从方块列表中移除该方块
+        const index = this.brickManager.getBricksList().findIndex(item => item === brickData);
+        if (index > -1) {
+            const bricksList = this.brickManager.getBricksList();
+            this.editingData.brickData = bricksList.splice(index, 1)[0];
+            this.brickManager.setBricksList(bricksList);
+        } else {
+            console.error("未找到方块数据:", brickData);
+        }
+    }
+
+    /**
+     * 方块拖动事件处理
+     */
+    private onBrickDrag(brickData: BrickData, position: Vec3, startPos: Vec2, delta: Vec2): void {
+        // 如果操作标记为false,不处理拖动
+        if (!this.operateFlag) return;
+
+        // 清除旧的编辑数据
+        this.editingData.brickData = brickData;
+        this.editingData.gridList.length = 0;
+
+        // 如果方块可旋转,隐藏旋转节点
+        if (brickData.rotateFlag && brickData.rotateNode) {
+            brickData.rotateNode.active = false;
+        }
+
+        // 恢复所有网格颜色
+        this.gridManager.gridColorRecovery();
+
+        // 移动方块到新位置
+        if (brickData.brickNode) {
+            brickData.brickNode.setWorldPosition(position);
+            brickData.brickNode.scale.set(1, 1, 1);
+        }
+
+        // 检查方块每个子网格是否与游戏网格重叠
+        const tempGridList: GridData[] = [];
+        let allEmptyGrids: boolean = true; // 标记是否所有网格都为空
+
+        if (brickData.brickNode) {
+            brickData.brickNode.children.forEach((childNode) => {
+                const childWorldPos = childNode.getWorldPosition();
+
+                // 查找与子网格重叠的游戏网格
+                let matchedGrid: GridData | null = null;
+                const gridList = this.gridManager.getGridList();
+
+                for (let row = 0; row < this.gridManager.getRows() && !matchedGrid; row++) {
+                    for (let col = 0; col < this.gridManager.getCols() && !matchedGrid; col++) {
+                        const grid = gridList[row][col];
+                        if (!grid || !grid.gridNode) continue;
+
+                        const gridPos = grid.gridNode.getWorldPosition();
+                        if (Vec3.distance(gridPos, childWorldPos) <= (this.gridManager.getItemSize() / 2)) {
+                            matchedGrid = grid;
+                        }
+                    }
+                }
+
+                if (matchedGrid) {
+                    tempGridList.push(matchedGrid);
+                    // 检查是否有非空网格
+                    if (matchedGrid.status !== CellState.EMPTY) {
+                        allEmptyGrids = false;
+                    }
+                }
+            });
+        }
+
+        // 检查是否所有子网格都有对应的游戏网格,且都是空的
+        const canPlace = tempGridList.length === brickData.gridConfig.length && allEmptyGrids;
+
+        // 更新编辑中的网格列表
+        if (canPlace) {
+            this.editingData.gridList = [...tempGridList];
+        }
+
+        // 更新网格颜色提示 - 显示可放置状态
+        tempGridList.forEach(grid => {
+            this.gridManager.updateGridHighlight(grid, canPlace);
+        });
+    }
+
+    /**
+     * 方块拖动结束事件处理
+     */
+    private onBrickEndDrag(brickData: BrickData, canPlace: boolean): void {
+        // 如果操作标记为false,不处理拖动结束
+        if (!this.operateFlag || this.adShowingFlag) return;
+
+        // 临时关闭操作标记,避免重复触发
+        this.operateFlag = false;
+
+        // 恢复所有网格颜色
+        this.gridManager.gridColorRecovery();
+
+        // 检查是否为旋转操作(点击)
+        if (brickData.rotateFlag &&
+            brickData.brickNode &&
+            this.editingData.gridList.length === 0) {
+
+            // 将方块添加回列表
+            this.brickManager.setBricksList([...this.brickManager.getBricksList(), brickData]);
+
+            // 恢复方块到初始位置
+            if (brickData.brickNode) {
+                this.brickNode.addChild(brickData.brickNode);
+                brickData.brickNode.setWorldPosition(brickData.brickInitPos);
+
+                // 显示旋转节点
+                if (brickData.rotateNode) {
+                    brickData.rotateNode.active = true;
+                }
+
+                // 执行旋转
+                this.brickManager.brickGridRotate(brickData).then(() => {
+                    this.operateFlag = true;
+                });
+
+                // 延迟隐藏旋转节点
+                this.scheduleOnce(() => {
+                    if (brickData.rotateNode) {
+                        brickData.rotateNode.active = false;
+                    }
+                }, 0.4);
+            }
+        }
+        // 检查是否可以放置
+        else if (this.editingData.gridList.length > 0) {
+            // 处理引导模式特殊逻辑
+            if (this.guideManager.getIsGuideMode() && this.guideManager.getGuideStep() > 0) {
+                const targetGrids = this.editingData.gridList;
+
+                // 如果格子数量不足,直接视为无效放置
+                if (!targetGrids || targetGrids.length !== brickData.gridConfig.length) {
+                    this.handleInvalidPlacement(brickData);
+                    return;
+                }
+
+                // 模拟砖块落下后的状态
+                const tempGridList = this.gridManager.copyGridList();
+                for (const grid of targetGrids) {
+                    tempGridList[grid.row][grid.col].status = CellState.FILLED;
+                }
+
+                const simulateResult = this.gridManager.gridEliminateCheck(tempGridList);
+                const canEliminate = simulateResult.gridEliminateList.length > 0;
+
+                // 在引导模式下,如果不能消除则视为无效放置
+                if (!canEliminate) {
+                    this.handleInvalidPlacement(brickData);
+                    return;
+                }
+            }
+
+            // 计算放置的格子数量
+            const placedGridCount = this.editingData.gridList.length;
+
+            // 获取中心位置用于显示分数
+            let centerPos = new Vec3(0, 0, 0);
+            if (this.editingData.gridList.length > 0 && this.editingData.gridList[0].gridNode) {
+                centerPos = this.editingData.gridList[0].gridNode.getWorldPosition().clone();
+
+                if (this.editingData.gridList.length > 1) {
+                    // 计算所有格子的平均位置作为中心点
+                    for (let i = 1; i < this.editingData.gridList.length; i++) {
+                        const gridNode = this.editingData.gridList[i].gridNode;
+                        if (gridNode) {
+                            centerPos.add(gridNode.getWorldPosition());
+                        }
+                    }
+                    const validGridCount = this.editingData.gridList.filter(grid => grid.gridNode).length;
+                    centerPos.x /= validGridCount;
+                    centerPos.y /= validGridCount;
+                }
+            }
+
+            // 放置方块到网格
+            this.editingData.gridList.forEach(grid => {
+                grid.status = CellState.FILLED;
+                grid.type = brickData.type;
+                this.gridManager.generateGrid(grid);
+            });
+
+            // 显示放置得分动画
+            this.animationManager.showScoreAnimation(
+                centerPos,
+                placedGridCount,
+                this.placementBaseScore
+            );
+
+            // 标记需要重置消除计数器
+            this.shouldResetEliminateCount = true;
+
+            // 销毁方块节点
+            if (brickData.brickNode) {
+                brickData.brickNode.destroy();
+            }
+
+            // 添加新方块到待选区
+            this.brickManager.addBrick(brickData.index);
+
+            // 检查消除
+            this.scheduleOnce(() => {
+                this.gridEliminate().then((hasElimination) => {
+                    // 如果没有消除,确保下次消除会重置计数
+                    if (!hasElimination) {
+                        this.shouldResetEliminateCount = true;
+                    }
+
+                    this.operateFlag = true;
+
+                    // 处理新手引导
+                    if (this.guideManager.getIsGuideMode()) {
+                        this.scheduleOnce(() => {
+                            this.guideManager.checkNextStep();
+                        }, 0.3);
+                    } else {
+                        // 检查游戏是否结束
+                        this.prompt(false).then(canContinue => {
+                            if (!canContinue) {
+                                this.gameOver();
+                            }
+                        });
+                    }
+                });
+            }, 0.1);
+        } else {
+            // 无法放置,将方块返回原位置
+            this.handleInvalidPlacement(brickData);
+        }
+    }
+
+    /**
+     * 处理无效放置
+     */
+    private handleInvalidPlacement(brickData: BrickData): void {
+        // 将方块添加回列表
+        this.brickManager.setBricksList([...this.brickManager.getBricksList(), brickData]);
+
+        if (brickData.brickNode) {
+            // 添加回弹动画
+            tween(brickData.brickNode)
+                .to(0.2, {
+                    worldPosition: brickData.brickInitPos,
+                    scale: new Vec3(0.6, 0.6, 0.6)
+                })
+                .call(() => {
+                    this.operateFlag = true;
+                    if (brickData.brickNode) {
+                        this.brickNode.addChild(brickData.brickNode);
+                        brickData.brickNode.setWorldPosition(brickData.brickInitPos);
+                    }
+                })
+                .start();
+        } else {
+            this.operateFlag = true;
+        }
+    }
+
+    /**
+     * 添加事件监听
+     */
+    private addEventListeners(): void {
+        oops.message.on(GameEvent.RestartGame, this.restartGame, this);
+        oops.message.on(GameEvent.DoubleSpeedOpenSuccess, this.doubleSpeedOpenSuccess, this);
+        oops.message.on(GameEvent.openView, this.openView, this);
+        oops.message.on(GameEvent.showCoinAnimation, this.showCoinAnimation, this);
+        oops.message.on(GameEvent.Resurrection, this.onResurrection, this);
+        oops.message.on(GameEvent.updateHbAndWxCoin, this.updateCoin, this);
+        oops.message.on(GameEvent.StartAutoGame, this.startAutoGame, this);
+    }
+
+    /**
+     * 初始化数据
+     */
+    private initData(): void {
+        this.operateFlag = true;
+        this.gameState = GameState.READY;
+        this.shouldResetEliminateCount = true;
+        this.currentCombo = 0;
+        this.uiManager.initData();
+    }
+
+    /**
+     * 更新金币
+     */
+    private updateCoin(): void {
+        this.uiManager.updateCoin();
+    }
+
+    /**
+     * 重启游戏
+     */
+    private restartGame(): void {
+        if (this.gameState === GameState.READY) return;
+
+        this.initData();
+        this.uiManager.setData();
+        this.initGame();
+        this.uiManager.initButtonState(this.autoPlayManager.getAutoState());
+        this.uiManager.updateWelfarePoint();
+    }
+
+    /**
+     * 开始自动游戏
+     */
+    private startAutoGame(): void {
+        this.btn_auto();
+    }
+
+    /**
+     * 显示金币动画
+     */
+    private showCoinAnimation(event: string, args: string): void {
+        const lastPos = this.moveNode.getWorldPosition();
+        const score = this.uiManager.getScore();
+
+        // 显示金币动画
+        this.animationManager.showCoinAnimation(lastPos, score, !!args);
+    }
+
+    /**
+     * 打开视图
+     */
+    private openView(event: string, args: string): void {
+        this.uiManager.openView(args);
+    }
+
+    /**
+     * 复活处理
+     */
+    private onResurrection(): void {
+        console.log("复活游戏,分数不清零");
+        // 复活逻辑实现
+    }
+
+    /**
+     * 二倍速开启成功
+     */
+    private doubleSpeedOpenSuccess(): void {
+        if (this.gameState !== GameState.PLAYING) {
+            return;
+        }
+
+        if (this.callback) {
+            this.unschedule(this.callback);
+        }
+
+        this.isDoubleSpeed = true;
+        this.animationManager.setDoubleSpeed(true, 2);
+        this.autoPlayManager.setDoubleSpeed(true);
+
+        // 设置倒计时
+        this.doubleSpeedTime = smc.game.GameModel.doubleSpeedTime || 15;
+
+        if (this.doubleSpeedTime <= 0) {
+            return;
+        }
+
+        // 如果没有开启自动,则开启
+        if (!this.autoPlayManager.getAutoState()) {
+            this.btn_auto();
+        }
+
+        // 设置倒计时回调
+        this.callback = () => {
+            if (!this.adShowingFlag && this.gameState === GameState.PLAYING) {
+                this.doubleSpeedTime--;
+                this.uiManager.updateDoubleSpeedTime(this.doubleSpeedTime);
+
+                // 时间到了
+                if (this.doubleSpeedTime <= 0) {
+                    this.lab_doubleTime.string = "二倍速";
+                    this.isDoubleSpeed = false;
+                    this.animationManager.setDoubleSpeed(false);
+                    this.autoPlayManager.setDoubleSpeed(false);
+
+                    // 再打开继续二倍速页面
+                    oops.gui.open(UIID.KeepSpeed);
+                    this.unschedule(this.callback as Function);
+                }
+            }
+        };
+
+        this.schedule(this.callback, 1);
+    }
+
+    /**
+     * 设置游戏状态
+     */
+    private setGameState(state: GameState): void {
+        this.gameState = state;
+        switch (state) {
+            case GameState.READY:
+                break;
+
+            case GameState.PLAYING:
+                break;
+
+            case GameState.PAUSED:
+                break;
+
+            case GameState.GAME_OVER:
+                // 打开游戏结束界面
+                this.autoPlayManager.setAutoState(false);
+                this.uiManager.setAutoState(false);
+                this.adShowingFlag = false;
+                break;
+
+            case GameState.GAME_PASS:
+                break;
+        }
+    }
+
+    /**
+     * 检查是否可以继续游戏
+     */
+    private prompt(tipFlag = true): Promise<boolean> {
+        // TODO: 实现提示逻辑
+        return Promise.resolve(true);
+    }
+
+    /**
+     * 游戏结束处理
+     */
+    private gameOver(): void {
+        this.setGameState(GameState.GAME_OVER);
+        console.log("游戏结束");
+        oops.gui.open(UIID.GameOver);
+    }
+
+    /**
+     * 消除格子
+     */
+    private gridEliminate(): Promise<boolean> {
+        // TODO: 实现格子消除逻辑
+        return Promise.resolve(false);
+    }
+
+    // =============== 按钮事件处理 ===============
+
+    /**
+     * 设置按钮点击
+     */
+    private btn_setting(): void {
+        this.uiManager.onSettingBtnClick();
+    }
+
+    /**
+     * 提现按钮点击
+     */
+    private btn_withdraw(): void {
+        this.uiManager.onWithdrawBtnClick();
+    }
+
+    /**
+     * 奖励按钮点击
+     */
+    private btn_award(): void {
+        this.uiManager.onAwardBtnClick();
+    }
+
+    /**
+     * 双倍速按钮点击
+     */
+    private btn_double(): void {
+        this.uiManager.onDoubleBtnClick();
+    }
+
+    /**
+     * 自动按钮点击
+     */
+    private btn_auto(): void {
+        const newState = !this.autoPlayManager.getAutoState();
+        this.autoPlayManager.setAutoState(newState);
+        this.uiManager.setAutoState(newState);
+
+        this.gameState = GameState.PLAYING;
+
+        if (newState) {
+            this.executeAutoPlace();
+        }
+    }
+
+    /**
+     * 执行自动放置
+     */
+    private executeAutoPlace(): void {
+        if (!this.autoPlayManager.getAutoState() || this.gameState !== GameState.PLAYING || this.adShowingFlag) {
+            return;
+        }
+
+        this.autoPlayManager.executeAutoPlace((success) => {
+            if (!success) {
+                // 游戏结束
+                this.autoPlayManager.setAutoState(false);
+                this.uiManager.setAutoState(false);
+                this.gameOver();
+                return;
+            }
+
+            // 消除检查
+            this.gridEliminate().then(() => {
+                this.prompt(false).then((canContinue) => {
+                    if (!canContinue) {
+                        this.gameOver();
+                    } else if (this.autoPlayManager.getAutoState()) {
+                        // 继续自动放置
+                        this.scheduleOnce(() => {
+                            this.executeAutoPlace();
+                        }, 0.4);
+                    }
+                });
+            });
+        });
+    }
+
+    /** 视图对象通过 ecs.Entity.remove(eliminateViewComp) 删除组件是触发组件处理自定义释放逻辑 */
+    reset() {
+        this.node.destroy();
+    }
+} 

+ 9 - 0
assets/script/game/view/eliminate/EliminateViewComp.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "5326478a-2c93-4154-be56-1a1dc8db4c5b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 38 - 0
assets/script/game/view/eliminate/README.md

@@ -0,0 +1,38 @@
+# 消除游戏模块重构
+
+## 重构目标
+
+将原有的`EliminateViewComp.ts`文件按照功能职责进行拆分,提高代码的可维护性和可读性。
+
+## 文件结构
+
+- `EliminateTypes.ts` - 类型定义文件,包含游戏中使用的所有接口和枚举
+- `EliminateGridManager.ts` - 网格管理器,负责处理网格相关功能
+- `EliminateBrickManager.ts` - 方块管理器,负责处理砖块相关功能
+- `EliminateAnimationManager.ts` - 动画管理器,负责处理游戏中的动画效果
+- `EliminateGuideManager.ts` - 引导管理器,负责处理新手引导功能
+- `EliminateAutoPlayManager.ts` - 自动游戏管理器,负责处理自动模式功能
+- `EliminateUIManager.ts` - UI管理器,负责处理UI交互功能
+- `EliminateViewComp.ts` - 主组件文件,协调各个管理器工作
+
+## 重构思路
+
+1. 按功能模块拆分代码,每个模块只负责自己的职责
+2. 使用依赖注入模式,主组件创建并管理各个管理器
+3. 各个管理器之间通过主组件进行通信,避免直接依赖
+4. 使用接口和类型定义增强代码的可读性和类型安全性
+
+## 待完成工作
+
+- [ ] 完善`EliminateViewComp.ts`中的`onBrickDrag`方法
+- [ ] 完善`EliminateViewComp.ts`中的`prompt`方法
+- [ ] 完善`EliminateViewComp.ts`中的`gridEliminate`方法
+- [ ] 完善`EliminateViewComp.ts`中的按钮事件绑定
+- [ ] 进一步优化各个管理器之间的通信方式
+
+## 后续优化方向
+
+1. 引入状态模式管理游戏状态
+2. 使用事件系统优化组件间通信
+3. 增加单元测试提高代码质量
+4. 提取配置数据到配置文件中,便于调整游戏参数 

+ 11 - 0
assets/script/game/view/eliminate/README.md.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.0.1",
+  "importer": "text",
+  "imported": true,
+  "uuid": "cfd95234-a25d-43e7-aa9b-73c2b5422fb4",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}