refactor(tooltip): 优化提示系统使用对象池并改进动画效果

重构提示系统,引入对象池管理节点提升性能,改进动画效果包括缩放、位移和淡出,调整提示位置和层级防止重叠,修复父节点翻转时的显示问题
This commit is contained in:
walkpan
2026-01-02 17:27:53 +08:00
parent ebd67472c7
commit c40414173d
5 changed files with 266 additions and 212 deletions

View File

@@ -104,9 +104,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -171,9 +171,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -238,9 +238,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -356,9 +356,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -423,9 +423,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -554,9 +554,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.4444444444444444 0.4444444477558136
], ],
"_values": [ "_values": [
{ {
@@ -621,9 +621,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.4444444444444444 0.4444444477558136
], ],
"_values": [ "_values": [
{ {
@@ -687,8 +687,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.16666666666666666, 0.1666666716337204,
0.2777777777777778 0.2777777910232544
], ],
"_values": [ "_values": [
{ {
@@ -780,9 +780,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -847,9 +847,9 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -913,9 +913,9 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.16666666666666666, 0.1666666716337204,
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1019,8 +1019,8 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.2777777777777778, 0.2777777910232544,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1073,8 +1073,8 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.2777777777777778, 0.2777777910232544,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1126,7 +1126,7 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778 0.2777777910232544
], ],
"_values": [ "_values": [
{ {
@@ -1205,8 +1205,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1246,8 +1246,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1287,8 +1287,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1380,8 +1380,8 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.3333333333333333, 0.3333333432674408,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1434,8 +1434,8 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.3333333333333333, 0.3333333432674408,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1488,8 +1488,8 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.3333333333333333, 0.3333333432674408,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1592,8 +1592,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1633,8 +1633,8 @@
{ {
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0.2777777777777778, 0.2777777910232544,
0.6666666666666666 0.6666666865348816
], ],
"_values": [ "_values": [
{ {
@@ -1739,7 +1739,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1784,7 +1784,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1829,7 +1829,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1925,7 +1925,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -1970,7 +1970,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -2015,7 +2015,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -2111,7 +2111,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -2156,7 +2156,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {
@@ -2201,7 +2201,7 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.5555555555555556 0.5555555820465088
], ],
"_values": [ "_values": [
{ {

View File

@@ -115,7 +115,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 100, "y": 0,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -574,7 +574,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 100, "y": 0,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -1033,7 +1033,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 100, "y": 0,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -1676,7 +1676,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": -37, "y": 20,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -1969,7 +1969,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 0, "y": 20,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -2867,7 +2867,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 20, "y": 0,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -3257,7 +3257,7 @@
"_lpos": { "_lpos": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": 0,
"y": 100, "y": 0,
"z": 0 "z": 0
}, },
"_lrot": { "_lrot": {
@@ -3745,7 +3745,7 @@
"node": { "node": {
"__id__": 1 "__id__": 1
}, },
"_enabled": true, "_enabled": false,
"__prefab": { "__prefab": {
"__id__": 151 "__id__": 151
}, },

View File

@@ -266,20 +266,26 @@ export class HeroViewComp extends CCComp {
} }
/** 技能提示 */ /** 技能提示 */
private tooltip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 120) { private tooltip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 50) {
let tip = ecs.getEntity<Tooltip>(Tooltip);
let pos = v3(0, 60); let pos = v3(0, 60);
pos.y = pos.y + y; pos.y = pos.y + y;
tip.load(pos, type, value, s_uuid, this.node); Tooltip.load(pos, type, value, s_uuid, this.node);
} }
/** 血量提示(伤害数字) */ /** 血量提示(伤害数字) */
private hp_tip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 120) { private hp_tip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 0) {
let tip = ecs.getEntity<Tooltip>(Tooltip);
let x = this.node.position.x; let x = this.node.position.x;
let ny = this.node.getComponent(UITransform).height + y; // 获取怪物高度的一半,定位到中心点
let halfHeight = 0;
const transform = this.node.getComponent(UITransform);
if (transform) {
halfHeight = transform.height / 2;
}
// 起点设为怪物中心位置 + 20偏移
let ny = this.node.position.y + halfHeight + 20;
let pos = v3(x, ny, 0); let pos = v3(x, ny, 0);
tip.load(pos, type, value, s_uuid, this.node.parent); Tooltip.load(pos, type, value, s_uuid, this.node.parent);
} }
/** 护盾吸收提示 */ /** 护盾吸收提示 */

View File

@@ -4,11 +4,19 @@ import { BoxSet } from "../common/config/GameSet";
import { SkillSet } from "../common/config/SkillSet"; import { SkillSet } from "../common/config/SkillSet";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
import { TooltipCom } from "./TooltipCom"; import { TooltipCom } from "./TooltipCom";
import { instantiate, Node, Prefab, Vec3 ,tween, v3,animation,Label,resources,SpriteFrame,Sprite} from "cc"; import { instantiate, Node, Prefab, Vec3 ,tween, v3,animation,Label,resources,SpriteFrame,Sprite, NodePool} from "cc";
/** Skill 模块 */ /** Skill 模块 */
@ecs.register(`Tooltip`) @ecs.register(`Tooltip`)
export class Tooltip extends ecs.Entity { export class Tooltip extends ecs.Entity {
/** 对象池 */
static pool: NodePool = new NodePool();
/** 回收节点 */
static put(node: Node) {
this.pool.put(node);
}
/** ---------- 数据层 ---------- */ /** ---------- 数据层 ---------- */
// SkillModel!: SkillModelComp; // SkillModel!: SkillModelComp;
@@ -29,22 +37,23 @@ export class Tooltip extends ecs.Entity {
this.remove(TooltipCom); this.remove(TooltipCom);
super.destroy(); super.destroy();
} }
load(pos: Vec3 = Vec3.ZERO,type:number=1,vaule:string="",s_uuid:number=1001,parent:any=null,cd:number=1) { static load(pos: Vec3 = Vec3.ZERO,type:number=1,vaule:string="",s_uuid:number=1001,parent:any=null,cd:number=1) {
let node: Node;
var path = "game/skill/buff/tooltip"; if (Tooltip.pool.size() > 0) {
var prefab: Prefab = oops.res.get(path, Prefab)!; node = Tooltip.pool.get()!;
var node = instantiate(prefab); } else {
node.parent = parent; var path = "game/skill/buff/tooltip";
if(parent.scale.x < 0){ var prefab: Prefab = oops.res.get(path, Prefab)!;
node.setScale(-node.scale.x, node.scale.y, 0); node = instantiate(prefab);
} }
node.setPosition(pos)
node.parent = parent;
node.setPosition(pos);
node.active = true;
var sv = node.getComponent(TooltipCom)!; var sv = node.getComponent(TooltipCom)!;
// console.log("load tooltip type",type,vaule,s_uuid); sv.init(type, vaule, s_uuid);
sv.stype = type;
sv.value = vaule; // this.add(sv); // 不要添加到单例实体上,否则会覆盖或导致单例被销毁
sv.s_uuid = s_uuid;
sv.alive_time = 0.5;
this.add(sv)
} }
} }

View File

@@ -1,8 +1,9 @@
import { _decorator,Collider2D ,Contact2DType,v3,IPhysics2DContact,Vec3, tween, Label,resources,SpriteFrame,Sprite} from "cc"; import { _decorator, Collider2D, Contact2DType, v3, IPhysics2DContact, Vec3, tween, Label, resources, SpriteFrame, Sprite, UIOpacity, Color, math, Tween } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { SkillSet } from "../common/config/SkillSet"; import { SkillSet } from "../common/config/SkillSet";
import { TooltipTypes } from "../common/config/GameSet"; import { TooltipTypes } from "../common/config/GameSet";
import { Tooltip } from "./Tooltip";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -10,130 +11,168 @@ const { ccclass, property } = _decorator;
@ccclass('TooltipCom') @ccclass('TooltipCom')
@ecs.register('TooltipView', false) @ecs.register('TooltipView', false)
export class TooltipCom extends CCComp { export class TooltipCom extends CCComp {
/** 视图层逻辑代码分离演示 */ stype: number = 1; // 1:减少生命值2增加生命值3技能图标
// start() { value: string = "";
// // var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 s_uuid: number = 1001;
// // this.on(ModuleEvent.Cmd, this.onHandler, this);
// }
stype:number = 1; // 1:减少生命值2增加生命值3技能图标
value:string = "";
s_uuid:number = 1001;
alive_time:number = 0.3;
skill_name_time=0.5;
scale:number = 1;
start() {
switch(this.stype){
case TooltipTypes.life:
this.node.setPosition(v3(this.node.position.x,this.node.position.y))
this.node.setSiblingIndex(100);
this.node.getChildByName("loss_life").getChildByName("hp").getComponent(Label).string = this.value;
this.node.getChildByName("loss_life").active=true;
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.health:
this.node.setSiblingIndex(110);
this.node.getChildByName("add_life").getChildByName("hp").getComponent(Label).string = this.value;
this.node.getChildByName("add_life").active=true;
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.addmp:
this.node.setSiblingIndex(110);
this.node.getChildByName("add_mp").getChildByName("mp").getComponent(Label).string = this.value;
this.node.getChildByName("add_mp").active=true;
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.crit:
this.node.setPosition(v3(this.node.position.x,this.node.position.y))
this.node.setSiblingIndex(200);
this.node.getChildByName("bloss").getChildByName("hp").getComponent(Label).string = this.value;
this.node.getChildByName("bloss").active=true;
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.skill:
const skillConfig = SkillSet[this.s_uuid];
if (skillConfig) {
this.node.getChildByName("skill").getChildByName("name").getComponent(Label).string = "<"+skillConfig.name+">";
} else {
this.node.getChildByName("skill").getChildByName("name").getComponent(Label).string = "";
}
this.node.getChildByName("skill").active=true;
this.node.setPosition(v3(this.node.position.x,this.node.position.y+30))
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.uskill:
this.node.getChildByName("uskill").getChildByName("name").getComponent(Label).string = this.value;
this.node.getChildByName("uskill").active=true;
this.node.setPosition(v3(this.node.position.x,this.node.position.y+30))
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.lvup:
// this.node.getChildByName("lvup").getChildByName("name").getComponent(Label).string = this.value;
this.node.getChildByName("lvup").active=true;
this.node.setPosition(v3(this.node.position.x,this.node.position.y-30))
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.apup:
this.node.getChildByName("apup").getChildByName("num").getComponent(Label).string = "+"+this.value;
this.node.getChildByName("apup").active=true;
this.node.setPosition(v3(this.node.position.x,this.node.position.y-60))
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.hpup:
this.node.getChildByName("hpup").getChildByName("num").getComponent(Label).string = "+"+this.value;
this.node.getChildByName("hpup").active=true;
this.node.setPosition(v3(this.node.position.x,this.node.position.y-60))
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
case TooltipTypes.shield:
this.node.setSiblingIndex(110);
this.node.getChildByName("add_life").getChildByName("hp").getComponent(Label).string = this.value;
this.node.getChildByName("add_life").active=true;
this.scheduleOnce(()=>{
this.ent.destroy()
},0.5)
break
}
// console.log("TooltipView start:",this.node.getSiblingIndex());
// 动画参数配置
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) {
this.stype = type;
this.value = value;
this.s_uuid = uuid;
// 初始化或获取 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坐标方便统一处理
let currentY = this.node.position.y;
switch (this.stype) {
case TooltipTypes.life: // 普通伤害
this.node.setPosition(v3(this.node.position.x + offsetX, currentY));
this.node.setSiblingIndex(topSiblingIndex);
this.setupLabel("loss_life", "hp", this.value);
scaleMax = 1.5;
break;
case TooltipTypes.health: // 治疗
this.node.setSiblingIndex(topSiblingIndex);
this.setupLabel("add_life", "hp", this.value);
isHeal = true;
break;
case TooltipTypes.addmp: // 回蓝
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.node.setPosition(v3(this.node.position.x, currentY));
this.node.setSiblingIndex(topSiblingIndex);
break;
case TooltipTypes.uskill:
this.setupLabel("uskill", "name", this.value);
this.node.setPosition(v3(this.node.position.x, this.node.position.y + 30));
this.node.setSiblingIndex(topSiblingIndex);
break;
case TooltipTypes.lvup:
this.node.getChildByName("lvup").active = true;
this.node.setPosition(v3(this.node.position.x, this.node.position.y - 30));
this.node.setSiblingIndex(topSiblingIndex);
break;
case TooltipTypes.apup:
this.setupLabel("apup", "num", "+" + this.value);
this.node.setPosition(v3(this.node.position.x, this.node.position.y - 60));
this.node.setSiblingIndex(topSiblingIndex);
break;
case TooltipTypes.hpup:
this.setupLabel("hpup", "num", "+" + this.value);
this.node.setPosition(v3(this.node.position.x, this.node.position.y - 60));
this.node.setSiblingIndex(topSiblingIndex);
break;
case TooltipTypes.shield:
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;
}
}
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' });
// 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) { update(deltaTime: number) {
} }
do_up(){
tween(this.node).to(
this.alive_time,
{position:v3(this.node.position.x,this.node.position.y+60), },
{
onComplete:()=>{ this.ent.destroy()},
easing:"linear"
}
).start()
}
to_destroy() {
this.ent.destroy()
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() { reset() {
this.node.destroy(); // 使用对象池回收
Tooltip.put(this.node);
} }
} }