时间和定时器系统
ECS 框架提供了完整的时间管理和定时器系统,包括时间缩放、帧时间计算和灵活的定时器调度功能。
Time 类
Section titled “Time 类”Time 类是框架的时间管理核心,提供了游戏时间相关的所有功能。
基本时间属性
Section titled “基本时间属性”import { Time } from '@esengine/ecs-framework';
class GameSystem extends EntitySystem { protected process(entities: readonly Entity[]): void { // 获取帧时间(秒) const deltaTime = Time.deltaTime;
// 获取未缩放的帧时间 const unscaledDelta = Time.unscaledDeltaTime;
// 获取游戏总时间 const totalTime = Time.totalTime;
// 获取当前帧数 const frameCount = Time.frameCount;
console.log(`第 ${frameCount} 帧,帧时间: ${deltaTime}s,总时间: ${totalTime}s`); }}框架提供两种暂停方式,适用于不同场景:
Core.paused(推荐)
Section titled “Core.paused(推荐)”Core.paused 是真正的暂停,设置后整个游戏循环停止:
import { Core } from '@esengine/ecs-framework';
class PauseMenuSystem extends EntitySystem { public pauseGame(): void { // 真正暂停 - 所有系统停止执行 Core.paused = true; console.log('游戏已暂停'); }
public resumeGame(): void { // 恢复游戏 Core.paused = false; console.log('游戏已恢复'); }
public togglePause(): void { Core.paused = !Core.paused; console.log(Core.paused ? '游戏已暂停' : '游戏已恢复'); }}Time.timeScale = 0
Section titled “Time.timeScale = 0”Time.timeScale = 0 只是让 deltaTime 变为 0,系统仍然在执行:
class SlowMotionSystem extends EntitySystem { public freezeTime(): void { // 时间冻结 - 系统仍在执行,只是 deltaTime = 0 Time.timeScale = 0; }}两种方式对比
Section titled “两种方式对比”| 特性 | Core.paused = true | Time.timeScale = 0 |
|---|---|---|
| 系统执行 | ❌ 完全停止 | ✅ 仍在执行 |
| CPU 开销 | 零 | 正常开销 |
| Time 更新 | ❌ 停止 | ✅ 继续(deltaTime=0) |
| 定时器 | ❌ 停止 | ✅ 继续(但时间不走) |
| 适用场景 | 暂停菜单、游戏暂停 | 慢动作、时间冻结特效 |
推荐:
- 暂停菜单、真正的游戏暂停 → 使用
Core.paused = true - 慢动作、子弹时间等特效 → 使用
Time.timeScale
Time 类支持时间缩放功能,可以实现慢动作、快进等效果:
class TimeControlSystem extends EntitySystem { public enableSlowMotion(): void { // 设置为慢动作(50%速度) Time.timeScale = 0.5; console.log('慢动作模式启用'); }
public enableFastForward(): void { // 设置为快进(200%速度) Time.timeScale = 2.0; console.log('快进模式启用'); }
public enableBulletTime(): void { // 子弹时间效果(10%速度) Time.timeScale = 0.1; console.log('子弹时间启用'); }
public resumeNormalSpeed(): void { // 恢复正常速度 Time.timeScale = 1.0; console.log('恢复正常速度'); }
protected process(entities: readonly Entity[]): void { // deltaTime 会受到 timeScale 影响 const scaledDelta = Time.deltaTime; // 受时间缩放影响 const realDelta = Time.unscaledDeltaTime; // 不受时间缩放影响
for (const entity of entities) { const movement = entity.getComponent(Movement); if (movement) { // 使用缩放时间进行游戏逻辑更新 movement.update(scaledDelta); }
const ui = entity.getComponent(UIComponent); if (ui) { // UI 动画使用真实时间,不受游戏时间缩放影响 ui.update(realDelta); } } }}时间检查工具
Section titled “时间检查工具”class CooldownSystem extends EntitySystem { private lastAttackTime = 0; private lastSpawnTime = 0;
constructor() { super(Matcher.all(Weapon)); }
protected process(entities: readonly Entity[]): void { // 检查攻击冷却 if (Time.checkEvery(1.5, this.lastAttackTime)) { this.performAttack(); this.lastAttackTime = Time.totalTime; }
// 检查生成间隔 if (Time.checkEvery(3.0, this.lastSpawnTime)) { this.spawnEnemy(); this.lastSpawnTime = Time.totalTime; } }
private performAttack(): void { console.log('执行攻击!'); }
private spawnEnemy(): void { console.log('生成敌人!'); }}Core.schedule 定时器系统
Section titled “Core.schedule 定时器系统”Core 提供了强大的定时器调度功能,可以创建一次性或重复执行的定时器。
基本定时器使用
Section titled “基本定时器使用”import { Core } from '@esengine/ecs-framework';
class GameScene extends Scene { protected initialize(): void { // 创建一次性定时器 this.createOneTimeTimers();
// 创建重复定时器 this.createRepeatingTimers();
// 创建带上下文的定时器 this.createContextTimers(); }
private createOneTimeTimers(): void { // 2秒后执行一次 Core.schedule(2.0, false, null, (timer) => { console.log('2秒延迟执行'); });
// 5秒后显示提示 Core.schedule(5.0, false, this, (timer) => { const scene = timer.getContext<GameScene>(); scene.showTip('游戏提示:5秒已过!'); }); }
private createRepeatingTimers(): void { // 每秒重复执行 const heartbeatTimer = Core.schedule(1.0, true, null, (timer) => { console.log(`游戏心跳 - 总时间: ${Time.totalTime.toFixed(1)}s`); });
// 可以保存定时器引用用于后续控制 this.saveTimerReference(heartbeatTimer); }
private createContextTimers(): void { const gameData = { score: 0, level: 1 };
// 每2秒增加分数 Core.schedule(2.0, true, gameData, (timer) => { const data = timer.getContext<typeof gameData>(); data.score += 10; console.log(`分数增加!当前分数: ${data.score}`); }); }
private saveTimerReference(timer: any): void { // 可以稍后停止定时器 setTimeout(() => { timer.stop(); console.log('定时器已停止'); }, 10000); // 10秒后停止 }
private showTip(message: string): void { console.log('提示:', message); }}class TimerControlExample { private attackTimer: any; private spawnerTimer: any;
public startCombat(): void { // 启动攻击定时器 this.attackTimer = Core.schedule(0.5, true, this, (timer) => { const self = timer.getContext<TimerControlExample>(); self.performAttack(); });
// 启动敌人生成定时器 this.spawnerTimer = Core.schedule(3.0, true, null, (timer) => { this.spawnEnemy(); }); }
public stopCombat(): void { // 停止所有战斗相关定时器 if (this.attackTimer) { this.attackTimer.stop(); console.log('攻击定时器已停止'); }
if (this.spawnerTimer) { this.spawnerTimer.stop(); console.log('生成定时器已停止'); } }
public resetAttackTimer(): void { // 重置攻击定时器 if (this.attackTimer) { this.attackTimer.reset(); console.log('攻击定时器已重置'); } }
private performAttack(): void { console.log('执行攻击'); }
private spawnEnemy(): void { console.log('生成敌人'); }}复杂定时器场景
Section titled “复杂定时器场景”class AdvancedTimerUsage { private powerUpDuration = 0; private powerUpActive = false;
public activatePowerUp(): void { if (this.powerUpActive) { console.log('能力提升已激活'); return; }
this.powerUpActive = true; this.powerUpDuration = 10; // 10秒持续时间
console.log('能力提升激活!');
// 每秒更新剩余时间 const countdownTimer = Core.schedule(1.0, true, this, (timer) => { const self = timer.getContext<AdvancedTimerUsage>(); self.powerUpDuration--;
console.log(`能力提升剩余时间: ${self.powerUpDuration}秒`);
if (self.powerUpDuration <= 0) { self.deactivatePowerUp(); timer.stop(); // 停止倒计时 } });
// 能力提升结束定时器(备用) Core.schedule(10.0, false, this, (timer) => { const self = timer.getContext<AdvancedTimerUsage>(); if (self.powerUpActive) { self.deactivatePowerUp(); } }); }
private deactivatePowerUp(): void { this.powerUpActive = false; this.powerUpDuration = 0; console.log('能力提升结束'); }
// 创建波次攻击定时器 public startWaveAttack(): void { let waveCount = 0; const maxWaves = 5;
const waveTimer = Core.schedule(2.0, true, { waveCount, maxWaves }, (timer) => { const context = timer.getContext<{ waveCount: number, maxWaves: number }>(); context.waveCount++;
console.log(`第 ${context.waveCount} 波攻击!`);
if (context.waveCount >= context.maxWaves) { console.log('所有波次攻击完成'); timer.stop(); } }); }
// 创建条件定时器 public startConditionalTimer(): void { Core.schedule(0.1, true, this, (timer) => { const self = timer.getContext<AdvancedTimerUsage>();
// 检查某个条件 if (self.shouldStopTimer()) { console.log('条件满足,停止定时器'); timer.stop(); return; }
// 继续执行定时器逻辑 self.performTimerAction(); }); }
private shouldStopTimer(): boolean { // 检查停止条件 return Time.totalTime > 30; // 30秒后停止 }
private performTimerAction(): void { console.log('执行定时器动作'); }}实际应用示例
Section titled “实际应用示例”技能冷却系统
Section titled “技能冷却系统”class SkillCooldownSystem extends EntitySystem { constructor() { super(Matcher.all(SkillComponent)); }
protected process(entities: readonly Entity[]): void { for (const entity of entities) { const skill = entity.getComponent(SkillComponent);
// 更新技能冷却 if (skill.isOnCooldown) { skill.cooldownRemaining -= Time.deltaTime;
if (skill.cooldownRemaining <= 0) { skill.cooldownRemaining = 0; skill.isOnCooldown = false; console.log(`技能 ${skill.name} 冷却完成`); } } } }
public useSkill(entity: Entity, skillName: string): boolean { const skill = entity.getComponent(SkillComponent);
if (skill.isOnCooldown) { console.log(`技能 ${skillName} 还在冷却中,剩余 ${skill.cooldownRemaining.toFixed(1)}秒`); return false; }
// 执行技能 this.executeSkill(entity, skill);
// 开始冷却 skill.isOnCooldown = true; skill.cooldownRemaining = skill.cooldownDuration;
return true; }
private executeSkill(entity: Entity, skill: SkillComponent): void { console.log(`执行技能: ${skill.name}`); // 技能效果逻辑 }}游戏状态定时器
Section titled “游戏状态定时器”class GameStateManager { private gamePhase = 'preparation'; private phaseTimer: any;
public startGame(): void { this.startPreparationPhase(); }
private startPreparationPhase(): void { this.gamePhase = 'preparation'; console.log('准备阶段开始 - 10秒准备时间');
this.phaseTimer = Core.schedule(10.0, false, this, (timer) => { const self = timer.getContext<GameStateManager>(); self.startCombatPhase(); }); }
private startCombatPhase(): void { this.gamePhase = 'combat'; console.log('战斗阶段开始 - 60秒战斗时间');
this.phaseTimer = Core.schedule(60.0, false, this, (timer) => { const self = timer.getContext<GameStateManager>(); self.startResultPhase(); });
// 每10秒刷新一波敌人 Core.schedule(10.0, true, null, (timer) => { if (this.gamePhase === 'combat') { this.spawnEnemyWave(); } else { timer.stop(); // 战斗阶段结束时停止刷新 } }); }
private startResultPhase(): void { this.gamePhase = 'result'; console.log('结算阶段开始 - 5秒结算时间');
this.phaseTimer = Core.schedule(5.0, false, this, (timer) => { const self = timer.getContext<GameStateManager>(); self.endGame(); }); }
private endGame(): void { console.log('游戏结束'); this.gamePhase = 'ended'; }
private spawnEnemyWave(): void { console.log('刷新敌人波次'); }
public getCurrentPhase(): string { return this.gamePhase; }}1. 合理使用时间类型
Section titled “1. 合理使用时间类型”class MovementSystem extends EntitySystem { protected process(entities: readonly Entity[]): void { for (const entity of entities) { const movement = entity.getComponent(Movement);
// ✅ 游戏逻辑使用缩放时间 movement.position.x += movement.velocity.x * Time.deltaTime;
// ✅ UI动画使用真实时间(不受游戏暂停影响) const ui = entity.getComponent(UIAnimation); if (ui) { ui.update(Time.unscaledDeltaTime); } } }}2. 定时器管理
Section titled “2. 定时器管理”class TimerManager { private timers: any[] = [];
public createManagedTimer(duration: number, repeats: boolean, callback: () => void): any { const timer = Core.schedule(duration, repeats, null, callback); this.timers.push(timer); return timer; }
public stopAllTimers(): void { for (const timer of this.timers) { timer.stop(); } this.timers = []; }
public cleanupCompletedTimers(): void { this.timers = this.timers.filter(timer => !timer.isDone); }}3. 避免过多的定时器
Section titled “3. 避免过多的定时器”// ❌ 避免:为每个实体创建定时器class BadExample extends EntitySystem { protected onAdded(entity: Entity): void { Core.schedule(1.0, true, entity, (timer) => { // 每个实体一个定时器,性能差 }); }}
// ✅ 推荐:在系统中统一管理时间class GoodExample extends EntitySystem { private lastUpdateTime = 0;
protected process(entities: readonly Entity[]): void { // 每秒执行一次逻辑 if (Time.checkEvery(1.0, this.lastUpdateTime)) { this.processAllEntities(entities); this.lastUpdateTime = Time.totalTime; } }
private processAllEntities(entities: readonly Entity[]): void { // 批量处理所有实体 }}4. 定时器上下文使用
Section titled “4. 定时器上下文使用”interface TimerContext { entityId: number; duration: number; onComplete: () => void;}
class ContextualTimerExample { public createEntityTimer(entityId: number, duration: number, onComplete: () => void): void { const context: TimerContext = { entityId, duration, onComplete };
Core.schedule(duration, false, context, (timer) => { const ctx = timer.getContext<TimerContext>(); console.log(`实体 ${ctx.entityId} 的定时器完成`); ctx.onComplete(); }); }}时间和定时器系统是游戏开发中的重要工具,正确使用这些功能能让你的游戏逻辑更加精确和可控。