- 将 HeroAttrsComp 中的技能数组和独立 CD 映射重构为统一的 HSkillInfo 对象记录 - 在 SDataCom 中新增 skill_lv 字段,并在 Skill 加载时传入技能等级 - 更新 Hero 和 Monster 初始化逻辑以适配新的技能数据结构 - 修改 SCastSystem 以传递技能等级并影响技能效果 - 更新 heroSet 配置,将 skills 字段类型改为 Record<number, HSkillInfo>
221 lines
7.4 KiB
TypeScript
221 lines
7.4 KiB
TypeScript
import { instantiate, Node, Prefab, Vec3 ,v3,resources,SpriteFrame,Sprite,SpriteAtlas, BoxCollider2D, NodePool, tween, Tween} from "cc";
|
||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||
import { smc } from "../common/SingletonModuleComp";
|
||
import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet";
|
||
import { HeroInfo } from "../common/config/heroSet";
|
||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||
import { HeroViewComp } from "./HeroViewComp";
|
||
import { MoveComp } from "./MoveComp";
|
||
import { mLogger } from "../common/Logger";
|
||
/** 角色实体 */
|
||
@ecs.register(`Monster`)
|
||
export class Monster extends ecs.Entity {
|
||
HeroModel!: HeroAttrsComp;
|
||
HeroView!: HeroViewComp;
|
||
MonMove!: MoveComp;
|
||
private debugMode: boolean = false; // 是否启用调试模式
|
||
|
||
// 多键对象池:Map<prefabPath, NodePool>
|
||
static pools: Map<string, NodePool> = new Map();
|
||
static readonly MAX_POOL_SIZE: number = 12;
|
||
static readonly MAX_POOL_TOTAL: number = 60;
|
||
private static totalPoolSize(): number {
|
||
let total = 0;
|
||
this.pools.forEach((pool) => {
|
||
total += pool.size();
|
||
});
|
||
return total;
|
||
}
|
||
|
||
static getFromPool(path: string): Node | null {
|
||
if (this.pools.has(path)) {
|
||
const pool = this.pools.get(path)!;
|
||
while (pool.size() > 0) {
|
||
const node = pool.get();
|
||
if (node && node.isValid) {
|
||
return node;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
static putToPool(path: string, node: Node) {
|
||
if (!node || !node.isValid) return;
|
||
if (!this.pools.has(path)) {
|
||
this.pools.set(path, new NodePool());
|
||
}
|
||
const pool = this.pools.get(path)!;
|
||
if (pool.size() >= this.MAX_POOL_SIZE || this.totalPoolSize() >= this.MAX_POOL_TOTAL) {
|
||
node.destroy();
|
||
return;
|
||
}
|
||
pool.put(node);
|
||
}
|
||
|
||
static clearPools() {
|
||
this.pools.forEach((pool) => {
|
||
while (pool.size() > 0) {
|
||
const node = pool.get();
|
||
if (node && node.isValid) {
|
||
node.destroy();
|
||
}
|
||
}
|
||
pool.clear();
|
||
});
|
||
this.pools.clear();
|
||
}
|
||
|
||
static getPoolStats() {
|
||
let total = 0;
|
||
this.pools.forEach((pool) => {
|
||
total += pool.size();
|
||
});
|
||
return {
|
||
paths: this.pools.size,
|
||
total,
|
||
maxPerPath: this.MAX_POOL_SIZE,
|
||
maxTotal: this.MAX_POOL_TOTAL
|
||
};
|
||
}
|
||
|
||
protected init() {
|
||
this.addComponents<ecs.Comp>(
|
||
MoveComp,
|
||
HeroAttrsComp,
|
||
);
|
||
}
|
||
|
||
destroy(): void {
|
||
// 回收节点到对象池
|
||
const model = this.get(HeroAttrsComp);
|
||
const view = this.get(HeroViewComp);
|
||
if (model && view && view.node && view.node.isValid) {
|
||
const path = "game/heros/" + HeroInfo[model.hero_uuid].path;
|
||
Monster.putToPool(path, view.node);
|
||
}
|
||
|
||
this.remove(HeroViewComp);
|
||
this.remove(HeroAttrsComp);
|
||
super.destroy();
|
||
}
|
||
|
||
/** 加载角色 */
|
||
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, is_boss:boolean=false, dropToY:number = pos.y) {
|
||
scale=-1
|
||
let size=1
|
||
var scene = smc.map.MapView.scene;
|
||
var path = "game/heros/"+HeroInfo[uuid].path;
|
||
|
||
// 尝试从池中获取
|
||
let node = Monster.getFromPool(path);
|
||
if (!node) {
|
||
var prefab: Prefab = oops.res.get(path, Prefab)!;
|
||
node = instantiate(prefab);
|
||
}
|
||
|
||
node.parent = scene.entityLayer!.node!.getChildByName("HERO")!;
|
||
var view = node.getComponent(HeroViewComp)!;
|
||
const collider = node.getComponent(BoxCollider2D);
|
||
if (collider) {
|
||
collider.enabled = false;
|
||
}
|
||
|
||
node.setScale(size*node.scale.x,size*node.scale.y);
|
||
node.setPosition(pos)
|
||
const model = this.get(HeroAttrsComp);
|
||
let hero = HeroInfo[uuid]; // 共用英雄数据
|
||
// 设置 View 层属性(表现相关)
|
||
view.scale = scale;
|
||
view.box_group = BoxSet.MONSTER;
|
||
// 设置 Model 层属性 基础属性
|
||
model.hero_uuid = uuid;
|
||
model.hero_name = hero.name;
|
||
model.hp = model.hp_max = hero.hp;
|
||
model.ap = hero.ap;
|
||
model.speed = hero.speed; // 使用成长后的速度
|
||
model.type = hero.type;
|
||
model.fac = FacSet.MON;
|
||
model.is_boss =is_boss
|
||
if(!model.is_boss){
|
||
model.is_kalami = true;
|
||
}
|
||
model.skills = {};
|
||
for (const key in hero.skills) {
|
||
const skill = hero.skills[key];
|
||
if (!skill) continue;
|
||
model.skills[skill.uuid] = { ...skill, ccd: skill.cd };
|
||
}
|
||
model.updateSkillDistanceCache();
|
||
//根据刷怪控制脚本对ap和hp进行加强
|
||
|
||
|
||
|
||
this.add(view);
|
||
// 重置视图状态(对象池复用时必须)
|
||
view.init();
|
||
oops.message.dispatchEvent("monster_load",this)
|
||
// 初始化移动参数,包括线路和生成顺序
|
||
const move = this.get(MoveComp);
|
||
move.reset();
|
||
move.direction = -1; // 向左移动
|
||
move.targetX = Math.max(-320, Math.min(320, pos.x));
|
||
move.baseY = dropToY;
|
||
move.moving = false;
|
||
const dropDistance = Math.abs(pos.y - dropToY);
|
||
const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200));
|
||
Tween.stopAllByTarget(node);
|
||
tween(node)
|
||
.to(dropDuration, { position: v3(pos.x, dropToY, 0) })
|
||
.call(() => {
|
||
if (!node || !node.isValid) return;
|
||
node.setPosition(pos.x, dropToY, 0);
|
||
move.moving = true;
|
||
if (collider) {
|
||
collider.enabled = true;
|
||
collider.group = BoxSet.MONSTER;
|
||
collider.apply();
|
||
}
|
||
})
|
||
.start();
|
||
smc.vmdata.mission_data.mon_num++
|
||
}
|
||
|
||
|
||
reset() {
|
||
// 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放
|
||
super.destroy();
|
||
}
|
||
|
||
}
|
||
@ecs.register('MonLifecycleSystem')
|
||
export class MonLifecycleSystem extends ecs.ComblockSystem
|
||
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
||
debugMode: boolean = false; // 是否启用调试模式
|
||
|
||
filter() {
|
||
return ecs.allOf(MoveComp);
|
||
}
|
||
|
||
entityEnter(e: ecs.Entity): void {
|
||
// 怪物实体创建时的特殊处理
|
||
const heroAttrs = e.get(HeroAttrsComp);
|
||
if (heroAttrs) {
|
||
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: ${heroAttrs.hero_name}`);
|
||
} else {
|
||
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: 实体ID ${e.eid}`);
|
||
}
|
||
}
|
||
|
||
entityRemove(e: ecs.Entity): void {
|
||
// 怪物实体销毁时的清理工作
|
||
const heroAttrs = e.get(HeroAttrsComp);
|
||
if (heroAttrs) {
|
||
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: ${heroAttrs.hero_name}`);
|
||
} else {
|
||
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: 实体ID ${e.eid}`);
|
||
}
|
||
}
|
||
}
|