* docs(modules): 添加框架模块文档 添加以下模块的完整文档: - FSM (状态机): 状态定义、转换条件、优先级、事件监听 - Timer (定时器): 定时器调度、冷却系统、服务令牌 - Spatial (空间索引): GridSpatialIndex、AOI 兴趣区域管理 - Pathfinding (寻路): A* 算法、网格地图、导航网格、路径平滑 - Procgen (程序化生成): 噪声函数、种子随机数、加权随机 所有文档均基于实际源码 API 编写,包含: - 快速开始示例 - 完整 API 参考 - 实际使用案例 - 蓝图节点说明 - 最佳实践建议 * docs(modules): 添加 Blueprint 模块文档和所有模块英文版 新增中文文档: - Blueprint (蓝图可视化脚本): VM、自定义节点、组合系统、触发器 新增英文文档 (docs/en/modules/): - FSM: State machine API, transitions, ECS integration - Timer: Timers, cooldowns, service tokens - Spatial: Grid spatial index, AOI management - Pathfinding: A*, grid map, NavMesh, path smoothing - Procgen: Noise functions, seeded random, weighted random - Blueprint: Visual scripting, custom nodes, composition 所有文档均基于实际源码 API 编写。
7.5 KiB
7.5 KiB
Timer System
@esengine/timer provides a flexible timer and cooldown system for delayed execution, repeating tasks, skill cooldowns, and more.
Installation
npm install @esengine/timer
Quick Start
import { createTimerService } from '@esengine/timer';
// Create timer service
const timerService = createTimerService();
// One-time timer (executes after 1 second)
const handle = timerService.schedule('myTimer', 1000, () => {
console.log('Timer fired!');
});
// Repeating timer (every 100ms)
timerService.scheduleRepeating('heartbeat', 100, () => {
console.log('Tick');
});
// Cooldown system (5 second cooldown)
timerService.startCooldown('skill_fireball', 5000);
if (timerService.isCooldownReady('skill_fireball')) {
useFireball();
timerService.startCooldown('skill_fireball', 5000);
}
// Update in game loop
function gameLoop(deltaTime: number) {
timerService.update(deltaTime);
}
Core Concepts
Timer vs Cooldown
| Feature | Timer | Cooldown |
|---|---|---|
| Purpose | Delayed code execution | Rate limiting |
| Callback | Has callback function | No callback |
| Repeat | Supports repeating | One-time |
| Query | Query remaining time | Query progress/ready status |
TimerHandle
Handle object returned when scheduling a timer:
interface TimerHandle {
readonly id: string; // Timer ID
readonly isValid: boolean; // Whether valid (not cancelled)
cancel(): void; // Cancel timer
}
TimerInfo
Timer information object:
interface TimerInfo {
readonly id: string; // Timer ID
readonly remaining: number; // Remaining time (ms)
readonly repeating: boolean; // Whether repeating
readonly interval?: number; // Interval (repeating only)
}
CooldownInfo
Cooldown information object:
interface CooldownInfo {
readonly id: string; // Cooldown ID
readonly duration: number; // Total duration (ms)
readonly remaining: number; // Remaining time (ms)
readonly progress: number; // Progress (0-1, 0=started, 1=finished)
readonly isReady: boolean; // Whether ready
}
API Reference
createTimerService
function createTimerService(config?: TimerServiceConfig): ITimerService
Configuration:
| Property | Type | Default | Description |
|---|---|---|---|
maxTimers |
number |
0 |
Maximum timer count (0 = unlimited) |
maxCooldowns |
number |
0 |
Maximum cooldown count (0 = unlimited) |
Timer API
schedule
Schedule a one-time timer:
const handle = timerService.schedule('explosion', 2000, () => {
createExplosion();
});
// Cancel early
handle.cancel();
scheduleRepeating
Schedule a repeating timer:
// Execute every second
timerService.scheduleRepeating('regen', 1000, () => {
player.hp += 5;
});
// Execute immediately once, then repeat every second
timerService.scheduleRepeating('tick', 1000, () => {
console.log('Tick');
}, true); // immediate = true
cancel / cancelById
Cancel timers:
// Cancel by handle
handle.cancel();
// or
timerService.cancel(handle);
// Cancel by ID
timerService.cancelById('regen');
hasTimer
Check if timer exists:
if (timerService.hasTimer('explosion')) {
console.log('Explosion is pending');
}
getTimerInfo
Get timer information:
const info = timerService.getTimerInfo('explosion');
if (info) {
console.log(`Remaining: ${info.remaining}ms`);
console.log(`Repeating: ${info.repeating}`);
}
Cooldown API
startCooldown
Start a cooldown:
timerService.startCooldown('skill_fireball', 5000);
isCooldownReady / isOnCooldown
Check cooldown status:
if (timerService.isCooldownReady('skill_fireball')) {
castFireball();
timerService.startCooldown('skill_fireball', 5000);
}
if (timerService.isOnCooldown('skill_fireball')) {
console.log('On cooldown...');
}
getCooldownProgress / getCooldownRemaining
Get cooldown progress:
// Progress 0-1 (0=started, 1=complete)
const progress = timerService.getCooldownProgress('skill_fireball');
console.log(`Progress: ${(progress * 100).toFixed(0)}%`);
// Remaining time (ms)
const remaining = timerService.getCooldownRemaining('skill_fireball');
console.log(`Remaining: ${(remaining / 1000).toFixed(1)}s`);
getCooldownInfo
Get complete cooldown info:
const info = timerService.getCooldownInfo('skill_fireball');
if (info) {
console.log(`Duration: ${info.duration}ms`);
console.log(`Remaining: ${info.remaining}ms`);
console.log(`Progress: ${info.progress}`);
console.log(`Ready: ${info.isReady}`);
}
resetCooldown / clearAllCooldowns
Reset cooldowns:
// Reset single cooldown
timerService.resetCooldown('skill_fireball');
// Clear all cooldowns (e.g., on respawn)
timerService.clearAllCooldowns();
Lifecycle
update
Update timer service (call every frame):
function gameLoop(deltaTime: number) {
timerService.update(deltaTime); // deltaTime in ms
}
clear
Clear all timers and cooldowns:
timerService.clear();
Debug Properties
console.log(timerService.activeTimerCount);
console.log(timerService.activeCooldownCount);
const timerIds = timerService.getActiveTimerIds();
const cooldownIds = timerService.getActiveCooldownIds();
Practical Examples
Skill Cooldown System
import { createTimerService, type ITimerService } from '@esengine/timer';
class SkillSystem {
private timerService: ITimerService;
private skills: Map<string, SkillData> = new Map();
constructor() {
this.timerService = createTimerService();
}
useSkill(skillId: string): boolean {
const skill = this.skills.get(skillId);
if (!skill) return false;
if (!this.timerService.isCooldownReady(skillId)) {
const remaining = this.timerService.getCooldownRemaining(skillId);
console.log(`Skill ${skillId} on cooldown, ${remaining}ms remaining`);
return false;
}
this.executeSkill(skill);
this.timerService.startCooldown(skillId, skill.cooldown);
return true;
}
update(dt: number): void {
this.timerService.update(dt);
}
}
DOT Effects
class EffectSystem {
private timerService: ITimerService;
applyDOT(target: Entity, damage: number, duration: number): void {
const dotId = `dot_${target.id}_${Date.now()}`;
let elapsed = 0;
this.timerService.scheduleRepeating(dotId, 1000, () => {
elapsed += 1000;
target.takeDamage(damage);
if (elapsed >= duration) {
this.timerService.cancelById(dotId);
}
});
}
}
Blueprint Nodes
Cooldown Nodes
StartCooldown- Start cooldownIsCooldownReady- Check if cooldown is readyGetCooldownProgress- Get cooldown progressGetCooldownInfo- Get cooldown infoResetCooldown- Reset cooldown
Timer Nodes
HasTimer- Check if timer existsCancelTimer- Cancel timerGetTimerRemaining- Get timer remaining time
Service Token
For dependency injection:
import { TimerServiceToken, createTimerService } from '@esengine/timer';
services.register(TimerServiceToken, createTimerService());
const timerService = services.get(TimerServiceToken);