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:
157
assets/scripts/visual/EntityDisplayRefs.ts
Normal file
157
assets/scripts/visual/EntityDisplayRefs.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { Size, SpriteFrame } from 'cc';
|
||||
import { CELL_PIXEL } from '../core/GridConstants';
|
||||
import { getThemeEntityDisplayCellBoxes } from '../theme/ThemeDatabase';
|
||||
|
||||
/** 内置默认(themes-database 未加载时使用) */
|
||||
export const DEFAULT_ENTITY_CELL_BOX = {
|
||||
player: { w: 0.68, h: 0.9 },
|
||||
vehicle: { w: 0.96, h: 0.88 },
|
||||
prop: { w: 0.52, h: 0.69 },
|
||||
propGround: { w: 0.52, h: 0.69 },
|
||||
} as const;
|
||||
|
||||
/** 装饰物相对可拾取物的缩放比 */
|
||||
const PROP_DECOR_RATIO = 0.45 / 0.69;
|
||||
|
||||
const cellW = (ratio: number) => CELL_PIXEL * ratio;
|
||||
const cellH = (ratio: number) => CELL_PIXEL * ratio;
|
||||
|
||||
export function getEntityCellBox(theme?: string) {
|
||||
if (theme) return getThemeEntityDisplayCellBoxes(theme);
|
||||
return { ...DEFAULT_ENTITY_CELL_BOX };
|
||||
}
|
||||
|
||||
export const DEFAULT_PLAYER_ANCHOR_Y = 0.35;
|
||||
/** Unity silu ship pivot y = 0.45 */
|
||||
export const DEFAULT_VEHICLE_ANCHOR_Y = 0.45;
|
||||
|
||||
export function getEntityDisplaySizes(theme?: string) {
|
||||
const box = getEntityCellBox(theme);
|
||||
return {
|
||||
player: {
|
||||
width: cellW(box.player.w),
|
||||
height: cellH(box.player.h),
|
||||
},
|
||||
vehicle: {
|
||||
width: cellW(box.vehicle.w),
|
||||
height: cellH(box.vehicle.h),
|
||||
},
|
||||
prop: {
|
||||
width: cellW(box.prop.w),
|
||||
height: cellH(box.prop.h),
|
||||
},
|
||||
propGround: {
|
||||
width: cellW(box.propGround.w),
|
||||
height: cellH(box.propGround.h),
|
||||
},
|
||||
prop_decor: {
|
||||
width: cellW(box.prop.w) * PROP_DECOR_RATIO,
|
||||
height: cellH(box.prop.h) * PROP_DECOR_RATIO,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** @deprecated 使用 getEntityDisplaySizes(theme) */
|
||||
export const ENTITY_CELL_BOX = DEFAULT_ENTITY_CELL_BOX;
|
||||
|
||||
/** @deprecated 使用 getEntityDisplaySizes(theme) */
|
||||
export const SANXING_ENTITY_DISPLAY = {
|
||||
get player() { return getEntityDisplaySizes().player; },
|
||||
get vehicle() { return getEntityDisplaySizes().vehicle; },
|
||||
get prop() { return getEntityDisplaySizes().prop; },
|
||||
get prop_decor() { return getEntityDisplaySizes().prop_decor; },
|
||||
};
|
||||
|
||||
export type EntityDisplayKind = 'player' | 'vehicle' | 'prop' | 'propGround' | 'prop_decor';
|
||||
|
||||
type SpawnKindLike = 'player' | 'vehicle' | 'prop' | 'prop_decor';
|
||||
|
||||
export function entityPlaceholderSize(kind: SpawnKindLike, theme?: string): { width: number; height: number } {
|
||||
const sizes = getEntityDisplaySizes(theme);
|
||||
if (kind === 'prop_decor') return sizes.prop_decor;
|
||||
if (kind === 'prop') return sizes.prop;
|
||||
if (kind === 'vehicle') return sizes.vehicle;
|
||||
return sizes.player;
|
||||
}
|
||||
|
||||
export function spriteOriginalSize(sf: SpriteFrame): { width: number; height: number } {
|
||||
const rect = sf.rect;
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
return { width: rect.width, height: rect.height };
|
||||
}
|
||||
let w = sf.originalSize?.width ?? 0;
|
||||
let h = sf.originalSize?.height ?? 0;
|
||||
if (w <= 0 || h <= 0) {
|
||||
w = sf.texture?.width ?? 1;
|
||||
h = sf.texture?.height ?? 1;
|
||||
}
|
||||
return { width: Math.max(1, w), height: Math.max(1, h) };
|
||||
}
|
||||
|
||||
/** 等比缩放,完整落入主题包围盒(contain) */
|
||||
export function fitEntityDisplaySize(
|
||||
kind: EntityDisplayKind,
|
||||
sf: SpriteFrame,
|
||||
scaleMul = 1,
|
||||
theme?: string,
|
||||
): { width: number; height: number; anchorX: number; anchorY: number } {
|
||||
const s = computeEntityUniformScale(kind, sf, scaleMul, theme);
|
||||
return sizeFromUniformScale(sf, s, kind, theme);
|
||||
}
|
||||
|
||||
/** 单帧 contain 缩放系数(序列动画各帧共用,避免画布尺寸不同导致比例跳变) */
|
||||
export function computeEntityUniformScale(
|
||||
kind: EntityDisplayKind,
|
||||
sf: SpriteFrame,
|
||||
scaleMul = 1,
|
||||
theme?: string,
|
||||
): number {
|
||||
const mul = Math.max(0.1, Math.min(4, scaleMul));
|
||||
const { width: ow, height: oh } = spriteOriginalSize(sf);
|
||||
const ref = getEntityDisplaySizes(theme)[kind];
|
||||
return Math.min(ref.width * mul / ow, ref.height * mul / oh);
|
||||
}
|
||||
|
||||
export function sizeFromUniformScale(
|
||||
sf: SpriteFrame,
|
||||
uniformScale: number,
|
||||
kind: EntityDisplayKind = 'player',
|
||||
theme?: string,
|
||||
): { width: number; height: number; anchorX: number; anchorY: number } {
|
||||
const { width: ow, height: oh } = spriteOriginalSize(sf);
|
||||
let anchorY = 0;
|
||||
if (kind === 'player') {
|
||||
anchorY = DEFAULT_PLAYER_ANCHOR_Y;
|
||||
} else if (kind === 'vehicle') {
|
||||
anchorY = DEFAULT_VEHICLE_ANCHOR_Y;
|
||||
} else if (kind !== 'prop' && kind !== 'propGround' && kind !== 'prop_decor') {
|
||||
anchorY = DEFAULT_PLAYER_ANCHOR_Y;
|
||||
}
|
||||
return {
|
||||
width: ow * uniformScale,
|
||||
height: oh * uniformScale,
|
||||
anchorX: 0.5,
|
||||
anchorY,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列帧脚点对齐:各帧保留原始比例,仅调 anchorY。
|
||||
* 脚离画布底边像素一致时:anchorY = baseAnchorY * refOh / oh
|
||||
*/
|
||||
export function playerSeqFrameAnchorY(
|
||||
sf: SpriteFrame,
|
||||
refSf: SpriteFrame,
|
||||
baseAnchorY = DEFAULT_PLAYER_ANCHOR_Y,
|
||||
): number {
|
||||
const oh = Math.max(1, spriteOriginalSize(sf).height);
|
||||
const refOh = Math.max(1, spriteOriginalSize(refSf).height);
|
||||
if (oh === refOh) return baseAnchorY;
|
||||
return baseAnchorY * refOh / oh;
|
||||
}
|
||||
|
||||
/** 动态 SpriteFrame 补全 originalSize(ImageAsset 直载时 Cocos 默认为 0) */
|
||||
export function ensureSpriteFrameSize(sf: SpriteFrame, width: number, height: number) {
|
||||
if (sf.originalSize.width > 0 && sf.originalSize.height > 0) return;
|
||||
sf.originalSize = new Size(Math.max(1, width), Math.max(1, height));
|
||||
}
|
||||
Reference in New Issue
Block a user