feat(map): 新增装备商店道具列表组件与配置
1. 新增ItemListComp组件实现单个装备道具的UI渲染与购买逻辑 2. 新增道具预制体元数据配置 3. 完善MissionCardComp的装备商店相关节点与预制体引用
This commit is contained in:
5232
assets/resources/gui/element/item.prefab
Normal file
5232
assets/resources/gui/element/item.prefab
Normal file
File diff suppressed because it is too large
Load Diff
13
assets/resources/gui/element/item.prefab.meta
Normal file
13
assets/resources/gui/element/item.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "2986f629-e688-418c-9bfc-806485474e36",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "item"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
224
assets/script/game/map/ItemListComp.ts
Normal file
224
assets/script/game/map/ItemListComp.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file ItemListComp.ts
|
||||
* @description 装备商店单个装备项组件(UI 视图层 + 购买逻辑)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 渲染单个装备卡的显示信息(名称、等级、属性词条、图标)。
|
||||
* 2. 处理购买点击 → 扣费 → 派发 UseEquipCard 事件触发装备生效。
|
||||
*
|
||||
* 装备使用机制:
|
||||
* 与技能卡使用流程一致——购买后派发 GameEvent.UseEquipCard,
|
||||
* 由 MissEquipComp 接收并创建 EquipBoxComp 实体,
|
||||
* EquipBoxComp 按 Field 类型被动驻场,属性加成由 FieldSkillHelper 全局聚合。
|
||||
*/
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { _decorator, Node, Sprite, Label, NodeEventType } 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 { CardConfig } from "../common/config/CardSet";
|
||||
import { EquipPoolList } from "../common/config/EquipSet";
|
||||
import { FieldSkillSet } from "../common/config/SkillSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { MissionEconomy } from "./MissionEconomy";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* ItemListComp —— 装备商店单个装备项
|
||||
*
|
||||
* 由 MissionCardComp.populateEquipments() 实例化。
|
||||
* 以图标 + 名称 + 属性词条 + 购买按钮的形式呈现。
|
||||
*/
|
||||
@ccclass('ItemListComp')
|
||||
@ecs.register('ItemListComp', false)
|
||||
export class ItemListComp extends CCComp {
|
||||
private debugMode: boolean = false;
|
||||
|
||||
// ======================== 编辑器绑定节点 ========================
|
||||
|
||||
/** 装备图标节点 */
|
||||
@property({ type: Node })
|
||||
private icon_node: Node = null;
|
||||
|
||||
/** 背景节点 */
|
||||
@property({ type: Node })
|
||||
private bg_node: Node = null;
|
||||
|
||||
/** 装备名称 */
|
||||
@property(Label)
|
||||
private name_label: Label = null;
|
||||
|
||||
/** 属性词条 1 */
|
||||
@property(Label)
|
||||
private fied1: Label = null;
|
||||
/** 属性词条 2 */
|
||||
@property(Label)
|
||||
private fied2: Label = null;
|
||||
/** 属性词条 3 */
|
||||
@property(Label)
|
||||
private fied3: Label = null;
|
||||
|
||||
/** 等级标签 */
|
||||
@property(Label)
|
||||
private level_label: Label = null;
|
||||
|
||||
/** 购买按钮节点 */
|
||||
@property({ type: Node })
|
||||
private buy_node: Node = null;
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 当前装备的卡牌配置 */
|
||||
private cardData: CardConfig | null = null;
|
||||
/** 是否已购买 */
|
||||
private isPurchased: boolean = false;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
onLoad() {
|
||||
this.buy_node?.on(NodeEventType.TOUCH_END, this.onBuyClick, this);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
super.onDestroy();
|
||||
if (this.buy_node && this.buy_node.isValid) {
|
||||
this.buy_node.off(NodeEventType.TOUCH_END, this.onBuyClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 数据初始化 ========================
|
||||
|
||||
/**
|
||||
* 初始化装备卡数据并渲染 UI
|
||||
*
|
||||
* @param data 装备卡配置(必须为 trigger_type=Field 的装备卡)
|
||||
*/
|
||||
applyCardData(data: CardConfig): void {
|
||||
if (!data) return;
|
||||
this.cardData = data;
|
||||
this.isPurchased = false;
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
// ======================== UI 渲染 ========================
|
||||
|
||||
updateUI() {
|
||||
if (!this.cardData) return;
|
||||
|
||||
const cardConfig = EquipPoolList.find(c => c.uuid === this.cardData!.uuid);
|
||||
|
||||
// 名称
|
||||
if (this.name_label) {
|
||||
this.name_label.string = cardConfig?.name || "";
|
||||
}
|
||||
|
||||
// 等级标签(★ 表示卡牌等级)
|
||||
if (this.level_label) {
|
||||
const lv = this.cardData.card_lv ?? 1;
|
||||
this.level_label.string = lv >= 2 ? "★".repeat(lv - 1) : "";
|
||||
}
|
||||
|
||||
// 属性词条(最多显示 3 条,对应 fied1/fied2/fied3)
|
||||
const fieldLabels = [this.fied1, this.fied2, this.fied3];
|
||||
const fields = this.cardData.field || [];
|
||||
for (let i = 0; i < fieldLabels.length; i++) {
|
||||
if (!fieldLabels[i]) continue;
|
||||
if (i < fields.length) {
|
||||
const fieldConfig = FieldSkillSet[fields[i]];
|
||||
fieldLabels[i].string = fieldConfig?.info || "";
|
||||
fieldLabels[i].node.active = true;
|
||||
} else {
|
||||
fieldLabels[i].string = "";
|
||||
fieldLabels[i].node.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 图标(取第一个 field 词条的图标)
|
||||
if (this.icon_node && fields.length > 0) {
|
||||
const iconId = FieldSkillSet[fields[0]]?.icon || "";
|
||||
this.updateIcon(this.icon_node, iconId);
|
||||
}
|
||||
|
||||
// 购买按钮费用显示
|
||||
if (this.buy_node) {
|
||||
this.buy_node.active = true;
|
||||
const costLabel = this.buy_node.getChildByName("num")?.getComponent(Label)
|
||||
|| this.buy_node.getComponentInChildren(Label);
|
||||
if (costLabel) {
|
||||
costLabel.string = `${this.cardData.cost ?? 0}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 更新图标精灵 */
|
||||
private updateIcon(node: Node, iconId: string) {
|
||||
if (!node || !iconId) return;
|
||||
const sprite = node.getComponent(Sprite) || node.getComponentInChildren(Sprite);
|
||||
if (!sprite) return;
|
||||
if (smc.uiconsAtlas) {
|
||||
const frame = smc.uiconsAtlas.getSpriteFrame(iconId);
|
||||
sprite.spriteFrame = frame || null;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 购买逻辑 ========================
|
||||
|
||||
/**
|
||||
* 购买点击处理:
|
||||
* 1. 扣除金币(失败则提示并中止)。
|
||||
* 2. 派发 UseSkillCard 事件,触发与技能卡相同的生效流程。
|
||||
* 3. 标记已购买,隐藏购买按钮。
|
||||
*
|
||||
* 装备生效链路:
|
||||
* UseSkillCard → MissSkillsComp.addSkill() → SBox ECS 实体 → SkillBoxComp(Field 类型)
|
||||
* → FieldSkillHelper.getFieldSkillTotalValue() 全局聚合属性加成
|
||||
*/
|
||||
private onBuyClick() {
|
||||
if (!this.cardData || this.isPurchased) return;
|
||||
|
||||
oops.audio.playEffect("music/button");
|
||||
|
||||
// 扣费
|
||||
const cost = this.cardData.cost ?? 0;
|
||||
const success = MissionEconomy.spendCoin(cost);
|
||||
if (!success) {
|
||||
oops.message.dispatchEvent(GameEvent.ShowSmallTip, "buy_coin");
|
||||
mLogger.log(this.debugMode, "ItemListComp", "purchase failed: not enough coin", {
|
||||
uuid: this.cardData.uuid,
|
||||
cost
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 派发 UseEquipCard,装备生效流程由 MissEquipComp 接收处理
|
||||
oops.message.dispatchEvent(GameEvent.UseEquipCard, this.cardData);
|
||||
|
||||
// 标记已购买
|
||||
this.isPurchased = true;
|
||||
if (this.buy_node) {
|
||||
this.buy_node.active = false;
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, "ItemListComp", "equipment purchased", {
|
||||
uuid: this.cardData.uuid,
|
||||
cost
|
||||
});
|
||||
}
|
||||
|
||||
/** 标记为已购买状态(用于跨波次保持购买记录) */
|
||||
setPurchased(): void {
|
||||
this.isPurchased = true;
|
||||
if (this.buy_node) {
|
||||
this.buy_node.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** ECS 组件移除时销毁节点 */
|
||||
reset() {
|
||||
if (this.node && this.node.isValid) {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/game/map/ItemListComp.ts.meta
Normal file
9
assets/script/game/map/ItemListComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6a8f7102-8d50-4e7e-ab12-e76380e1f8b4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -104,29 +104,34 @@ export class MissionCardComp extends CCComp {
|
||||
/** 英雄卡牌池cards_node显示隐藏 */
|
||||
@property(Node)
|
||||
showHeros: Node = null!
|
||||
/** 关闭英雄卡池按钮(仅负责收起 cards_node) */
|
||||
@property(Node)
|
||||
closeHeros: Node = null!
|
||||
/** 卡池升级按钮节点(已废弃,保留节点引用防止 editor 报错) */
|
||||
/** 英雄卡牌池cards_node显示隐藏 */
|
||||
|
||||
@property(Node)
|
||||
showEquips: Node = null!
|
||||
/** 关闭英雄卡池按钮(仅负责收起 cards_node) */
|
||||
@property(Node)
|
||||
closeEquips: Node = null!
|
||||
@property(Node)
|
||||
showSkills: Node = null!
|
||||
@property(Node)
|
||||
closeSkills: Node = null!
|
||||
|
||||
@property(Node)
|
||||
equipsPanNode: Node = null!
|
||||
@property(Node)
|
||||
equipsBoxNode: Node = null!
|
||||
@property(Prefab)
|
||||
equipPrefab: Prefab = null!
|
||||
/** 卡池升级按钮节点(已废弃,保留节点引用防止 editor 报错) */
|
||||
/** 英雄卡牌池cards_node显示隐藏 */
|
||||
@property(Node)
|
||||
showShop: Node = null!
|
||||
/** 关闭英雄卡池按钮(仅负责收起 cards_node) */
|
||||
@property(Node)
|
||||
closeShop: Node = null!
|
||||
@property(Node)
|
||||
shopPanNode: Node = null!
|
||||
@property(Node)
|
||||
shopBoxNode: Node = null!
|
||||
@property(Prefab)
|
||||
itemPrefab: Prefab = null!
|
||||
/** 卡池升级按钮节点(已废弃,保留节点引用防止 editor 报错) */
|
||||
@property(Node)
|
||||
cards_up: Node = null!
|
||||
|
||||
Reference in New Issue
Block a user