feat: 新增技能图标组件与UI优化

1. 新增SSkillBoxComp技能小图标组件,支持技能展示与状态控制
2. 优化CardLiteComp选中态动画,改为缩放高亮效果
3. 为英雄列表、任务主页添加顶部栏显示控制逻辑
4. 调整部分预制件布局与节点配置
This commit is contained in:
pan
2026-08-25 10:50:28 +08:00
parent 8ce83dc5e2
commit a8aa876a74
10 changed files with 5604 additions and 824 deletions

View File

@@ -37,6 +37,9 @@ const { ccclass, property } = _decorator;
export class CardLiteComp extends CCComp {
private debugMode: boolean = false;
/** 选中态放大倍率 */
private static readonly SELECT_SCALE: number = 1.08;
// ======================== 编辑器绑定节点 ========================
@property(Node)
@@ -109,12 +112,15 @@ export class CardLiteComp extends CCComp {
}
/**
* 设置选中态:切换根节点下 `active` 子节点的显隐(不再通过缩放表达选中)。
* 设置选中态:选中卡微微放大,取消选中恢复原尺寸。
* @param selected 是否选中
*/
setSelected(selected: boolean) {
const mark = this.node.getChildByName("active");
if (mark) mark.active = selected;
Tween.stopAllByTarget(this.node);
const target = selected ? CardLiteComp.SELECT_SCALE : 1;
tween(this.node)
.to(0.12, { scale: new Vec3(target, target, 1) }, { easing: 'quadOut' })
.start();
}
// ======================== 事件绑定 ========================

View File

@@ -87,6 +87,9 @@ export class HerosListComp extends CCComp {
@property(Node)
chip_node = null!
/** 技能描述节点() */
@property(Node)
infos_node = null!
/** 升级特效动画节点(内含升级效果 Animation,点击升级时从头播放) */
@property(Node)
upgrade_anim_node = null!

View File

@@ -54,6 +54,9 @@ export class MissionHomeComp extends CCComp {
/** 天赋按钮节点 */
@property(Node)
tals_btn = null!
/** 顶部栏节点(仅主页显示) */
@property(Node)
top_bar_node = null!
@property(Node)
@@ -197,6 +200,9 @@ export class MissionHomeComp extends CCComp {
}
private showPage(page: Node) {
// 进入分页时隐藏顶部栏,仅主页显示
this.top_bar_node.active = false
this.heros_page.active = (page === this.heros_page)
this.talents_page.active = (page === this.talents_page)
this.ranks_page.active = (page === this.ranks_page)
@@ -208,6 +214,9 @@ export class MissionHomeComp extends CCComp {
}
private hideAllPages() {
// 回到主页时恢复顶部栏显示
this.top_bar_node.active = true
this.heros_page.active = false
this.talents_page.active = false
this.ranks_page.active = false

View File

@@ -0,0 +1,148 @@
import { _decorator, Node, Sprite, Label } 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 { CardTriggerType } from "../common/config/CardSet";
import { EquipPoolList } from "../common/config/EquipSet";
import { SkillSet, FieldSkillSet } from "../common/config/SkillSet";
import { FieldEntry } from "../common/config/heroSet";
import { smc } from "../common/SingletonModuleComp";
const { ccclass, property } = _decorator;
/**
* 技能小图标组件
*
* 由 MissSkillsComp.addSkill() 实例化并初始化。
* 在战场上以图标 + 剩余次数的形式呈现。
*/
@ccclass('SSkillBoxComp')
@ecs.register('SSkillBoxComp', false)
export class SSkillBoxComp extends CCComp {
/** 技能图标节点 */
@property({ type: Node })
private icon_node: Node = null;
/** 技能图标节点:下面有 green blue purple red yellow 5个不同颜色节点*/
@property({ type: Node })
private bg_node: Node = null;
/** 技能等级标签 */
@property(Label)
private lv_label: Label = null;
/** 锁定遮罩节点(active 时表示技能未激活) */
@property({ type: Node })
private locked: Node = null;
/** 技能 UUID */
private s_uuid: number = 0;
/** 卡牌等级 */
private card_lv: number = 1;
/** 卡牌自定义图标ID(优先级最高,未定义则按 trigger_type 自动取) */
private card_icon?: string;
/** 触发类型(默认即时,保持向后兼容) */
private trigger_type: CardTriggerType = CardTriggerType.Instant;
/** 驻场技能词条列表(uuid 指向 FieldSkillSet 底座,value 为生效数值) */
public field: FieldEntry[] = [];
/**
* 初始化技能卡效果:
* 1. 从 EquipPoolList 查询装备卡的触发配置(含 trigger_type)。
* 2. 更新 UI 显示(图标 + 次数)。
*
* @param uuid 卡牌 UUID
* @param card_lv 技能卡等级
*/
init(uuid: number, card_lv: number) {
this.card_lv = card_lv;
// 装备卡配置已迁移至 EquipPoolList
const config = EquipPoolList.find(c => c.uuid === uuid);
if (config) {
this.s_uuid = config.skill ?? uuid; // 获取实际的技能 UUID
this.card_icon = config.icon; // 保存卡牌自定义图标(优先级最高)
this.trigger_type = config.trigger_type ?? CardTriggerType.Instant;
} else {
this.s_uuid = uuid;
}
this.updateUI();
}
/**
* 设置技能激活状态:
* - locked = true → 显示锁定遮罩,技能未激活
* - locked = false → 隐藏锁定遮罩,技能已激活
*/
setLocked(locked: boolean) {
if (this.locked) {
this.locked.active = locked;
}
}
/**
* 根据技能等级切换 bg_node 下的颜色子节点显示。
* 等级与颜色对应关系(技能卡 wave 档位):
* card_lv 1 (wave 1) → green
* card_lv 2 (wave 5) → blue
* card_lv 3 (wave 8) → purple
*/
private updateBgNode() {
if (!this.bg_node) return;
const lvToColor: Record<number, string> = {
1: "green",
2: "blue",
3: "purple",
};
const targetColor = lvToColor[this.card_lv];
this.bg_node.children.forEach(child => {
child.active = (child.name === targetColor);
});
}
/**
* 更新 UI:
* - 背景:根据技能等级切换对应颜色子节点显示
* - 图标:从 uicons 图集获取
* - 等级标签:显示技能卡等级
*/
updateUI() {
// 按技能等级切换背景颜色节点(与 getLvColor 等级配色一致)
this.updateBgNode();
// 加载技能图标
if (this.icon_node) {
// 优先使用卡牌自定义 icon;未定义则按 trigger_type 自动取
let iconId: string | undefined = this.card_icon;
if (!iconId) {
if (this.trigger_type === CardTriggerType.Interval) {
iconId = this.s_uuid ? SkillSet[this.s_uuid]?.icon : undefined;
} else if (this.trigger_type === CardTriggerType.Field) {
const fieldUuid = this.field?.[0]?.uuid;
iconId = fieldUuid ? FieldSkillSet[fieldUuid]?.icon : undefined;
}
}
if (this.icon_node && this.icon_node.isValid) {
let sprite = this.icon_node.getComponent(Sprite) || this.icon_node.addComponent(Sprite);
if (smc.uiconsAtlas && iconId) {
const frame = smc.uiconsAtlas.getSpriteFrame(iconId);
sprite.spriteFrame = frame || null; // 取不到时清空,避免残留
} else {
sprite.spriteFrame = null;
}
}
}
// 显示技能等级
if (this.lv_label) {
this.lv_label.string = `${this.card_lv}`;
}
}
/** ECS 组件移除时销毁节点 */
reset() {
if (this.node && this.node.isValid) {
this.node.destroy();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "36150383-6711-44b9-83d7-0d7af167584d",
"files": [],
"subMetas": {},
"userData": {}
}