角色视图 数据逻辑 依ecs 框架进行重构

This commit is contained in:
walkpan
2025-10-30 08:56:37 +08:00
parent edb7f23918
commit a79cb9f35d
10 changed files with 1274 additions and 602 deletions

View File

@@ -5,15 +5,200 @@
* @LastEditTime: 2022-08-17 13:43:25
*/
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { Attrs, AttrsType, BType, NeAttrs } from "../common/config/HeroAttrs";
import { BuffConf } from "../common/config/SkillSet";
import { HeroInfo, AttrSet } from "../common/config/heroSet";
/**
* 角色属性数据
* 怪物属性数据模型 - 存储纯数据,不含表现逻辑
* 简化版本只保留临时buff系统移除持久型buff
*
* 注意HeroModelComp 中有详细的 ECS 架构分析,迁移方案见那个文件
*/
@ecs.register('MonModel')
export class MonModelComp extends ecs.Comp {
/** 角色编号 */
// ==================== 角色基础信息 ====================
hero_uuid: number = 1001;
hero_name: string = "monster";
lv: number = 1;
type: number = 0; // 0近战 1远程 2辅助
fac: number = 1; // 0:hero 1:monster默认为怪物
// ==================== 动态属性值 ====================
hp: number = 100; // 当前血量
mp: number = 100; // 当前魔法值
shield: number = 0; // 当前护盾
Attrs: any = []; // 最终属性数组经过Buff计算后
NeAttrs: any = []; // 负面状态数组
// ==================== Buff/Debuff 系统 ====================
/** 临时型buff数组 - 按时间自动过期怪物只使用临时buff */
BUFFS_TEMP: Record<number, Array<{value: number, BType: BType, remainTime: number}>> = {};
// ==================== 标记状态 ====================
is_dead: boolean = false;
is_count_dead: boolean = false;
is_boss: boolean = false;
is_big_boss: boolean = false;
is_master: boolean = false;
is_friend: boolean = false;
is_kalami: boolean = false;
// ==================== 计数统计 ====================
atk_count: number = 0; // 攻击次数
atked_count: number = 0; // 被攻击次数
// ==================== 技能配置 ====================
skills: any = [];
addBuff(buffConf: BuffConf) {
// 怪物只使用临时buff
const attrIndex = buffConf.buff;
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);
}
recalculateSingleAttr(attrIndex: number) {
const baseValues: Record<number, number> = {
[Attrs.HP_MAX]: this.base_hp, [Attrs.MP_MAX]: this.base_mp, [Attrs.DEF]: this.base_def,
[Attrs.AP]: this.base_ap, [Attrs.MAP]: this.base_map, [Attrs.SPEED]: this.base_speed, [Attrs.SHIELD_MAX]: 0
};
const baseVal = baseValues[attrIndex] !== undefined ? baseValues[attrIndex] : 0;
let totalValue = baseVal, totalRatio = 0;
// 怪物只计算临时buff
if (this.BUFFS_TEMP[attrIndex]) {
for (const buff of this.BUFFS_TEMP[attrIndex]) {
if (buff.BType === BType.VALUE) totalValue += buff.value;
else totalRatio += buff.value;
}
}
const attrType = AttrsType[attrIndex];
this.Attrs[attrIndex] = attrType === BType.RATIO ? totalValue + totalRatio : Math.floor(totalValue * (1 + totalRatio / 100));
this.clampSingleAttr(attrIndex);
}
private clampSingleAttr(attrIndex: number) {
switch(attrIndex) {
case Attrs.HP_MAX: case Attrs.MP_MAX: case Attrs.DEF: case Attrs.AP: case Attrs.MAP:
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;
}
}
updateTemporaryBuffsDebuffs(dt: number) {
const affectedAttrs = new Set<number>();
for (const attrIndex in this.BUFFS_TEMP) {
const buffs = this.BUFFS_TEMP[attrIndex];
buffs.forEach(buff => {
buff.remainTime -= dt;
if (buff.remainTime <= 0) buffs.splice(buffs.indexOf(buff), 1);
});
if (buffs.length === 0) {
delete this.BUFFS_TEMP[attrIndex];
affectedAttrs.add(parseInt(attrIndex));
}
}
for (const key in this.NeAttrs) {
this.NeAttrs[key].remainTime -= dt;
if (this.NeAttrs[key].remainTime <= 0) this.NeAttrs[key].remainTime = 0;
}
affectedAttrs.forEach(attrIndex => this.recalculateSingleAttr(attrIndex));
}
clearBuffs(attrIndex?: number, isBuff: boolean = true): void {
if (attrIndex === undefined) {
for (const idx in this.BUFFS_TEMP) this.clearBuffsForAttr(parseInt(idx), isBuff);
} else {
this.clearBuffsForAttr(attrIndex, isBuff);
}
}
private clearBuffsForAttr(attrIndex: number, isBuff: boolean): void {
if (!this.BUFFS_TEMP[attrIndex]) return;
this.BUFFS_TEMP[attrIndex] = this.BUFFS_TEMP[attrIndex].filter(buff => {
const shouldClear = isBuff ? buff.value > 0 : buff.value < 0;
return !shouldClear;
});
if (this.BUFFS_TEMP[attrIndex].length === 0) delete this.BUFFS_TEMP[attrIndex];
this.recalculateSingleAttr(attrIndex);
}
clearNeAttr(neAttrIndex: number): void {
if (this.NeAttrs[neAttrIndex]) {
this.NeAttrs[neAttrIndex].value = 0;
this.NeAttrs[neAttrIndex].time = 0;
}
}
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;
}
reset() {
this.hero_uuid = 1001;
this.hero_name = "monster";
this.lv = 1;
this.type = 0;
this.fac = 1;
this.hp = 100;
this.mp = 100;
this.shield = 0;
this.Attrs = [];
this.NeAttrs = [];
this.BUFFS_TEMP = {}; // 只重置临时buff
this.is_dead = false;
this.is_count_dead = false;
this.is_boss = false;
this.is_big_boss = false;
this.is_master = false;
this.is_friend = false;
this.is_kalami = false;
this.atk_count = 0;
this.atked_count = 0;
this.skills = [];
}
}
/**
* ==================== 怪物属性更新系统 ====================
*
* 与 HeroAttrSystem 类似,但针对怪物
* 可以复用相同逻辑,也可以定制不同规则
*/
export class MonAttrSystem extends ecs.ComblockSystem
implements ecs.ISystemUpdate {
filter(): ecs.IMatcher {
return ecs.allOf(MonModelComp);
}
update(e: ecs.Entity): void {
const model = e.get(MonModelComp);
if (!model || model.is_dead) return;
// 怪物的属性更新逻辑(可以与英雄不同)
model.updateTemporaryBuffsDebuffs(this.dt);
// 怪物可能没有自然回复,或者回复速度不同
// model.mp += MonUpSet.MP * this.dt;
// model.hp += MonUpSet.HP * this.dt;
}
}