You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
AdLike2048/assets/script/battle/view/CombatHaveTextListView.ts

113 lines
3.7 KiB

import { instantiate, Layout, Node } from 'cc';
import { Weapon2TileType, type MapTileBoard, type MapTileRecord } from 'db://assets/mx/module/merge';
import type { MapManager } from '../map/legacy/MapManager';
import { WeaponComposeConfigProvider } from '../bag/WeaponComposeConfigProvider';
import { TextGrid } from './TextGrid';
import { buildTextGridEntityData } from '../combat/TowerQueryService';
interface PlacedTextEntry {
gridIndex: number;
tile: MapTileRecord;
}
/**
* 战斗阶段左侧「已放置文字」列表(ui_haveTextList)
* 以 ui_haveTextList 的第一个子节点为模版克隆展示。
*/
export class CombatHaveTextListView {
private _root: Node | null = null;
private _template: Node | null = null;
private _items: Node[] = [];
bind(root: Node): void {
this.unbind();
this._root = root;
this._template = root.children[0] ?? null;
if (this._template) {
this._template.active = false;
}
this._ensureLayout();
}
unbind(): void {
this._clearItems();
this._root = null;
this._template = null;
}
/** 根据当前地图字块刷新列表 */
refresh(map: MapManager, board: MapTileBoard | null): void {
this._clearItems();
if (!this._root?.isValid || !this._template?.isValid || !board) return;
WeaponComposeConfigProvider.instance.load();
const entries = this._collectTextTiles(map, board);
for (const entry of entries) {
const item = instantiate(this._template);
item.parent = this._root;
item.active = true;
this._applyTile(item, entry);
this._items.push(item);
}
this._root.getComponent(Layout)?.updateLayout();
}
setVisible(visible: boolean): void {
if (this._root?.isValid) {
this._root.active = visible;
}
}
private _collectTextTiles(map: MapManager, board: MapTileBoard): PlacedTextEntry[] {
const entries: PlacedTextEntry[] = [];
board.forEachTile((gridIndex, tile) => {
const type = WeaponComposeConfigProvider.instance.getWeapon2Type(tile.weapon2Id);
if (type !== Weapon2TileType.Single && type !== Weapon2TileType.Combo) return;
entries.push({ gridIndex, tile });
});
entries.sort((a, b) => {
const ga = map.getMapGridByIndex(a.gridIndex);
const gb = map.getMapGridByIndex(b.gridIndex);
if (!ga || !gb) return a.gridIndex - b.gridIndex;
if (ga.Row !== gb.Row) return ga.Row - gb.Row;
return ga.Col - gb.Col;
});
return entries;
}
private _applyTile(item: Node, entry: PlacedTextEntry): void {
const textNode = item.getChildByName('textGrid') ?? item.children[0];
if (!textNode?.isValid) return;
const comp = textNode.getComponent(TextGrid) ?? textNode.addComponent(TextGrid);
const { tile, gridIndex } = entry;
const entity = buildTextGridEntityData(
{ kind: 'map', gridIndex },
tile,
{ player: gg.game.localPlayer },
);
if (!entity) return;
comp.setData(entity);
comp.enableDrag(false);
}
private _ensureLayout(): void {
if (!this._root?.isValid) return;
let layout = this._root.getComponent(Layout);
if (!layout) {
layout = this._root.addComponent(Layout);
layout.type = Layout.Type.HORIZONTAL;
layout.resizeMode = Layout.ResizeMode.CONTAINER;
layout.spacingX = 8;
}
}
private _clearItems(): void {
for (const item of this._items) {
if (item?.isValid) item.destroy();
}
this._items.length = 0;
}
}