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.
645 lines
23 KiB
645 lines
23 KiB
import { _decorator, assetManager, Color, Component, instantiate, isValid, Node, Sprite, SpriteFrame, tween, Tween } from 'cc';
|
|
import { GBundle } from '../../../game/ConfigRes';
|
|
import {
|
|
hideGridFallSpine,
|
|
hideGridOpenSpine,
|
|
hideGridUpgradeSpine,
|
|
playGridFallSpineDeferred,
|
|
playGridOpenSpineDeferred,
|
|
playGridUpgradeSpineDeferred,
|
|
} from '../../view/GridUpgradeSpineEffect';
|
|
import { DEV, EDITOR } from 'cc/env';
|
|
const { ccclass, property, executeInEditMode } = _decorator;
|
|
|
|
/** 拖拽引导:可走格被阻挡时的红色 tint */
|
|
const BLOCKED_WALK_TINT = new Color(255, 96, 96, 255);
|
|
/** 铲开挖:格子 dig 遮罩 fallback 渐隐时长(秒;正常走 Spine timeScale 推算) */
|
|
const OPEN_GRID_FILL_DURATION_SEC = 1.2;
|
|
|
|
@ccclass('MapGrid')
|
|
@executeInEditMode(true)
|
|
export class MapGrid extends Component {
|
|
@property({ displayName: '是否可以通行' })
|
|
get isCanWalk(): boolean {
|
|
return this._isCanWalk;
|
|
}
|
|
set isCanWalk(value: boolean) {
|
|
this._isCanWalk = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isCanWalk: boolean = true;
|
|
|
|
@property({ displayName: '是否可放置文字' })
|
|
get isCanPutText(): boolean {
|
|
return this._isCanPutText;
|
|
}
|
|
set isCanPutText(value: boolean) {
|
|
this._isCanPutText = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isCanPutText: boolean = false;
|
|
|
|
@property({ displayName: '是否可摆放格子' })
|
|
get isCanPutGrid(): boolean {
|
|
return this._isCanPutGrid;
|
|
}
|
|
set isCanPutGrid(value: boolean) {
|
|
this._isCanPutGrid = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isCanPutGrid: boolean = true;
|
|
|
|
/**
|
|
* 是否参与解锁。
|
|
* 解锁区域 ID 大于 0 时按区域依次解锁。
|
|
*/
|
|
@property({ displayName: '是否可被解锁' })
|
|
get isCanBeDig(): boolean {
|
|
return this._isCanBeDig;
|
|
}
|
|
set isCanBeDig(value: boolean) {
|
|
this._isCanBeDig = value;
|
|
this.updateGrid();
|
|
this._refreshSiblingUnlockSkin();
|
|
}
|
|
@property
|
|
private _isCanBeDig: boolean = false;
|
|
|
|
/** 解锁区域 ID。同一 ID 的格子一起解锁,必须先完成较小的 ID。条件读关卡表 unlockland。 */
|
|
@property({ displayName: '解锁区域ID' })
|
|
get unlockAreaId(): number {
|
|
return this._unlockAreaId;
|
|
}
|
|
set unlockAreaId(value: number) {
|
|
this._unlockAreaId = value;
|
|
this.updateGrid();
|
|
this._refreshSiblingUnlockSkin();
|
|
}
|
|
@property
|
|
private _unlockAreaId = 0;
|
|
|
|
/** 当前正在解锁的区域(由 MapAreaUnlock 写入) */
|
|
get waitingUnlock(): boolean {
|
|
return this._waitingUnlock;
|
|
}
|
|
set waitingUnlock(value: boolean) {
|
|
if (this._waitingUnlock === value) return;
|
|
this._waitingUnlock = value;
|
|
this.updateGrid();
|
|
}
|
|
private _waitingUnlock = false;
|
|
|
|
/**
|
|
* 未解锁的区域格:勾选可解锁且区域 ID 大于 0,还不能放文字。
|
|
*/
|
|
get isAreaUnlock(): boolean {
|
|
return this._isCanBeDig && this._unlockAreaId > 0 && !this._isCanPutText && !this._isCanWalk;
|
|
}
|
|
|
|
|
|
get isCanRemove(): boolean {
|
|
return this._isCanRemove;
|
|
}
|
|
set isCanRemove(value: boolean) {
|
|
this._isCanRemove = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isCanRemove: boolean = false;
|
|
|
|
@property({ displayName: '是否可以被雷击' })
|
|
get isCanBeThunder(): boolean {
|
|
return this._isCanBeThunder;
|
|
}
|
|
set isCanBeThunder(value: boolean) {
|
|
this._isCanBeThunder = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isCanBeThunder: boolean = false;
|
|
|
|
//@property({ displayName: '是否最佳摆放点' })
|
|
get isBestPlace(): boolean {
|
|
return this._isBestPlace;
|
|
}
|
|
set isBestPlace(value: boolean) {
|
|
this._isBestPlace = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isBestPlace = false;
|
|
|
|
/** 是否是免费推荐点 */
|
|
//@property({ displayName: '是否免费推荐点' })
|
|
get isFreePlace(): boolean {
|
|
return this._isFreePlace;
|
|
}
|
|
set isFreePlace(value: boolean) {
|
|
this._isFreePlace = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _isFreePlace = false;
|
|
|
|
/** 阵营区域ID
|
|
* 该ID可用于多种战斗模式,策划会根据战斗模式需求配置对应的地图和关卡数据,比如:
|
|
* 1.普通闯关模式和部分副本模式只需要一个阵营,所用到的地图就只会配置1一个阵营ID
|
|
* 2.PVP、PVE副本和其他特殊副本会配置多个阵营ID。
|
|
* 3.正常情况下,普通模式和PVE模式1代表己方,2代表敌方。
|
|
*/
|
|
@property({ displayName: '阵营区域ID' })
|
|
get CampAreaID(): number {
|
|
return this._CampAreaID;
|
|
}
|
|
set CampAreaID(value: number) {
|
|
this._CampAreaID = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _CampAreaID = 1;
|
|
|
|
/**
|
|
* 玩家主区域 ID(与阵营区域 ID 独立)。
|
|
* 阵营格可跨区域;本字段只表示该格属于哪边主区域。
|
|
* 当前仅万箭齐发用:只选己方区域内的敌方阵营通行格。
|
|
*/
|
|
@property({ displayName: '区域ID' })
|
|
get AreaID(): number {
|
|
return this._AreaID;
|
|
}
|
|
set AreaID(value: number) {
|
|
this._AreaID = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _AreaID = 1;
|
|
|
|
/**怪物移速倍速 */
|
|
@property({ displayName: '怪物移速倍速' })
|
|
get MonsterSpeed(): number {
|
|
return this._MonsterSpeed;
|
|
}
|
|
set MonsterSpeed(value: number) {
|
|
this._MonsterSpeed = value;
|
|
this.updateGrid();
|
|
}
|
|
@property
|
|
private _MonsterSpeed = 1;
|
|
|
|
/** 动态推荐点已占用(由 MapManager.updateRecommendPoints 设置) */
|
|
ShowGuidePos = false;
|
|
|
|
/** 蜘蛛精蛛网占用(禁止 type3 放置) */
|
|
hasSpiderWeb = false;
|
|
|
|
@property({ type: SpriteFrame })
|
|
walkSprite: SpriteFrame = null;
|
|
@property({ type: SpriteFrame })
|
|
putSprite: SpriteFrame = null;
|
|
@property({ type: SpriteFrame })
|
|
digSprite: SpriteFrame = null;
|
|
@property({ type: SpriteFrame })
|
|
waitUnlockedSprite: SpriteFrame = null;
|
|
|
|
/**是否是引导状态(拖拽时可落子格:仅控制 addIcon 绿色加号) */
|
|
get isGuideStatus(): boolean {
|
|
return this._isGuideStatus;
|
|
}
|
|
set isGuideStatus(value: boolean) {
|
|
this._isGuideStatus = value;
|
|
if (value) this._isBlockedGuideStatus = false;
|
|
this.updateAddIcon();
|
|
}
|
|
private _isGuideStatus: boolean = false;
|
|
|
|
/** 拖拽引导:不可落子但相关的可走格(仅 type3 红底,不显示加号) */
|
|
get isBlockedGuideStatus(): boolean {
|
|
return this._isBlockedGuideStatus;
|
|
}
|
|
set isBlockedGuideStatus(value: boolean) {
|
|
this._isBlockedGuideStatus = value;
|
|
if (value) this._isGuideStatus = false;
|
|
this.updateAddIcon();
|
|
}
|
|
private _isBlockedGuideStatus = false;
|
|
|
|
/**
|
|
* 运行时显示可走格底图(与编辑器 isCanWalk + walkSprite 一致)。
|
|
* 拖拽时由 MapDragGuideHelper 仅对 type3 可落子可走格打开。
|
|
*/
|
|
get showWalkSprite(): boolean {
|
|
return this._showWalkSprite;
|
|
}
|
|
set showWalkSprite(value: boolean) {
|
|
if (this._showWalkSprite === value) return;
|
|
this._showWalkSprite = value;
|
|
if (value) this._showBlockedWalkSprite = false;
|
|
this.updateGrid();
|
|
}
|
|
private _showWalkSprite = false;
|
|
|
|
/** 拖拽引导:type3 不可落子的可走格(walkSprite 红色 tint) */
|
|
get showBlockedWalkSprite(): boolean {
|
|
return this._showBlockedWalkSprite;
|
|
}
|
|
set showBlockedWalkSprite(value: boolean) {
|
|
if (this._showBlockedWalkSprite === value) return;
|
|
this._showBlockedWalkSprite = value;
|
|
if (value) this._showWalkSprite = false;
|
|
this.updateGrid();
|
|
}
|
|
private _showBlockedWalkSprite = false;
|
|
|
|
/** 拖拽悬停选中(仅当前目标格显示 select 节点) */
|
|
get isSelectStatus(): boolean {
|
|
return this._isSelectStatus;
|
|
}
|
|
set isSelectStatus(value: boolean) {
|
|
this._isSelectStatus = value;
|
|
if (value) this._isRedSelectStatus = false;
|
|
this.updateSelect();
|
|
}
|
|
private _isSelectStatus = false;
|
|
|
|
/** 拖拽悬停不可放置格(显示 redSelect) */
|
|
get isRedSelectStatus(): boolean {
|
|
return this._isRedSelectStatus;
|
|
}
|
|
set isRedSelectStatus(value: boolean) {
|
|
this._isRedSelectStatus = value;
|
|
if (value) this._isSelectStatus = false;
|
|
this.updateSelect();
|
|
}
|
|
private _isRedSelectStatus = false;
|
|
|
|
|
|
/** 行 */
|
|
Row = 0;
|
|
/** 列 */
|
|
Col = 0;
|
|
/** 网格索引 */
|
|
Index = 0;
|
|
|
|
statusSprite: Sprite = null;
|
|
/** 开挖遮罩(digSprite + fillRange,盖在 statusSprite 之上) */
|
|
iconNode: Node | null = null;
|
|
iconSprite: Sprite | null = null;
|
|
addIcon: Node = null;
|
|
addIconSprite: Sprite | null = null;
|
|
private _addIconGreenFrame: SpriteFrame | null = null;
|
|
selectNode: Node = null;
|
|
redSelectNode: Node | null = null;
|
|
/** openSpine 是否已播完 */
|
|
private _openSpineDone = false;
|
|
/** fillRange 渐隐是否已播完 */
|
|
private _openFillDone = false;
|
|
/** dig 遮罩 fill 渐隐是否进行中(rebuild 可能停 tween 却不清遮罩) */
|
|
private _openFillPlaying = false;
|
|
/** 封格 dig 遮罩 fill 0→1 是否进行中 */
|
|
private _sealFillCoverPlaying = false;
|
|
/** playOpenEffect 完成回调 */
|
|
private _openEffectComplete: (() => void) | null = null;
|
|
|
|
protected onLoad(): void {
|
|
this.statusSprite = this.node.getComponent(Sprite) || this.node.addComponent(Sprite);
|
|
// 格子坐标由预制体绝对定位;禁止 TRIMMED/RAW 随 spriteFrame 改 contentSize,否则父节点 Layout 会重排整图
|
|
this.statusSprite.sizeMode = Sprite.SizeMode.CUSTOM;
|
|
this.statusSprite.type = Sprite.Type.SIMPLE;
|
|
this.iconNode = this.node.getChildByName('icon');
|
|
this.iconSprite = this.iconNode?.getComponent(Sprite) ?? null;
|
|
if (this.iconSprite?.isValid) {
|
|
this.iconSprite.sizeMode = Sprite.SizeMode.CUSTOM;
|
|
}
|
|
if (this.iconNode?.isValid) this.iconNode.active = false;
|
|
this.addIcon = this.node.getChildByName('addIcon');
|
|
this.addIconSprite = this.addIcon?.getComponent(Sprite) ?? null;
|
|
this._addIconGreenFrame = this.addIconSprite?.spriteFrame ?? null;
|
|
this.selectNode = this.node.getChildByName('select');
|
|
this.redSelectNode = this.node.getChildByName('redSelect');
|
|
hideGridUpgradeSpine(this.node);
|
|
hideGridFallSpine(this.node);
|
|
hideGridOpenSpine(this.node);
|
|
}
|
|
|
|
/** 合成/升级成功时播放 spine「升级效果」,播完自动隐藏 */
|
|
playUpgradeEffect(): void {
|
|
playGridUpgradeSpineDeferred(this.node);
|
|
}
|
|
|
|
/** 文字落到空格时播放 fallSpine「animation」,播完自动隐藏 */
|
|
playFallEffect(): void {
|
|
playGridFallSpineDeferred(this.node);
|
|
}
|
|
|
|
/** 未开启格开挖:openSpine 冒烟 + dig 遮罩 fillRange 1→0(并行) */
|
|
playOpenEffect(onComplete?: () => void): void {
|
|
this._openEffectComplete = onComplete ?? null;
|
|
this._openSpineDone = false;
|
|
this._openFillDone = false;
|
|
this.updateGrid();
|
|
this._playOpenGridFillReveal(true);
|
|
playGridOpenSpineDeferred(this.node, this._onOpenSpineRevealDone.bind(this));
|
|
}
|
|
|
|
/**
|
|
* 开挖链:铲 Spine 结束后播 openSpine 冒烟(onComplete 可选,仅表示冒烟播完)。
|
|
*/
|
|
playOpenSpineSmoke(onComplete?: () => void): void {
|
|
this._openEffectComplete = onComplete ?? null;
|
|
this.updateGrid();
|
|
playGridOpenSpineDeferred(this.node, this._onOpenSpineSmokeDone.bind(this));
|
|
}
|
|
|
|
/** openSpine 冒烟播完(playOpenEffect 并行链) */
|
|
private _onOpenSpineRevealDone(): void {
|
|
this._openSpineDone = true;
|
|
this._tryFinishOpenEffect();
|
|
}
|
|
|
|
/** openSpine 冒烟播完(开挖链) */
|
|
private _onOpenSpineSmokeDone(): void {
|
|
const cb = this._openEffectComplete;
|
|
this._openEffectComplete = null;
|
|
this.updateGrid();
|
|
cb?.();
|
|
}
|
|
|
|
/** dig 遮罩 fillRange 渐隐播完 */
|
|
private _onOpenGridFillRevealDone(finishOpenEffect: boolean): void {
|
|
this._openFillPlaying = false;
|
|
this._clearOpenGridFillOverlay();
|
|
if (!finishOpenEffect) return;
|
|
this._openFillDone = true;
|
|
this._tryFinishOpenEffect();
|
|
}
|
|
|
|
/** 冒烟与 fill 均结束后回调 */
|
|
private _tryFinishOpenEffect(): void {
|
|
if (!this._openSpineDone || !this._openFillDone) return;
|
|
const cb = this._openEffectComplete;
|
|
this._openEffectComplete = null;
|
|
this.updateGrid();
|
|
cb?.();
|
|
}
|
|
|
|
/**
|
|
* 千里眼封格:Put 皮上叠 dig 遮罩,fillRange 0→1。
|
|
* @param durationSec 渐显时长;省略则用与开挖相同的 fallback
|
|
*/
|
|
playSealDigFillCover(durationSec?: number): void {
|
|
const overlay = this.iconSprite;
|
|
const overlayNode = this.iconNode;
|
|
if (!overlay?.isValid || !overlayNode?.isValid || !this.digSprite || !this.putSprite) {
|
|
this.updateGrid();
|
|
return;
|
|
}
|
|
const fillSec = durationSec != null && durationSec > 0
|
|
? durationSec
|
|
: OPEN_GRID_FILL_DURATION_SEC;
|
|
Tween.stopAllByTarget(overlay);
|
|
this._sealFillCoverPlaying = true;
|
|
if (this.statusSprite?.isValid) this.statusSprite.spriteFrame = this.putSprite;
|
|
overlayNode.active = true;
|
|
overlayNode.setSiblingIndex(this.node.children.length - 1);
|
|
overlay.spriteFrame = this.digSprite;
|
|
overlay.type = Sprite.Type.FILLED;
|
|
overlay.fillType = Sprite.FillType.HORIZONTAL;
|
|
overlay.fillStart = 0;
|
|
overlay.fillRange = 0;
|
|
tween(overlay)
|
|
.to(fillSec, { fillRange: 1 })
|
|
.call(this._onSealDigFillCoverDone.bind(this))
|
|
.start();
|
|
}
|
|
|
|
/** 封格遮罩渐显结束:露出可开挖格 */
|
|
private _onSealDigFillCoverDone(): void {
|
|
this._sealFillCoverPlaying = false;
|
|
this._clearOpenGridFillOverlay();
|
|
this.updateGrid();
|
|
}
|
|
|
|
/** 播放 dig 遮罩 fillRange 1→0,露出下方可放置格 */
|
|
private _playOpenGridFillReveal(finishOpenEffect: boolean, durationSec?: number): void {
|
|
const overlay = this.iconSprite;
|
|
const overlayNode = this.iconNode;
|
|
if (!overlay?.isValid || !overlayNode?.isValid || !this.digSprite) {
|
|
this._onOpenGridFillRevealDone(finishOpenEffect);
|
|
return;
|
|
}
|
|
|
|
const fillSec = durationSec != null && durationSec > 0
|
|
? durationSec
|
|
: OPEN_GRID_FILL_DURATION_SEC;
|
|
|
|
Tween.stopAllByTarget(overlay);
|
|
this._openFillPlaying = true;
|
|
overlayNode.active = true;
|
|
overlayNode.setSiblingIndex(this.node.children.length - 1);
|
|
overlay.spriteFrame = this.digSprite;
|
|
overlay.type = Sprite.Type.FILLED;
|
|
overlay.fillType = Sprite.FillType.HORIZONTAL;
|
|
overlay.fillStart = 0;
|
|
overlay.fillRange = 1;
|
|
|
|
tween(overlay)
|
|
.to(fillSec, { fillRange: 0 })
|
|
.call(this._onOpenGridFillRevealDone.bind(this, finishOpenEffect))
|
|
.start();
|
|
}
|
|
|
|
/**
|
|
* 从当前 fillRange 续播 dig 遮罩渐隐(rebuild 打断 tween 后用)。
|
|
* @param finishOpenEffect 是否计入 playOpenEffect 完成条件
|
|
* @param fromRange 起始 fillRange
|
|
*/
|
|
private _resumeOpenGridFillReveal(finishOpenEffect: boolean, fromRange: number): void {
|
|
const overlay = this.iconSprite;
|
|
const overlayNode = this.iconNode;
|
|
if (!overlay?.isValid || !overlayNode?.isValid || !this.digSprite) {
|
|
this._onOpenGridFillRevealDone(finishOpenEffect);
|
|
return;
|
|
}
|
|
const from = Math.max(0, Math.min(1, fromRange));
|
|
if (from <= 0.01) {
|
|
this._onOpenGridFillRevealDone(finishOpenEffect);
|
|
return;
|
|
}
|
|
Tween.stopAllByTarget(overlay);
|
|
this._openFillPlaying = true;
|
|
overlayNode.active = true;
|
|
overlayNode.setSiblingIndex(this.node.children.length - 1);
|
|
overlay.spriteFrame = this.digSprite;
|
|
overlay.type = Sprite.Type.FILLED;
|
|
overlay.fillType = Sprite.FillType.HORIZONTAL;
|
|
overlay.fillStart = 0;
|
|
overlay.fillRange = from;
|
|
const duration = OPEN_GRID_FILL_DURATION_SEC * from;
|
|
tween(overlay)
|
|
.to(duration, { fillRange: 0 })
|
|
.call(this._onOpenGridFillRevealDone.bind(this, finishOpenEffect))
|
|
.start();
|
|
}
|
|
|
|
/** 清理开挖遮罩 tween 与节点 */
|
|
private _clearOpenGridFillOverlay(): void {
|
|
this._openFillPlaying = false;
|
|
this._sealFillCoverPlaying = false;
|
|
const overlay = this.iconSprite;
|
|
if (overlay?.isValid) {
|
|
Tween.stopAllByTarget(overlay);
|
|
overlay.fillRange = 0;
|
|
overlay.type = Sprite.Type.SIMPLE;
|
|
overlay.spriteFrame = null;
|
|
}
|
|
if (this.iconNode?.isValid) {
|
|
this.iconNode.active = false;
|
|
}
|
|
}
|
|
|
|
/** 中断/跳过开挖表现时清理 openSpine 与 dig 遮罩(AI Dig→Put 必调) */
|
|
clearDigOpenFx(): void {
|
|
this._abortOpenEffect();
|
|
this.updateGrid();
|
|
}
|
|
|
|
/** 中断进行中的开挖表现 */
|
|
private _abortOpenEffect(): void {
|
|
this._clearOpenGridFillOverlay();
|
|
hideGridOpenSpine(this.node);
|
|
this._openSpineDone = true;
|
|
this._openFillDone = true;
|
|
this._openEffectComplete = null;
|
|
}
|
|
|
|
protected onEnable(): void {
|
|
this.updateGrid();
|
|
}
|
|
|
|
protected onDisable(): void {
|
|
this._abortOpenEffect();
|
|
if (this.statusSprite) this.statusSprite.spriteFrame = null;
|
|
}
|
|
|
|
updateGrid() {
|
|
if (this.statusSprite) {
|
|
if (this.isCanWalk) {
|
|
if (this._showWalkSprite) {
|
|
this.statusSprite.spriteFrame = this.walkSprite;
|
|
this.statusSprite.color = Color.WHITE;
|
|
} else if (this._showBlockedWalkSprite) {
|
|
this.statusSprite.spriteFrame = this.walkSprite;
|
|
this.statusSprite.color = BLOCKED_WALK_TINT;
|
|
} else {
|
|
this.statusSprite.spriteFrame = EDITOR ? this.walkSprite : null;
|
|
this.statusSprite.color = Color.WHITE;
|
|
}
|
|
}
|
|
else if (this.isCanPutText && !this.isCanWalk) {
|
|
// 解锁区域已开:Dig 皮;普通可放置:Put 皮
|
|
this.statusSprite.spriteFrame = this._unlockAreaId > 0 ? this.digSprite : this.putSprite;
|
|
// fill 未在播却挂着 dig 遮罩 → 白格看起来像未开挖
|
|
if (!this._openFillPlaying && !this._sealFillCoverPlaying && this.iconNode?.isValid && this.iconNode.active) {
|
|
console.log('[MapGrid] Put 格残留 dig 遮罩,随 updateGrid 清理', this.Index);
|
|
this._clearOpenGridFillOverlay();
|
|
}
|
|
}
|
|
else if (this.isCanBeDig && !this.isCanPutText && !this.isCanWalk) {
|
|
if (this._sealFillCoverPlaying && this.putSprite) {
|
|
this.statusSprite.spriteFrame = this.putSprite;
|
|
} else if (this._showsWaitUnlock()) {
|
|
// 当前可解锁区域
|
|
this.statusSprite.spriteFrame = this.waitUnlockedSprite;
|
|
} else if (this._unlockAreaId > 0) {
|
|
// 还没轮到的解锁区域
|
|
this.statusSprite.spriteFrame = this.putSprite;
|
|
} else {
|
|
this.statusSprite.spriteFrame = this.digSprite;
|
|
}
|
|
}
|
|
else {
|
|
this.statusSprite.spriteFrame = null;
|
|
}
|
|
}
|
|
this.updateAddIcon();
|
|
}
|
|
|
|
/** 区域 ID 变化后,刷新同层其它解锁格的等待图 */
|
|
private _refreshSiblingUnlockSkin(): void {
|
|
const parent = this.node.parent;
|
|
if (!parent) return;
|
|
const children = parent.children;
|
|
for (let i = 0; i < children.length; i++) {
|
|
if (children[i] === this.node) continue;
|
|
const grid = children[i].getComponent(MapGrid);
|
|
if (!grid?.isCanBeDig || grid.unlockAreaId <= 0) continue;
|
|
grid.updateGrid();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 当前可解锁区域显示 Wait Unlocked;未轮到的区域用 Put。
|
|
* 编辑器里取同层最小解锁区域 ID,方便直接看第一块。
|
|
*/
|
|
private _showsWaitUnlock(): boolean {
|
|
if (this._waitingUnlock) return true;
|
|
if (!EDITOR || !this.isAreaUnlock) return false;
|
|
const parent = this.node.parent;
|
|
if (!parent) return false;
|
|
let minId = this._unlockAreaId;
|
|
const children = parent.children;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const grid = children[i].getComponent(MapGrid);
|
|
if (!grid?.isAreaUnlock) continue;
|
|
if (grid.unlockAreaId < minId) minId = grid.unlockAreaId;
|
|
}
|
|
return this._unlockAreaId === minId;
|
|
}
|
|
|
|
/** 格子上的 addIcon:拖拽引导时仅在可落子格显示绿色加号 */
|
|
private updateAddIcon(): void {
|
|
if (!this.addIcon || !isValid(this.addIcon)) return;
|
|
const show = this.isGuideStatus;
|
|
this.addIcon.active = show;
|
|
if (!show || !this.addIconSprite) return;
|
|
if (this._addIconGreenFrame) {
|
|
this.addIconSprite.spriteFrame = this._addIconGreenFrame;
|
|
}
|
|
}
|
|
|
|
/** 格子上的 select / redSelect:背包拖线悬停目标格时显示 */
|
|
private updateSelect(): void {
|
|
if (this.selectNode && isValid(this.selectNode)) {
|
|
this.selectNode.active = this._isSelectStatus;
|
|
}
|
|
const redSelect = this._ensureRedSelectNode();
|
|
if (redSelect && isValid(redSelect)) {
|
|
redSelect.active = this._isRedSelectStatus;
|
|
}
|
|
}
|
|
|
|
/** mapGrid 预制体无 redSelect 时,运行时从 select 克隆并替换为红色加号图 */
|
|
private _ensureRedSelectNode(): Node | null {
|
|
if (this.redSelectNode?.isValid) return this.redSelectNode;
|
|
this.redSelectNode = this.node.getChildByName('redSelect');
|
|
if (this.redSelectNode?.isValid) return this.redSelectNode;
|
|
if (!this.selectNode?.isValid) return null;
|
|
|
|
this.redSelectNode = instantiate(this.selectNode);
|
|
this.redSelectNode.name = 'redSelect';
|
|
this.redSelectNode.parent = this.node;
|
|
this.redSelectNode.active = false;
|
|
|
|
const spr = this.redSelectNode.getComponent(Sprite);
|
|
if (spr) {
|
|
const bundle = assetManager.getBundle(GBundle.BattleGame);
|
|
const redSf = bundle?.get('texture/ui/红色加号/spriteFrame', SpriteFrame) as SpriteFrame | null;
|
|
if (redSf) spr.spriteFrame = redSf;
|
|
}
|
|
return this.redSelectNode;
|
|
}
|
|
|
|
}
|
|
|