From 0ba0bf4d443f0fcaea93ce925ad1c2e233ed6a48 Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Sun, 19 Apr 2026 12:23:59 +0800 Subject: [PATCH] fix: improve SceneManager type safety and code quality --- src/core/Game.ts | 45 +++++++++++++++++++++-------------------- src/scene/SceneManager.ts | 51 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/core/Game.ts b/src/core/Game.ts index 4e26196..cfe2e98 100644 --- a/src/core/Game.ts +++ b/src/core/Game.ts @@ -17,7 +17,7 @@ class Game { public designWidth: number = 750; - public info = { + public info: { width: number; height: number } = { width: 0, height: 0, }; @@ -55,8 +55,8 @@ class Game { width: screenWidth, height: screenHeight, antialias: true, - backgroundAlpha: 255, - resolution: 2, + backgroundAlpha: 1, + resolution: window.devicePixelRatio || 1, backgroundColor: 0x1d9ce0, }); @@ -100,36 +100,37 @@ class Game { 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; + 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.y = clientHeight; + 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; } - 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) { + if (currentOrientation === Orientation.Portrait) { this._stage.rotation = 0; - this._stage.y = 0; - const scaleRatio = offsetWidth / this.designWidth; + this._stage.position.set(0, 0); + const scaleRatio = clientWidth / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); - this.info.width = offsetHeight / scaleRatio; - this.info.height = offsetWidth / scaleRatio; + this.info.width = clientWidth / scaleRatio; + this.info.height = clientHeight / scaleRatio; } else { this._stage.rotation = -Math.PI / 2; - this._stage.y = offsetHeight; - const scaleRatio = offsetWidth / this.designWidth; + this._stage.position.set(0, clientWidth); + const scaleRatio = clientHeight / this.designWidth; this._stage.scale.set(scaleRatio, scaleRatio); - this.info.width = offsetHeight / scaleRatio; - this.info.height = offsetWidth / scaleRatio; + this.info.width = clientHeight / scaleRatio; + this.info.height = clientWidth / scaleRatio; } } diff --git a/src/scene/SceneManager.ts b/src/scene/SceneManager.ts index 1453b9f..0b4f18f 100644 --- a/src/scene/SceneManager.ts +++ b/src/scene/SceneManager.ts @@ -6,6 +6,12 @@ import { SceneType } from "@/enums/SceneType"; import { BaseScene } from "./BaseScene"; import type { SceneConfig, IBaseScene } from "./types"; +declare global { + interface Container { + _isHolderLast?: boolean; + } +} + type StageChangeCallback = ( current: IBaseScene, previous: IBaseScene | undefined @@ -56,6 +62,11 @@ class SceneManager { /** 注册场景 */ registerScene(scene: IBaseScene): void { + if (!scene.name) { + logger.warn("SceneManager: scene name cannot be empty"); + return; + } + if (this.scenes.has(scene.name)) { logger.warn(`SceneManager: scene "${scene.name}" already registered`); } @@ -76,6 +87,11 @@ class SceneManager { /** 初始化入口场景 */ initScene(name: string): void { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + return; + } + const scene = this.getSceneOrThrow(name); this._currentScene = scene; @@ -89,6 +105,11 @@ class SceneManager { /** 切换场景 */ async changeScene(name: string, options?: { isHolderLast?: boolean }): Promise { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + return; + } + const previous = this._currentScene; if (!previous) { throw new Error(`SceneManager: no current scene, call initScene first`); @@ -100,7 +121,6 @@ class SceneManager { if (previous.type === SceneType.Normal) { if (options?.isHolderLast) { previous.stage.visible = false; - // @ts-ignore 标记保留 previous.stage._isHolderLast = true; } else { // 销毁场景 @@ -123,11 +143,12 @@ class SceneManager { // 处理目标场景 if (target.type === SceneType.Normal) { - // @ts-ignore if (target.stage._isHolderLast) { target.stage.visible = true; } else { - this.game.stage.addChild(target.stage); + if (!this.game.stage.children.includes(target.stage)) { + this.game.stage.addChild(target.stage); + } } } else if (target.type === SceneType.Resident) { target.stage.visible = true; @@ -139,7 +160,7 @@ class SceneManager { target._assetsLoaded = true; } - if (!target._layoutDone || target.stage !== this.getSceneOrThrow(name).stage) { + if (!target._layoutDone) { await target.layout?.(); target._layoutDone = true; } @@ -149,15 +170,25 @@ class SceneManager { // 触发回调 await this.emitStageChange(target, previous); - logger.debug(`SceneManager: changed from "${previous?.name}" to "${name}"`); + logger.debug(`SceneManager: changed from "${previous.name}" to "${name}"`); } /** 获取已注册场景 */ getScene(name: string): IBaseScene | undefined { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + return undefined; + } + return this.scenes.get(name); } getSceneOrThrow(name: string): IBaseScene { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + throw new Error("SceneManager: scene name cannot be empty"); + } + const scene = this.scenes.get(name); if (!scene) { throw new Error(`SceneManager: scene "${name}" not registered`); @@ -167,6 +198,11 @@ class SceneManager { /** 确保场景存在,不存在则创建容器 */ ensureSceneExists(name: string, type: SceneType = SceneType.Normal): Container { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + return new Container(); + } + if (this.scenes.has(name)) { return this.getSceneOrThrow(name).stage; } @@ -187,6 +223,11 @@ class SceneManager { } hasScene(name: string): boolean { + if (!name) { + logger.warn("SceneManager: scene name cannot be empty"); + return false; + } + return this.scenes.has(name); } }