diff --git a/src/core/Game.ts b/src/core/Game.ts new file mode 100644 index 0000000..4e26196 --- /dev/null +++ b/src/core/Game.ts @@ -0,0 +1,144 @@ +import { + autoDetectRenderer, + Container, + Renderer, + Ticker, +} from "pixi.js"; +import { Orientation } from "@/enums/Orientation"; +import { initDevtools } from "@pixi/devtools"; +import { logger } from "./Logger"; + +class Game { + private static instance: Game; + private _stage: Container; + private _renderer: Renderer; + private _ticker: Ticker; + private orientation: Orientation = Orientation.Portrait; + + public designWidth: number = 750; + + public info = { + width: 0, + height: 0, + }; + + private constructor() {} + + static getInstance(): Game { + if (!Game.instance) { + Game.instance = new Game(); + } + return Game.instance; + } + + public get renderer(): Renderer { + return this._renderer; + } + + public get stage(): Container { + return this._stage; + } + + public get ticker(): Ticker { + return this._ticker; + } + + async init(): Promise { + const screenWidth = document.documentElement.clientWidth; + const screenHeight = document.documentElement.clientHeight; + + this._stage = new Container(); + this._stage.label = "root"; + + this._renderer = await autoDetectRenderer({ + autoDensity: true, + width: screenWidth, + height: screenHeight, + antialias: true, + backgroundAlpha: 255, + resolution: 2, + backgroundColor: 0x1d9ce0, + }); + + this.renderer.resize(screenWidth, screenHeight); + document.body.appendChild(this.renderer.canvas); + + window.addEventListener("resize", () => { + this.updateView(); + }); + + this._ticker = Ticker.shared; + this._ticker.autoStart = true; + + if (import.meta.env.DEV) { + initDevtools({ stage: this._stage, renderer: this._renderer }); + } + + this.updateView(); + logger.info("Game initialized", { screenWidth, screenHeight }); + } + + getInfo(): { width: number; height: number } { + return { ...this.info }; + } + + setOrientation(orientation: Orientation): void { + this.orientation = orientation; + this.updateView(); + } + + private detectCurrentOrientation(): Orientation { + const isLandscape = window.innerWidth > window.innerHeight; + return isLandscape ? Orientation.Landscape : Orientation.Portrait; + } + + updateView(): void { + const clientWidth = document.documentElement.clientWidth; + const clientHeight = document.documentElement.clientHeight; + + this.renderer.resize(clientWidth, clientHeight); + + const currentOrientation = this.detectCurrentOrientation(); + + let offsetWidth = clientWidth; + let offsetHeight = clientHeight; + + if (this.orientation === Orientation.Landscape) { + if (currentOrientation === Orientation.Landscape) { + this._stage.rotation = 0; + this._stage.y = 0; + } else { + this._stage.rotation = -Math.PI / 2; + this._stage.y = clientHeight; + } + const scaleRatio = clientWidth / this.designWidth; + this._stage.scale.set(scaleRatio, scaleRatio); + this.info.width = offsetWidth / scaleRatio; + this.info.height = offsetHeight / scaleRatio; + } else { + if (currentOrientation === Orientation.Landscape) { + this._stage.rotation = 0; + this._stage.y = 0; + const scaleRatio = offsetWidth / this.designWidth; + this._stage.scale.set(scaleRatio, scaleRatio); + this.info.width = offsetHeight / scaleRatio; + this.info.height = offsetWidth / scaleRatio; + } else { + this._stage.rotation = -Math.PI / 2; + this._stage.y = offsetHeight; + const scaleRatio = offsetWidth / this.designWidth; + this._stage.scale.set(scaleRatio, scaleRatio); + this.info.width = offsetHeight / scaleRatio; + this.info.height = offsetWidth / scaleRatio; + } + } + + this.render(); + } + + render(): void { + this.renderer.render(this.stage); + } +} + +export default Game; \ No newline at end of file