Files
cocos/assets/scripts/theme/ThemeBackground.ts
刘宇飞 d393302388 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>
2026-06-16 15:30:58 +08:00

83 lines
3.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}