1. 新增技能触发类型背景标识,支持追击/反击/复活等状态显示 2. 扩展技能提示接口,新增触发类型参数传递 3. 新增list-me列表预制体及其元数据 4. 调整部分UI精灵帧与布局参数 5. 修复技能名称显示调用参数不匹配问题
242 lines
10 KiB
TypeScript
242 lines
10 KiB
TypeScript
import { _decorator, Collider2D, Contact2DType, v3, IPhysics2DContact, Vec3, tween, Label, resources, SpriteFrame, Sprite, UIOpacity, Color, math, Tween,Node } from "cc";
|
||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||
import { SkillSet } from "../common/config/SkillSet";
|
||
import { FacSet, TooltipTypes } from "../common/config/GameSet";
|
||
import { SkillTriggerType } from "../common/config/heroSet";
|
||
import { Tooltip } from "./Tooltip";
|
||
|
||
const { ccclass, property } = _decorator;
|
||
|
||
/** 视图层对象 */
|
||
@ccclass('TooltipCom')
|
||
@ecs.register('TooltipView', false)
|
||
export class TooltipCom extends CCComp {
|
||
@property(Node)
|
||
atking_bg: Node = null;
|
||
@property(Node)
|
||
atked_bg: Node = null;
|
||
@property(Node)
|
||
fstart_bg: Node = null;
|
||
@property(Node)
|
||
fend_bg: Node = null;
|
||
@property(Node)
|
||
dead_bg: Node = null;
|
||
@property(Node)
|
||
revive_bg: Node = null;
|
||
|
||
stype: number = 1; // 1:减少生命值,2:增加生命值,3:技能图标
|
||
value: string = "";
|
||
s_uuid: number = 1001;
|
||
fac: number = FacSet.MON;
|
||
/** 当前技能喊话对应的触发类型(空字符串表示普通主动技能) */
|
||
triggerType: string = "";
|
||
|
||
// 动画参数配置
|
||
private readonly popDuration = 0.15;
|
||
private readonly driftDuration = 0.5;
|
||
private readonly fadeDuration = 0.2;
|
||
|
||
private _uiOpacity: UIOpacity | null = null;
|
||
|
||
start() {
|
||
// 首次加载时如果未手动调用 init,则自动初始化(防止直接挂载场景的情况)
|
||
// 但在当前架构下,Tooltip 都是通过 Tooltip.load 创建的,所以 start 可以留空或仅做基本检查
|
||
}
|
||
|
||
/** 初始化并播放动画 */
|
||
init(type: number, value: string, uuid: number, fac: number = FacSet.MON, triggerType: string = "") {
|
||
this.stype = type;
|
||
this.value = value;
|
||
this.s_uuid = uuid;
|
||
this.fac = fac;
|
||
this.triggerType = triggerType;
|
||
|
||
// 初始化或获取 UIOpacity 组件
|
||
this._uiOpacity = this.node.getComponent(UIOpacity);
|
||
if (!this._uiOpacity) {
|
||
this._uiOpacity = this.node.addComponent(UIOpacity);
|
||
}
|
||
this._uiOpacity.opacity = 255;
|
||
|
||
// 检测父节点翻转
|
||
let sx = 1;
|
||
if (this.node.parent && this.node.parent.scale.x < 0) {
|
||
sx = -1;
|
||
}
|
||
|
||
// 🔥 关键修复:停止当前节点和 UIOpacity 上的所有缓动
|
||
Tween.stopAllByTarget(this.node);
|
||
if (this._uiOpacity) {
|
||
Tween.stopAllByTarget(this._uiOpacity);
|
||
this._uiOpacity.opacity = 255;
|
||
}
|
||
|
||
this.node.setScale(v3(0, 0, 1)); // 初始缩放为0
|
||
this.node.active = true; // 确保节点激活
|
||
|
||
// 重置所有子节点状态
|
||
this.node.children.forEach(child => child.active = false);
|
||
|
||
let scaleMax = 1.5;
|
||
let isCrit = false;
|
||
let isHeal = false;
|
||
|
||
// 初始随机偏移,防止完全重叠
|
||
const offsetX = (Math.random() - 0.5) * 40;
|
||
|
||
// 设置极高的渲染层级,防止被怪物遮挡
|
||
const topSiblingIndex = 9999;
|
||
|
||
// 临时变量,存储当前Y坐标,方便统一处理。增加60的Y轴基础偏移,防止伤害飘字等遮挡血条
|
||
let currentY = this.node.position.y + 30;
|
||
|
||
switch (this.stype) {
|
||
case TooltipTypes.life: // 普通伤害
|
||
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
this.setupLabel(this.fac === FacSet.HERO ? "hloss" : "loss_life", "hp", this.value);
|
||
scaleMax = 1.5;
|
||
break;
|
||
case TooltipTypes.health: // 治疗
|
||
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
this.setupLabel("add_life", "hp", this.value);
|
||
isHeal = true;
|
||
break;
|
||
case TooltipTypes.addmp: // 回蓝
|
||
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
this.setupLabel("add_mp", "mp", this.value);
|
||
isHeal = true;
|
||
break;
|
||
case TooltipTypes.crit: // 暴击
|
||
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex + 100); // 暴击层级更高
|
||
this.setupLabel("bloss", "hp", this.value);
|
||
scaleMax = 3.0; // 暴击放大
|
||
isCrit = true;
|
||
break;
|
||
case TooltipTypes.skill:
|
||
const skillConfig = SkillSet[this.s_uuid];
|
||
const skillName = skillConfig ? skillConfig.name : "";
|
||
this.setupLabel("skill", "name", skillName+this.value);
|
||
// this.node.setPosition(v3(this.node.position.x, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
// 根据触发类型激活对应的背景标识(追击/反击/起手/生息/亡语/复活)
|
||
this.setupTriggerBg(this.triggerType);
|
||
break;
|
||
case TooltipTypes.uskill:
|
||
this.setupLabel("uskill", "name", this.value);
|
||
this.node.setPosition(v3(this.node.position.x, currentY + 30));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
break;
|
||
case TooltipTypes.lvup:
|
||
this.node.getChildByName("lvup").active = true;
|
||
this.node.setPosition(v3(this.node.position.x, currentY - 30));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
break;
|
||
case TooltipTypes.apup:
|
||
this.setupLabel("apup", "num", "+" + this.value);
|
||
this.node.setPosition(v3(this.node.position.x, currentY - 60));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
break;
|
||
case TooltipTypes.hpup:
|
||
this.setupLabel("hpup", "num", "+" + this.value);
|
||
this.node.setPosition(v3(this.node.position.x, currentY - 60));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
break;
|
||
case TooltipTypes.shield:
|
||
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
|
||
this.node.setSiblingIndex(topSiblingIndex);
|
||
this.setupLabel("add_life", "hp", this.value);
|
||
break;
|
||
}
|
||
|
||
this.playAnimation(scaleMax, isCrit, isHeal, sx);
|
||
}
|
||
|
||
private setupLabel(nodeName: string, labelNodeName: string, text: string) {
|
||
const node = this.node.getChildByName(nodeName);
|
||
if (node) {
|
||
node.active = true;
|
||
const label = node.getChildByName(labelNodeName)?.getComponent(Label);
|
||
if (label) label.string = text;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据技能触发类型激活对应的背景标识节点
|
||
* 仅 TooltipTypes.skill 走此分支,其他飘字类型不受影响
|
||
* 对象池复用场景下先统一关闭所有 _bg,避免上一次的状态残留
|
||
*/
|
||
private setupTriggerBg(triggerType: string) {
|
||
// 先关闭所有触发类型背景,防止节点池复用时残留
|
||
this.atking_bg && (this.atking_bg.active = false);
|
||
this.atked_bg && (this.atked_bg.active = false);
|
||
this.fstart_bg && (this.fstart_bg.active = false);
|
||
this.fend_bg && (this.fend_bg.active = false);
|
||
this.dead_bg && (this.dead_bg.active = false);
|
||
this.revive_bg && (this.revive_bg.active = false);
|
||
|
||
if (!triggerType) return;
|
||
|
||
const bgMap: Record<string, Node | null> = {
|
||
[SkillTriggerType.Atking]: this.atking_bg,
|
||
[SkillTriggerType.Atked]: this.atked_bg,
|
||
[SkillTriggerType.FStart]: this.fstart_bg,
|
||
[SkillTriggerType.FEnd]: this.fend_bg,
|
||
[SkillTriggerType.Dead]: this.dead_bg,
|
||
[SkillTriggerType.Revive]: this.revive_bg,
|
||
};
|
||
const bg = bgMap[triggerType];
|
||
if (bg) bg.active = true;
|
||
}
|
||
|
||
playAnimation(scaleMax: number, isCrit: boolean, isHeal: boolean, sx: number = 1) {
|
||
// 随机 X 轴偏移 (防止重叠)
|
||
const randomX = (Math.random() - 0.5) * 60;
|
||
const moveY = 80;
|
||
|
||
const t = tween(this.node);
|
||
|
||
// 1. 爆发阶段 (Pop)
|
||
t.to(this.popDuration, { scale: v3(sx * scaleMax, scaleMax, 1) }, { easing: 'backOut' });
|
||
|
||
const isSkill = this.stype === TooltipTypes.skill;
|
||
|
||
if (isSkill) {
|
||
// 技能类型的提示:回弹后稍作停留,然后原地快速淡出
|
||
t.to(this.popDuration, { scale: v3(sx * 1.2, 1.2, 1) });
|
||
t.delay(0.2);
|
||
t.parallel(
|
||
tween(this._uiOpacity).to(this.fadeDuration, { opacity: 0 })
|
||
);
|
||
} else {
|
||
// 2. 漂移阶段 (Drift) & 3. 淡出 (Fade)
|
||
// 其他类型提示:并行执行恢复缩放、位移和淡出
|
||
t.parallel(
|
||
tween(this.node).to(this.popDuration, { scale: v3(sx * 1.2, 1.2, 1) }), // 回弹到正常大小 (稍微放大)
|
||
tween(this.node).by(this.driftDuration, { position: v3(isHeal ? 0 : randomX, moveY, 0) }, { easing: 'sineOut' }), // 治疗垂直飘,其他随机飘
|
||
tween(this._uiOpacity).delay(this.driftDuration - this.fadeDuration).to(this.fadeDuration, { opacity: 0 }) // 最后阶段淡出
|
||
);
|
||
}
|
||
|
||
// 结束销毁
|
||
t.call(() => {
|
||
// this.ent.destroy(); // 不要销毁实体,而是直接回收节点
|
||
Tooltip.put(this.node);
|
||
}).start();
|
||
}
|
||
|
||
update(deltaTime: number) {
|
||
|
||
}
|
||
|
||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||
reset() {
|
||
// 使用对象池回收
|
||
Tooltip.put(this.node);
|
||
}
|
||
}
|