时间和定时器系统
ECS 框架提供了完整的时间管理和定时器系统,包括时间缩放、帧时间计算和灵活的定时器调度功能。
Time 类
Time 类是框架的时间管理核心,提供了游戏时间相关的所有功能。
基本时间属性
typescript
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`);
}
}
时间缩放
Time 类支持时间缩放功能,可以实现慢动作、快进等效果:
typescript
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 pauseGame(): void {
// 暂停游戏(时间静止)
Time.timeScale = 0;
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);
}
}
}
}
时间检查工具
typescript
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 定时器系统
Core 提供了强大的定时器调度功能,可以创建一次性或重复执行的定时器。
基本定时器使用
typescript
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);
}
}
定时器控制
typescript
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('生成敌人');
}
}
复杂定时器场景
typescript
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('执行定时器动作');
}
}
实际应用示例
技能冷却系统
typescript
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}`);
// 技能效果逻辑
}
}
游戏状态定时器
typescript
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. 合理使用时间类型
typescript
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. 定时器管理
typescript
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. 避免过多的定时器
typescript
// ❌ 避免:为每个实体创建定时器
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. 定时器上下文使用
typescript
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();
});
}
}
时间和定时器系统是游戏开发中的重要工具,正确使用这些功能能让你的游戏逻辑更加精确和可控。