Files
pixelheros/assets/script/game/hero/TalComp.ts
walkpan 650bcccc58 feat(天赋系统): 重构天赋触发机制并添加天赋点数系统
- 移除升级触发类型(TriType.LUP)及相关逻辑,改为通过英雄配置定义天赋点数获取规则
- 新增天赋点数接口(ITalPts)和配置字段,支持攻击、受击等不同触发条件
- 在天赋配置中添加点数获取(Pts)和消耗(CPts)字段
- 移除必杀技触发类型(TriType.MAX)的处理逻辑
- 优化TalComp组件结构,移除不必要的heroView引用
- 添加天赋系统设计文档(taldev.md)
2026-02-21 23:45:23 +08:00

296 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { _decorator } from "cc";
import { mLogger } from "../common/Logger";
import { basename } from "path/win32";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { Attrs, BType } from "../common/config/HeroAttrs";
import { BuffConf } from "../common/config/SkillSet";
import { TalAttrs, talConf, TalEffet, TalTarget, TriType} from "../common/config/TalSet";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp";
import { ITalPts } from "../common/config/heroSet";
const { property } = _decorator;
/**
* 天赋槽位接口定义
* 描述单个天赋的数据结构
*/
export interface TalSlot {
uuid: number; // 天赋唯一标识符
name: string; // 天赋名称
triType: TriType; // 天赋触发类型
target: TalTarget;
effet: TalEffet;
attrs?:TalAttrs //触发的attrs效果的对应attrs value: number; // 触发的效果数值
vType:BType; // 数值型还是百分比型
value: number; // 触发的效果数值
value_add: number; // 触发的效果数值增量
count: number; // 执行次数,及可以触发的次数
count_add: number; // 执行次数增量
Trigger: number; // 天赋触发阈值
Trigger_add: number; // 天赋触发阈值减值
desc: string; // 天赋描述(说明触发条件和效果)
cur: number; // 当前累积值
}
/**
* 天赋系统组件类
* 作为ECS架构中的组件负责管理英雄的天赋系统
*
* 核心功能:
* - 初始化英雄天赋系统
* - 添加新天赋到英雄
* - 累积天赋触发进度
* - 检查并触发满足条件的天赋
* - 管理天赋效果数值
*/
@ecs.register('TalComp', true)
export class TalComp extends ecs.Comp {
@property({ tooltip: "是否启用调试日志" })
private debugMode: boolean = false;
/** 天赋集合以天赋ID为键存储所有已获得的天赋 */
Tals: Record<number, TalSlot> = {};
TalPts:Record<number,ITalPts> = {};
init(heroUuid: number) {
// 初始化天赋集合
this.Tals = {};
this.TalPts = {};
// 监听升级事件
oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this);
// 监听天赋选择事件
oops.message.on(GameEvent.UseTalentCard, this.onUseTalentCard, this);
}
onDestroy() {
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.off(GameEvent.UseTalentCard, this.onUseTalentCard, this);
}
/**
* 处理天赋选择事件
* @param event 事件名
* @param args 天赋UUID
*/
private onUseTalentCard(event: string, args: any) {
const uuid = args as number;
mLogger.log(this.debugMode, 'TalComp', `[TalComp] 收到天赋选择事件,添加天赋 ID: ${uuid}`);
this.addTal(uuid);
}
/**
* 处理英雄升级事件,触发升级类型的天赋
*/
private onLevelUp(event: string, args: any) {
// 只有当前实体是主角时才处理虽然TalComp只挂载在主角上但为了安全起见可以再确认或者直接处理
// GameEvent.CanUpdateLv 事件参数 { lv: number }
mLogger.log(this.debugMode, 'TalComp', `[TalComp] 监听到升级事件,当前等级: ${args.lv}`);
}
/**
* 为英雄添加一个新天赋
* @param uuid 要添加的天赋ID
*
* 添加流程:
* 1. 检查天赋是否已存在
* 2. 检查天赋配置是否存在
* 3. 创建并初始化天赋数据
*/
addTal(uuid: number,v_add:number = 0,c_add:number = 0,t_add:number = 0) {
// 检查天赋是否已存在
if (this.Tals[uuid]) {
mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋已存在,执行叠加逻辑 ID:${uuid}`);
const tConf = talConf[uuid];
if (tConf) {
// 叠加效果数值
this.Tals[uuid].value_add += tConf.value;
}
return;
}
// 获取天赋配置
const tConf = talConf[uuid];
if (!tConf) {
mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋配置不存在,天赋ID:${uuid}`);
return;
}
// 创建并初始化天赋数据
this.Tals[uuid] = {
uuid: uuid,
name: tConf.name,
triType: tConf.triType,
target: tConf.target,
effet: tConf.effet,
attrs: tConf.attrs,
vType: tConf.vType,
value: tConf.value, // 效果数值初始为配置值
value_add: v_add, // 效果数值增量初始为0
count: tConf.count, // 执行次数,及可以触发的次数
count_add: c_add, // 执行次数增量初始为0
Trigger: tConf.Trigger, // 触发阈值(后续可从配置中读取)
Trigger_add: t_add, // 触发阈值增量初始为0
desc: tConf.desc,
cur: 0, // 当前累积值初始为0
};
mLogger.log(this.debugMode, 'TalComp', `[TalComp]添加天赋成功,天赋ID:${uuid}`);
}
checkTal() {
return Object.keys(this.Tals).length > 0;
}
getTriggers() {
// 存储所有触发的天赋
let Triggers: Record<string, TalSlot> = {};
// 遍历所有天赋
for (let uuid in this.Tals) {
const talent = this.Tals[uuid];
if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发
mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋触发,天赋ID:${uuid}`);
// 重置累积值
talent.cur = 0;
// 添加到触发列表
Triggers[uuid] = talent;
}
}
// 判断是否有天赋被触发
return Triggers;
}
/**
* 更新天赋的效果数值
* @param uuid 天赋ID
* @param val 要增减的数值
*
* 功能:
* - 用于调整天赋的实际效果数值
* - 可通过正负数来增加或减少效果
*/
updateVal(uuid: number, val: number) {
// 检查天赋是否存在
if (!this.Tals[uuid]) {
mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`);
return;
}
// 更新天赋效果数值
this.Tals[uuid].value_add += val;
}
updateTrigger(uuid: number, val: number) {
// 检查天赋是否存在
if (!this.Tals[uuid]) {
mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`);
return;
}
// 更新天赋触发阈值
this.Tals[uuid].Trigger_add += val;
if (this.Tals[uuid].Trigger-this.Tals[uuid].Trigger_add <= 1) {
this.Tals[uuid].Trigger_add = this.Tals[uuid].Trigger-1;
}
}
/**
* 更新指定类型天赋的累积值
* @param triType 天赋触发类型
* @param val 要增加的累积值默认值为1
*
* 设计注意:
* - 当前实现只会更新第一个匹配类型的天赋
* - 累积值用于后续判断是否触发天赋效果
*/
updateCur(triType: TriType, val: number = 1) {
// 遍历所有天赋
for (let uuid in this.Tals) {
const talent = this.Tals[uuid];
// 找到所有匹配类型的天赋并更新
if (talent.triType == triType) {
talent.cur += val;
this.checkTrigger(talent.uuid);
}
}
}
checkTrigger(uuid:number){
const talent = this.Tals[uuid];
if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发
mLogger.log(this.debugMode, 'TalComp', `[TalComp]天赋触发,天赋ID:${uuid}`);
for(let i=0;i<(talent.count+talent.count_add);i++){
this.doTriggerTal(talent.uuid);
}
// 重置累积值
talent.cur = 0;
}
}
//执行天赋触发效果
// 功能:
// - 根据天赋类型执行相应的效果
// - 支持计数型和数值型天赋
// --heroAttrs.addTalent 是计数型天赋buff heroAttrs.addTalBuff 是数值型天赋buff
doTriggerTal(uuid: number) {
// 检查天赋是否存在
if (!this.Tals[uuid]) {
mLogger.error(this.debugMode, 'TalComp', `[TalComp]天赋不存在,天赋ID:${uuid}`);
return;
}
const talent = this.Tals[uuid];
const heroAttrs=this.ent.get(HeroAttrsComp);
switch(talent.effet){
case TalEffet.ATK_DMG:
heroAttrs.addCountTal(TalEffet.ATK_DMG, talent.value + talent.value_add);
break;
case TalEffet.SKILL_DMG:
heroAttrs.addCountTal(TalEffet.SKILL_DMG, talent.value + talent.value_add);
break;
case TalEffet.DEF:
heroAttrs.addCountTal(TalEffet.DEF, talent.value + talent.value_add);
break;
case TalEffet.HP:
heroAttrs.add_hp(talent.value + talent.value_add,talent.vType == BType.VALUE);
break;
case TalEffet.WFUNY:
heroAttrs.addCountTal(TalEffet.WFUNY, talent.value + talent.value_add);
break;
case TalEffet.D_SKILL:
heroAttrs.addCountTal(TalEffet.D_SKILL, talent.value + talent.value_add);
break;
case TalEffet.C_ATK:
heroAttrs.addCountTal(TalEffet.C_ATK, talent.value + talent.value_add);
break;
case TalEffet.C_SKILL:
heroAttrs.addCountTal(TalEffet.C_SKILL, talent.value + talent.value_add);
break;
case TalEffet.C_MSKILL:
heroAttrs.addCountTal(TalEffet.C_MSKILL, talent.value + talent.value_add);
break;
case TalEffet.BUFF: //临时buff
heroAttrs.addValueTal(talent.uuid, talent.attrs, talent.vType, talent.value + talent.value_add);
break;
case TalEffet.ATTR: //永久属性
// 修正:强制类型转换为 number (Attrs 是数字枚举)
let attrIndex = talent.attrs as unknown as number;
// 如果 TalAttrs 存在且需要映射,请取消注释下一行
// attrIndex = Attrs[TalAttrs[talent.attrs]];
let b:BuffConf={buff:attrIndex, BType:talent.vType, value:talent.value + talent.value_add, time:0, chance:100 }
heroAttrs.addBuff(b);
break;
}
}
/**
* 重置组件状态
*/
reset() {
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.off(GameEvent.UseTalentCard, this.onUseTalentCard, this);
this.Tals = {};
}
}