|
|
@@ -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;
|
|
|
+ }
|
|
|
}
|