import { autoDetectRenderer, Container, Renderer, Ticker, } from "pixi.js"; import { Orientation } from "@/enums/Orientation"; import { initDevtools } from "@pixi/devtools"; import { logger } from "./Logger"; import { tweenManager } from "@/utils/Tween"; 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: number; height: number } = { 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: 1, resolution: window.devicePixelRatio || 1, 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; this._ticker.add(() => { tweenManager.update(); }); 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(); if (this.orientation === Orientation.Landscape) { if (currentOrientation === Orientation.Landscape) { this._stage.rotation = 0; this._stage.position.set(0, 0); const scaleRatio = clientWidth / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); this.info.width = clientWidth / scaleRatio; this.info.height = clientHeight / scaleRatio; } else { this._stage.rotation = Math.PI / 2; this._stage.position.set(0, 0); const scaleRatio = clientHeight / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); this.info.width = clientHeight / scaleRatio; this.info.height = clientWidth / scaleRatio; } } else { if (currentOrientation === Orientation.Portrait) { this._stage.rotation = 0; this._stage.position.set(0, 0); const scaleRatio = clientWidth / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); this.info.width = clientWidth / scaleRatio; this.info.height = clientHeight / scaleRatio; } else { this._stage.rotation = -Math.PI / 2; this._stage.position.set(0, clientWidth); const scaleRatio = clientHeight / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); this.info.width = clientHeight / scaleRatio; this.info.height = clientWidth / scaleRatio; } } this.render(); } render(): void { this.renderer.render(this.stage); } } export default Game;