184 lines
6.3 KiB
TypeScript
184 lines
6.3 KiB
TypeScript
import EventQueue from "../Events/EventQueue";
|
|
import Input from "../Input/Input";
|
|
import InputHandler from "../Input/InputHandler";
|
|
import Recorder from "../Playback/Recorder";
|
|
import Debug from "../Debug/Debug";
|
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
|
import Viewport from "../SceneGraph/Viewport";
|
|
import SceneManager from "../Scene/SceneManager";
|
|
import AudioManager from "../Sound/AudioManager";
|
|
import Stats from "../Debug/Stats";
|
|
import RenderingManager from "../Rendering/RenderingManager";
|
|
import CanvasRenderer from "../Rendering/CanvasRenderer";
|
|
import Color from "../Utils/Color";
|
|
import GameOptions from "./GameOptions";
|
|
import GameLoop from "./GameLoop";
|
|
import FixedUpdateGameLoop from "./FixedUpdateGameLoop";
|
|
import EnvironmentInitializer from "./EnvironmentInitializer";
|
|
import Vec2 from "../DataTypes/Vec2";
|
|
|
|
/**
|
|
* The main loop of the game engine.
|
|
* Handles the update order, and initializes all subsystems.
|
|
* The Game manages the update cycle, and requests animation frames to render to the browser.
|
|
*/
|
|
export default class Game {
|
|
gameOptions: GameOptions;
|
|
private showDebug: boolean;
|
|
private showStats: boolean;
|
|
|
|
// The game loop
|
|
private loop: GameLoop;
|
|
|
|
// Game canvas and its width and height
|
|
readonly GAME_CANVAS: HTMLCanvasElement;
|
|
readonly DEBUG_CANVAS: HTMLCanvasElement;
|
|
readonly WIDTH: number;
|
|
readonly HEIGHT: number;
|
|
private viewport: Viewport;
|
|
private ctx: CanvasRenderingContext2D;
|
|
private clearColor: Color;
|
|
|
|
// All of the necessary subsystems that need to run here
|
|
private eventQueue: EventQueue;
|
|
private inputHandler: InputHandler;
|
|
private recorder: Recorder;
|
|
private resourceManager: ResourceManager;
|
|
private sceneManager: SceneManager;
|
|
private audioManager: AudioManager;
|
|
private renderingManager: RenderingManager;
|
|
|
|
/**
|
|
* Creates a new Game
|
|
* @param options The options for Game initialization
|
|
*/
|
|
constructor(options?: Record<string, any>){
|
|
// Before anything else, build the environment
|
|
EnvironmentInitializer.setup();
|
|
|
|
// Typecast the config object to a GameConfig object
|
|
this.gameOptions = GameOptions.parse(options);
|
|
|
|
this.showDebug = this.gameOptions.showDebug;
|
|
this.showStats = this.gameOptions.showStats;
|
|
|
|
// Create an instance of a game loop
|
|
this.loop = new FixedUpdateGameLoop();
|
|
|
|
// Get the game canvas and give it a background color
|
|
this.GAME_CANVAS = <HTMLCanvasElement>document.getElementById("game-canvas");
|
|
this.DEBUG_CANVAS = <HTMLCanvasElement>document.getElementById("debug-canvas");
|
|
|
|
// Give the canvas a size and get the rendering context
|
|
this.WIDTH = this.gameOptions.viewportSize.x;
|
|
this.HEIGHT = this.gameOptions.viewportSize.y;
|
|
|
|
// For now, just hard code a canvas renderer. We can do this with options later
|
|
this.renderingManager = new CanvasRenderer();
|
|
this.initializeGameWindow();
|
|
this.ctx = this.renderingManager.initializeCanvas(this.GAME_CANVAS, this.WIDTH, this.HEIGHT);
|
|
this.clearColor = new Color(this.gameOptions.clearColor.r, this.gameOptions.clearColor.g, this.gameOptions.clearColor.b);
|
|
|
|
// Initialize debugging and stats
|
|
Debug.initializeDebugCanvas(this.DEBUG_CANVAS, this.WIDTH, this.HEIGHT);
|
|
Stats.initStats();
|
|
|
|
if(this.gameOptions.showStats) {
|
|
// Find the stats output and make it no longer hidden
|
|
document.getElementById("stats").hidden = false;
|
|
}
|
|
|
|
// Size the viewport to the game canvas
|
|
const viewportSize = new Vec2(this.WIDTH, this.HEIGHT);
|
|
this.viewport = new Viewport(viewportSize.scaled(0.5), viewportSize);
|
|
|
|
// Initialize all necessary game subsystems
|
|
this.eventQueue = EventQueue.getInstance();
|
|
this.inputHandler = new InputHandler(this.GAME_CANVAS);
|
|
Input.initialize(this.viewport, this.gameOptions.inputs);
|
|
this.recorder = new Recorder();
|
|
this.resourceManager = ResourceManager.getInstance();
|
|
this.sceneManager = new SceneManager(this.viewport, this.renderingManager);
|
|
this.audioManager = AudioManager.getInstance();
|
|
}
|
|
|
|
/**
|
|
* Set up the game window that holds the canvases
|
|
*/
|
|
private initializeGameWindow(): void {
|
|
const gameWindow = document.getElementById("game-window");
|
|
|
|
// Set the height of the game window
|
|
gameWindow.style.width = this.WIDTH + "px";
|
|
gameWindow.style.height = this.HEIGHT + "px";
|
|
}
|
|
|
|
/**
|
|
* Retreives the SceneManager from the Game
|
|
* @returns The SceneManager
|
|
*/
|
|
getSceneManager(): SceneManager {
|
|
return this.sceneManager;
|
|
}
|
|
|
|
/**
|
|
* Starts the game
|
|
*/
|
|
start(): void {
|
|
// Set the update function of the loop
|
|
this.loop.doUpdate = (deltaT: number) => this.update(deltaT);
|
|
|
|
// Set the render function of the loop
|
|
this.loop.doRender = () => this.render();
|
|
|
|
// Start the loop
|
|
this.loop.start();
|
|
}
|
|
|
|
/**
|
|
* Updates all necessary subsystems of the game. Defers scene updates to the sceneManager
|
|
* @param deltaT The time sine the last update
|
|
*/
|
|
update(deltaT: number): void {
|
|
// Handle all events that happened since the start of the last loop
|
|
this.eventQueue.update(deltaT);
|
|
|
|
// Update the input data structures so game objects can see the input
|
|
Input.update(deltaT);
|
|
|
|
// Update the recording of the game
|
|
this.recorder.update(deltaT);
|
|
|
|
// Update all scenes
|
|
this.sceneManager.update(deltaT);
|
|
|
|
// Update all sounds
|
|
this.audioManager.update(deltaT);
|
|
|
|
// Load or unload any resources if needed
|
|
this.resourceManager.update(deltaT);
|
|
}
|
|
|
|
/**
|
|
* Clears the canvas and defers scene rendering to the sceneManager. Renders the debug canvas
|
|
*/
|
|
render(): void {
|
|
// Clear the canvases
|
|
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
|
Debug.clearCanvas();
|
|
|
|
// Game Canvas
|
|
this.ctx.fillStyle = this.clearColor.toString();
|
|
this.ctx.fillRect(0, 0, this.WIDTH, this.HEIGHT);
|
|
this.sceneManager.render();
|
|
|
|
// Debug render
|
|
if(this.showDebug){
|
|
Debug.render();
|
|
}
|
|
|
|
if(this.showStats){
|
|
Stats.render();
|
|
}
|
|
}
|
|
} |