import { _decorator, Component, director, game, Label, resources, SpriteFrame } from 'cc'; import { App } from './App'; import { CARDS_DIR } from '../ui/game/CardLibrary'; const { ccclass, property } = _decorator; /** If the art has not arrived by then, open the lobby anyway rather than hang. */ const PRELOAD_TIMEOUT = 10; /** * The loader scene, per ARCHITECTURE.md: bring the modules up, then hand over * to the lobby. Everything that must exist before any gameplay runs belongs * here, and nowhere else. * * Every step reports itself to the on-screen label and to the console, because * a loader that stalls silently is the hardest kind of bug to diagnose from a * bug report — "it shows a green screen" should never again be all we know. */ @ccclass('Bootstrap') export class Bootstrap extends Component { @property({ tooltip: 'Scene to open once the modules are ready.' }) nextScene = 'lobby'; @property({ type: Label, tooltip: 'Shows what the loader is doing.' }) statusLabel: Label | null = null; private _handedOver = false; start(): void { // A phone that throttles to 30 fps makes the card animations stutter; // asking for 60 up front is cheap and the engine falls back on its own. game.frameRate = 60; this._report('starting modules'); App.create(); // Warm the card art here rather than on the first deal: thirty-seven // sprites are the only sizeable load in the game, and a loader scene is // exactly where a player expects to wait for it. this._report('loading cards'); resources.loadDir(CARDS_DIR, SpriteFrame, (error, frames) => { if (error) { console.error('[bootstrap] could not preload the card art', error); } else { console.log(`[bootstrap] ${frames.length} card sprites ready`); } this._openLobby(); }); // A failed bundle can leave that callback unfired. The lobby does not // need the art to show, so never let the loader be a dead end. this.scheduleOnce(() => { if (!this._handedOver) { console.warn('[bootstrap] card art did not arrive in time, opening the lobby anyway'); this._openLobby(); } }, PRELOAD_TIMEOUT); } private _openLobby(): void { if (this._handedOver) { return; } this._handedOver = true; this._report('opening lobby'); director.loadScene(this.nextScene, (error) => { if (error) { console.error(`[bootstrap] could not open '${this.nextScene}'`, error); this._report(`could not open ${this.nextScene}`); } }); } private _report(what: string): void { console.log(`[bootstrap] ${what}`); if (this.statusLabel) { this.statusLabel.string = what; } } }