Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
82
assets/scripts/theme/ThemeBackground.ts
Normal file
82
assets/scripts/theme/ThemeBackground.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Sprite, UITransform, Node, view, Layers, director, find } from 'cc';
|
||||
import { normalizeTexturePath } from '../visual/EntityTextureResolver';
|
||||
import { VisualAssets } from '../visual/VisualAssets';
|
||||
import { getThemeBackground } from './ThemeRegistry';
|
||||
|
||||
const BG_NODE_NAME = 'LevelThemeBackground';
|
||||
/** 与主关卡 UI_2D、HUD UI_3D 分离,由 BgCamera 固定渲染 */
|
||||
const BG_LAYER = Layers.Enum.DEFAULT;
|
||||
|
||||
/** 按关卡 theme 应用背景图(BgOverlay + BgCamera,不随主相机缩放/拖拽) */
|
||||
export class ThemeBackground {
|
||||
static resolveHost(entrance: Node | null): Node | null {
|
||||
const scene = entrance?.scene ?? director.getScene();
|
||||
if (!scene) return null;
|
||||
return find('BgOverlay', scene);
|
||||
}
|
||||
|
||||
/** 移除误挂在 GameRoot / MainLevelEntrance 等处的旧背景节点 */
|
||||
static purgeStaleNodes(entrance: Node | null) {
|
||||
const scene = entrance?.scene ?? director.getScene();
|
||||
if (!scene) return;
|
||||
const host = find('BgOverlay', scene);
|
||||
const walk = (node: Node) => {
|
||||
for (const ch of [...node.children]) {
|
||||
if (ch.name === BG_NODE_NAME && ch.parent !== host) {
|
||||
ch.destroy();
|
||||
} else {
|
||||
walk(ch);
|
||||
}
|
||||
}
|
||||
};
|
||||
walk(scene);
|
||||
}
|
||||
|
||||
static async apply(entrance: Node | null, themeId: string | undefined): Promise<void> {
|
||||
const parent = this.resolveHost(entrance);
|
||||
if (!parent?.isValid) return;
|
||||
this.purgeStaleNodes(entrance);
|
||||
|
||||
const path = normalizeTexturePath(getThemeBackground(themeId));
|
||||
let bgNode = parent.getChildByName(BG_NODE_NAME);
|
||||
if (!path) {
|
||||
if (bgNode) bgNode.active = false;
|
||||
return;
|
||||
}
|
||||
if (!bgNode) {
|
||||
bgNode = new Node(BG_NODE_NAME);
|
||||
bgNode.parent = parent;
|
||||
bgNode.addComponent(UITransform);
|
||||
bgNode.addComponent(Sprite);
|
||||
}
|
||||
bgNode.layer = BG_LAYER;
|
||||
bgNode.active = true;
|
||||
bgNode.setSiblingIndex(0);
|
||||
bgNode.setPosition(0, 0, 0);
|
||||
bgNode.setScale(1, 1, 1);
|
||||
|
||||
const sf = await VisualAssets.loadTexturePath(path);
|
||||
if (!sf || !bgNode?.isValid) return;
|
||||
const ui = bgNode.getComponent(UITransform)!;
|
||||
const spr = bgNode.getComponent(Sprite)!;
|
||||
spr.spriteFrame = sf;
|
||||
spr.sizeMode = Sprite.SizeMode.CUSTOM;
|
||||
this.layoutFullScreen(bgNode, sf);
|
||||
}
|
||||
|
||||
private static layoutFullScreen(bgNode: Node, sf: NonNullable<Awaited<ReturnType<typeof VisualAssets.loadTexturePath>>>) {
|
||||
const ui = bgNode.getComponent(UITransform)!;
|
||||
const vs = view.getVisibleSize();
|
||||
const scale = Math.max(vs.width / sf.originalSize.width, vs.height / sf.originalSize.height);
|
||||
ui.setContentSize(sf.originalSize.width * scale, sf.originalSize.height * scale);
|
||||
ui.setAnchorPoint(0.5, 0.5);
|
||||
bgNode.setPosition(0, 0, 0);
|
||||
}
|
||||
|
||||
static clear(entrance: Node | null) {
|
||||
this.purgeStaleNodes(entrance);
|
||||
const parent = this.resolveHost(entrance);
|
||||
const bgNode = parent?.getChildByName(BG_NODE_NAME);
|
||||
if (bgNode) bgNode.active = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user