no message

This commit is contained in:
2026-07-06 09:43:46 +08:00
parent 4564ac5f47
commit ff1542c24f
22 changed files with 8771 additions and 309 deletions

View File

@@ -0,0 +1,182 @@
/**
* Unity 2D 绘制排序(对齐主站 GraphicsSettings + 预制体 SortingOrder + TilemapRenderer Individual
*
* - GraphicsSettings: TransparencySortMode=CustomAxis, axis=(0, 1, -0.26)
* - TilemapRenderer: SortingOrder=2, Mode=Individual, SortOrder=TopRight → 每格 -(cellX+cellY)
* - nProp=1, Tilemap/Vehicle=2, Prop=3, Player=4
* - 仅贴图 WallBlock 可遮挡实体;可行走砖永在实体之下
* - 砖↔砖:格子深度(南 y 小 → 前,同 y 东 x 大 → 前)→ JumpBlock 抬高 Y → Individual order
*/
import { Vec3 } from 'cc';
import { CommonDefine } from '../core/Define';
import { cellToWorldCenter } from '../core/GridCoords';
/** Unity GraphicsSettings.asset m_TransparencySortAxis */
export const UNITY_TRANSPARENCY_AXIS = { x: 0, y: 1, z: -0.26 } as const;
/** Unity SpriteRenderer / TilemapRenderer m_SortingOrder */
export const UNITY_SORTING_ORDER = {
nProp: 1,
tilemap: 2,
vehicle: 2,
prop: 3,
player: 4,
} as const;
const ORDER_SCALE = 10_000;
const DEPTH_SCALE = 100;
/** JumpBlock 行走面比 Baseblock 抬高的最小 Y 差px超过则优先比 depthY */
const TILE_ELEVATION_Y_THRESHOLD = 12;
export function isWallBlockTileName(tileName: string): boolean {
return tileName === CommonDefine.BlockWall;
}
export function isWalkableTileName(tileName: string): boolean {
return tileName === CommonDefine.BlockBase || tileName === CommonDefine.BlockJump;
}
/** Unity TilemapRenderer Individual + TopRightbaseOrder - (cellX+cellY) */
export function unityTileIndividualSortingOrder(cellX: number, cellY: number): number {
return UNITY_SORTING_ORDER.tilemap - cellX - cellY;
}
export function unityTransparencyDepth(worldX: number, worldY: number, worldZ = 0): number {
return worldX * UNITY_TRANSPARENCY_AXIS.x
+ worldY * UNITY_TRANSPARENCY_AXIS.y
+ worldZ * UNITY_TRANSPARENCY_AXIS.z;
}
export function unityCompositeSortKey(
sortingOrder: number,
depthWorldY: number,
depthWorldZ = 0,
bias = 0,
): number {
const depth = unityTransparencyDepth(0, depthWorldY, depthWorldZ);
return sortingOrder * ORDER_SCALE + depth * DEPTH_SCALE + bias;
}
export function unityCellCenterY(cellX: number, cellY: number): number {
return cellToWorldCenter(new Vec3(cellX, cellY, 0)).y;
}
export interface UnitySortableTile {
cellX: number;
cellY: number;
tileName: string;
centerY: number;
depthY: number;
}
export interface UnitySortableEntity {
sortingOrder: number;
cellX: number;
cellY: number;
centerY: number;
depthY: number;
isPlayer: boolean;
isPickable: boolean;
}
/** 返回值 > 0 表示 (ax,ay) 应排在 (bx,by) 之后(更靠前) */
export function compareIsoDrawOrder(ax: number, ay: number, bx: number, by: number): number {
const ka = ax + ay;
const kb = bx + by;
if (ka !== kb) return kb - ka;
return ax - bx;
}
function wallFaceSamples(wallX: number, wallY: number): { x: number; y: number }[] {
return [{ x: wallX, y: wallY - 1 }, { x: wallX - 1, y: wallY }];
}
function compareWallActorIso(
actor: { x: number; y: number },
wallX: number,
wallY: number,
): number {
let actorAhead = 0;
for (const face of wallFaceSamples(wallX, wallY)) {
const iso = compareIsoDrawOrder(actor.x, actor.y, face.x, face.y);
if (iso < 0) return iso;
if (iso > actorAhead) actorAhead = iso;
}
return actorAhead;
}
/** 返回值 > 0 实体更靠前;< 0 墙应挡住 */
function compareUnityEntityToWall(
entity: UnitySortableEntity,
tile: UnitySortableTile,
): number {
const cell = { x: entity.cellX, y: entity.cellY };
for (const face of wallFaceSamples(tile.cellX, tile.cellY)) {
if (face.x === cell.x && face.y === cell.y) return 1;
}
const tileOrder = unityTileIndividualSortingOrder(tile.cellX, tile.cellY);
if (tileOrder > entity.sortingOrder) return -1;
const wallIso = compareWallActorIso(cell, tile.cellX, tile.cellY);
if (wallIso < 0) {
if (tile.cellX === cell.x && tile.cellY === cell.y - 1) return -1;
if (tile.cellY < cell.y) return 1;
return -1;
}
const tileAhead = (tile.cellX + tile.cellY) - (cell.x + cell.y);
if (wallIso > 0 && tileAhead > 0) return -1;
if (wallIso > 0) return wallIso;
const yCmp = Math.round(entity.depthY * DEPTH_SCALE) - Math.round(tile.depthY * DEPTH_SCALE);
if (yCmp !== 0) return yCmp;
if (tileAhead !== 0) return -tileAhead;
return compareIsoDrawOrder(tile.cellX, tile.cellY, cell.x, cell.y);
}
/** 砖块格子深度南侧cellY 小更靠前同行西侧cellX 小)更靠前 */
export function compareTileCellDepth(ax: number, ay: number, bx: number, by: number): number {
if (ay !== by) return by - ay;
return bx - ax;
}
/**
* 砖↔砖格子深度优先下方砖挡上方砖JumpBlock 抬高再比 depthY。
*/
export function compareUnityTileToTile(a: UnitySortableTile, b: UnitySortableTile): number {
const cellCmp = compareTileCellDepth(a.cellX, a.cellY, b.cellX, b.cellY);
if (cellCmp !== 0) return cellCmp;
const yCmp = Math.round(a.depthY * DEPTH_SCALE) - Math.round(b.depthY * DEPTH_SCALE);
if (Math.abs(yCmp) >= TILE_ELEVATION_Y_THRESHOLD) return yCmp;
return unityTileIndividualSortingOrder(a.cellX, a.cellY)
- unityTileIndividualSortingOrder(b.cellX, b.cellY);
}
/**
* 实体 vs 砖块
* 非 WallBlock 永在实体之下;仅墙砖可遮挡。
*/
export function compareUnityEntityToTile(
entity: UnitySortableEntity,
tile: UnitySortableTile,
): number {
if (!isWallBlockTileName(tile.tileName)) {
return 1;
}
return compareUnityEntityToWall(entity, tile);
}
export function compareUnityEntityToEntity(a: UnitySortableEntity, b: UnitySortableEntity): number {
const keyA = unityCompositeSortKey(a.sortingOrder, a.depthY);
const keyB = unityCompositeSortKey(b.sortingOrder, b.depthY);
if (keyA !== keyB) return keyA - keyB;
const iso = (a.cellX + a.cellY) - (b.cellX + b.cellY);
if (iso !== 0) return iso;
if (a.isPlayer && !b.isPlayer) return 1;
if (b.isPlayer && !a.isPlayer) return -1;
return 0;
}