UNPKG

juno-console

Version:

Juno is a clean and lightweight 2D game framework written in TypeScript for making tiny HTML5 Games.

103 lines (90 loc) 2.69 kB
/** * @author Digitsensitive <digit.sensitivee@gmail.com> * @copyright 2018 Digitsensitive * @description Juno Core: Game Loop * * This is the core game loop of the juno html5 game framework. * Juno uses a fixed update time step with a variable rendering. This * means, that it updates with a fixed time step, but can drop rendering * frames to catch up. * * The Game Loop makes use of EventEmitter to communicate. * * Regarding Request Animation Frame Juno uses the most basic implementation. * * Regarding Time Juno uses the most basic implementation of performane.now * (see polyfills/performance.now.ts). * * References: * http://gameprogrammingpatterns.com/game-loop.html (Date: 2018-09-09) * https://gafferongames.com/post/fix_your_timestep (Date: 2018-09-09) * http://www.koonsolo.com/news/dewitters-gameloop (Date: 2018-09-09) * https://github.com/sethvincent/gameloop (Date: 2018-09-09) * * @license {@link https://github.com/digitsensitive/juno-console/blob/master/license.txt|MIT License} */ import { EventEmitter } from "eventemitter3"; import { ElapsedTime } from "../polyfills/performance.now"; export class GameLoop extends EventEmitter { private accumulator: number; private currentTime: number; private fps: number; private paused: boolean; private step: number; constructor() { super(); this.fps = 60; this.paused = false; this.step = 1 / this.fps; } /** * Start the game loop * @param state [name of the state to start] */ public start(state: string): void { this.init(); this.paused = false; this.currentTime = ElapsedTime(); this.accumulator = 0; this.frame(); } /** * Execution of one frame (= tick). */ private frame(): void { if (!this.paused) { let newTime = ElapsedTime(); // it is important that frameTime is in seconds // because this.step is also in seconds let frameTime = (newTime - this.currentTime) / 1000; this.currentTime = newTime; this.accumulator += frameTime; while (this.accumulator >= this.step) { this.update(this.step); this.accumulator -= this.step; } this.render(this.accumulator / this.step); requestAnimationFrame(this.frame.bind(this)); } } /** * Init the game */ private init(): void { this.emit("init"); } /** * Update the game * @param interval [interval in seconds] */ private update(interval: number): void { this.emit("update", interval); } /** * Render the game * @param delta [delta in seconds] */ private render(delta: number): void { this.emit("render", delta); } }