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.
186 lines
6.8 KiB
186 lines
6.8 KiB
import { _decorator, CCString, Color, Component, Graphics, Node, UITransform, v3 } from 'cc';
|
|
import { MapGrid } from './MapGrid';
|
|
const { ccclass, property, executeInEditMode } = _decorator;
|
|
|
|
@ccclass('MapGridStatusDebug')
|
|
@executeInEditMode
|
|
export class MapGridStatusDebug extends Component {
|
|
|
|
@property({ type: [Color], displayName: '状态颜色数组(按状态字段顺序)' })
|
|
colorArr: Color[] = [
|
|
new Color(0x20, 0xEC, 0x1B, 0xFF), // 20EC1B
|
|
new Color(0xFF, 0xFF, 0xFF, 0xFF), // FFFFFF
|
|
new Color(0xF3, 0x41, 0x29, 0xC8), // F34129C8
|
|
new Color(0x2B, 0xC8, 0xFC, 0xC8), // 2BC8FCC8
|
|
new Color(0xFF, 0x99, 0x00, 0xC8), // FF9900C8
|
|
new Color(0xF3, 0xD4, 0x58, 0xC8), // F3D458C8
|
|
new Color(0x00, 0x00, 0x00, 0xFF), // 000000
|
|
];
|
|
|
|
@property({ type: [CCString], displayName: '状态字段数组(可扩展)' })
|
|
statusKeys: string[] = [
|
|
'isCanWalk',
|
|
'isCanPutObstacle',
|
|
'isCanRemove',
|
|
'isCanBeThunder',
|
|
'isBestPlace',
|
|
'isFreePlace',
|
|
'isBroken',
|
|
];
|
|
|
|
@property({ displayName: '单个色块尺寸' })
|
|
blockSize: number = 8;
|
|
|
|
@property({ displayName: '色块间距' })
|
|
blockGap: number = 1;
|
|
|
|
@property({ displayName: '格子内边距X' })
|
|
insetX: number = 2;
|
|
|
|
@property({ displayName: '格子内边距Y' })
|
|
insetY: number = 2;
|
|
|
|
private _graphics: Graphics = null;
|
|
private _selfTf: UITransform = null;
|
|
private _gridRoot: Node = null;
|
|
private _grids: MapGrid[] = [];
|
|
private _gridTfs: UITransform[] = [];
|
|
private _lastMasks: number[] = [];
|
|
private _lastWorldX: number[] = [];
|
|
private _lastWorldY: number[] = [];
|
|
private _lastGridW: number[] = [];
|
|
private _lastGridH: number[] = [];
|
|
private _lastConfigSignature = '';
|
|
private _tmpWorld = v3();
|
|
private _tmpLocal = v3();
|
|
|
|
onLoad(): void {
|
|
this._graphics = this.node.getComponent(Graphics);
|
|
this._selfTf = this.node.getComponent(UITransform);
|
|
if (!this._graphics) {
|
|
this._graphics = this.node.addComponent(Graphics);
|
|
}
|
|
if (!this._selfTf) {
|
|
this._selfTf = this.node.addComponent(UITransform);
|
|
}
|
|
this.rebuildGridCache();
|
|
this.updateStatus(true);
|
|
}
|
|
|
|
protected update(dt: number): void {
|
|
this.updateStatus();
|
|
}
|
|
|
|
private rebuildGridCache() {
|
|
this._gridRoot = this.node.parent?.getChildByName("格子") || null;
|
|
this._grids = this._gridRoot ? this._gridRoot.getComponentsInChildren(MapGrid) : [];
|
|
this._gridTfs = new Array(this._grids.length);
|
|
this._lastMasks = new Array(this._grids.length);
|
|
this._lastWorldX = new Array(this._grids.length);
|
|
this._lastWorldY = new Array(this._grids.length);
|
|
this._lastGridW = new Array(this._grids.length);
|
|
this._lastGridH = new Array(this._grids.length);
|
|
for (let i = 0; i < this._grids.length; i++) {
|
|
this._gridTfs[i] = this._grids[i]?.node?.getComponent(UITransform) || null;
|
|
this._lastMasks[i] = -1;
|
|
this._lastWorldX[i] = NaN;
|
|
this._lastWorldY[i] = NaN;
|
|
this._lastGridW[i] = NaN;
|
|
this._lastGridH[i] = NaN;
|
|
}
|
|
}
|
|
|
|
private getConfigSignature() {
|
|
return `${this.statusKeys.join('|')}|${this.blockSize}|${this.blockGap}|${this.insetX}|${this.insetY}|${this.colorArr.length}`;
|
|
}
|
|
|
|
private getGridMask(grid: MapGrid) {
|
|
let mask = 0;
|
|
const maxBits = Math.min(31, this.statusKeys.length);
|
|
for (let i = 0; i < maxBits; i++) {
|
|
if ((grid as any)[this.statusKeys[i]]) {
|
|
mask |= (1 << i);
|
|
}
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
updateStatus(force = false) {
|
|
if (!this._graphics || !this._selfTf) return;
|
|
if (!this._gridRoot || !this._gridRoot.isValid) {
|
|
this.rebuildGridCache();
|
|
}
|
|
if (this._grids.length <= 0 || this.statusKeys.length <= 0) {
|
|
this._graphics.clear();
|
|
return;
|
|
}
|
|
|
|
const configSignature = this.getConfigSignature();
|
|
let dirty = force || (configSignature !== this._lastConfigSignature);
|
|
|
|
const count = this.statusKeys.length;
|
|
const blockW = this.blockSize;
|
|
const blockH = this.blockSize;
|
|
const step = blockW + this.blockGap;
|
|
|
|
for (let i = 0; i < this._grids.length; i++) {
|
|
const grid = this._grids[i];
|
|
if (!grid || !grid.node?.isValid) continue;
|
|
const gridTf = this._gridTfs[i];
|
|
if (!gridTf) continue;
|
|
const world = grid.node.worldPosition;
|
|
const mask = this.getGridMask(grid);
|
|
const gridW = gridTf.width;
|
|
const gridH = gridTf.height;
|
|
if (mask !== this._lastMasks[i]
|
|
|| world.x !== this._lastWorldX[i]
|
|
|| world.y !== this._lastWorldY[i]
|
|
|| gridW !== this._lastGridW[i]
|
|
|| gridH !== this._lastGridH[i]) {
|
|
dirty = true;
|
|
}
|
|
this._lastMasks[i] = mask;
|
|
this._lastWorldX[i] = world.x;
|
|
this._lastWorldY[i] = world.y;
|
|
this._lastGridW[i] = gridW;
|
|
this._lastGridH[i] = gridH;
|
|
}
|
|
|
|
if (!dirty) return;
|
|
|
|
this._graphics.clear();
|
|
this._lastConfigSignature = configSignature;
|
|
|
|
for (let i = 0; i < this._grids.length; i++) {
|
|
const grid = this._grids[i];
|
|
if (!grid || !grid.node?.isValid) continue;
|
|
const gridTf = this._gridTfs[i];
|
|
if (!gridTf) continue;
|
|
const world = grid.node.worldPosition;
|
|
this._tmpWorld.set(world.x, world.y, world.z);
|
|
this._selfTf.convertToNodeSpaceAR(this._tmpWorld, this._tmpLocal);
|
|
const gridW = gridTf.width;
|
|
const gridH = gridTf.height;
|
|
const startX = this._tmpLocal.x - gridW / 2 + this.insetX;
|
|
const startY = this._tmpLocal.y + gridH / 2 - this.insetY - blockH;
|
|
const contentW = Math.max(1, gridW - this.insetX * 2);
|
|
const maxCols = Math.max(1, Math.floor((contentW + this.blockGap) / step));
|
|
const mask = this._lastMasks[i];
|
|
|
|
for (let j = 0; j < count; j++) {
|
|
const value = j < 31 ? ((mask & (1 << j)) !== 0) : !!(grid as any)[this.statusKeys[j]];
|
|
if (!value) continue;
|
|
const color = this.colorArr[j] || this.colorArr[this.colorArr.length - 1] || Color.WHITE;
|
|
const col = j % maxCols;
|
|
const row = Math.floor(j / maxCols);
|
|
const x = startX + col * step;
|
|
const y = startY - row * step;
|
|
this._graphics.fillColor = color;
|
|
this._graphics.rect(x, y, blockW, blockH);
|
|
this._graphics.fill();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|