同步主站 Cocos 当前工程:关卡资源、运行脚本与打包工具。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
_decorator, Button, Component, director, find,
|
||||
Label, Node, Sprite, SpriteFrame, UITransform, view, AudioSource, Color, Layers,
|
||||
Label, Node, Sprite, SpriteFrame, UITransform, view, Color, Layers,
|
||||
tween, Tween, Vec3, Widget,
|
||||
} from 'cc';
|
||||
import { EventManager, EventType } from '../core/EventManager';
|
||||
@@ -9,7 +9,7 @@ import { ViewController } from '../controller/ViewController';
|
||||
import { LineGridRenderer } from '../gameplay/LineGridRenderer';
|
||||
import { Movement } from '../gameplay/Movement';
|
||||
import { GameAudio } from '../audio/GameAudio';
|
||||
import { loadThemeCharacterPortrait, loadUIIcon, UIIconKey } from './UIStyleAssets';
|
||||
import { loadThemeCharacterPortrait, loadUIIcon, loadDirectionIcon, UIIconKey } from './UIStyleAssets';
|
||||
import {
|
||||
getThemeHudIconScale, getThemePortraitFlipX, getThemePortraitScale,
|
||||
} from '../theme/ThemeRegistry';
|
||||
@@ -31,6 +31,12 @@ const UNITY_PAD_TOP = 20;
|
||||
const UNITY_PORTRAIT = 194;
|
||||
const UNITY_PAD_LEFT = 40;
|
||||
const UNITY_PAD_TOP_PORTRAIT = 28;
|
||||
/** Unity UIMain/ImageDirection:401×176,左下锚点,距边 31 */
|
||||
const UNITY_DIR_W = 401;
|
||||
const UNITY_DIR_H = 176;
|
||||
const UNITY_DIR_PAD = 31;
|
||||
/** 左下角 X/Y 罗盘:先隐藏,改好后再打开 */
|
||||
const SHOW_DIRECTION_GIZMO = false;
|
||||
const REF_WIDTH = 2560;
|
||||
|
||||
const scaleUi = (v: number) => v * (DESIGN_WIDTH / REF_WIDTH);
|
||||
@@ -42,6 +48,9 @@ const PAD_TOP = Math.round(scaleUi(UNITY_PAD_TOP));
|
||||
const PORTRAIT_SIZE = Math.round(scaleUi(UNITY_PORTRAIT));
|
||||
const PAD_LEFT = Math.round(scaleUi(UNITY_PAD_LEFT));
|
||||
const PAD_TOP_PORTRAIT = Math.round(scaleUi(UNITY_PAD_TOP_PORTRAIT));
|
||||
const DIR_W = Math.round(scaleUi(UNITY_DIR_W) * 2.5);
|
||||
const DIR_H = Math.round(scaleUi(UNITY_DIR_H) * 2.5);
|
||||
const PAD_DIR = Math.round(scaleUi(UNITY_DIR_PAD));
|
||||
|
||||
/** 点击时短暂放大再回弹 */
|
||||
const BTN_POP_SCALE = 1.14;
|
||||
@@ -68,6 +77,7 @@ export class UIMain extends Component {
|
||||
private nodePlaySpeed: IconSlot | null = null;
|
||||
private nodeAudio: IconSlot | null = null;
|
||||
private portraitSprite: Sprite | null = null;
|
||||
private directionSprite: Sprite | null = null;
|
||||
private textLabel: Label | null = null;
|
||||
private uiBuilt = false;
|
||||
private readonly buttons: BtnLayout[] = [];
|
||||
@@ -188,6 +198,7 @@ export class UIMain extends Component {
|
||||
|
||||
this.buildTextArea();
|
||||
this.buildThemePortrait();
|
||||
this.buildDirectionGizmo();
|
||||
this.node.setSiblingIndex(this.node.parent!.children.length - 1);
|
||||
this.layoutPanel();
|
||||
view.on('canvas-resize', this.layoutPanel, this);
|
||||
@@ -242,6 +253,78 @@ export class UIMain extends Component {
|
||||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||||
}
|
||||
|
||||
/** 对齐 Unity UIMain/ImageDirection:每关左下角等距 X/Y 罗盘 */
|
||||
private buildDirectionGizmo() {
|
||||
const overlay = this.node.parent;
|
||||
if (!overlay) return;
|
||||
|
||||
let root = overlay.getChildByName('ImageDirection');
|
||||
if (!SHOW_DIRECTION_GIZMO) {
|
||||
if (root?.isValid) root.active = false;
|
||||
this.directionSprite = null;
|
||||
return;
|
||||
}
|
||||
if (!root) {
|
||||
root = new Node('ImageDirection');
|
||||
root.parent = overlay;
|
||||
}
|
||||
root.layer = HUD_LAYER;
|
||||
root.active = true;
|
||||
|
||||
const ui = root.getComponent(UITransform) ?? root.addComponent(UITransform);
|
||||
ui.setAnchorPoint(0, 0);
|
||||
ui.setContentSize(DIR_W, DIR_H);
|
||||
|
||||
const sprite = root.getComponent(Sprite) ?? root.addComponent(Sprite);
|
||||
sprite.sizeMode = Sprite.SizeMode.CUSTOM;
|
||||
sprite.color = new Color(255, 255, 255, 255);
|
||||
this.directionSprite = sprite;
|
||||
|
||||
this.layoutDirectionGizmo();
|
||||
this.scheduleOnce(() => this.layoutDirectionGizmo(), 0);
|
||||
void this.refreshDirectionGizmo();
|
||||
}
|
||||
|
||||
private layoutDirectionGizmo() {
|
||||
const root = this.directionSprite?.node ?? this.node.parent?.getChildByName('ImageDirection');
|
||||
if (!root?.isValid) return;
|
||||
|
||||
const debugBar = this.node.parent?.getChildByName('GameplayDebugBar');
|
||||
const debugLift = debugBar?.active ? 64 : 0;
|
||||
|
||||
const widget = root.getComponent(Widget) ?? root.addComponent(Widget);
|
||||
widget.isAlignBottom = true;
|
||||
widget.isAlignLeft = true;
|
||||
widget.isAlignTop = false;
|
||||
widget.isAlignRight = false;
|
||||
widget.left = PAD_DIR;
|
||||
widget.bottom = PAD_DIR + debugLift;
|
||||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||||
widget.updateAlignment();
|
||||
}
|
||||
|
||||
private async refreshDirectionGizmo() {
|
||||
if (!this.directionSprite) return;
|
||||
const sf = await loadDirectionIcon();
|
||||
if (!sf || !this.directionSprite?.isValid) return;
|
||||
this.applyDirectionSprite(sf);
|
||||
}
|
||||
|
||||
private applyDirectionSprite(sf: SpriteFrame) {
|
||||
if (!this.directionSprite?.isValid) return;
|
||||
const root = this.directionSprite.node;
|
||||
const ui = root.getComponent(UITransform) ?? root.addComponent(UITransform);
|
||||
const { width: ow, height: oh } = spriteOriginalSize(sf);
|
||||
const scale = Math.min(DIR_W / Math.max(ow, 1), DIR_H / Math.max(oh, 1));
|
||||
const w = Math.max(1, Math.round(ow * scale));
|
||||
const h = Math.max(1, Math.round(oh * scale));
|
||||
ui.setAnchorPoint(0, 0);
|
||||
ui.setContentSize(w, h);
|
||||
this.directionSprite.spriteFrame = sf;
|
||||
this.directionSprite.sizeMode = Sprite.SizeMode.CUSTOM;
|
||||
this.layoutDirectionGizmo();
|
||||
}
|
||||
|
||||
private layoutPanel = () => {
|
||||
syncEmbeddedCamerasOrtho();
|
||||
this.syncOverlaySize();
|
||||
@@ -269,6 +352,7 @@ export class UIMain extends Component {
|
||||
const portrait = this.portraitSprite?.node.parent
|
||||
?? this.node.parent?.getChildByName('ImageBall');
|
||||
portrait?.getComponent(Widget)?.updateAlignment();
|
||||
this.layoutDirectionGizmo();
|
||||
};
|
||||
|
||||
private ensureIconButton(name: string, onClick: () => void): IconSlot {
|
||||
@@ -487,16 +571,12 @@ export class UIMain extends Component {
|
||||
}
|
||||
|
||||
private applyAudioVolume() {
|
||||
const vol = this.audioMute ? 0 : 1;
|
||||
const scene = director.getScene();
|
||||
if (!scene) return;
|
||||
for (const src of scene.getComponentsInChildren(AudioSource)) {
|
||||
src.volume = vol;
|
||||
}
|
||||
GameAudio.setMuted(this.audioMute);
|
||||
}
|
||||
|
||||
private onLevelInit = () => {
|
||||
this.setText('');
|
||||
this.applyAudioVolume();
|
||||
this.layoutDirectionGizmo();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,6 +71,13 @@ export function clearUIIconCache() {
|
||||
frameCache.clear();
|
||||
}
|
||||
|
||||
/** Unity UIMain/ImageDirection:等距 X/Y 罗盘(resources/textures/ui/ui-direction) */
|
||||
export async function loadDirectionIcon(): Promise<SpriteFrame | null> {
|
||||
const sf = await loadSpriteAt('textures/ui/ui-direction');
|
||||
if (!sf) console.warn('[UIStyleAssets] 方向罗盘贴图加载失败');
|
||||
return sf;
|
||||
}
|
||||
|
||||
/** 地图左上角角色肖像(优先 entities.portrait,否则 playerFront) */
|
||||
export async function loadThemeCharacterPortrait(
|
||||
options: EntityVisualOptions = {},
|
||||
|
||||
Reference in New Issue
Block a user