fix(boss): keep phase outline authoritative over level tint and pool reuse

Reuse existing outline-green/outline-glow materials (P2 green / P3 red); phase outline now takes priority over level tint during boss lifetime (init/lv_up both route through BossPhaseComp), and HeroViewComp.reset clears the material back to default so pooled monster nodes never inherit a boss's red/green edge.
This commit is contained in:
panFD
2026-10-10 00:40:47 +08:00
parent a122d0904c
commit 74d03facd9
2 changed files with 30 additions and 22 deletions

View File

@@ -16,6 +16,7 @@ import { Tooltip } from "../skill/Tooltip";
import { timedCom } from "../skill/timedCom"; import { timedCom } from "../skill/timedCom";
import { oneCom } from "../skill/oncend"; import { oneCom } from "../skill/oncend";
import { FlashSprite } from "./hit-flash-white/scripts/FlashSprite"; import { FlashSprite } from "./hit-flash-white/scripts/FlashSprite";
import { BossPhaseComp } from "./BossPhaseComp";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -89,7 +90,6 @@ export class HeroViewComp extends CCComp {
this.deadCD = 0; this.deadCD = 0;
this.lastBarUpdateTime = 0; this.lastBarUpdateTime = 0;
this.status_change("idle"); this.status_change("idle");
// 初始化头顶状态栏 // 初始化头顶状态栏
const topNode = this.node.getChildByName("top"); const topNode = this.node.getChildByName("top");
this.topBar = topNode.getComponent(HeroTopBarComp) || topNode.addComponent(HeroTopBarComp); this.topBar = topNode.getComponent(HeroTopBarComp) || topNode.addComponent(HeroTopBarComp);
@@ -98,9 +98,14 @@ export class HeroViewComp extends CCComp {
/** 方向 */ /** 方向 */
this.node.setScale(this.scale * Math.abs(this.node.scale.x), 1 * this.node.scale.y); // 确保 scale.x 为正后再乘方向 this.node.setScale(this.scale * Math.abs(this.node.scale.x), 1 * this.node.scale.y); // 确保 scale.x 为正后再乘方向
// 🔥 重置描边 // 🔥 重置描边:Boss 阶段描边优先(Boss 存活期不被等级描边覆盖),其余按等级
const phaseComp = this.ent ? this.ent.get(BossPhaseComp) : null;
if (phaseComp && phaseComp.index > 0) {
this.applyBossPhaseOutline(phaseComp.index);
} else {
this.applyOutlineByLevel(); this.applyOutlineByLevel();
} }
}
/** /**
* View 层每帧更新 * View 层每帧更新
@@ -162,9 +167,14 @@ export class HeroViewComp extends CCComp {
public lv_up() { public lv_up() {
this.spawnTimedFx("game/skill/buff/buff_lvup", this.node, 1.0); this.spawnTimedFx("game/skill/buff/buff_lvup", this.node, 1.0);
// 升级时同步更新描边 // 升级时同步更新描边:Boss 阶段描边优先(与 init 口径一致)
const phaseComp = this.ent ? this.ent.get(BossPhaseComp) : null;
if (phaseComp && phaseComp.index > 0) {
this.applyBossPhaseOutline(phaseComp.index);
} else {
this.applyOutlineByLevel(); this.applyOutlineByLevel();
} }
}
/** 按英雄等级应用描边(升级/初始化共用入口) */ /** 按英雄等级应用描边(升级/初始化共用入口) */
private applyOutlineByLevel() { private applyOutlineByLevel() {
@@ -577,6 +587,13 @@ export class HeroViewComp extends CCComp {
this.deadCD = 0 this.deadCD = 0
this.lastBarUpdateTime = 0 this.lastBarUpdateTime = 0
// 清掉描边材质:防 Boss 阶段描边(绿/红)随对象池节点复用串到小怪/英雄身上
const flashSprite = this.getFlashSprite();
if (flashSprite && flashSprite.defaultMaterial) {
flashSprite.orginalFlashMaterial = flashSprite.defaultMaterial;
flashSprite.sprite?.setSharedMaterial(flashSprite.defaultMaterial, 0);
}
// 清理伤害队列 // 清理伤害队列
this.damageQueue.length = 0; this.damageQueue.length = 0;
this.isProcessingDamage = false; this.isProcessingDamage = false;

View File

@@ -7,15 +7,9 @@ export class FlashSprite extends Component {
@property(Material) @property(Material)
hitFlashMaterial: Material | null = null; hitFlashMaterial: Material | null = null;
@property({ type: Material, tooltip: '绿色描边材质(2级)' }) @property({ type: Material, tooltip: '绿色描边材质(2级 / Boss阶段2)' })
outlineMatGreen: Material | null = null; outlineMatGreen: Material | null = null;
@property({ type: Material, tooltip: '淡绿描边材质(Boss阶段2)' })
outlineMatGreenLight: Material | null = null;
@property({ type: Material, tooltip: '深绿描边材质(Boss阶段2备选)' })
outlineMatGreenDark: Material | null = null;
@property({ type: Material, tooltip: '蓝色描边材质(3级)' }) @property({ type: Material, tooltip: '蓝色描边材质(3级)' })
outlineMatBlue: Material | null = null; outlineMatBlue: Material | null = null;
@@ -25,8 +19,8 @@ export class FlashSprite extends Component {
@property({ type: Material, tooltip: '黄色描边材质(5级)' }) @property({ type: Material, tooltip: '黄色描边材质(5级)' })
outlineMatYellow: Material | null = null; outlineMatYellow: Material | null = null;
@property({ type: Material, tooltip: '红色描边材质(Boss阶段3)' }) @property({ type: Material, tooltip: '红色描边材质(Boss阶段3,即 outline-glow)' })
outlineMatRed: Material | null = null; outlineMatGlow: Material | null = null;
orginalFlashMaterial: Material | null = null; orginalFlashMaterial: Material | null = null;
defaultMaterial: Material | null = null; // 缓存最原始的无描边材质 defaultMaterial: Material | null = null; // 缓存最原始的无描边材质
@@ -75,12 +69,11 @@ export class FlashSprite extends Component {
/** /**
* 按 Boss 阶段设置描边材质(优先级高于等级描边) * 按 Boss 阶段设置描边材质(优先级高于等级描边)
* Why: Boss 阶段是战斗强反馈(绿色警告 / 红色危险),与英雄等级成长是两套视觉语言, * Why: Boss 阶段是战斗强反馈(P2 绿=警告 / P3 红=危险),与英雄等级成长是两套视觉语言,
* 用独立通道避免污染 setOutlineByLevel 的等级语义 * 用独立通道避免污染 setOutlineByLevel 的等级语义;材质复用现有 outline-green / outline-glow
* @param phase 阶段索引:1=P2 绿 / 2=P3 红 / 0=P1 恢复默认 * @param phase 阶段索引:1=P2 绿 / 2=P3 红 / 0=P1 恢复默认
* @param greenShade P2 绿色色调:'light' 淡绿(默认)/ 'dark' 深绿
*/ */
public setOutlineByBossPhase(phase: number, greenShade: 'light' | 'dark' = 'light') { public setOutlineByBossPhase(phase: number) {
if (!this.sprite) { if (!this.sprite) {
this.sprite = this.node.getComponent(Sprite); this.sprite = this.node.getComponent(Sprite);
} }
@@ -88,11 +81,9 @@ export class FlashSprite extends Component {
let targetMat: Material | null = null; let targetMat: Material | null = null;
if (phase === 1) { if (phase === 1) {
targetMat = greenShade === 'dark' targetMat = this.outlineMatGreen;
? (this.outlineMatGreenDark ?? this.outlineMatGreenLight ?? this.outlineMatGreen)
: (this.outlineMatGreenLight ?? this.outlineMatGreenDark ?? this.outlineMatGreen);
} else if (phase >= 2) { } else if (phase >= 2) {
targetMat = this.outlineMatRed ?? this.outlineMatYellow; targetMat = this.outlineMatGlow ?? this.outlineMatYellow;
} else { } else {
targetMat = this.defaultMaterial; targetMat = this.defaultMaterial;
} }