feat(blueprint): 添加蓝图触发器系统 (#323)

* feat(blueprint): 添加蓝图触发器系统

- TriggerTypes: 定义触发器类型和上下文接口
  - tick/input/collision/message/timer/stateEnter/stateExit/custom
  - 各类型的上下文接口和工厂函数

- TriggerCondition: 触发条件系统
  - ITriggerCondition 接口
  - 复合条件 (CompositeCondition, NotCondition)
  - 通用条件 (AlwaysTrue, AlwaysFalse, TriggerType, EntityId)
  - 特定类型条件 (InputAction, MessageName, StateName, TimerId, CollisionEntity, CustomEvent)
  - ConditionBuilder 链式 API

- BlueprintTrigger: 触发器核心实现
  - IBlueprintTrigger 接口
  - BlueprintTrigger 实现类
  - TriggerRegistry 触发器注册表
  - 各类型触发器工厂函数

- TriggerDispatcher: 触发器调度系统
  - ITriggerDispatcher 调度器接口
  - TriggerDispatcher 实现
  - EntityTriggerManager 实体触发器管理器

* feat(blueprint): 添加触发器相关事件节点

- EventInput: 输入事件节点 (action/value/pressed/released)
- EventCollisionEnter/Exit: 碰撞事件节点
- EventMessage: 消息事件节点
- EventTimer: 定时器事件节点
- EventStateEnter/Exit: 状态机事件节点
This commit is contained in:
YHH
2025-12-25 11:35:29 +08:00
committed by GitHub
parent 6b8b65ae16
commit 4089051731
12 changed files with 2424 additions and 2 deletions

View File

@@ -9,6 +9,9 @@ export * from './types';
// Runtime
export * from './runtime';
// Triggers
export * from './triggers';
// Nodes (import to register)
import './nodes';

View File

@@ -0,0 +1,118 @@
/**
* @zh 碰撞事件节点 - 碰撞发生时触发
* @en Event Collision Node - Triggered on collision events
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* @zh EventCollisionEnter 节点模板
* @en EventCollisionEnter node template
*/
export const EventCollisionEnterTemplate: BlueprintNodeTemplate = {
type: 'EventCollisionEnter',
title: 'Event Collision Enter',
category: 'event',
color: '#CC0000',
description: 'Triggered when collision starts / 碰撞开始时触发',
keywords: ['collision', 'enter', 'hit', 'overlap', 'event'],
menuPath: ['Event', 'Collision', 'Enter'],
inputs: [],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'otherEntityId',
type: 'string',
displayName: 'Other Entity'
},
{
name: 'pointX',
type: 'float',
displayName: 'Point X'
},
{
name: 'pointY',
type: 'float',
displayName: 'Point Y'
},
{
name: 'normalX',
type: 'float',
displayName: 'Normal X'
},
{
name: 'normalY',
type: 'float',
displayName: 'Normal Y'
}
]
};
/**
* @zh EventCollisionEnter 节点执行器
* @en EventCollisionEnter node executor
*/
@RegisterNode(EventCollisionEnterTemplate)
export class EventCollisionEnterExecutor implements INodeExecutor {
execute(_node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
otherEntityId: '',
pointX: 0,
pointY: 0,
normalX: 0,
normalY: 0
}
};
}
}
/**
* @zh EventCollisionExit 节点模板
* @en EventCollisionExit node template
*/
export const EventCollisionExitTemplate: BlueprintNodeTemplate = {
type: 'EventCollisionExit',
title: 'Event Collision Exit',
category: 'event',
color: '#CC0000',
description: 'Triggered when collision ends / 碰撞结束时触发',
keywords: ['collision', 'exit', 'end', 'separate', 'event'],
menuPath: ['Event', 'Collision', 'Exit'],
inputs: [],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'otherEntityId',
type: 'string',
displayName: 'Other Entity'
}
]
};
/**
* @zh EventCollisionExit 节点执行器
* @en EventCollisionExit node executor
*/
@RegisterNode(EventCollisionExitTemplate)
export class EventCollisionExitExecutor implements INodeExecutor {
execute(_node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
otherEntityId: ''
}
};
}
}

View File

@@ -0,0 +1,79 @@
/**
* @zh 输入事件节点 - 输入触发时触发
* @en Event Input Node - Triggered on input events
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* @zh EventInput 节点模板
* @en EventInput node template
*/
export const EventInputTemplate: BlueprintNodeTemplate = {
type: 'EventInput',
title: 'Event Input',
category: 'event',
color: '#CC0000',
description: 'Triggered when input action occurs / 输入动作发生时触发',
keywords: ['input', 'key', 'button', 'action', 'event'],
menuPath: ['Event', 'Input'],
inputs: [
{
name: 'action',
type: 'string',
displayName: 'Action',
defaultValue: ''
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'action',
type: 'string',
displayName: 'Action'
},
{
name: 'value',
type: 'float',
displayName: 'Value'
},
{
name: 'pressed',
type: 'bool',
displayName: 'Pressed'
},
{
name: 'released',
type: 'bool',
displayName: 'Released'
}
]
};
/**
* @zh EventInput 节点执行器
* @en EventInput node executor
*
* @zh 注意:事件节点的输出由 VM 在触发时通过 setOutputs 设置
* @en Note: Event node outputs are set by VM via setOutputs when triggered
*/
@RegisterNode(EventInputTemplate)
export class EventInputExecutor implements INodeExecutor {
execute(node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
action: node.data?.action ?? '',
value: 0,
pressed: false,
released: false
}
};
}
}

View File

@@ -0,0 +1,70 @@
/**
* @zh 消息事件节点 - 接收消息时触发
* @en Event Message Node - Triggered when message is received
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* @zh EventMessage 节点模板
* @en EventMessage node template
*/
export const EventMessageTemplate: BlueprintNodeTemplate = {
type: 'EventMessage',
title: 'Event Message',
category: 'event',
color: '#CC0000',
description: 'Triggered when a message is received / 接收到消息时触发',
keywords: ['message', 'receive', 'broadcast', 'event', 'signal'],
menuPath: ['Event', 'Message'],
inputs: [
{
name: 'messageName',
type: 'string',
displayName: 'Message Name',
defaultValue: ''
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'messageName',
type: 'string',
displayName: 'Message'
},
{
name: 'senderId',
type: 'string',
displayName: 'Sender ID'
},
{
name: 'payload',
type: 'any',
displayName: 'Payload'
}
]
};
/**
* @zh EventMessage 节点执行器
* @en EventMessage node executor
*/
@RegisterNode(EventMessageTemplate)
export class EventMessageExecutor implements INodeExecutor {
execute(node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
messageName: node.data?.messageName ?? '',
senderId: '',
payload: null
}
};
}
}

View File

@@ -0,0 +1,132 @@
/**
* @zh 状态事件节点 - 状态机状态变化时触发
* @en Event State Node - Triggered on state machine state changes
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* @zh EventStateEnter 节点模板
* @en EventStateEnter node template
*/
export const EventStateEnterTemplate: BlueprintNodeTemplate = {
type: 'EventStateEnter',
title: 'Event State Enter',
category: 'event',
color: '#CC0000',
description: 'Triggered when entering a state / 进入状态时触发',
keywords: ['state', 'enter', 'fsm', 'machine', 'event'],
menuPath: ['Event', 'State', 'Enter'],
inputs: [
{
name: 'stateName',
type: 'string',
displayName: 'State Name',
defaultValue: ''
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'stateMachineId',
type: 'string',
displayName: 'State Machine'
},
{
name: 'currentState',
type: 'string',
displayName: 'Current State'
},
{
name: 'previousState',
type: 'string',
displayName: 'Previous State'
}
]
};
/**
* @zh EventStateEnter 节点执行器
* @en EventStateEnter node executor
*/
@RegisterNode(EventStateEnterTemplate)
export class EventStateEnterExecutor implements INodeExecutor {
execute(node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
stateMachineId: '',
currentState: node.data?.stateName ?? '',
previousState: ''
}
};
}
}
/**
* @zh EventStateExit 节点模板
* @en EventStateExit node template
*/
export const EventStateExitTemplate: BlueprintNodeTemplate = {
type: 'EventStateExit',
title: 'Event State Exit',
category: 'event',
color: '#CC0000',
description: 'Triggered when exiting a state / 退出状态时触发',
keywords: ['state', 'exit', 'leave', 'fsm', 'machine', 'event'],
menuPath: ['Event', 'State', 'Exit'],
inputs: [
{
name: 'stateName',
type: 'string',
displayName: 'State Name',
defaultValue: ''
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'stateMachineId',
type: 'string',
displayName: 'State Machine'
},
{
name: 'currentState',
type: 'string',
displayName: 'Current State'
},
{
name: 'previousState',
type: 'string',
displayName: 'Previous State'
}
]
};
/**
* @zh EventStateExit 节点执行器
* @en EventStateExit node executor
*/
@RegisterNode(EventStateExitTemplate)
export class EventStateExitExecutor implements INodeExecutor {
execute(node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
stateMachineId: '',
currentState: '',
previousState: node.data?.stateName ?? ''
}
};
}
}

View File

@@ -0,0 +1,70 @@
/**
* @zh 定时器事件节点 - 定时器触发时调用
* @en Event Timer Node - Triggered when timer fires
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* @zh EventTimer 节点模板
* @en EventTimer node template
*/
export const EventTimerTemplate: BlueprintNodeTemplate = {
type: 'EventTimer',
title: 'Event Timer',
category: 'event',
color: '#CC0000',
description: 'Triggered when a timer fires / 定时器触发时执行',
keywords: ['timer', 'delay', 'schedule', 'event', 'interval'],
menuPath: ['Event', 'Timer'],
inputs: [
{
name: 'timerId',
type: 'string',
displayName: 'Timer ID',
defaultValue: ''
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'timerId',
type: 'string',
displayName: 'Timer ID'
},
{
name: 'isRepeating',
type: 'bool',
displayName: 'Is Repeating'
},
{
name: 'timesFired',
type: 'int',
displayName: 'Times Fired'
}
]
};
/**
* @zh EventTimer 节点执行器
* @en EventTimer node executor
*/
@RegisterNode(EventTimerTemplate)
export class EventTimerExecutor implements INodeExecutor {
execute(node: BlueprintNode): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
timerId: node.data?.timerId ?? '',
isRepeating: false,
timesFired: 0
}
};
}
}

View File

@@ -1,8 +1,16 @@
/**
* Event Nodes - Entry points for blueprint execution
* 事件节点 - 蓝图执行的入口点
* @zh 事件节点 - 蓝图执行的入口点
* @en Event Nodes - Entry points for blueprint execution
*/
// 生命周期事件 | Lifecycle events
export * from './EventBeginPlay';
export * from './EventTick';
export * from './EventEndPlay';
// 触发器事件 | Trigger events
export * from './EventInput';
export * from './EventCollision';
export * from './EventMessage';
export * from './EventTimer';
export * from './EventState';

View File

@@ -0,0 +1,497 @@
/**
* @zh 蓝图触发器
* @en Blueprint Trigger
*
* @zh 定义触发器的核心实现
* @en Defines core trigger implementation
*/
import type { TriggerType, ITriggerContext } from './TriggerTypes';
import type { ITriggerCondition } from './TriggerCondition';
import { AlwaysTrueCondition } from './TriggerCondition';
// =============================================================================
// 触发器接口 | Trigger Interface
// =============================================================================
/**
* @zh 触发器回调函数类型
* @en Trigger callback function type
*/
export type TriggerCallback = (context: ITriggerContext) => void;
/**
* @zh 蓝图触发器接口
* @en Blueprint trigger interface
*/
export interface IBlueprintTrigger {
/**
* @zh 触发器唯一标识
* @en Trigger unique identifier
*/
readonly id: string;
/**
* @zh 触发器类型
* @en Trigger type
*/
readonly type: TriggerType;
/**
* @zh 触发器条件
* @en Trigger conditions
*/
readonly condition: ITriggerCondition;
/**
* @zh 是否启用
* @en Is enabled
*/
enabled: boolean;
/**
* @zh 优先级(越高越先执行)
* @en Priority (higher executes first)
*/
readonly priority: number;
/**
* @zh 检查是否应该触发
* @en Check if should fire
*/
shouldFire(context: ITriggerContext): boolean;
/**
* @zh 执行触发器
* @en Execute trigger
*/
fire(context: ITriggerContext): void;
}
/**
* @zh 触发器配置
* @en Trigger configuration
*/
export interface TriggerConfig {
/**
* @zh 触发器 ID
* @en Trigger ID
*/
id?: string;
/**
* @zh 触发器类型
* @en Trigger type
*/
type: TriggerType;
/**
* @zh 触发条件
* @en Trigger condition
*/
condition?: ITriggerCondition;
/**
* @zh 是否启用
* @en Is enabled
*/
enabled?: boolean;
/**
* @zh 优先级
* @en Priority
*/
priority?: number;
/**
* @zh 回调函数
* @en Callback function
*/
callback?: TriggerCallback;
}
// =============================================================================
// 触发器实现 | Trigger Implementation
// =============================================================================
let _triggerId = 0;
/**
* @zh 生成唯一触发器 ID
* @en Generate unique trigger ID
*/
function generateTriggerId(): string {
return `trigger_${++_triggerId}`;
}
/**
* @zh 蓝图触发器实现
* @en Blueprint trigger implementation
*/
export class BlueprintTrigger implements IBlueprintTrigger {
readonly id: string;
readonly type: TriggerType;
readonly condition: ITriggerCondition;
readonly priority: number;
enabled: boolean;
private readonly _callback?: TriggerCallback;
private readonly _callbacks: Set<TriggerCallback> = new Set();
constructor(config: TriggerConfig) {
this.id = config.id ?? generateTriggerId();
this.type = config.type;
this.condition = config.condition ?? new AlwaysTrueCondition();
this.priority = config.priority ?? 0;
this.enabled = config.enabled ?? true;
this._callback = config.callback;
}
/**
* @zh 检查是否应该触发
* @en Check if should fire
*/
shouldFire(context: ITriggerContext): boolean {
if (!this.enabled) {
return false;
}
if (context.type !== this.type && this.type !== 'custom') {
return false;
}
return this.condition.evaluate(context);
}
/**
* @zh 执行触发器
* @en Execute trigger
*/
fire(context: ITriggerContext): void {
if (this._callback) {
this._callback(context);
}
for (const callback of this._callbacks) {
callback(context);
}
}
/**
* @zh 添加回调
* @en Add callback
*/
addCallback(callback: TriggerCallback): void {
this._callbacks.add(callback);
}
/**
* @zh 移除回调
* @en Remove callback
*/
removeCallback(callback: TriggerCallback): void {
this._callbacks.delete(callback);
}
/**
* @zh 清除所有回调
* @en Clear all callbacks
*/
clearCallbacks(): void {
this._callbacks.clear();
}
}
// =============================================================================
// 触发器注册表 | Trigger Registry
// =============================================================================
/**
* @zh 触发器注册表接口
* @en Trigger registry interface
*/
export interface ITriggerRegistry {
/**
* @zh 注册触发器
* @en Register trigger
*/
register(trigger: IBlueprintTrigger): void;
/**
* @zh 注销触发器
* @en Unregister trigger
*/
unregister(triggerId: string): boolean;
/**
* @zh 获取触发器
* @en Get trigger
*/
get(triggerId: string): IBlueprintTrigger | undefined;
/**
* @zh 获取所有触发器
* @en Get all triggers
*/
getAll(): IBlueprintTrigger[];
/**
* @zh 按类型获取触发器
* @en Get triggers by type
*/
getByType(type: TriggerType): IBlueprintTrigger[];
/**
* @zh 清除所有触发器
* @en Clear all triggers
*/
clear(): void;
}
/**
* @zh 触发器注册表实现
* @en Trigger registry implementation
*/
export class TriggerRegistry implements ITriggerRegistry {
private readonly _triggers: Map<string, IBlueprintTrigger> = new Map();
private readonly _triggersByType: Map<TriggerType, Set<string>> = new Map();
/**
* @zh 注册触发器
* @en Register trigger
*/
register(trigger: IBlueprintTrigger): void {
if (this._triggers.has(trigger.id)) {
console.warn(`Trigger ${trigger.id} already registered, overwriting`);
}
this._triggers.set(trigger.id, trigger);
if (!this._triggersByType.has(trigger.type)) {
this._triggersByType.set(trigger.type, new Set());
}
this._triggersByType.get(trigger.type)!.add(trigger.id);
}
/**
* @zh 注销触发器
* @en Unregister trigger
*/
unregister(triggerId: string): boolean {
const trigger = this._triggers.get(triggerId);
if (!trigger) {
return false;
}
this._triggers.delete(triggerId);
const typeSet = this._triggersByType.get(trigger.type);
if (typeSet) {
typeSet.delete(triggerId);
}
return true;
}
/**
* @zh 获取触发器
* @en Get trigger
*/
get(triggerId: string): IBlueprintTrigger | undefined {
return this._triggers.get(triggerId);
}
/**
* @zh 获取所有触发器
* @en Get all triggers
*/
getAll(): IBlueprintTrigger[] {
return Array.from(this._triggers.values());
}
/**
* @zh 按类型获取触发器
* @en Get triggers by type
*/
getByType(type: TriggerType): IBlueprintTrigger[] {
const typeSet = this._triggersByType.get(type);
if (!typeSet) {
return [];
}
const triggers: IBlueprintTrigger[] = [];
for (const id of typeSet) {
const trigger = this._triggers.get(id);
if (trigger) {
triggers.push(trigger);
}
}
return triggers.sort((a, b) => b.priority - a.priority);
}
/**
* @zh 清除所有触发器
* @en Clear all triggers
*/
clear(): void {
this._triggers.clear();
this._triggersByType.clear();
}
/**
* @zh 获取触发器数量
* @en Get trigger count
*/
get count(): number {
return this._triggers.size;
}
}
// =============================================================================
// 工厂函数 | Factory Functions
// =============================================================================
/**
* @zh 创建触发器
* @en Create trigger
*/
export function createTrigger(config: TriggerConfig): BlueprintTrigger {
return new BlueprintTrigger(config);
}
/**
* @zh 创建 Tick 触发器
* @en Create tick trigger
*/
export function createTickTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'tick',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建输入触发器
* @en Create input trigger
*/
export function createInputTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'input',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建碰撞触发器
* @en Create collision trigger
*/
export function createCollisionTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'collision',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建消息触发器
* @en Create message trigger
*/
export function createMessageTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'message',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建定时器触发器
* @en Create timer trigger
*/
export function createTimerTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'timer',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建状态进入触发器
* @en Create state enter trigger
*/
export function createStateEnterTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'stateEnter',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建状态退出触发器
* @en Create state exit trigger
*/
export function createStateExitTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'stateExit',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 创建自定义触发器
* @en Create custom trigger
*/
export function createCustomTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'custom',
condition: options?.condition,
priority: options?.priority,
callback
});
}

View File

@@ -0,0 +1,479 @@
/**
* @zh 触发器条件系统
* @en Trigger Condition System
*
* @zh 提供触发器触发前的条件检查能力
* @en Provides condition checking before trigger fires
*/
import type {
ITriggerContext,
TriggerType,
IInputTriggerContext,
IMessageTriggerContext,
IStateTriggerContext,
ITimerTriggerContext,
ICollisionTriggerContext,
ICustomTriggerContext
} from './TriggerTypes';
// =============================================================================
// 条件接口 | Condition Interface
// =============================================================================
/**
* @zh 触发器条件接口
* @en Trigger condition interface
*/
export interface ITriggerCondition {
/**
* @zh 条件类型标识
* @en Condition type identifier
*/
readonly type: string;
/**
* @zh 评估条件是否满足
* @en Evaluate if condition is met
*
* @param context - @zh 触发器上下文 @en Trigger context
* @returns @zh 条件是否满足 @en Whether condition is met
*/
evaluate(context: ITriggerContext): boolean;
}
/**
* @zh 条件组合逻辑
* @en Condition combination logic
*/
export type ConditionLogic = 'and' | 'or';
// =============================================================================
// 复合条件 | Composite Conditions
// =============================================================================
/**
* @zh 复合条件 - 组合多个条件
* @en Composite condition - combines multiple conditions
*/
export class CompositeCondition implements ITriggerCondition {
readonly type = 'composite';
constructor(
private readonly _conditions: ITriggerCondition[],
private readonly _logic: ConditionLogic = 'and'
) {}
evaluate(context: ITriggerContext): boolean {
if (this._conditions.length === 0) {
return true;
}
if (this._logic === 'and') {
return this._conditions.every(c => c.evaluate(context));
} else {
return this._conditions.some(c => c.evaluate(context));
}
}
}
/**
* @zh 非条件 - 取反
* @en Not condition - negates
*/
export class NotCondition implements ITriggerCondition {
readonly type = 'not';
constructor(private readonly _condition: ITriggerCondition) {}
evaluate(context: ITriggerContext): boolean {
return !this._condition.evaluate(context);
}
}
// =============================================================================
// 通用条件 | Generic Conditions
// =============================================================================
/**
* @zh 始终为真的条件
* @en Always true condition
*/
export class AlwaysTrueCondition implements ITriggerCondition {
readonly type = 'alwaysTrue';
evaluate(_context: ITriggerContext): boolean {
return true;
}
}
/**
* @zh 始终为假的条件
* @en Always false condition
*/
export class AlwaysFalseCondition implements ITriggerCondition {
readonly type = 'alwaysFalse';
evaluate(_context: ITriggerContext): boolean {
return false;
}
}
/**
* @zh 触发器类型条件
* @en Trigger type condition
*/
export class TriggerTypeCondition implements ITriggerCondition {
readonly type = 'triggerType';
constructor(private readonly _allowedTypes: TriggerType[]) {}
evaluate(context: ITriggerContext): boolean {
return this._allowedTypes.includes(context.type);
}
}
/**
* @zh 实体 ID 条件
* @en Entity ID condition
*/
export class EntityIdCondition implements ITriggerCondition {
readonly type = 'entityId';
constructor(
private readonly _entityId: string,
private readonly _checkSource: boolean = true
) {}
evaluate(context: ITriggerContext): boolean {
if (this._checkSource) {
return context.sourceEntityId === this._entityId;
}
return false;
}
}
/**
* @zh 自定义函数条件
* @en Custom function condition
*/
export class FunctionCondition implements ITriggerCondition {
readonly type = 'function';
constructor(
private readonly _predicate: (context: ITriggerContext) => boolean
) {}
evaluate(context: ITriggerContext): boolean {
return this._predicate(context);
}
}
// =============================================================================
// 特定类型条件 | Type-Specific Conditions
// =============================================================================
/**
* @zh 输入动作条件
* @en Input action condition
*/
export class InputActionCondition implements ITriggerCondition {
readonly type = 'inputAction';
constructor(
private readonly _action: string,
private readonly _checkPressed?: boolean,
private readonly _checkReleased?: boolean
) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'input') {
return false;
}
const inputContext = context as unknown as IInputTriggerContext;
if (inputContext.action !== this._action) {
return false;
}
if (this._checkPressed !== undefined && inputContext.pressed !== this._checkPressed) {
return false;
}
if (this._checkReleased !== undefined && inputContext.released !== this._checkReleased) {
return false;
}
return true;
}
}
/**
* @zh 消息名称条件
* @en Message name condition
*/
export class MessageNameCondition implements ITriggerCondition {
readonly type = 'messageName';
constructor(private readonly _messageName: string) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'message') {
return false;
}
const messageContext = context as unknown as IMessageTriggerContext;
return messageContext.messageName === this._messageName;
}
}
/**
* @zh 状态名称条件
* @en State name condition
*/
export class StateNameCondition implements ITriggerCondition {
readonly type = 'stateName';
constructor(
private readonly _stateName: string,
private readonly _checkCurrent: boolean = true
) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'stateEnter' && context.type !== 'stateExit') {
return false;
}
const stateContext = context as unknown as IStateTriggerContext;
if (this._checkCurrent) {
return stateContext.currentState === this._stateName;
} else {
return stateContext.previousState === this._stateName;
}
}
}
/**
* @zh 定时器 ID 条件
* @en Timer ID condition
*/
export class TimerIdCondition implements ITriggerCondition {
readonly type = 'timerId';
constructor(private readonly _timerId: string) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'timer') {
return false;
}
const timerContext = context as unknown as ITimerTriggerContext;
return timerContext.timerId === this._timerId;
}
}
/**
* @zh 碰撞实体条件
* @en Collision entity condition
*/
export class CollisionEntityCondition implements ITriggerCondition {
readonly type = 'collisionEntity';
constructor(
private readonly _otherEntityId?: string,
private readonly _checkEnter?: boolean,
private readonly _checkExit?: boolean
) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'collision') {
return false;
}
const collisionContext = context as unknown as ICollisionTriggerContext;
if (this._otherEntityId !== undefined && collisionContext.otherEntityId !== this._otherEntityId) {
return false;
}
if (this._checkEnter !== undefined && collisionContext.isEnter !== this._checkEnter) {
return false;
}
if (this._checkExit !== undefined && collisionContext.isExit !== this._checkExit) {
return false;
}
return true;
}
}
/**
* @zh 自定义事件名称条件
* @en Custom event name condition
*/
export class CustomEventCondition implements ITriggerCondition {
readonly type = 'customEvent';
constructor(private readonly _eventName: string) {}
evaluate(context: ITriggerContext): boolean {
if (context.type !== 'custom') {
return false;
}
const customContext = context as unknown as ICustomTriggerContext;
return customContext.eventName === this._eventName;
}
}
// =============================================================================
// 条件构建器 | Condition Builder
// =============================================================================
/**
* @zh 条件构建器 - 链式 API
* @en Condition builder - fluent API
*/
export class ConditionBuilder {
private _conditions: ITriggerCondition[] = [];
private _logic: ConditionLogic = 'and';
/**
* @zh 设置组合逻辑为 AND
* @en Set combination logic to AND
*/
and(): this {
this._logic = 'and';
return this;
}
/**
* @zh 设置组合逻辑为 OR
* @en Set combination logic to OR
*/
or(): this {
this._logic = 'or';
return this;
}
/**
* @zh 添加触发器类型条件
* @en Add trigger type condition
*/
ofType(...types: TriggerType[]): this {
this._conditions.push(new TriggerTypeCondition(types));
return this;
}
/**
* @zh 添加实体 ID 条件
* @en Add entity ID condition
*/
fromEntity(entityId: string): this {
this._conditions.push(new EntityIdCondition(entityId));
return this;
}
/**
* @zh 添加输入动作条件
* @en Add input action condition
*/
onInput(action: string, options?: { pressed?: boolean; released?: boolean }): this {
this._conditions.push(new InputActionCondition(action, options?.pressed, options?.released));
return this;
}
/**
* @zh 添加消息条件
* @en Add message condition
*/
onMessage(messageName: string): this {
this._conditions.push(new MessageNameCondition(messageName));
return this;
}
/**
* @zh 添加状态条件
* @en Add state condition
*/
onState(stateName: string, checkCurrent: boolean = true): this {
this._conditions.push(new StateNameCondition(stateName, checkCurrent));
return this;
}
/**
* @zh 添加定时器条件
* @en Add timer condition
*/
onTimer(timerId: string): this {
this._conditions.push(new TimerIdCondition(timerId));
return this;
}
/**
* @zh 添加碰撞条件
* @en Add collision condition
*/
onCollision(options?: { entityId?: string; isEnter?: boolean; isExit?: boolean }): this {
this._conditions.push(new CollisionEntityCondition(
options?.entityId,
options?.isEnter,
options?.isExit
));
return this;
}
/**
* @zh 添加自定义事件条件
* @en Add custom event condition
*/
onCustomEvent(eventName: string): this {
this._conditions.push(new CustomEventCondition(eventName));
return this;
}
/**
* @zh 添加自定义函数条件
* @en Add custom function condition
*/
where(predicate: (context: ITriggerContext) => boolean): this {
this._conditions.push(new FunctionCondition(predicate));
return this;
}
/**
* @zh 添加取反条件
* @en Add negated condition
*/
not(condition: ITriggerCondition): this {
this._conditions.push(new NotCondition(condition));
return this;
}
/**
* @zh 构建条件
* @en Build condition
*/
build(): ITriggerCondition {
if (this._conditions.length === 0) {
return new AlwaysTrueCondition();
}
if (this._conditions.length === 1) {
return this._conditions[0];
}
return new CompositeCondition(this._conditions, this._logic);
}
}
/**
* @zh 创建条件构建器
* @en Create condition builder
*/
export function condition(): ConditionBuilder {
return new ConditionBuilder();
}

View File

@@ -0,0 +1,461 @@
/**
* @zh 触发器调度器
* @en Trigger Dispatcher
*
* @zh 负责分发触发器事件到订阅者
* @en Responsible for dispatching trigger events to subscribers
*/
import type { TriggerType, ITriggerContext } from './TriggerTypes';
import type { IBlueprintTrigger, ITriggerRegistry, TriggerCallback } from './BlueprintTrigger';
import { TriggerRegistry } from './BlueprintTrigger';
// =============================================================================
// 调度器接口 | Dispatcher Interface
// =============================================================================
/**
* @zh 触发结果
* @en Trigger result
*/
export interface TriggerResult {
/**
* @zh 触发器 ID
* @en Trigger ID
*/
triggerId: string;
/**
* @zh 是否成功
* @en Is successful
*/
success: boolean;
/**
* @zh 错误信息
* @en Error message
*/
error?: string;
}
/**
* @zh 调度结果
* @en Dispatch result
*/
export interface DispatchResult {
/**
* @zh 上下文
* @en Context
*/
context: ITriggerContext;
/**
* @zh 触发的触发器数量
* @en Number of triggers fired
*/
triggeredCount: number;
/**
* @zh 各触发器结果
* @en Results of each trigger
*/
results: TriggerResult[];
}
/**
* @zh 触发器调度器接口
* @en Trigger dispatcher interface
*/
export interface ITriggerDispatcher {
/**
* @zh 调度触发器
* @en Dispatch trigger
*/
dispatch(context: ITriggerContext): DispatchResult;
/**
* @zh 异步调度触发器
* @en Async dispatch trigger
*/
dispatchAsync(context: ITriggerContext): Promise<DispatchResult>;
/**
* @zh 订阅触发器类型
* @en Subscribe to trigger type
*/
subscribe(type: TriggerType, callback: TriggerCallback): () => void;
/**
* @zh 取消订阅
* @en Unsubscribe
*/
unsubscribe(type: TriggerType, callback: TriggerCallback): void;
/**
* @zh 获取注册表
* @en Get registry
*/
readonly registry: ITriggerRegistry;
}
// =============================================================================
// 调度器实现 | Dispatcher Implementation
// =============================================================================
/**
* @zh 触发器调度器实现
* @en Trigger dispatcher implementation
*/
export class TriggerDispatcher implements ITriggerDispatcher {
private readonly _registry: ITriggerRegistry;
private readonly _typeSubscribers: Map<TriggerType, Set<TriggerCallback>> = new Map();
private readonly _globalSubscribers: Set<TriggerCallback> = new Set();
private _isDispatching: boolean = false;
private _pendingContexts: ITriggerContext[] = [];
constructor(registry?: ITriggerRegistry) {
this._registry = registry ?? new TriggerRegistry();
}
get registry(): ITriggerRegistry {
return this._registry;
}
/**
* @zh 调度触发器
* @en Dispatch trigger
*/
dispatch(context: ITriggerContext): DispatchResult {
if (this._isDispatching) {
this._pendingContexts.push(context);
return {
context,
triggeredCount: 0,
results: []
};
}
this._isDispatching = true;
try {
const result = this._doDispatch(context);
while (this._pendingContexts.length > 0) {
const pendingContext = this._pendingContexts.shift()!;
this._doDispatch(pendingContext);
}
return result;
} finally {
this._isDispatching = false;
}
}
/**
* @zh 执行调度
* @en Do dispatch
*/
private _doDispatch(context: ITriggerContext): DispatchResult {
const results: TriggerResult[] = [];
let triggeredCount = 0;
const triggers = this._registry.getByType(context.type);
for (const trigger of triggers) {
if (trigger.shouldFire(context)) {
try {
trigger.fire(context);
triggeredCount++;
results.push({
triggerId: trigger.id,
success: true
});
} catch (error) {
results.push({
triggerId: trigger.id,
success: false,
error: error instanceof Error ? error.message : String(error)
});
}
}
}
this._notifySubscribers(context);
return {
context,
triggeredCount,
results
};
}
/**
* @zh 通知订阅者
* @en Notify subscribers
*/
private _notifySubscribers(context: ITriggerContext): void {
const typeSubscribers = this._typeSubscribers.get(context.type);
if (typeSubscribers) {
for (const callback of typeSubscribers) {
try {
callback(context);
} catch (error) {
console.error(`Trigger subscriber error: ${error}`);
}
}
}
for (const callback of this._globalSubscribers) {
try {
callback(context);
} catch (error) {
console.error(`Global trigger subscriber error: ${error}`);
}
}
}
/**
* @zh 异步调度触发器
* @en Async dispatch trigger
*/
async dispatchAsync(context: ITriggerContext): Promise<DispatchResult> {
return new Promise((resolve) => {
queueMicrotask(() => {
resolve(this.dispatch(context));
});
});
}
/**
* @zh 订阅触发器类型
* @en Subscribe to trigger type
*/
subscribe(type: TriggerType, callback: TriggerCallback): () => void {
if (!this._typeSubscribers.has(type)) {
this._typeSubscribers.set(type, new Set());
}
this._typeSubscribers.get(type)!.add(callback);
return () => this.unsubscribe(type, callback);
}
/**
* @zh 取消订阅
* @en Unsubscribe
*/
unsubscribe(type: TriggerType, callback: TriggerCallback): void {
const subscribers = this._typeSubscribers.get(type);
if (subscribers) {
subscribers.delete(callback);
}
}
/**
* @zh 订阅所有触发器
* @en Subscribe to all triggers
*/
subscribeAll(callback: TriggerCallback): () => void {
this._globalSubscribers.add(callback);
return () => this.unsubscribeAll(callback);
}
/**
* @zh 取消订阅所有
* @en Unsubscribe from all
*/
unsubscribeAll(callback: TriggerCallback): void {
this._globalSubscribers.delete(callback);
}
/**
* @zh 清除所有订阅
* @en Clear all subscriptions
*/
clearSubscriptions(): void {
this._typeSubscribers.clear();
this._globalSubscribers.clear();
}
}
// =============================================================================
// 实体触发器管理器 | Entity Trigger Manager
// =============================================================================
/**
* @zh 实体触发器管理器接口
* @en Entity trigger manager interface
*/
export interface IEntityTriggerManager {
/**
* @zh 为实体注册触发器
* @en Register trigger for entity
*/
registerForEntity(entityId: string, trigger: IBlueprintTrigger): void;
/**
* @zh 注销实体的触发器
* @en Unregister trigger from entity
*/
unregisterFromEntity(entityId: string, triggerId: string): boolean;
/**
* @zh 获取实体的所有触发器
* @en Get all triggers for entity
*/
getEntityTriggers(entityId: string): IBlueprintTrigger[];
/**
* @zh 清除实体的所有触发器
* @en Clear all triggers for entity
*/
clearEntityTriggers(entityId: string): void;
/**
* @zh 调度器
* @en Dispatcher
*/
readonly dispatcher: ITriggerDispatcher;
}
/**
* @zh 实体触发器管理器实现
* @en Entity trigger manager implementation
*/
export class EntityTriggerManager implements IEntityTriggerManager {
private readonly _dispatcher: ITriggerDispatcher;
private readonly _entityTriggers: Map<string, Set<string>> = new Map();
constructor(dispatcher?: ITriggerDispatcher) {
this._dispatcher = dispatcher ?? new TriggerDispatcher();
}
get dispatcher(): ITriggerDispatcher {
return this._dispatcher;
}
/**
* @zh 为实体注册触发器
* @en Register trigger for entity
*/
registerForEntity(entityId: string, trigger: IBlueprintTrigger): void {
this._dispatcher.registry.register(trigger);
if (!this._entityTriggers.has(entityId)) {
this._entityTriggers.set(entityId, new Set());
}
this._entityTriggers.get(entityId)!.add(trigger.id);
}
/**
* @zh 注销实体的触发器
* @en Unregister trigger from entity
*/
unregisterFromEntity(entityId: string, triggerId: string): boolean {
const entitySet = this._entityTriggers.get(entityId);
if (!entitySet) {
return false;
}
if (!entitySet.has(triggerId)) {
return false;
}
entitySet.delete(triggerId);
return this._dispatcher.registry.unregister(triggerId);
}
/**
* @zh 获取实体的所有触发器
* @en Get all triggers for entity
*/
getEntityTriggers(entityId: string): IBlueprintTrigger[] {
const entitySet = this._entityTriggers.get(entityId);
if (!entitySet) {
return [];
}
const triggers: IBlueprintTrigger[] = [];
for (const triggerId of entitySet) {
const trigger = this._dispatcher.registry.get(triggerId);
if (trigger) {
triggers.push(trigger);
}
}
return triggers;
}
/**
* @zh 清除实体的所有触发器
* @en Clear all triggers for entity
*/
clearEntityTriggers(entityId: string): void {
const entitySet = this._entityTriggers.get(entityId);
if (!entitySet) {
return;
}
for (const triggerId of entitySet) {
this._dispatcher.registry.unregister(triggerId);
}
this._entityTriggers.delete(entityId);
}
/**
* @zh 调度触发器到实体
* @en Dispatch trigger to entity
*/
dispatchToEntity(entityId: string, context: ITriggerContext): DispatchResult {
const entityTriggers = this.getEntityTriggers(entityId);
const results: TriggerResult[] = [];
let triggeredCount = 0;
for (const trigger of entityTriggers) {
if (trigger.shouldFire(context)) {
try {
trigger.fire(context);
triggeredCount++;
results.push({
triggerId: trigger.id,
success: true
});
} catch (error) {
results.push({
triggerId: trigger.id,
success: false,
error: error instanceof Error ? error.message : String(error)
});
}
}
}
return {
context,
triggeredCount,
results
};
}
}
// =============================================================================
// 工厂函数 | Factory Functions
// =============================================================================
/**
* @zh 创建触发器调度器
* @en Create trigger dispatcher
*/
export function createTriggerDispatcher(registry?: ITriggerRegistry): TriggerDispatcher {
return new TriggerDispatcher(registry);
}
/**
* @zh 创建实体触发器管理器
* @en Create entity trigger manager
*/
export function createEntityTriggerManager(dispatcher?: ITriggerDispatcher): EntityTriggerManager {
return new EntityTriggerManager(dispatcher);
}

View File

@@ -0,0 +1,400 @@
/**
* @zh 蓝图触发器类型定义
* @en Blueprint Trigger Type Definitions
*
* @zh 定义触发器的核心类型和接口
* @en Defines core types and interfaces for triggers
*/
// =============================================================================
// 触发器类型 | Trigger Types
// =============================================================================
/**
* @zh 触发器类型枚举
* @en Trigger type enumeration
*/
export type TriggerType =
| 'tick' // 每帧触发 | Every frame
| 'input' // 输入事件 | Input event
| 'collision' // 碰撞事件 | Collision event
| 'message' // 消息事件 | Message event
| 'timer' // 定时器事件 | Timer event
| 'stateEnter' // 状态进入 | State enter
| 'stateExit' // 状态退出 | State exit
| 'custom'; // 自定义事件 | Custom event
/**
* @zh 触发器类型常量
* @en Trigger type constants
*/
export const TriggerTypes = {
TICK: 'tick' as const,
INPUT: 'input' as const,
COLLISION: 'collision' as const,
MESSAGE: 'message' as const,
TIMER: 'timer' as const,
STATE_ENTER: 'stateEnter' as const,
STATE_EXIT: 'stateExit' as const,
CUSTOM: 'custom' as const
} as const;
// =============================================================================
// 触发器上下文 | Trigger Context
// =============================================================================
/**
* @zh 触发器上下文基础接口
* @en Trigger context base interface
*/
export interface ITriggerContext {
/**
* @zh 触发器类型
* @en Trigger type
*/
readonly type: TriggerType;
/**
* @zh 触发时间戳
* @en Trigger timestamp
*/
readonly timestamp: number;
/**
* @zh 触发源实体 ID
* @en Source entity ID
*/
readonly sourceEntityId?: string;
/**
* @zh 附加数据
* @en Additional data
*/
readonly data?: Record<string, unknown>;
}
/**
* @zh Tick 触发器上下文
* @en Tick trigger context
*/
export interface ITickTriggerContext extends ITriggerContext {
readonly type: 'tick';
/**
* @zh 增量时间(秒)
* @en Delta time (seconds)
*/
readonly deltaTime: number;
/**
* @zh 帧计数
* @en Frame count
*/
readonly frameCount: number;
}
/**
* @zh 输入触发器上下文
* @en Input trigger context
*/
export interface IInputTriggerContext extends ITriggerContext {
readonly type: 'input';
/**
* @zh 输入动作名称
* @en Input action name
*/
readonly action: string;
/**
* @zh 输入值
* @en Input value
*/
readonly value: number | boolean;
/**
* @zh 是否刚按下
* @en Is just pressed
*/
readonly pressed?: boolean;
/**
* @zh 是否刚释放
* @en Is just released
*/
readonly released?: boolean;
}
/**
* @zh 碰撞触发器上下文
* @en Collision trigger context
*/
export interface ICollisionTriggerContext extends ITriggerContext {
readonly type: 'collision';
/**
* @zh 碰撞的另一个实体 ID
* @en Other entity ID in collision
*/
readonly otherEntityId: string;
/**
* @zh 碰撞点
* @en Collision point
*/
readonly point?: { x: number; y: number };
/**
* @zh 碰撞法线
* @en Collision normal
*/
readonly normal?: { x: number; y: number };
/**
* @zh 是否开始碰撞
* @en Is collision start
*/
readonly isEnter: boolean;
/**
* @zh 是否结束碰撞
* @en Is collision end
*/
readonly isExit: boolean;
}
/**
* @zh 消息触发器上下文
* @en Message trigger context
*/
export interface IMessageTriggerContext extends ITriggerContext {
readonly type: 'message';
/**
* @zh 消息名称
* @en Message name
*/
readonly messageName: string;
/**
* @zh 发送者 ID
* @en Sender ID
*/
readonly senderId?: string;
/**
* @zh 消息负载
* @en Message payload
*/
readonly payload?: unknown;
}
/**
* @zh 定时器触发器上下文
* @en Timer trigger context
*/
export interface ITimerTriggerContext extends ITriggerContext {
readonly type: 'timer';
/**
* @zh 定时器 ID
* @en Timer ID
*/
readonly timerId: string;
/**
* @zh 是否循环触发
* @en Is repeating
*/
readonly isRepeating: boolean;
/**
* @zh 已触发次数
* @en Times fired
*/
readonly timesFired: number;
}
/**
* @zh 状态触发器上下文
* @en State trigger context
*/
export interface IStateTriggerContext extends ITriggerContext {
readonly type: 'stateEnter' | 'stateExit';
/**
* @zh 状态机 ID
* @en State machine ID
*/
readonly stateMachineId: string;
/**
* @zh 当前状态
* @en Current state
*/
readonly currentState: string;
/**
* @zh 之前状态
* @en Previous state
*/
readonly previousState?: string;
}
/**
* @zh 自定义触发器上下文
* @en Custom trigger context
*/
export interface ICustomTriggerContext extends ITriggerContext {
readonly type: 'custom';
/**
* @zh 事件名称
* @en Event name
*/
readonly eventName: string;
}
/**
* @zh 所有触发器上下文的联合类型
* @en Union type of all trigger contexts
*/
export type TriggerContext =
| ITickTriggerContext
| IInputTriggerContext
| ICollisionTriggerContext
| IMessageTriggerContext
| ITimerTriggerContext
| IStateTriggerContext
| ICustomTriggerContext;
// =============================================================================
// 工厂函数 | Factory Functions
// =============================================================================
/**
* @zh 创建 Tick 触发器上下文
* @en Create tick trigger context
*/
export function createTickContext(
deltaTime: number,
frameCount: number,
sourceEntityId?: string
): ITickTriggerContext {
return {
type: 'tick',
timestamp: Date.now(),
deltaTime,
frameCount,
sourceEntityId
};
}
/**
* @zh 创建输入触发器上下文
* @en Create input trigger context
*/
export function createInputContext(
action: string,
value: number | boolean,
options?: {
pressed?: boolean;
released?: boolean;
sourceEntityId?: string;
}
): IInputTriggerContext {
return {
type: 'input',
timestamp: Date.now(),
action,
value,
pressed: options?.pressed,
released: options?.released,
sourceEntityId: options?.sourceEntityId
};
}
/**
* @zh 创建碰撞触发器上下文
* @en Create collision trigger context
*/
export function createCollisionContext(
otherEntityId: string,
isEnter: boolean,
options?: {
point?: { x: number; y: number };
normal?: { x: number; y: number };
sourceEntityId?: string;
}
): ICollisionTriggerContext {
return {
type: 'collision',
timestamp: Date.now(),
otherEntityId,
isEnter,
isExit: !isEnter,
point: options?.point,
normal: options?.normal,
sourceEntityId: options?.sourceEntityId
};
}
/**
* @zh 创建消息触发器上下文
* @en Create message trigger context
*/
export function createMessageContext(
messageName: string,
payload?: unknown,
options?: {
senderId?: string;
sourceEntityId?: string;
}
): IMessageTriggerContext {
return {
type: 'message',
timestamp: Date.now(),
messageName,
payload,
senderId: options?.senderId,
sourceEntityId: options?.sourceEntityId
};
}
/**
* @zh 创建定时器触发器上下文
* @en Create timer trigger context
*/
export function createTimerContext(
timerId: string,
isRepeating: boolean,
timesFired: number,
sourceEntityId?: string
): ITimerTriggerContext {
return {
type: 'timer',
timestamp: Date.now(),
timerId,
isRepeating,
timesFired,
sourceEntityId
};
}
/**
* @zh 创建状态触发器上下文
* @en Create state trigger context
*/
export function createStateContext(
type: 'stateEnter' | 'stateExit',
stateMachineId: string,
currentState: string,
previousState?: string,
sourceEntityId?: string
): IStateTriggerContext {
return {
type,
timestamp: Date.now(),
stateMachineId,
currentState,
previousState,
sourceEntityId
};
}
/**
* @zh 创建自定义触发器上下文
* @en Create custom trigger context
*/
export function createCustomContext(
eventName: string,
data?: Record<string, unknown>,
sourceEntityId?: string
): ICustomTriggerContext {
return {
type: 'custom',
timestamp: Date.now(),
eventName,
data,
sourceEntityId
};
}

View File

@@ -0,0 +1,105 @@
/**
* @zh 蓝图触发器模块
* @en Blueprint Triggers Module
*
* @zh 提供蓝图触发器系统的所有导出
* @en Provides all exports for the blueprint trigger system
*/
// =============================================================================
// 触发器类型 | Trigger Types
// =============================================================================
export type {
TriggerType,
ITriggerContext,
ITickTriggerContext,
IInputTriggerContext,
ICollisionTriggerContext,
IMessageTriggerContext,
ITimerTriggerContext,
IStateTriggerContext,
ICustomTriggerContext,
TriggerContext
} from './TriggerTypes';
export {
TriggerTypes,
createTickContext,
createInputContext,
createCollisionContext,
createMessageContext,
createTimerContext,
createStateContext,
createCustomContext
} from './TriggerTypes';
// =============================================================================
// 触发器条件 | Trigger Conditions
// =============================================================================
export type {
ITriggerCondition,
ConditionLogic
} from './TriggerCondition';
export {
CompositeCondition,
NotCondition,
AlwaysTrueCondition,
AlwaysFalseCondition,
TriggerTypeCondition,
EntityIdCondition,
FunctionCondition,
InputActionCondition,
MessageNameCondition,
StateNameCondition,
TimerIdCondition,
CollisionEntityCondition,
CustomEventCondition,
ConditionBuilder,
condition
} from './TriggerCondition';
// =============================================================================
// 蓝图触发器 | Blueprint Trigger
// =============================================================================
export type {
TriggerCallback,
IBlueprintTrigger,
TriggerConfig,
ITriggerRegistry
} from './BlueprintTrigger';
export {
BlueprintTrigger,
TriggerRegistry,
createTrigger,
createTickTrigger,
createInputTrigger,
createCollisionTrigger,
createMessageTrigger,
createTimerTrigger,
createStateEnterTrigger,
createStateExitTrigger,
createCustomTrigger
} from './BlueprintTrigger';
// =============================================================================
// 触发器调度器 | Trigger Dispatcher
// =============================================================================
export type {
TriggerResult,
DispatchResult,
ITriggerDispatcher,
IEntityTriggerManager
} from './TriggerDispatcher';
export {
TriggerDispatcher,
EntityTriggerManager,
createTriggerDispatcher,
createEntityTriggerManager
} from './TriggerDispatcher';