/** * 等距绘制排序(重设计) * * 单一全序标量,无成环、无特判互打: * frontKey = -(cellX + cellY) * CELL // 更小 x+y → 屏幕更靠下 → 更靠前 * + typeRank // 同对角条带内:地板 < 金币 < 载具 < 角色 < 墙 * * 移动中:当前格与下一格的排序值按位移进度插值,落地后再钉新格。 * 载具 rank 低于矮砖,墙砖仍更高所以能挡住载具。 * 贴墙南/西立面格上的实体:抬到该墙之上(露脚)。 * 角色按 frontKey 插入;漏到后面的矮砖补到角色下面,遇到该挡人的墙即停。 * 砖与砖进关后冻结,走路不改。 * 载具与矮砖仍按 frontKey,可被镜头方向的矮砖挡住。 * 角色永远盖过同条带载具。 */ 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_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; } /** 矮砖:仅 Baseblock / kuai11。不含 JumpBlock、墙砖 WallBlock。 */ export function isShortFloorTile(tileName: string): boolean { return tileName === CommonDefine.BlockBase || tileName === 'kuai11'; } 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; // 载具始终低于矮砖:墙 RANK_WALL 仍更高所以能挡住;移动中若用落点+载具 rank 会漏到矮砖上面 return RANK_FLOOR - 1; } /** 越大越靠前(后绘制) */ 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: Math.round(entity.cellX), y: Math.round(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(镜头方向的矮砖可以挡住载具)。 * 角色对矮砖(Baseblock / kuai11)永远在上;墙砖仍按 frontKey / 贴墙抬升。 */ export function compareUnityEntityToTile( entity: UnitySortableEntity, tile: UnitySortableTile, ): number { if (entity.isPlayer && isShortFloorTile(tile.tileName)) { return 1; } const lift = entityFaceLiftOverWall(entity, tile); const eKey = lift != null ? lift + 1 : entityDrawFrontKey(entity); return eKey - tileDrawFrontKey(tile); }