角色视图 数据逻辑 依ecs 框架进行重构
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user