---
title: "Time and Timer System"
---

The ECS framework provides a complete time management and timer system, including time scaling, frame time calculation, and flexible timer scheduling.

## Time Class

The Time class is the core of the framework's time management, providing all game time-related functionality.

### Basic Time Properties

```typescript
import { Time } from '@esengine/ecs-framework';

class GameSystem extends EntitySystem {
  protected process(entities: readonly Entity[]): void {
    // Get frame time (seconds)
    const deltaTime = Time.deltaTime;

    // Get unscaled frame time
    const unscaledDelta = Time.unscaledDeltaTime;

    // Get total game time
    const totalTime = Time.totalTime;

    // Get current frame count
    const frameCount = Time.frameCount;

    console.log(`Frame ${frameCount}, delta: ${deltaTime}s, total: ${totalTime}s`);
  }
}
```

### Game Pause

The framework provides two pause methods for different scenarios:

#### Core.paused (Recommended)

`Core.paused` is a **true pause** - when set, the entire game loop stops:

```typescript
import { Core } from '@esengine/ecs-framework';

class PauseMenuSystem extends EntitySystem {
  public pauseGame(): void {
    // True pause - all systems stop executing
    Core.paused = true;
    console.log('Game paused');
  }

  public resumeGame(): void {
    // Resume game
    Core.paused = false;
    console.log('Game resumed');
  }

  public togglePause(): void {
    Core.paused = !Core.paused;
    console.log(Core.paused ? 'Game paused' : 'Game resumed');
  }
}
```

#### Time.timeScale = 0

`Time.timeScale = 0` only makes `deltaTime` become 0, **systems still execute**:

```typescript
class SlowMotionSystem extends EntitySystem {
  public freezeTime(): void {
    // Time freeze - systems still execute, just deltaTime = 0
    Time.timeScale = 0;
  }
}
```

#### Comparison

| Feature | `Core.paused = true` | `Time.timeScale = 0` |
|---------|---------------------|---------------------|
| System Execution | Completely stopped | Still running |
| CPU Overhead | Zero | Normal overhead |
| Time Updates | Stopped | Continues (deltaTime=0) |
| Timers | Stopped | Continues (but time doesn't advance) |
| Use Cases | Pause menu, game pause | Slow motion, bullet time effects |

**Recommendations**:
- Pause menu, true game pause → Use `Core.paused = true`
- Slow motion, bullet time effects → Use `Time.timeScale`

### Time Scaling

The Time class supports time scaling for slow motion, fast forward, and other effects:

```typescript
class TimeControlSystem extends EntitySystem {
  public enableSlowMotion(): void {
    // Set to slow motion (50% speed)
    Time.timeScale = 0.5;
    console.log('Slow motion enabled');
  }

  public enableFastForward(): void {
    // Set to fast forward (200% speed)
    Time.timeScale = 2.0;
    console.log('Fast forward enabled');
  }

  public enableBulletTime(): void {
    // Bullet time effect (10% speed)
    Time.timeScale = 0.1;
    console.log('Bullet time enabled');
  }

  public resumeNormalSpeed(): void {
    // Resume normal speed
    Time.timeScale = 1.0;
    console.log('Normal speed resumed');
  }

  protected process(entities: readonly Entity[]): void {
    // deltaTime is affected by timeScale
    const scaledDelta = Time.deltaTime; // Affected by time scale
    const realDelta = Time.unscaledDeltaTime; // Not affected by time scale

    for (const entity of entities) {
      const movement = entity.getComponent(Movement);
      if (movement) {
        // Use scaled time for game logic updates
        movement.update(scaledDelta);
      }

      const ui = entity.getComponent(UIComponent);
      if (ui) {
        // UI animations use real time, not affected by game time scale
        ui.update(realDelta);
      }
    }
  }
}
```

### Time Check Utilities

```typescript
class CooldownSystem extends EntitySystem {
  private lastAttackTime = 0;
  private lastSpawnTime = 0;

  constructor() {
    super(Matcher.all(Weapon));
  }

  protected process(entities: readonly Entity[]): void {
    // Check attack cooldown
    if (Time.checkEvery(1.5, this.lastAttackTime)) {
      this.performAttack();
      this.lastAttackTime = Time.totalTime;
    }

    // Check spawn interval
    if (Time.checkEvery(3.0, this.lastSpawnTime)) {
      this.spawnEnemy();
      this.lastSpawnTime = Time.totalTime;
    }
  }

  private performAttack(): void {
    console.log('Performing attack!');
  }

  private spawnEnemy(): void {
    console.log('Spawning enemy!');
  }
}
```

## Core.schedule Timer System

Core provides powerful timer scheduling functionality for creating one-time or repeating timers.

### Basic Timer Usage

```typescript
import { Core } from '@esengine/ecs-framework';

class GameScene extends Scene {
  protected initialize(): void {
    // Create one-time timers
    this.createOneTimeTimers();

    // Create repeating timers
    this.createRepeatingTimers();

    // Create timers with context
    this.createContextTimers();
  }

  private createOneTimeTimers(): void {
    // Execute once after 2 seconds
    Core.schedule(2.0, false, null, (timer) => {
      console.log('Executed after 2 second delay');
    });

    // Show tip after 5 seconds
    Core.schedule(5.0, false, this, (timer) => {
      const scene = timer.getContext<GameScene>();
      scene.showTip('Game tip: 5 seconds have passed!');
    });
  }

  private createRepeatingTimers(): void {
    // Execute every second
    const heartbeatTimer = Core.schedule(1.0, true, null, (timer) => {
      console.log(`Game heartbeat - Total time: ${Time.totalTime.toFixed(1)}s`);
    });

    // Save timer reference for later control
    this.saveTimerReference(heartbeatTimer);
  }

  private createContextTimers(): void {
    const gameData = { score: 0, level: 1 };

    // Add score every 2 seconds
    Core.schedule(2.0, true, gameData, (timer) => {
      const data = timer.getContext<typeof gameData>();
      data.score += 10;
      console.log(`Score increased! Current score: ${data.score}`);
    });
  }

  private saveTimerReference(timer: any): void {
    // Can stop timer later
    setTimeout(() => {
      timer.stop();
      console.log('Timer stopped');
    }, 10000); // Stop after 10 seconds
  }

  private showTip(message: string): void {
    console.log('Tip:', message);
  }
}
```

### Timer Control

```typescript
class TimerControlExample {
  private attackTimer: any;
  private spawnerTimer: any;

  public startCombat(): void {
    // Start attack timer
    this.attackTimer = Core.schedule(0.5, true, this, (timer) => {
      const self = timer.getContext<TimerControlExample>();
      self.performAttack();
    });

    // Start enemy spawn timer
    this.spawnerTimer = Core.schedule(3.0, true, null, (timer) => {
      this.spawnEnemy();
    });
  }

  public stopCombat(): void {
    // Stop all combat-related timers
    if (this.attackTimer) {
      this.attackTimer.stop();
      console.log('Attack timer stopped');
    }

    if (this.spawnerTimer) {
      this.spawnerTimer.stop();
      console.log('Spawn timer stopped');
    }
  }

  public resetAttackTimer(): void {
    // Reset attack timer
    if (this.attackTimer) {
      this.attackTimer.reset();
      console.log('Attack timer reset');
    }
  }

  private performAttack(): void {
    console.log('Performing attack');
  }

  private spawnEnemy(): void {
    console.log('Spawning enemy');
  }
}
```

## Best Practices

### 1. Use Appropriate Time Types

```typescript
class MovementSystem extends EntitySystem {
  protected process(entities: readonly Entity[]): void {
    for (const entity of entities) {
      const movement = entity.getComponent(Movement);

      // Use scaled time for game logic
      movement.position.x += movement.velocity.x * Time.deltaTime;

      // Use real time for UI animations (not affected by game pause)
      const ui = entity.getComponent(UIAnimation);
      if (ui) {
        ui.update(Time.unscaledDeltaTime);
      }
    }
  }
}
```

### 2. Timer Management

```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. Avoid Too Many Timers

```typescript
// Avoid: Creating a timer for each entity
class BadExample extends EntitySystem {
  protected onAdded(entity: Entity): void {
    Core.schedule(1.0, true, entity, (timer) => {
      // One timer per entity - poor performance
    });
  }
}

// Recommended: Manage time uniformly in the system
class GoodExample extends EntitySystem {
  private lastUpdateTime = 0;

  protected process(entities: readonly Entity[]): void {
    // Execute logic once per second
    if (Time.checkEvery(1.0, this.lastUpdateTime)) {
      this.processAllEntities(entities);
      this.lastUpdateTime = Time.totalTime;
    }
  }

  private processAllEntities(entities: readonly Entity[]): void {
    // Batch process all entities
  }
}
```

### 4. Timer Context Usage

```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(`Timer for entity ${ctx.entityId} completed`);
      ctx.onComplete();
    });
  }
}
```

The time and timer system is an essential tool in game development. Using these features correctly will make your game logic more precise and controllable.
