/** * 等距绘制排序(重设计) * * 单一全序标量,无成环、无特判互打: * frontKey = -(cellX + cellY) * CELL // 更小 x+y → 屏幕更靠下 → 更靠前 * + typeRank // 同对角条带内:地板 < 金币 < 载具 < 角色 < 墙 * * 移动中采样拆开: * - 角色:朝前落点 / 朝后起点 * - 载具:朝前起点(防浮到前砖上)/ 朝后落点(防途中比落点更靠前而不被下方砖挡) * 贴墙南/西立面格上的实体:抬到该墙之上(露脚)。 * 角色永远盖过同条带载具。 */ import { Vec3 } from 'cc'; import { CommonDefine } from '../core/Define'; import { cellToWorldCenter } from '../core/GridCoords'; export const UNITY_TRANSPARENCY_AXIS = { x: 0, y: 1, z: -0.26 } as const; export const UNITY_SORTING_ORDER = { nProp: 1, tilemap: 2, vehicle: 2, prop: 3, player: 4, } as const; const CELL = 100; /** 同对角条带内层级:地板 < 金币 < 载具 < 角色 < 墙立面 */ const RANK_FLOOR = 0; const RANK_PICKABLE = 20; const RANK_VEHICLE = 30; const RANK_PLAYER = 35; const RANK_WALL = 40; export function isWallBlockTileName(tileName: string): boolean { return tileName === CommonDefine.BlockWall; } export function isWalkableTileName(tileName: string): boolean { return tileName === CommonDefine.BlockBase || tileName === CommonDefine.BlockJump; } 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 * 10_000 + depth * 100 + 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; } export function compareTileCellDepth(ax: number, ay: number, bx: number, by: number): number { return compareIsoDrawOrder(ax, ay, bx, by); } function wallFaceSamples(wallX: number, wallY: number): { x: number; y: number }[] { return [{ x: wallX, y: wallY - 1 }, { x: wallX - 1, y: wallY }]; } function typeRankForTile(tileName: string): number { return isWallBlockTileName(tileName) ? RANK_WALL : RANK_FLOOR; } function typeRankForEntity(entity: UnitySortableEntity): number { if (entity.isPickable) return RANK_PICKABLE; if (entity.isPlayer) return RANK_PLAYER; return RANK_VEHICLE; } /** 越大越靠前(后绘制) */ export function isoDrawFrontKey(cellX: number, cellY: number, typeRank: number): number { return -(cellX + cellY) * CELL + typeRank; } export function tileDrawFrontKey(tile: UnitySortableTile): number { return isoDrawFrontKey(tile.cellX, tile.cellY, typeRankForTile(tile.tileName)); } export function entityDrawFrontKey(entity: UnitySortableEntity): number { return isoDrawFrontKey(entity.cellX, entity.cellY, typeRankForEntity(entity)); } /** * 若实体踩在某墙南/西立面上,应露在该墙前面。 * 返回需要超过的墙 frontKey,否则 null。 */ export function entityFaceLiftOverWall( entity: UnitySortableEntity, tile: UnitySortableTile, ): number | null { if (!isWallBlockTileName(tile.tileName)) return null; 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 tileDrawFrontKey(tile); } } return null; } /** 实体相对整张关卡的 frontKey(含贴墙抬升) */ export function entityDrawFrontKeyWithWalls( entity: UnitySortableEntity, walls: UnitySortableTile[], ): number { let key = entityDrawFrontKey(entity); for (const w of walls) { const lift = entityFaceLiftOverWall(entity, w); if (lift != null && key <= lift) key = lift + 1; } return key; } export function compareUnityTileToTile(a: UnitySortableTile, b: UnitySortableTile): number { const d = tileDrawFrontKey(a) - tileDrawFrontKey(b); if (d !== 0) return d; return a.cellX - b.cellX; } export function compareUnityEntityToEntity(a: UnitySortableEntity, b: UnitySortableEntity): number { const d = entityDrawFrontKey(a) - entityDrawFrontKey(b); if (d !== 0) return d; if (a.isPlayer && !b.isPlayer) return 1; if (b.isPlayer && !a.isPlayer) return -1; return a.sortingOrder - b.sortingOrder; } /** * 实体 vs 砖:统一用 frontKey。 * (保留函数供外部/测试调用;排序主路径用 build 里的 key) */ export function compareUnityEntityToTile( entity: UnitySortableEntity, tile: UnitySortableTile, ): number { if (!isWallBlockTileName(tile.tileName)) { // 地板永在实体下 return 1; } const lift = entityFaceLiftOverWall(entity, tile); const eKey = lift != null ? lift + 1 : entityDrawFrontKey(entity); return eKey - tileDrawFrontKey(tile); }