All files / ts engineLoop.ts

100% Statements 30/30
100% Branches 10/10
100% Functions 9/9
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72  1x 1x               1x               5x       17x 17x 17x 17x       10x 1x   9x 9x       5x       2x 2x       16x 9x 9x   16x       9x 9x       9x 9x 7x 7x 6x   7x   2x 1x      
import { IScene } from "./components/scene.js";
import { IParent, Parent } from "./models/parent.js";
import { IFrameTime, FrameTime } from "./models/frameTime.js";
import { ISurfaceSettings } from "./controller/surface/surfaceSettings.js";
 
export interface IEngineLoop extends IParent<IScene> {
    readonly isActive: boolean;
    start(): void;
    stop(): void;
}
export abstract class EngineLoop extends Parent<IScene> implements IEngineLoop {
 
    private readonly _window: Window;
    private readonly _surfaceSettings: ISurfaceSettings;
 
    private _isActive: boolean;
 
    public get isActive(): boolean {
        return this._isActive;
    }
 
    public constructor(surfaceSettings: ISurfaceSettings, window: Window) {
        super();
        this._isActive = false;
        this._window = window;
        this._surfaceSettings = surfaceSettings;
    }
    
    public start(): void {
        if (this._isActive) {
            return;
        }
        this._isActive = true;
        this.request(0);
    }
 
    public stop(): void {
        this._isActive = false;
    }
 
    public override destroy(): void {
        super.destroy();
        this.stop();
    }
 
    private request(startTime: number): void {
        const requestFrame = (endTime: number): void => {
            const frameTime = new FrameTime(startTime, endTime);
            this.loop(frameTime)
        };
        this._window.requestAnimationFrame(requestFrame);
    }
 
    private loop(frameTime: IFrameTime): void {
        const surfaceSettings = this._surfaceSettings;
        const expectedDelta = surfaceSettings.frameLimit > 0
            ? 1000 / surfaceSettings.frameLimit
            : frameTime.delta;
 
        const actualDelta = Math.round(expectedDelta - frameTime.delta);
        if (actualDelta <= 0) {
            this.children.forEach(scene => scene.update(frameTime));
            if (this._isActive) {
                this.request(frameTime.end);
            }
            return;
        }
        if (this._isActive) {
            this.request(frameTime.start);
        }
    }
}