mirror of
https://github.com/motajs/template.git
synced 2026-05-20 09:11:10 +08:00
feat: 触发器收集
This commit is contained in:
parent
7428f41c93
commit
03dc5ea60b
@ -33,7 +33,11 @@ import {
|
|||||||
DamageSystem,
|
DamageSystem,
|
||||||
EnemyContext,
|
EnemyContext,
|
||||||
IEnemyContext,
|
IEnemyContext,
|
||||||
MapDamage
|
ITriggerCollector,
|
||||||
|
ITriggerRegistry,
|
||||||
|
MapDamage,
|
||||||
|
TriggerCollector,
|
||||||
|
TriggerRegistry
|
||||||
} from '@user/data-system';
|
} from '@user/data-system';
|
||||||
import {
|
import {
|
||||||
CommonAuraConverter,
|
CommonAuraConverter,
|
||||||
@ -78,6 +82,8 @@ export class CoreState implements ICoreState {
|
|||||||
|
|
||||||
// Layer 2 内容
|
// Layer 2 内容
|
||||||
readonly enemyContext: IEnemyContext<IEnemyAttr, IHeroAttr>;
|
readonly enemyContext: IEnemyContext<IEnemyAttr, IHeroAttr>;
|
||||||
|
readonly triggerRegistry: ITriggerRegistry;
|
||||||
|
readonly triggerCollector: ITriggerCollector;
|
||||||
|
|
||||||
// 用户层内容
|
// 用户层内容
|
||||||
readonly loadProgress: ILoadProgressTotal;
|
readonly loadProgress: ILoadProgressTotal;
|
||||||
@ -95,26 +101,43 @@ export class CoreState implements ICoreState {
|
|||||||
> = new Map();
|
> = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
//#region L0 初始化
|
||||||
|
|
||||||
|
// 朝向
|
||||||
|
this.roleFace = new RoleFaceBinder();
|
||||||
|
this.faceManager = new FaceManager();
|
||||||
|
const dir4 = new Dir4FaceHandler();
|
||||||
|
const dir8 = new Dir8FaceHandler();
|
||||||
|
this.faceManager.register(FaceGroup.Dir4, dir4);
|
||||||
|
this.faceManager.registerById('dir4', dir4);
|
||||||
|
this.faceManager.register(FaceGroup.Dir8, dir8);
|
||||||
|
this.faceManager.registerById('dir8', dir8);
|
||||||
|
|
||||||
|
// 图块
|
||||||
const tileStore = new TileStore<LegacyTileData>();
|
const tileStore = new TileStore<LegacyTileData>();
|
||||||
tileStore.attachLegacyConverter(new TileLegacyBridge());
|
tileStore.attachLegacyConverter(new TileLegacyBridge());
|
||||||
this.tileStore = tileStore;
|
this.tileStore = tileStore;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region L1 初始化
|
||||||
|
|
||||||
|
// Flag 系统
|
||||||
|
this.flags = new FlagSystem();
|
||||||
|
|
||||||
|
// 地图
|
||||||
this.maps = new MapStore(tileStore, this);
|
this.maps = new MapStore(tileStore, this);
|
||||||
|
|
||||||
this.loadProgress = new LoadProgressTotal();
|
// 勇士
|
||||||
this.dataLoader = new MotaDataLoader(this.loadProgress);
|
|
||||||
|
|
||||||
//#region 勇士初始化
|
|
||||||
|
|
||||||
const heroMover = new HeroMover();
|
const heroMover = new HeroMover();
|
||||||
const heroAttribute = new HeroAttribute(HERO_DEFAULT_ATTRIBUTE);
|
const heroAttribute = new HeroAttribute(HERO_DEFAULT_ATTRIBUTE);
|
||||||
const heroState = new HeroState(heroMover, heroAttribute);
|
const heroState = new HeroState(heroMover, heroAttribute);
|
||||||
this.hero = heroState;
|
this.hero = heroState;
|
||||||
|
|
||||||
//#endregion
|
this.loadProgress = new LoadProgressTotal();
|
||||||
|
this.dataLoader = new MotaDataLoader(this.loadProgress);
|
||||||
|
|
||||||
//#region 怪物初始化
|
// 怪物管理器
|
||||||
|
|
||||||
// 怪物管理器初始化
|
|
||||||
const comparer = new MainEnemyComparer();
|
const comparer = new MainEnemyComparer();
|
||||||
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
||||||
enemyManager.attachEnemyComparer(comparer);
|
enemyManager.attachEnemyComparer(comparer);
|
||||||
@ -126,7 +149,12 @@ export class CoreState implements ICoreState {
|
|||||||
enemyManager.setAttributeDefaults('point', 0);
|
enemyManager.setAttributeDefaults('point', 0);
|
||||||
registerSpecials(enemyManager);
|
registerSpecials(enemyManager);
|
||||||
this.enemyManager = enemyManager;
|
this.enemyManager = enemyManager;
|
||||||
// 怪物上下文初始化
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region L2 初始化
|
||||||
|
|
||||||
|
// 怪物上下文
|
||||||
const enemyContext = new EnemyContext<IEnemyAttr, IHeroAttr>(this);
|
const enemyContext = new EnemyContext<IEnemyAttr, IHeroAttr>(this);
|
||||||
const damageSystem = new DamageSystem(enemyContext);
|
const damageSystem = new DamageSystem(enemyContext);
|
||||||
const mapDamage = new MapDamage(enemyContext);
|
const mapDamage = new MapDamage(enemyContext);
|
||||||
@ -142,10 +170,18 @@ export class CoreState implements ICoreState {
|
|||||||
enemyContext.bindHero(heroAttribute);
|
enemyContext.bindHero(heroAttribute);
|
||||||
this.enemyContext = enemyContext;
|
this.enemyContext = enemyContext;
|
||||||
|
|
||||||
|
// 触发器注册与收集器
|
||||||
|
const triggerRegistry = new TriggerRegistry();
|
||||||
|
const triggerCollector = new TriggerCollector();
|
||||||
|
triggerCollector.attachRegistry(triggerRegistry);
|
||||||
|
this.triggerRegistry = triggerRegistry;
|
||||||
|
this.triggerCollector = triggerCollector;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 存档系统
|
//#region 顶层初始化
|
||||||
|
|
||||||
|
// 存档系统
|
||||||
this.saveSystem = new SaveSystem();
|
this.saveSystem = new SaveSystem();
|
||||||
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
||||||
this.saveSystem.config({
|
this.saveSystem.config({
|
||||||
@ -155,29 +191,16 @@ export class CoreState implements ICoreState {
|
|||||||
saveTimeTolerance: 100,
|
saveTimeTolerance: 100,
|
||||||
autosaveStackSize: 20
|
autosaveStackSize: 20
|
||||||
});
|
});
|
||||||
|
this.addSaveableContent('@system/hero', this.hero);
|
||||||
|
this.addSaveableContent('@system/flags', this.flags);
|
||||||
|
this.addSaveableContent('@system/maps', this.maps);
|
||||||
|
this.addSaveableContent('@system/enemy', this.enemyManager);
|
||||||
// 初始化存档数据库,不要动
|
// 初始化存档数据库,不要动
|
||||||
loading.once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
this.saveSystem.init(`@game/${core.firstData.name}`);
|
this.saveSystem.init(`@game/${core.firstData.name}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
//#endregion
|
// 加载初始化,先使用兼容层实现
|
||||||
|
|
||||||
//#region 其他初始化
|
|
||||||
|
|
||||||
// 朝向
|
|
||||||
this.roleFace = new RoleFaceBinder();
|
|
||||||
this.faceManager = new FaceManager();
|
|
||||||
const dir4 = new Dir4FaceHandler();
|
|
||||||
const dir8 = new Dir8FaceHandler();
|
|
||||||
this.faceManager.register(FaceGroup.Dir4, dir4);
|
|
||||||
this.faceManager.registerById('dir4', dir4);
|
|
||||||
this.faceManager.register(FaceGroup.Dir8, dir8);
|
|
||||||
this.faceManager.registerById('dir8', dir8);
|
|
||||||
|
|
||||||
this.flags = new FlagSystem();
|
|
||||||
|
|
||||||
// 加载先使用兼容层实现
|
|
||||||
loading.once('loaded', () => {
|
loading.once('loaded', () => {
|
||||||
this.initTileStore(core.maps.blocksInfo);
|
this.initTileStore(core.maps.blocksInfo);
|
||||||
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
||||||
@ -186,13 +209,6 @@ export class CoreState implements ICoreState {
|
|||||||
core.floors as Record<FloorIds, ResolvedFloor>
|
core.floors as Record<FloorIds, ResolvedFloor>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addSaveableContent('@system/hero', this.hero);
|
|
||||||
this.addSaveableContent('@system/flags', this.flags);
|
|
||||||
this.addSaveableContent('@system/maps', this.maps);
|
|
||||||
this.addSaveableContent('@system/enemy', this.enemyManager);
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export class TriggerCollection implements ITriggerCollection {
|
|||||||
private readonly triggerList: ITrigger[];
|
private readonly triggerList: ITrigger[];
|
||||||
|
|
||||||
constructor(triggers: Iterable<ITrigger>) {
|
constructor(triggers: Iterable<ITrigger>) {
|
||||||
this.triggerList = Array.from(triggers);
|
this.triggerList = [...triggers];
|
||||||
}
|
}
|
||||||
|
|
||||||
count(): number {
|
count(): number {
|
||||||
|
|||||||
112
packages-user/data-system/src/trigger/collector.ts
Normal file
112
packages-user/data-system/src/trigger/collector.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { IMapLayer } from '@user/data-base';
|
||||||
|
import {
|
||||||
|
ITrigger,
|
||||||
|
ITriggerCollection,
|
||||||
|
ITriggerCollector,
|
||||||
|
ITriggerRegistry
|
||||||
|
} from './types';
|
||||||
|
import { logger } from '@motajs/common';
|
||||||
|
import { TriggerCollection } from './collection';
|
||||||
|
|
||||||
|
export class TriggerCollector implements ITriggerCollector {
|
||||||
|
/** 当前收集器使用的注册对象 */
|
||||||
|
private registry: ITriggerRegistry | null = null;
|
||||||
|
|
||||||
|
collect(x: number, y: number, layer: IMapLayer): ITriggerCollection {
|
||||||
|
if (!this.registry) {
|
||||||
|
logger.warn(135);
|
||||||
|
return new TriggerCollection([]);
|
||||||
|
}
|
||||||
|
const staticType = layer.getTriggerType(x, y);
|
||||||
|
const staticTrigger = this.registry.create(staticType);
|
||||||
|
const dynamics = [...layer.dynamicLayer.getDynamicTilesAt(x, y)];
|
||||||
|
|
||||||
|
if (dynamics.length === 0) {
|
||||||
|
// 没有动态图块
|
||||||
|
if (staticTrigger) {
|
||||||
|
return new TriggerCollection([staticTrigger]);
|
||||||
|
} else {
|
||||||
|
return new TriggerCollection([]);
|
||||||
|
}
|
||||||
|
} else if (dynamics.length === 1) {
|
||||||
|
// 一个动态图块,只需要进行一次额外判断即可
|
||||||
|
const dynamic = dynamics[0];
|
||||||
|
const dynamicTrigger = this.registry.create(dynamic.triggerType);
|
||||||
|
// 直接穷举所有可能情况
|
||||||
|
if (!staticTrigger && !dynamicTrigger) {
|
||||||
|
return new TriggerCollection([]);
|
||||||
|
} else if (staticTrigger && !dynamicTrigger) {
|
||||||
|
return new TriggerCollection([staticTrigger]);
|
||||||
|
} else if (!staticTrigger && dynamicTrigger) {
|
||||||
|
return new TriggerCollection([dynamicTrigger]);
|
||||||
|
} else {
|
||||||
|
// 静态动态都有,则需要额外判断优先级,动态图层在前,因此包含等号
|
||||||
|
if (dynamicTrigger!.priority >= staticTrigger!.priority) {
|
||||||
|
const arr = [dynamicTrigger!, staticTrigger!];
|
||||||
|
return new TriggerCollection(arr);
|
||||||
|
} else {
|
||||||
|
const arr = [staticTrigger!, dynamicTrigger!];
|
||||||
|
return new TriggerCollection(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 动态图块大于两个,使用通用方案,记录重复触发器并抛出警告
|
||||||
|
const usedPriority = new Set<number>();
|
||||||
|
const duplicate = new Set<number>();
|
||||||
|
if (staticTrigger) {
|
||||||
|
// 有静态触发器
|
||||||
|
const lessTriggers: ITrigger[] = [];
|
||||||
|
const greaterTriggers: ITrigger[] = [];
|
||||||
|
// 先收集所有的触发器,并记录重复情况
|
||||||
|
for (const tile of layer.dynamicLayer.getDynamicTilesAt(x, y)) {
|
||||||
|
const trigger = this.registry.create(tile.triggerType);
|
||||||
|
if (trigger) {
|
||||||
|
if (usedPriority.has(trigger.priority)) {
|
||||||
|
duplicate.add(trigger.priority);
|
||||||
|
}
|
||||||
|
usedPriority.add(trigger.priority);
|
||||||
|
|
||||||
|
// 同优先级下动态在前,因此包含等号
|
||||||
|
if (trigger.priority >= staticTrigger.priority) {
|
||||||
|
greaterTriggers.push(trigger);
|
||||||
|
} else {
|
||||||
|
lessTriggers.push(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duplicate.size > 0) {
|
||||||
|
logger.warn(136, [...duplicate].join(','));
|
||||||
|
}
|
||||||
|
const arr = [
|
||||||
|
...greaterTriggers.sort((a, b) => b.priority - a.priority),
|
||||||
|
staticTrigger,
|
||||||
|
...lessTriggers.sort((a, b) => b.priority - a.priority)
|
||||||
|
];
|
||||||
|
return new TriggerCollection(arr);
|
||||||
|
} else {
|
||||||
|
// 没有静态触发器
|
||||||
|
const triggers: ITrigger[] = [];
|
||||||
|
for (const tile of layer.dynamicLayer.getDynamicTilesAt(x, y)) {
|
||||||
|
const trigger = this.registry.create(tile.triggerType);
|
||||||
|
if (trigger) {
|
||||||
|
if (usedPriority.has(trigger.priority)) {
|
||||||
|
duplicate.add(trigger.priority);
|
||||||
|
}
|
||||||
|
usedPriority.add(trigger.priority);
|
||||||
|
triggers.push(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duplicate.size > 0) {
|
||||||
|
logger.warn(136, [...duplicate].join(','));
|
||||||
|
}
|
||||||
|
return new TriggerCollection(
|
||||||
|
triggers.sort((a, b) => b.priority - a.priority)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachRegistry(registry: ITriggerRegistry | null): void {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './collection';
|
export * from './collection';
|
||||||
|
export * from './collector';
|
||||||
export * from './registry';
|
export * from './registry';
|
||||||
|
export * from './types';
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
import { IStateBase } from '@user/data-base';
|
import { IStateBase } from '@user/data-base';
|
||||||
import { IEnemyContext } from './combat';
|
import { IEnemyContext } from './combat';
|
||||||
|
import { ITriggerCollector, ITriggerRegistry } from './trigger';
|
||||||
|
|
||||||
export interface IStateSystem<TEnemy, THero> extends IStateBase<TEnemy, THero> {
|
export interface IStateSystem<TEnemy, THero> extends IStateBase<TEnemy, THero> {
|
||||||
/** 怪物上下文 */
|
/** 怪物上下文 */
|
||||||
readonly enemyContext: IEnemyContext<TEnemy, THero>;
|
readonly enemyContext: IEnemyContext<TEnemy, THero>;
|
||||||
|
/** 触发器注册 */
|
||||||
|
readonly triggerRegistry: ITriggerRegistry;
|
||||||
|
/** 触发器收集器 */
|
||||||
|
readonly triggerCollector: ITriggerCollector;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStateSystemExtended<TEnemy = unknown, THero = unknown> {
|
export interface IStateSystemExtended<TEnemy = unknown, THero = unknown> {
|
||||||
|
|||||||
@ -55,8 +55,7 @@
|
|||||||
"53": "Expected serializable value set as enemy's default attribute.",
|
"53": "Expected serializable value set as enemy's default attribute.",
|
||||||
"54": "Legacy '$1' API has been removed, consider using new APIs: '$2'.",
|
"54": "Legacy '$1' API has been removed, consider using new APIs: '$2'.",
|
||||||
"55": "Cannot load MapStore state: reference data (compareWith) has not been set.",
|
"55": "Cannot load MapStore state: reference data (compareWith) has not been set.",
|
||||||
"56": "Cannot convert legacy tile data since no tile legacy converter is attached to TileStore.",
|
"56": "Cannot convert legacy tile data since no tile legacy converter is attached to TileStore."
|
||||||
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency."
|
|
||||||
},
|
},
|
||||||
"warn": {
|
"warn": {
|
||||||
"1": "Resource with type of 'none' is loaded.",
|
"1": "Resource with type of 'none' is loaded.",
|
||||||
@ -193,6 +192,7 @@
|
|||||||
"132": "Trigger registry entry of $1 '$2' already exists, new factory will override old factory.",
|
"132": "Trigger registry entry of $1 '$2' already exists, new factory will override old factory.",
|
||||||
"133": "TileStore.addTile: tile number $1 already exists (id: '$2'), old tile data will be overridden.",
|
"133": "TileStore.addTile: tile number $1 already exists (id: '$2'), old tile data will be overridden.",
|
||||||
"134": "TileStore.addTile: tile id '$1' already maps to number $2, old tile data will be overridden.",
|
"134": "TileStore.addTile: tile id '$1' already maps to number $2, old tile data will be overridden.",
|
||||||
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency."
|
"135": "Expected a trigger registry attched before collect triggers.",
|
||||||
|
"136": "Unexpected duplicate trigger priority $1, which may cause trigger executed in an unexpected order."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user