Browse Source

方块合成

181404010226 5 months ago
parent
commit
4f80c1a24b

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0003/tx003.atlas

@@ -1,5 +1,5 @@
 
-tx001.png
+tx003.png
 size: 119, 311
 format: RGBA8888
 filter: Linear, Linear

+ 9 - 0
assets/scripts/AnimationSystem.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "c932ae2e-235d-47c1-9daf-5f2bc9690850",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 151 - 1
assets/scripts/CombatSystem/BlockManager.ts

@@ -2,6 +2,7 @@ import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec
 import { ConfigManager, WeaponConfig } from '../Core/ConfigManager';
 import { SaveDataManager } from '../LevelSystem/SaveDataManager';
 import { LevelSessionManager } from '../Core/LevelSessionManager';
+import { sp } from 'cc';
 const { ccclass, property } = _decorator;
 
 @ccclass('BlockManager')
@@ -487,7 +488,17 @@ export class BlockManager extends Component {
         } else if (this.tryPlaceBlockToGrid(this.currentDragBlock)) {
             this.handleSuccessfulPlacement(startLocation);
         } else {
-            this.returnBlockToOriginalPosition();
+            // 放置失败,尝试直接与重叠方块合成
+            if (this.tryMergeOnOverlap(this.currentDragBlock)) {
+                // 合成成功时,若来自 kuang 则扣费
+                if (startLocation !== 'grid') {
+                    const price = this.getBlockPrice(this.currentDragBlock);
+                    this.deductPlayerCoins(price);
+                }
+                // 当前拖拽块已被销毁(合并时),无需复位
+            } else {
+                this.returnBlockToOriginalPosition();
+            }
         }
     }
     
@@ -542,6 +553,9 @@ export class BlockManager extends Component {
             if (this.gameStarted) {
                 this.addLockedVisualHint(this.currentDragBlock);
             }
++
++            // 检查并执行合成
++            this.tryMergeBlock(this.currentDragBlock);
         } else {
             if (this.deductPlayerCoins(price)) {
                 this.clearTempStoredOccupiedGrids(this.currentDragBlock);
@@ -562,6 +576,9 @@ export class BlockManager extends Component {
                 if (this.gameStarted) {
                     this.addLockedVisualHint(this.currentDragBlock);
                 }
++
++                // 检查并执行合成
++                this.tryMergeBlock(this.currentDragBlock);
             } else {
                 this.returnBlockToOriginalPosition();
             }
@@ -1128,4 +1145,137 @@ export class BlockManager extends Component {
     private onRefreshButtonClicked() {
         this.refreshBlocks();
     }
+
+    /* =================== 合成逻辑 =================== */
+
+    private readonly rarityOrder: string[] = ['common','uncommon','rare','epic','legendary'];
+
+    /** 检查当前放置的方块能否与相同稀有度的方块合成 */
+    private tryMergeBlock(block: Node) {
+        const rarity = this.getBlockRarity(block);
+        if (!rarity) return;
+
+        // 在 placedBlocksContainer 中寻找与之重叠且同稀有度的其他方块
+        if (!this.placedBlocksContainer) return;
+
+        const weaponId = this.getBlockWeaponId(block);
+        const blockBB = this.getWorldAABB(block);
+        for (const other of this.placedBlocksContainer.children) {
+            if (other === block) continue;
+            if (this.getBlockRarity(other) !== rarity) continue;
+            if (this.getBlockWeaponId(other) !== weaponId) continue;
+
+            const otherBB = this.getWorldAABB(other);
+            if (this.rectIntersects(blockBB, otherBB)) {
+                // 找到合成目标
+                this.performMerge(block, other, rarity);
+                break;
+            }
+        }
+    }
+
+    private performMerge(target: Node, source: Node, rarity: string) {
+        // 隐藏价格标签并处理 db 关联
+        this.hidePriceLabel(source);
+        const srcDb = source['dbNode'];
+        if (srcDb) srcDb.active = false;
+
+        // 销毁被合并方块
+        source.destroy();
+
+        // 升级稀有度
+        const nextRarity = this.getNextRarity(rarity);
+        if (nextRarity) {
+            this.setBlockRarityColor(target, nextRarity);
+            // 如果有武器配置,也升级
+            const cfg = this.blockWeaponConfigs.get(target);
+            if (cfg) {
+                cfg.rarity = nextRarity;
+                this.blockWeaponConfigs.set(target, cfg);
+            }
+        }
+
+        // 播放烟雾动画
+        const worldPos = new Vec3();
+        target.getWorldPosition(worldPos);
+        this.spawnMergeSmoke(worldPos);
+
+        // 递归检查是否还能继续合成
+        if (nextRarity) {
+            this.tryMergeBlock(target);
+        }
+    }
+
+    private getBlockRarity(block: Node): string | null {
+        const cfg = this.blockWeaponConfigs.get(block);
+        if (cfg) return cfg.rarity;
+        // fallback based on sprite color maybe
+        return null;
+    }
+
+    private getNextRarity(rarity: string): string | null {
+        const idx = this.rarityOrder.indexOf(rarity);
+        if (idx === -1 || idx >= this.rarityOrder.length - 1) return null;
+        return this.rarityOrder[idx + 1];
+    }
+
+    private getWorldAABB(node: Node): Rect {
+        const ui = node.getComponent(UITransform);
+        if (!ui) return new Rect();
+        const pos = node.worldPosition;
+        const width = ui.width;
+        const height = ui.height;
+        return new Rect(pos.x - width/2, pos.y - height/2, width, height);
+    }
+
+    private rectIntersects(a: Rect, b: Rect): boolean {
+        return a.x < b.x + b.width &&
+               a.x + a.width > b.x &&
+               a.y < b.y + b.height &&
+               a.y + a.height > b.y;
+    }
+
+    /** 生成烟雾特效 */
+    private spawnMergeSmoke(worldPos: Vec3) {
+        const path = 'Animation/WeaponTx/tx0003/tx0003';
+        resources.load(path, sp.SkeletonData, (err, sData: sp.SkeletonData) => {
+            if (err || !sData) {
+                console.warn('加载合成烟雾动画失败', err);
+                return;
+            }
+            const node = new Node('MergeSmoke');
+            const skeleton = node.addComponent(sp.Skeleton);
+            skeleton.skeletonData = sData;
+            skeleton.premultipliedAlpha = false;
+            skeleton.setAnimation(0, 'animation', false);
+            skeleton.setCompleteListener(() => node.destroy());
+
+            const canvas = find('Canvas');
+            if (canvas) canvas.addChild(node);
+            node.setWorldPosition(worldPos);
+        });
+    }
+
+    /** 在放置失败时尝试与现有方块进行合成 */
+    private tryMergeOnOverlap(draggedBlock: Node): boolean {
+        if (!this.placedBlocksContainer) return false;
+        const rarity = this.getBlockRarity(draggedBlock);
+        if (!rarity) return false;
+
+        const weaponId = this.getBlockWeaponId(draggedBlock);
+        const dragBB = this.getWorldAABB(draggedBlock);
+        for (const target of this.placedBlocksContainer.children) {
+            if (target === draggedBlock) continue;
+            if (this.getBlockRarity(target) !== rarity) continue;
+            if (this.getBlockWeaponId(target) !== weaponId) continue;
+
+            const targetBB = this.getWorldAABB(target);
+            if (this.rectIntersects(dragBB, targetBB)) {
+                // 执行合并:目标保留,拖拽方块销毁
+                this.performMerge(target, draggedBlock, rarity);
+                return true;
+            }
+        }
+        return false;
+    }
 }