refactor(hero): 移除天赋系统和相关属性,简化英雄架构

- 删除 SCDSystem、HeroAttrSystem 等独立系统,将功能整合到现有组件
- 移除 TalComp 天赋组件及相关配置(TalSet、AttrSet、CardSet)
- 清理 HeroAttrs 中未使用的属性枚举,保留核心战斗属性
- 简化 Hero 实体创建逻辑,不再为主角挂载天赋组件
- 移除 SingletonModuleComp 中与天赋、经验、收集相关的数据管理
This commit is contained in:
panw
2026-03-11 17:32:29 +08:00
parent b354c7ed9a
commit 350bbafcfb
12 changed files with 44 additions and 2520 deletions

View File

@@ -6,7 +6,6 @@ import { BuffConf, SkillRange } from "../common/config/SkillSet";
import { HeroInfo, AttrSet, HType, JobUpConf } from "../common/config/heroSet";
import { HeroSkillsComp } from "./HeroSkills";
import { smc } from "../common/SingletonModuleComp";
import { AttrCards, PotionCards } from "../common/config/AttrSet";
import { mLogger } from "../common/Logger";
import { _decorator } from "cc";
@@ -29,23 +28,14 @@ export class HeroAttrsComp extends ecs.Comp {
fac: number = 0; // 0:hero 1:monster
rangeType:SkillRange = SkillRange.Melee;
// ==================== 基础属性(有初始值) ====================
base_ap: number = 0; // 基础攻击
base_def: number = 5; // 基础防御
base_hp: number = 100; // 基础血量
base_mp: number = 100; // 基础魔法值
base_speed: number = 100; // 基础移动速度
base_dis: number = 100; // 基础距离
// ==================== 动态属性值 ====================
hp: number = 100; // 当前血量
mp: number = 100; // 当前魔法值
ap: number = 0; // 基础攻击
hp: number = 100; // 基础血量
hp_max: number = 100; // 最大血量
speed: number = 100; // 基础移动速度
dis: number = 100; // 基础距离
shield: number = 0; // 当前护盾
Attrs: any = []; // 最终属性数组经过Buff计算后
NeAttrs: any = []; // 负面状态数组
//计数型天赋buff
Talents: Record<number, talTrigger> = {};
//数值型天赋buff
BUFFS_TAL: Record<number, {count:number,BType:BType,attrIndex:number,value: number}> = {};
shield_max: number = 0; // 最大护盾值
// ==================== 脏标签标记 ====================
dirty_hp: boolean = false; // 血量变更标记
@@ -58,11 +48,8 @@ export class HeroAttrsComp extends ecs.Comp {
// ==================== Buff/Debuff 系统 ====================
/** 持久型buff数组 - 不会自动过期 */
BUFFS: Record<number, Array<{value: number, BType: BType}>> = {};
/** 临时型buff数组 - 按时间自动过期 */
BUFFS_TEMP: Record<number, Array<{value: number, BType: BType, remainTime: number}>> = {};
BUFFS: Record<number, Array<{value: number, BType: BType,time:number}>> = {};
DEBUFFS: Record<number, Array<{value: number, BType: BType,time:number}>> = {};
// ==================== 标记状态 ====================
is_dead: boolean = false;
@@ -81,103 +68,7 @@ export class HeroAttrsComp extends ecs.Comp {
killed_count:number=0;
// 注意:技能数据已迁移到 HeroSkillsComp不再存储在这里
initEvent() {
// 监听升级事件
mLogger.log(this.debugMode, 'HeroAttrs', ` 注册升级事件监听`);
oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this);
// 移除卡牌事件监听,改为由 MissionCardComp 直接调用,避免非主角响应
// oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this);
// oops.message.on(GameEvent.UseAttrCard, this.onUseAttrCard, this);
}
removeEvent() {
mLogger.log(this.debugMode, 'HeroAttrs', ` 移除升级事件监听`);
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
// oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this);
// oops.message.off(GameEvent.UseAttrCard, this.onUseAttrCard, this);
}
onUseAttrCard(event: string, args: any) {
if (!this.is_master) return;
const uuid = args;
const attrCard = AttrCards[uuid];
if (attrCard) {
mLogger.log(this.debugMode, 'HeroAttrs', ` 使用属性卡: ${attrCard.desc}`);
// 构造 BuffConf默认使用 BType.VALUE永久生效 (time: 0)
const buffConf: BuffConf = {
buff: attrCard.attr,
value: attrCard.value,
BType: BType.VALUE,
time: 0,
chance: 1, // 必中
};
this.addBuff(buffConf);
smc.updateHeroInfo(this); // 确保同步到全局数据
oops.gui.toast(attrCard.desc);
}
}
onUseItemCard(event: string, args: any) {
if (!this.is_master) return;
const itemId = args;
// 1. 尝试从 PotionCards 获取 (新版药水)
const potion = PotionCards[itemId];
if (potion) {
mLogger.log(this.debugMode, 'HeroAttrs', ` 使用药水: ${potion.desc}`);
const buffConf: BuffConf = {
buff: potion.attr,
value: potion.value,
BType: BType.RATIO, // 药水默认是百分比加成
time: potion.duration,
chance: 1,
};
this.addBuff(buffConf);
oops.gui.toast(potion.desc);
return;
}
}
/**
* 处理英雄升级逻辑
*/
onLevelUp(event: string, args: any) {
mLogger.log(this.debugMode, 'HeroAttrs', ` 收到升级事件: is_master=${this.is_master}, args=${JSON.stringify(args)}`);
// 只有主角才响应升级事件
if (!this.is_master) return;
const newLv = args.lv;
mLogger.log(this.debugMode, 'HeroAttrs', ` 英雄升级处理: Lv.${this.lv} -> Lv.${newLv}`);
if (newLv > this.lv) {
this.lv = newLv;
// === 属性成长逻辑 ===
// 根据职业获取成长属性
const jobConf = JobUpConf[this.type as HType] || { hp: 30, ap: 5, def: 1 };
const hpGrow = jobConf.hp;
const apGrow = jobConf.ap;
const defGrow = jobConf.def;
this.base_hp += hpGrow;
this.base_ap += apGrow;
this.base_def += defGrow;
// 重新计算受影响的属性
this.recalculateSingleAttr(Attrs.HP_MAX);
this.recalculateSingleAttr(Attrs.AP);
this.recalculateSingleAttr(Attrs.DEF);
// 升级福利:回复 20% 最大生命值
const healRatio = 0.2;
const healAmount = Math.floor(this.Attrs[Attrs.HP_MAX] * healRatio);
this.add_hp(healAmount, true);
// 同步数据到全局
smc.updateHeroInfo(this);
// 简单的UI提示
// oops.gui.toast(`升级HP+${hpGrow} AP+${apGrow}`);
}
}
start(){
}
@@ -189,55 +80,12 @@ export class HeroAttrsComp extends ecs.Comp {
initAttrs() {
// 清空现有 buff/debuff
this.BUFFS = {};
this.BUFFS_TEMP = {};
this.BUFFS_TAL = {};
this.Talents = {};
this.DEBUFFS = {};
// 获取英雄配置
const heroInfo = HeroInfo[this.hero_uuid];
if (!heroInfo) return;
// 1. 重置为基础值
this.Attrs[Attrs.HP_MAX] = this.base_hp;
this.Attrs[Attrs.MP_MAX] = this.base_mp;
this.Attrs[Attrs.DEF] = this.base_def;
this.Attrs[Attrs.AP] = this.base_ap;
this.Attrs[Attrs.SPEED] = this.base_speed;
// 2. 初始化其他属性(无初始值的)
for (const attrKey in this.Attrs) {
const attrIndex = parseInt(attrKey);
if (
attrIndex !== Attrs.HP_MAX &&
attrIndex !== Attrs.MP_MAX &&
attrIndex !== Attrs.DEF &&
attrIndex !== Attrs.AP &&
attrIndex !== Attrs.SPEED
) {
this.Attrs[attrIndex] = 0;
}
}
// 加载初始 buff
if (heroInfo.buff && heroInfo.buff.length > 0) {
for (const buffConf of heroInfo.buff) {
this.addBuff(buffConf);
}
}
// 3. 应用全局属性加成 (强制重算受影响的属性)
if (this.fac === 0 && smc.global_attrs) {
for (const key in smc.global_attrs) {
const attrIndex = Number(key);
this.recalculateSingleAttr(attrIndex);
}
}
// 4. 初始化状态值 (确保满状态)
this.hp = this.Attrs[Attrs.HP_MAX];
this.mp = this.Attrs[Attrs.MP_MAX];
smc.updateHeroInfo(this);
}
/*******************基础属性管理********************/
@@ -245,7 +93,7 @@ export class HeroAttrsComp extends ecs.Comp {
const oldHp = this.hp;
let addValue = value;
if(!isValue){
addValue = value * this.Attrs[Attrs.HP_MAX] / 100;
addValue = value * this.hp_max / 100;
}
// ✅ 数据层只负责数据修改,不调用视图层
@@ -255,34 +103,16 @@ export class HeroAttrsComp extends ecs.Comp {
// }
this.hp += addValue;
this.hp = Math.max(0, Math.min(this.hp, this.Attrs[Attrs.HP_MAX]));
this.hp = Math.max(0, Math.min(this.hp, this.hp_max));
this.dirty_hp = true; // ✅ 仅标记需要更新
smc.updateHeroInfo(this);
mLogger.log(this.debugMode, 'HeroAttrs', ` HP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldHp.toFixed(1)} -> ${this.hp.toFixed(1)}`);
}
add_mp(value:number,isValue:boolean){
const oldMp = this.mp;
let addValue = value;
if(!isValue){
addValue = value * this.Attrs[Attrs.MP_MAX] / 100;
}
// ✅ 数据层只负责数据修改,不调用视图层
// let heroView = this.ent.get(HeroViewComp);
// if(heroView){
// heroView.mp_add(addValue);
// }
this.mp += addValue;
this.mp = Math.max(0, Math.min(this.mp, this.Attrs[Attrs.MP_MAX]));
this.dirty_mp = true; // ✅ 仅标记需要更新
mLogger.log(this.debugMode, 'HeroAttrs', ` MP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldMp.toFixed(1)} -> ${this.mp.toFixed(1)}`);
}
add_shield(value:number,isValue:boolean){
const oldShield = this.shield;
let addValue = value;
if(!isValue){
addValue = value * this.Attrs[Attrs.HP_MAX] / 100;
addValue = value * this.shield_max / 100;
}
this.shield += addValue;
this.dirty_shield = true; // 标记护盾需要更新
@@ -294,268 +124,21 @@ export class HeroAttrsComp extends ecs.Comp {
* @param buffConf buff 配置 (来自 SkillSet.BuffConf heroSet.buff)
*/
addBuff(buffConf: BuffConf) {
const isPermanent = buffConf.time === 0;
const attrIndex = buffConf.buff;
if (isPermanent) {
// 添加持久buff到BUFFS - 直接追加到数组
if (!this.BUFFS[attrIndex]) {
this.BUFFS[attrIndex] = [];
}
this.BUFFS[attrIndex].push({ value: buffConf.value, BType: buffConf.BType });
} else {
// 添加临时buff到BUFFS_TEMP - 直接追加到数组
if (!this.BUFFS_TEMP[attrIndex]) {
this.BUFFS_TEMP[attrIndex] = [];
}
this.BUFFS_TEMP[attrIndex].push({
value: buffConf.value,
BType: buffConf.BType,
remainTime: buffConf.time
});
}
// 重新计算受影响的属性
this.recalculateSingleAttr(attrIndex);
smc.updateHeroInfo(this); // 确保同步到全局数据
}
// ==================== 属性计算系统 ====================
private getBaseValue(attrIndex: number): number {
switch (attrIndex) {
case Attrs.HP_MAX: return this.base_hp;
case Attrs.MP_MAX: return this.base_mp;
case Attrs.DEF: return this.base_def;
case Attrs.AP: return this.base_ap;
case Attrs.SPEED: return this.base_speed;
case Attrs.SHIELD_MAX: return 0;
default: return 0;
}
}
/**
* 重新计算单个属性
* @param attrIndex 属性索引
*/
recalculateSingleAttr(attrIndex: number) {
const oldVal = this.Attrs[attrIndex] || 0;
const baseVal = this.getBaseValue(attrIndex);
// 2. 收集所有数值型 buff/debuff
let totalValue = baseVal;
// 遍历持久buff数组
if (this.BUFFS[attrIndex] && this.BUFFS[attrIndex].length > 0) {
for (const buff of this.BUFFS[attrIndex]) {
if (buff.BType === BType.VALUE) {
totalValue += buff.value;
}
}
}
// 遍历临时buff数组
if (this.BUFFS_TEMP[attrIndex] && this.BUFFS_TEMP[attrIndex].length > 0) {
for (const buff of this.BUFFS_TEMP[attrIndex]) {
if (buff.BType === BType.VALUE) {
totalValue += buff.value;
}
}
}
for (const key in this.BUFFS_TAL) {
const buff = this.BUFFS_TAL[Number(key)];
if (buff.attrIndex === attrIndex && buff.BType === BType.VALUE) {
totalValue += buff.value;
}
}
// 3. 收集所有百分比型 buff/debuff
let totalRatio = 0;
// 遍历持久buff数组
if (this.BUFFS[attrIndex] && this.BUFFS[attrIndex].length > 0) {
for (const buff of this.BUFFS[attrIndex]) {
if (buff.BType === BType.RATIO) {
totalRatio += buff.value;
}
}
}
// 遍历临时buff数组
if (this.BUFFS_TEMP[attrIndex] && this.BUFFS_TEMP[attrIndex].length > 0) {
for (const buff of this.BUFFS_TEMP[attrIndex]) {
if (buff.BType === BType.RATIO) {
totalRatio += buff.value;
}
}
}
for (const key in this.BUFFS_TAL) {
const buff = this.BUFFS_TAL[Number(key)];
if (buff.attrIndex === attrIndex && buff.BType === BType.RATIO) {
totalRatio += buff.value;
}
}
// 全局属性加成 (只对英雄生效,怪物不生效)
// this.fac === 0 代表英雄 (FacSet.HERO)
if (this.fac === 0 && smc.global_attrs && smc.global_attrs[attrIndex]) {
const [val, count] = smc.global_attrs[attrIndex];
const globalAdd = val * count;
totalRatio += globalAdd;
// mLogger.log(this.debugMode, 'HeroAttrs', ` 全局加成: ${this.hero_name} Attr=${attrIndex} Val=${val} Count=${count} Add=${globalAdd}%`);
}
// 4. 根据属性类型计算最终值
const attrType = AttrsType[attrIndex];
const isRatioAttr = attrType === BType.RATIO;
if (isRatioAttr) {
// 百分比型属性:直接加减
this.Attrs[attrIndex] = totalValue + totalRatio;
} else {
// 数值型属性:(基础值+数值) × (1 + 百分比/100)
this.Attrs[attrIndex] = Math.floor(totalValue * (1 + totalRatio / 100));
}
// 5. 确保属性值合理
this.clampSingleAttr(attrIndex);
if (oldVal !== this.Attrs[attrIndex]) {
mLogger.log(this.debugMode, 'HeroAttrs', ` 属性重算: ${this.hero_name}, 属性ID=${attrIndex}, ${oldVal} -> ${this.Attrs[attrIndex]} (Base=${baseVal}, Add=${totalValue-baseVal}, Ratio=${totalRatio}%)`);
}
}
/**
* 确保单个属性值合理
*/
private clampSingleAttr(attrIndex: number) {
switch(attrIndex) {
case Attrs.HP_MAX:
case Attrs.MP_MAX:
this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
break;
case Attrs.DEF:
case Attrs.AP:
this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
break;
case Attrs.CRITICAL:
case Attrs.DODGE:
case Attrs.HIT:
this.Attrs[attrIndex] = Math.max(0, Math.min(AttrSet.ATTR_MAX, this.Attrs[attrIndex]));
break;
}
}
// ==================== 临时 BUFF/DEBUFF 更新 ====================
/**
* 更新临时 buff/debuff 的剩余时间
* @param dt 时间增量
*/
updateTemporaryBuffsDebuffs(dt: number) {
const affectedAttrs = new Set<number>();
updateBuffsDebuffs(dt: number) {
// 更新临时型buff
for (const attrIndex in this.BUFFS_TEMP) {
const buffs = this.BUFFS_TEMP[attrIndex];
for (let i = buffs.length - 1; i >= 0; i--) {
const buff = buffs[i];
buff.remainTime -= dt;
if (buff.remainTime <= 0) {
buffs.splice(i, 1);
}
}
if (buffs.length === 0) {
delete this.BUFFS_TEMP[attrIndex];
affectedAttrs.add(parseInt(attrIndex));
}
}
// 负面状态更新
for (const key in this.NeAttrs) {
const debuff = this.NeAttrs[key];
debuff.remainTime -= dt;
if (debuff.remainTime <= 0) {
debuff.remainTime = 0;
}
}
// 只重新计算受影响的属性
affectedAttrs.forEach(attrIndex => {
this.recalculateSingleAttr(attrIndex);
});
}
// ==================== BUFF 辅助方法 ====================
/**
* 清空buff
* @param attrIndex 属性索引如果为空则清理所有buff
* @param isBuff true时清理value>0的增益bufffalse时清理value<0的减益buff
*/
clearBuffs(attrIndex?: number, isBuff: boolean = true): void {
if (attrIndex === undefined) {
for (const attrIndex in this.BUFFS_TEMP) {
this.clearBuffsForAttr(parseInt(attrIndex), isBuff);
}
} else {
this.clearBuffsForAttr(attrIndex, isBuff);
}
}
/**
* 清理指定属性的buff
* @param attrIndex 属性索引
* @param isBuff true清理增益bufffalse清理减益buff
*/
private clearBuffsForAttr(attrIndex: number, isBuff: boolean): void {
const buffContainer = this.BUFFS_TEMP;
if (!buffContainer[attrIndex]) return;
buffContainer[attrIndex] = buffContainer[attrIndex].filter(buff => {
const shouldClear = isBuff ? buff.value > 0 : buff.value < 0;
return !shouldClear;
});
if (buffContainer[attrIndex].length === 0) {
delete buffContainer[attrIndex];
}
this.recalculateSingleAttr(attrIndex);
}
// ==================== NeAttrs负面状态管理 ====================
/**
* 清理单个NeAttr负面状态
*/
clearNeAttr(neAttrIndex: number): void {
if (this.NeAttrs[neAttrIndex]) {
this.NeAttrs[neAttrIndex].value = 0;
this.NeAttrs[neAttrIndex].time = 0;
}
}
/**
* 清理所有NeAttrs负面状态
*/
clearAllNeAttrs(): void {
for (const key in this.NeAttrs) {
this.NeAttrs[key].value = 0;
this.NeAttrs[key].time = 0;
}
}
/**
* 检查是否处于眩晕状态
*/
public isStun(): boolean {
return this.NeAttrs[NeAttrs.IN_STUN]?.time > 0;
}
/**
* 检查是否处于冰冻状态
*/
public isFrost(): boolean {
return this.NeAttrs[NeAttrs.IN_FROST]?.time > 0;
}
// ==================== 技能距离缓存管理 ====================
/**
@@ -591,117 +174,23 @@ export class HeroAttrsComp extends ecs.Comp {
public getCachedMinSkillDistance(): number {
return this.minSkillDistance;
}
/**
* 添加数值型天赋buff 数值会进行累加count 时叠加层数
* @param t_uuid 天赋唯一标识
* @param attrIndex 属性索引
* @param bType buff类型(VALUE:数值型, RATIO:百分比型)
* @param value buff值
*/
addValueTal(t_uuid: number, attrIndex?: number, bType?: BType, value: number = 0) {
if (attrIndex === undefined || bType === undefined) return;
const buff = this.BUFFS_TAL[t_uuid];
if (!buff) {
this.BUFFS_TAL[t_uuid] = { count: 1, BType: bType, attrIndex, value };
} else {
buff.count += 1;
buff.value += value;
}
this.recalculateSingleAttr(attrIndex);
}
/**
* 添加计数型天赋每次添加数值已最新额覆盖久的count为可用次数
* @param eff 天赋效果ID
* @param value 天赋值
*/
addCountTal(eff: number, value: number) {
const t = this.Talents[eff] || { value: 0, count: 0 };
t.value = value;
t.count += 1;
this.Talents[eff] = t;
}
/**
* 使用计数型天赋,如风怒 ,必爆等天赋,只需要返回是否暴击的,使用这个方法
* @param eff 天赋效果ID
* @returns 是否使用成功
*/
useCountTal(eff: number): boolean {
const t = this.Talents[eff];
if (!t || t.count <= 0) return false;
t.count -= 1;
return true;
}
/**
* 使用计数型天赋并返回天赋值如额外5次 伤害+20% 5次受伤免伤20% 使用这个方法
* @param eff 天赋效果ID
* @returns 天赋值
*/
useCountValTal(eff: number): number {
const t = this.Talents[eff];
if (!t || t.value <= 0) return 0;
t.count -= 1;
return t.value;
}
/**
* 根据UUID移除数值型天赋buff
* @param t_uuid 天赋唯一标识
*/
useValueTalByUuid(t_uuid: number) {
const buff = this.BUFFS_TAL[t_uuid];
if (!buff) return;
buff.count--;
if (buff.count <= 0) {
delete this.BUFFS_TAL[t_uuid];
}
this.recalculateSingleAttr(buff.attrIndex);
}
/**
* 根据属性索引移除数值型天赋buff
* @param attrIndex 属性索引
*/
useValueTalByAttr(attrIndex: number) {
let changed = false;
for (const key in this.BUFFS_TAL) {
const b = this.BUFFS_TAL[Number(key)];
if (b && b.attrIndex === attrIndex) {
delete this.BUFFS_TAL[Number(key)];
changed = true;
}
}
if (changed) this.recalculateSingleAttr(attrIndex);
}
reset() {
this.removeEvent();
// 重置为初始状态
this.hero_uuid = 1001;
this.hero_name = "hero";
this.lv = 1;
this.type = 0;
this.fac = 0;
this.base_ap = 0;
this.base_def = 5;
this.base_hp = 100;
this.base_mp = 100;
this.base_speed = 100;
this.base_dis = 0;
this.ap = 0;
this.hp = 100;
this.speed = 100;
this.dis = 0;
this.hp = 100;
this.mp = 100;
this.shield = 0;
this.Attrs = [];
this.NeAttrs = [];
this.shield_max = 0;
this.BUFFS = {};
this.BUFFS_TEMP = {};
this.BUFFS_TAL = {};
this.Talents = {};
this.DEBUFFS = {};
// 重置技能距离缓存
this.maxSkillDistance = 0;
this.minSkillDistance = 0;