92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
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<string, string> = {
|
|
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;
|
|
}
|
|
}
|