Files
pixelheros/assets/script/game/hero/Mon.ts
walkpan 1bb2d6072e refactor: 移除眩晕机制并简化buff系统
- 删除眩晕相关属性、状态检查及动画触发
- 移除BType枚举,简化BuffConf结构,所有buff改为固定值类型
- 清理未使用的导入和配置项,包括debuffs数组和多个英雄属性
- 简化暴击伤害计算,移除施法者暴击伤害加成
- 重构冰冻状态检查逻辑,添加frost_end_time字段
2026-03-19 18:43:02 +08:00

221 lines
7.5 KiB
TypeScript
Raw 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 { 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.a_cd_max=hero.as
model.s_cd_max=hero.ss
model.back_chance=FightSet.BACK_CHANCE
// ✅ 初始化技能数据(迁移到 HeroSkillsComp
if(hero.skills[0]) model.atk_id=hero.skills[0]
if(hero.skills[1]) model.skill_id=hero.skills[1]
model.updateSkillDistanceCache(model.skill_id || model.atk_id);
//根据刷怪控制脚本对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}`);
}
}
}