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.

728 lines
26 KiB

3 weeks ago
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';
15 hours ago
import { EDITOR } from 'cc/env';
3 weeks ago
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;
15 hours ago
/** 是否可被开挖 */
@property({ displayName: '是否可开挖' })
3 weeks ago
get isCanBeDig(): boolean {
return this._isCanBeDig;
}
set isCanBeDig(value: boolean) {
this._isCanBeDig = value;
this.updateGrid();
}
@property
private _isCanBeDig: boolean = false;
2 weeks ago
/**
15 hours ago
* 运行时:八邻揭示后的宝箱 Dig 格(非序列化)。
* true 时用 waitUnlockedSprite;默认 Dig 无皮。
2 weeks ago
*/
15 hours ago
chestRevealed = false;
2 weeks ago
15 hours ago
/**
* 历史「解锁区域 ID」序列化残留:玩法已拆除,仅用于换皮。
* 地图把 digSprite 配成「土地块」、putSprite 配成「空地格子」时,区域格可放置须仍走 digSprite。
*/
@property({ visible: false })
private _unlockAreaId = 0;
3 weeks ago
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;
2 weeks ago
@property({ type: SpriteFrame })
waitUnlockedSprite: SpriteFrame = null;
3 weeks ago
/**是否是引导状态(拖拽时可落子格:仅控制 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;
15 hours ago
/** dig/白格 fill 是否进行中(rebuild 可能停 tween 却不清遮罩) */
3 weeks ago
private _openFillPlaying = false;
15 hours ago
/** 铲开挖白格 fill:true=0→1;playOpenEffect 仍为 dig 1→0 */
private _openFillGrowWhite = false;
3 weeks ago
/** 封格 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);
}
2 weeks ago
/** 未开启格开挖:openSpine 冒烟 + dig 遮罩 fillRange 1→0(并行) */
3 weeks ago
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));
}
/**
15 hours ago
* 铲开挖链:白格(digSprite=土地块)fillRange 0→1(与铲 Spine 并行)。
* @param durationSec 渐显时长;省略则用 fallback
* @param onComplete fill 播完回调
*/
playShovelDigFillReveal(durationSec?: number, onComplete?: () => void): void {
// 勿先 updateGrid 刷满 Put,否则看不到 0→1
this._playShovelLandFillReveal(durationSec, onComplete);
}
/**
* 铲开挖链:铲 Spine 结束后播 openSpine 冒烟(onComplete 可选,仅表示冒烟播完)。
3 weeks ago
*/
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();
}
2 weeks ago
/** openSpine 冒烟播完(开挖链) */
3 weeks ago
private _onOpenSpineSmokeDone(): void {
const cb = this._openEffectComplete;
this._openEffectComplete = null;
this.updateGrid();
cb?.();
}
15 hours ago
/** dig/白格 fill 播完 */
3 weeks ago
private _onOpenGridFillRevealDone(finishOpenEffect: boolean): void {
15 hours ago
const shovelCb = this._shovelFillComplete;
this._shovelFillComplete = null;
3 weeks ago
this._openFillPlaying = false;
this._clearOpenGridFillOverlay();
15 hours ago
this.updateGrid();
shovelCb?.();
3 weeks ago
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?.();
}
/**
2 weeks ago
* 千里眼封格:Put 皮上叠 dig 遮罩,fillRange 0→1。
3 weeks ago
* @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();
}
15 hours ago
/** 播放 dig 遮罩 fillRange 1→0,露出下方可放置格(playOpenEffect) */
3 weeks ago
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;
15 hours ago
this._openFillGrowWhite = false;
3 weeks ago
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();
}
15 hours ago
/** 铲开挖 fill 完成回调(仅本次) */
private _shovelFillComplete: (() => void) | null = null;
/**
* 铲开挖:格子 statusSprite 套 digSprite(土地块),fillRange 0→1。
* @param durationSec 渐显时长
* @param onComplete fill 播完
*/
private _playShovelLandFillReveal(durationSec?: number, onComplete?: () => void): void {
const sprite = this.statusSprite;
this._shovelFillComplete = onComplete ?? null;
if (!sprite?.isValid || !this.digSprite) {
console.warn('[MapGrid] 铲开挖缺 digSprite/statusSprite,跳过土地块 fill', this.Index);
this._onOpenGridFillRevealDone(false);
return;
}
const fillSec = durationSec != null && durationSec > 0
? durationSec
: OPEN_GRID_FILL_DURATION_SEC;
if (this.iconNode?.isValid) this.iconNode.active = false;
if (this.iconSprite?.isValid) {
Tween.stopAllByTarget(this.iconSprite);
}
Tween.stopAllByTarget(sprite);
this._openFillPlaying = true;
this._openFillGrowWhite = true;
sprite.sizeMode = Sprite.SizeMode.CUSTOM;
sprite.spriteFrame = this.digSprite;
sprite.type = Sprite.Type.FILLED;
sprite.fillType = Sprite.FillType.HORIZONTAL;
sprite.fillStart = 0;
sprite.fillRange = 0;
tween(sprite)
.to(fillSec, { fillRange: 1 })
.call(this._onOpenGridFillRevealDone.bind(this, false))
.start();
}
3 weeks ago
/**
15 hours ago
* 从当前 fillRange 续播(rebuild 打断 tween 后用)。
3 weeks ago
* @param finishOpenEffect 是否计入 playOpenEffect 完成条件
* @param fromRange 起始 fillRange
*/
private _resumeOpenGridFillReveal(finishOpenEffect: boolean, fromRange: number): void {
15 hours ago
const grow = this._openFillGrowWhite;
if (grow) {
this._resumeShovelLandFill(finishOpenEffect, fromRange);
return;
}
3 weeks ago
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();
}
15 hours ago
/**
* 续播铲开挖土地块 fill(statusSprite)。
* @param finishOpenEffect 是否计入 playOpenEffect
* @param fromRange 当前 fillRange
*/
private _resumeShovelLandFill(finishOpenEffect: boolean, fromRange: number): void {
const sprite = this.statusSprite;
if (!sprite?.isValid || !this.digSprite) {
this._onOpenGridFillRevealDone(finishOpenEffect);
return;
}
const from = Math.max(0, Math.min(1, fromRange));
if (from >= 0.99) {
this._onOpenGridFillRevealDone(finishOpenEffect);
return;
}
Tween.stopAllByTarget(sprite);
this._openFillPlaying = true;
this._openFillGrowWhite = true;
sprite.sizeMode = Sprite.SizeMode.CUSTOM;
sprite.spriteFrame = this.digSprite;
sprite.type = Sprite.Type.FILLED;
sprite.fillType = Sprite.FillType.HORIZONTAL;
sprite.fillStart = 0;
sprite.fillRange = from;
const duration = OPEN_GRID_FILL_DURATION_SEC * (1 - from);
tween(sprite)
.to(duration, { fillRange: 1 })
.call(this._onOpenGridFillRevealDone.bind(this, finishOpenEffect))
.start();
}
3 weeks ago
/** 清理开挖遮罩 tween 与节点 */
private _clearOpenGridFillOverlay(): void {
this._openFillPlaying = false;
15 hours ago
const wasWhite = this._openFillGrowWhite;
this._openFillGrowWhite = false;
3 weeks ago
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;
}
15 hours ago
if (wasWhite && this.statusSprite?.isValid) {
Tween.stopAllByTarget(this.statusSprite);
this.statusSprite.fillRange = 1;
this.statusSprite.type = Sprite.Type.SIMPLE;
}
3 weeks ago
}
/** 中断/跳过开挖表现时清理 openSpine 与 dig 遮罩(AI Dig→Put 必调) */
clearDigOpenFx(): void {
this._abortOpenEffect();
this.updateGrid();
}
15 hours ago
/**
* 铲挖收尾 rebuild 后修复:续播被打断的 fill,或清掉残留 dig 遮罩并刷回 Put 皮。
*/
repairShovelDigVisual(): void {
if (this._sealFillCoverPlaying) return;
if (this._openFillPlaying && this._openFillGrowWhite && this.statusSprite?.isValid) {
this._resumeShovelLandFill(false, this.statusSprite.fillRange);
return;
}
const overlay = this.iconSprite;
const overlayNode = this.iconNode;
if (this._openFillPlaying && overlay?.isValid && overlayNode?.isValid && overlayNode.active) {
this._resumeOpenGridFillReveal(false, overlay.fillRange);
this.updateGrid();
return;
}
if (overlayNode?.isValid && overlayNode.active) {
console.log('[MapGrid] Put 格 dig 遮罩残留,强制清理', this.Index);
}
this.clearDigOpenFx();
}
3 weeks ago
/** 中断进行中的开挖表现 */
private _abortOpenEffect(): void {
15 hours ago
this._shovelFillComplete = null;
3 weeks ago
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) {
15 hours ago
// 铲开挖白格 fill 进行中:勿打断 statusSprite FILLED
if (this._openFillPlaying && this._openFillGrowWhite) {
// keep fill tween
} else {
// 可放置:区域格用 digSprite(土地块),否则 putSprite
this.statusSprite.spriteFrame = this._putSkinFrame();
this.statusSprite.type = Sprite.Type.SIMPLE;
if (!this._openFillPlaying && !this._sealFillCoverPlaying && this.iconNode?.isValid && this.iconNode.active) {
console.log('[MapGrid] Put 格残留 dig 遮罩,随 updateGrid 清理', this.Index);
this._clearOpenGridFillOverlay();
}
3 weeks ago
}
}
else if (this.isCanBeDig && !this.isCanPutText && !this.isCanWalk) {
15 hours ago
// 可开挖默认无皮;已揭示宝箱格用 waitUnlocked(待解锁)
if (this._sealFillCoverPlaying) {
this.statusSprite.spriteFrame = this._putSkinFrame();
} else if (this.chestRevealed) {
if (!this.waitUnlockedSprite) {
console.warn('[MapGrid] 揭示宝箱格缺 waitUnlockedSprite', this.Index);
}
2 weeks ago
this.statusSprite.spriteFrame = this.waitUnlockedSprite;
} else {
15 hours ago
this.statusSprite.spriteFrame = null;
2 weeks ago
}
3 weeks ago
}
else {
this.statusSprite.spriteFrame = null;
}
}
this.updateAddIcon();
}
15 hours ago
/** 可放置格皮:区域解锁残留地图 digSprite 即浅色可放皮 */
private _putSkinFrame(): SpriteFrame | null {
if (this._unlockAreaId > 0 && this.digSprite) return this.digSprite;
return this.putSprite;
2 weeks ago
}
3 weeks ago
/** 格子上的 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;
}
}