import { _decorator, Component, director, screen, view, Settings, settings, sys, game, view as viewMgr } from 'cc'; import { DESIGN_WIDTH, DESIGN_HEIGHT, TARGET_FPS } from './common/Constants'; import { UIFlowMgr, ISceneEnter } from './ui/UIFlowMgr'; const { ccclass } = _decorator; /** * Game bootstrap component. Attached to the root node of the initial scene * (`assets/scenes/Boot.scene`). Responsible for: * * 1. Locking landscape orientation (requirement - tech-stack constraint). * 2. Forcing the design resolution to 960x540 with the "fit height" policy * so that any wider aspect ratio (18:9 / 19.5:9 / 20:9) simply extends * horizontally without distorting the UI (requirement 1.7 / 18.6). * 3. Locking frame rate to 30 fps (requirement 18.1-18.3). * 4. Loading the first gameplay-facing scene (story intro if not seen, else * main menu). This is the very first place we branch on the local storage * flag defined in `STORAGE_KEY.StoryIntroSeen` (requirement 19.5). * * NOTE: Do NOT put any heavy logic here; this component runs on the very * first frame and must stay cheap. */ @ccclass('GameBoot') export class GameBoot extends Component { protected onLoad(): void { this.lockOrientationLandscape(); this.applyDesignResolution(); this.lockFrameRate(); } protected start(): void { // Drive the very first scene transition through UIFlowMgr so that // story-intro / main-menu selection lives in one place (req 19.5). const flow = new UIFlowMgr(undefined, { onSceneEnter: (ev: ISceneEnter) => this.jumpToScene(ev), }); flow.onBoot(); } /** * Translate the abstract UIFlow event into a concrete Cocos scene load. * Boot scene itself never needs persisting; once we jump away the node * is discarded naturally. */ private jumpToScene(ev: ISceneEnter): void { const map: Record = { story_intro: 'StoryIntro', main_menu: 'MainMenu', }; const scene = map[ev.scene]; if (scene) { director.loadScene(scene); } } /** * Lock the device to landscape. On WeChat Mini Game this is declared in * `game.json` (deviceOrientation: "landscape"); on web/simulator we call * the `screen.orientation` API when available. */ private lockOrientationLandscape(): void { // `screen.orientation` is not declared as writable in every engine // build, so we access it guardedly. try { // @ts-ignore - engine API surface differs across platforms. if (typeof screen.orientation === 'number') { // macro.ORIENTATION_LANDSCAPE = 3 in Cocos Creator 3.8. // @ts-ignore - write is legal on runtime builds. screen.orientation = 3; } } catch (e) { // Silently ignore: editor preview already enforces orientation // through `profiles/v2/project.json`. } } /** * Apply the 960x540 landscape design resolution. Any physical screen * whose aspect ratio is >= 16:9 will simply show more horizontal world; * narrower screens (unlikely on landscape) will letterbox. */ private applyDesignResolution(): void { const v = view; v.setDesignResolutionSize(DESIGN_WIDTH, DESIGN_HEIGHT, 4 /* FIT_HEIGHT */); } /** Clamp the engine game loop to 30 fps. */ private lockFrameRate(): void { game.frameRate = TARGET_FPS; } }