first commmit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { _decorator, Component, director, Label, Node, Color, EventTouch, UITransform } from 'cc';
|
||||
import { ConfigMgr } from '../data/ConfigMgr';
|
||||
import { CCJsonLoader } from './CCJsonLoader';
|
||||
import { StorySceneCtrl } from '../ui/StorySceneCtrl';
|
||||
import { ensureCanvasSize, createLabel, createButton } from './MainMenuEntry';
|
||||
import { DESIGN_WIDTH, DESIGN_HEIGHT } from '../common/Constants';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* StoryIntro scene entry (task 9.1 hookup, req 19.x).
|
||||
*
|
||||
* Attach to the root of `StoryIntro.scene`. Inspector:
|
||||
* - labelNode: optional — if left empty and `autoBuildUI` is true, a
|
||||
* centered Label and a bottom-right "Skip" button are auto-created.
|
||||
* - storyId: story id in `configs/stories.json` (default `chapter_1_intro`).
|
||||
*
|
||||
* Tap anywhere → accelerate / advance (req 19.3).
|
||||
* "Skip" button → finish immediately (req 19.4).
|
||||
*/
|
||||
@ccclass('StorySceneEntry')
|
||||
export class StorySceneEntry extends Component {
|
||||
@property({ type: Node, tooltip: '打字机 Label 节点 (可留空,自动创建)' })
|
||||
public labelNode: Node | null = null;
|
||||
|
||||
@property({ tooltip: '对应 configs/stories.json 中的 id' })
|
||||
public storyId: string = 'chapter_1_intro';
|
||||
|
||||
@property({ tooltip: '是否自动创建 Label / Skip 按钮 / 背景遮罩' })
|
||||
public autoBuildUI: boolean = true;
|
||||
|
||||
private ctrl: StorySceneCtrl | undefined;
|
||||
|
||||
protected async onLoad(): Promise<void> {
|
||||
if (this.autoBuildUI && !this.labelNode) {
|
||||
this.buildDefaultUI();
|
||||
}
|
||||
// Full-screen tap accelerator: listen on the host node itself.
|
||||
this.node.on(Node.EventType.TOUCH_END, () => this.onTap(), this);
|
||||
|
||||
const cfg = await this.loadStoryConfig();
|
||||
this.ctrl = new StorySceneCtrl(cfg, undefined, {
|
||||
onTextChanged: (text) => this.updateLabel(text),
|
||||
onFinished: () => director.loadScene('Level_1_1'),
|
||||
});
|
||||
const outcome = this.ctrl.start();
|
||||
if (outcome === 'already_seen') {
|
||||
director.loadScene('Level_1_1');
|
||||
}
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
this.ctrl?.tick(dt);
|
||||
}
|
||||
|
||||
/** Tap handler (called by auto-built full-screen listener or external). */
|
||||
public onTap(): void {
|
||||
this.ctrl?.onTap();
|
||||
}
|
||||
|
||||
/** Bound to the "Skip" button. */
|
||||
public onSkip(): void {
|
||||
this.ctrl?.onSkip();
|
||||
}
|
||||
|
||||
private updateLabel(text: string): void {
|
||||
if (!this.labelNode) return;
|
||||
const label = this.labelNode.getComponent(Label);
|
||||
if (label) label.string = text;
|
||||
}
|
||||
|
||||
private async loadStoryConfig() {
|
||||
const mgr = new ConfigMgr(new CCJsonLoader());
|
||||
await mgr.load();
|
||||
return mgr.story(this.storyId);
|
||||
}
|
||||
|
||||
private buildDefaultUI(): void {
|
||||
ensureCanvasSize(this.node);
|
||||
// Ensure the root node can receive touch (size = design resolution).
|
||||
// Central typewriter label.
|
||||
this.labelNode = createLabel(this.node, '', 0, 0, 28, Color.WHITE);
|
||||
const ut = this.labelNode.getComponent(UITransform);
|
||||
if (ut) ut.setContentSize(DESIGN_WIDTH - 80, DESIGN_HEIGHT - 120);
|
||||
// Skip button at bottom-right.
|
||||
const skipX = DESIGN_WIDTH / 2 - 90;
|
||||
const skipY = -DESIGN_HEIGHT / 2 + 50;
|
||||
createButton(this.node, 'Skip >>', skipX, skipY, 140, 50, () => this.onSkip());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user