feat(物品系统): 添加物品使用功能及相关配置

- 在GameEvent枚举中添加UseItemCard事件
- 创建ItemSet物品配置表,包含8种不同效果的物品
- 在HeroAttrsComp中添加物品使用逻辑,处理物品效果应用
- 修改MissionCardComp支持物品购买界面和购买逻辑
- 添加物品购买后的视觉反馈和状态管理
This commit is contained in:
panw
2026-01-05 09:54:58 +08:00
parent 08487cd944
commit e576d19255
4 changed files with 218 additions and 3 deletions

View File

@@ -48,6 +48,7 @@ export enum GameEvent {
FuncSelect = "FuncSelect",
TalentSelect = "TalentSelect",
UseTalentCard = "UseTalentCard",
UseItemCard = "UseItemCard",
NewWave = "NewWave",
AD_BACK_TRUE = "AD_BACK_TRUE",
AD_BACK_FALSE = "AD_BACK_FALSE",

View File

@@ -0,0 +1,105 @@
import { Attrs, BType } from "./HeroAttrs";
/**
* 物品配置接口
*/
export interface ItemConf {
id: number;
name: string;
desc: string;
price: number;
duration: number; // 持续时间(秒)
attr: Attrs; // 提升的属性
value: number; // 提升的值
bType: BType; // 值类型(数值/百分比)
}
/**
* 物品配置表
* 20秒强效果60秒弱效果
*/
export const ItemSet: Record<number, ItemConf> = {
// ==================== 20秒强效果 (价格: 100) ====================
1001: {
id: 1001,
name: "狂暴药水",
desc: "20秒内攻击力+50%",
price: 100,
duration: 20,
attr: Attrs.AP,
value: 50,
bType: BType.RATIO
},
1002: {
id: 1002,
name: "急速药水",
desc: "20秒内攻速+50%",
price: 100,
duration: 20,
attr: Attrs.AS,
value: 50,
bType: BType.RATIO
},
1003: {
id: 1003,
name: "金钟罩",
desc: "20秒内防御+50%",
price: 100,
duration: 20,
attr: Attrs.DEF,
value: 50,
bType: BType.RATIO
},
1004: {
id: 1004,
name: "神行药水",
desc: "20秒内移速+50%",
price: 100,
duration: 20,
attr: Attrs.SPEED,
value: 50,
bType: BType.RATIO
},
// ==================== 60秒弱效果 (价格: 50) ====================
2001: {
id: 2001,
name: "力量药剂",
desc: "60秒内攻击力+20%",
price: 50,
duration: 60,
attr: Attrs.AP,
value: 20,
bType: BType.RATIO
},
2002: {
id: 2002,
name: "敏捷药剂",
desc: "60秒内攻速+20%",
price: 50,
duration: 60,
attr: Attrs.AS,
value: 20,
bType: BType.RATIO
},
2003: {
id: 2003,
name: "护甲药剂",
desc: "60秒内防御+20%",
price: 50,
duration: 60,
attr: Attrs.DEF,
value: 20,
bType: BType.RATIO
},
2004: {
id: 2004,
name: "轻灵药剂",
desc: "60秒内移速+20%",
price: 50,
duration: 60,
attr: Attrs.SPEED,
value: 20,
bType: BType.RATIO
},
};

View File

@@ -6,6 +6,7 @@ import { BuffConf } from "../common/config/SkillSet";
import { HeroInfo, AttrSet } from "../common/config/heroSet";
import { HeroSkillsComp } from "./HeroSkills";
import { smc } from "../common/SingletonModuleComp";
import { ItemSet } from "../common/config/ItemSet";
interface talTrigger{
@@ -78,10 +79,17 @@ export class HeroAttrsComp extends ecs.Comp {
onLoad() {
// 监听升级事件
oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this);
}
onDestroy() {
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this);
}
onUseItemCard(event: string, args: any) {
if (!this.is_master) return;
this.useItem(args);
}
/**
@@ -579,9 +587,40 @@ export class HeroAttrsComp extends ecs.Comp {
useValueTalByUuid(t_uuid: number) {
const buff = this.BUFFS_TAL[t_uuid];
if (!buff) return;
const attrIndex = buff.attrIndex;
delete this.BUFFS_TAL[t_uuid];
buff.count--;
if (buff.count <= 0) {
delete this.BUFFS_TAL[t_uuid];
}
this.recalculateSingleAttr(buff.attrIndex);
}
/**
* 使用物品
* @param itemId 物品ID
*/
useItem(itemId: number) {
const item = ItemSet[itemId];
if (!item) return;
console.log(`[HeroAttrs] 使用物品: ${item.name} (${item.desc})`);
// 直接添加到 BUFFS_TEMP
const attrIndex = item.attr;
if (!this.BUFFS_TEMP[attrIndex]) {
this.BUFFS_TEMP[attrIndex] = [];
}
this.BUFFS_TEMP[attrIndex].push({
value: item.value,
BType: item.bType,
remainTime: item.duration
});
// 重新计算受影响的属性
this.recalculateSingleAttr(attrIndex);
oops.gui.toast(`使用了 ${item.name}`);
}
/**

View File

@@ -1,9 +1,11 @@
import { _decorator, Label, Node, tween, Vec3 } from "cc";
import { _decorator, Label, Node, tween, Vec3, Color, Sprite } 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 { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { talConf, ItalConf } from "../common/config/TalSet";
import { ItemSet } from "../common/config/ItemSet";
import { smc } from "../common/SingletonModuleComp";
const { ccclass, property } = _decorator;
@@ -34,13 +36,18 @@ export class MissionCardComp extends CCComp {
// 当前卡片类型
curCardType: CardType = CardType.Talent;
// 已购买的卡片槽位标记 (用于物品购买)
purchasedSlots: boolean[] = [false, false, false, false, false];
onLoad() {
oops.message.on(GameEvent.TalentSelect, this.onTalentSelect, this);
oops.message.on(GameEvent.ShopOpen, this.onShopOpen, this);
}
onDestroy() {
oops.message.off(GameEvent.TalentSelect, this.onTalentSelect, this);
oops.message.off(GameEvent.ShopOpen, this.onShopOpen, this);
this.ent.destroy();
}
@@ -56,13 +63,28 @@ export class MissionCardComp extends CCComp {
if (card) {
const selected = card.getChildByName("selected");
if (selected) selected.active = false;
// 恢复缩放和颜色
card.setScale(1, 1, 1);
const sprite = card.getComponent(Sprite);
if (sprite) sprite.color = new Color(255, 255, 255);
}
});
// 重置购买状态
this.purchasedSlots = [false, false, false, false, false];
}
// 是否已经选择了天赋
private hasSelected: boolean = false;
private onShopOpen(event: string, args: any) {
this.node.active = true;
this.hasSelected = false;
this.curCardType = CardType.Potion;
this.resetCardStates();
this.refCards();
this.playShowAnimation();
}
private onTalentSelect(event: string, args: any) {
this.node.active = true;
this.hasSelected = false; // 重置选择状态
@@ -180,6 +202,47 @@ export class MissionCardComp extends CCComp {
}
if (selectedData && selectedCardNode) {
// 处理物品购买逻辑
if (this.curCardType === CardType.Potion) {
if (this.purchasedSlots[_index]) {
oops.gui.toast("该物品已购买");
return;
}
if (smc.vmdata.gold < selectedData.price) {
oops.gui.toast("金币不足");
return;
}
// 扣除金币
smc.updateGold(-selectedData.price);
// 发送使用物品事件
oops.message.dispatchEvent(GameEvent.UseItemCard, selectedData.id);
// 标记已购买
this.purchasedSlots[_index] = true;
// 视觉反馈 (变灰)
const sprite = selectedCardNode.getComponent(Sprite);
if (sprite) sprite.color = new Color(150, 150, 150);
oops.gui.toast("购买成功");
// 检查是否所有卡片都已购买,如果是则关闭
let allPurchased = true;
// 检查当前显示的卡片是否都买了
if (this.card1.active && !this.purchasedSlots[1]) allPurchased = false;
if (this.card2.active && !this.purchasedSlots[2]) allPurchased = false;
if (this.card3.active && !this.purchasedSlots[3]) allPurchased = false;
if (this.card4.active && !this.purchasedSlots[4]) allPurchased = false;
if (allPurchased) {
this.node.active = false;
}
return;
}
this.hasSelected = true;
console.log("选择卡片:", selectedData.name, "类型:", this.curCardType);
@@ -216,6 +279,13 @@ export class MissionCardComp extends CCComp {
}
}
/**
* 关闭界面
*/
close() {
this.node.active = false;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();