Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
162 lines
6.2 KiB
TypeScript
162 lines
6.2 KiB
TypeScript
import {
|
||
_decorator, Component, Node, Label, EditBox, Button, UITransform, Color, Widget,
|
||
} from 'cc';
|
||
import { GameManager } from '../manager/GameManager';
|
||
import { getMaxLevelId, getMinLevelId } from '../level/LevelRegistry';
|
||
|
||
const { ccclass } = _decorator;
|
||
|
||
/**
|
||
* 预览/运行时的关卡切换条(真实 Button,不依赖 Inspector 扩展)
|
||
*/
|
||
@ccclass('LevelSwitchBar')
|
||
export class LevelSwitchBar extends Component {
|
||
private editBox: EditBox | null = null;
|
||
|
||
static ensure(parent: Node): LevelSwitchBar {
|
||
let bar = parent.getChildByName('LevelSwitchBar');
|
||
if (!bar) {
|
||
bar = new Node('LevelSwitchBar');
|
||
bar.parent = parent;
|
||
bar.addComponent(LevelSwitchBar);
|
||
}
|
||
return bar.getComponent(LevelSwitchBar)!;
|
||
}
|
||
|
||
onLoad() {
|
||
this.buildUI();
|
||
}
|
||
|
||
private buildUI() {
|
||
const rootUi = this.node.getComponent(UITransform) || this.node.addComponent(UITransform);
|
||
rootUi.setContentSize(520, 48);
|
||
|
||
const hint = this.node.getChildByName('HintLabel') ?? new Node('HintLabel');
|
||
hint.parent = this.node;
|
||
const hintUi = hint.getComponent(UITransform) || hint.addComponent(UITransform);
|
||
hintUi.setContentSize(200, 36);
|
||
hint.setPosition(-160, 0, 0);
|
||
const hintLabel = hint.getComponent(Label) || hint.addComponent(Label);
|
||
hintLabel.string = `关卡 ${getMinLevelId()}–${getMaxLevelId()}`;
|
||
hintLabel.fontSize = 18;
|
||
hintLabel.color = new Color(200, 220, 255);
|
||
|
||
let inputNode = this.node.getChildByName('LevelInput');
|
||
if (!inputNode) {
|
||
inputNode = new Node('LevelInput');
|
||
inputNode.parent = this.node;
|
||
}
|
||
inputNode.setPosition(-20, 0, 0);
|
||
const inputUi = inputNode.getComponent(UITransform) || inputNode.addComponent(UITransform);
|
||
inputUi.setContentSize(80, 36);
|
||
this.editBox = inputNode.getComponent(EditBox) || inputNode.addComponent(EditBox);
|
||
this.editBox.placeholder = '关卡号';
|
||
this.editBox.string = '1';
|
||
this.editBox.fontSize = 20;
|
||
this.editBox.textLabel = this.ensureEditLabel(inputNode);
|
||
this.editBox.placeholderLabel = this.ensurePlaceholderLabel(inputNode);
|
||
|
||
let btnNode = this.node.getChildByName('BtnSwitchLevel');
|
||
if (!btnNode) {
|
||
btnNode = new Node('BtnSwitchLevel');
|
||
btnNode.parent = this.node;
|
||
}
|
||
btnNode.setPosition(120, 0, 0);
|
||
const btnUi = btnNode.getComponent(UITransform) || btnNode.addComponent(UITransform);
|
||
btnUi.setContentSize(140, 40);
|
||
const btn = btnNode.getComponent(Button) || btnNode.addComponent(Button);
|
||
btn.transition = Button.Transition.SCALE;
|
||
const btnLabel = this.ensureButtonLabel(btnNode);
|
||
btnLabel.string = '切换关卡';
|
||
btnLabel.fontSize = 20;
|
||
btnLabel.color = new Color(255, 255, 255);
|
||
btn.node.off(Button.EventType.CLICK);
|
||
btn.node.on(Button.EventType.CLICK, this.onClickSwitch, this);
|
||
|
||
let prevNode = this.node.getChildByName('BtnPrev');
|
||
if (!prevNode) {
|
||
prevNode = new Node('BtnPrev');
|
||
prevNode.parent = this.node;
|
||
}
|
||
prevNode.setPosition(200, 0, 0);
|
||
prevNode.getComponent(UITransform) || prevNode.addComponent(UITransform).setContentSize(56, 36);
|
||
const prevBtn = prevNode.getComponent(Button) || prevNode.addComponent(Button);
|
||
const prevLbl = this.ensureButtonLabel(prevNode);
|
||
prevLbl.string = '◀';
|
||
prevLbl.fontSize = 22;
|
||
prevNode.off(Button.EventType.CLICK);
|
||
prevNode.on(Button.EventType.CLICK, () => GameManager.instance?.prevLevel(), this);
|
||
|
||
let nextNode = this.node.getChildByName('BtnNext');
|
||
if (!nextNode) {
|
||
nextNode = new Node('BtnNext');
|
||
nextNode.parent = this.node;
|
||
}
|
||
nextNode.setPosition(248, 0, 0);
|
||
nextNode.getComponent(UITransform) || nextNode.addComponent(UITransform).setContentSize(56, 36);
|
||
const nextBtn = nextNode.getComponent(Button) || nextNode.addComponent(Button);
|
||
const nextLbl = this.ensureButtonLabel(nextNode);
|
||
nextLbl.string = '▶';
|
||
nextLbl.fontSize = 22;
|
||
nextNode.off(Button.EventType.CLICK);
|
||
nextNode.on(Button.EventType.CLICK, () => GameManager.instance?.nextLevel(), this);
|
||
|
||
const widget = this.node.getComponent(Widget) || this.node.addComponent(Widget);
|
||
widget.isAlignTop = true;
|
||
widget.top = 12;
|
||
widget.isAlignHorizontalCenter = true;
|
||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||
}
|
||
|
||
syncFromManager() {
|
||
const gm = GameManager.instance;
|
||
if (!gm || !this.editBox) return;
|
||
this.editBox.string = gm.inputLevel || String(gm.curLevelID);
|
||
}
|
||
|
||
private onClickSwitch() {
|
||
const gm = GameManager.instance;
|
||
if (!gm) {
|
||
console.warn('[LevelSwitchBar] GameManager 未就绪');
|
||
return;
|
||
}
|
||
if (this.editBox) {
|
||
gm.inputLevel = this.editBox.string.trim();
|
||
}
|
||
gm.clickSwitchLevel();
|
||
this.syncFromManager();
|
||
}
|
||
|
||
private ensureButtonLabel(btnNode: Node): Label {
|
||
let t = btnNode.getChildByName('Label');
|
||
if (!t) {
|
||
t = new Node('Label');
|
||
t.parent = btnNode;
|
||
t.addComponent(UITransform).setContentSize(140, 40);
|
||
}
|
||
return t.getComponent(Label) || t.addComponent(Label);
|
||
}
|
||
|
||
private ensureEditLabel(parent: Node): Label {
|
||
let t = parent.getChildByName('TEXT_LABEL');
|
||
if (!t) {
|
||
t = new Node('TEXT_LABEL');
|
||
t.parent = parent;
|
||
t.addComponent(UITransform).setContentSize(80, 36);
|
||
}
|
||
return t.getComponent(Label) || t.addComponent(Label);
|
||
}
|
||
|
||
private ensurePlaceholderLabel(parent: Node): Label {
|
||
let t = parent.getChildByName('PLACEHOLDER_LABEL');
|
||
if (!t) {
|
||
t = new Node('PLACEHOLDER_LABEL');
|
||
t.parent = parent;
|
||
t.addComponent(UITransform).setContentSize(80, 36);
|
||
}
|
||
const lb = t.getComponent(Label) || t.addComponent(Label);
|
||
lb.color = new Color(160, 160, 160);
|
||
return lb;
|
||
}
|
||
}
|