Files
cocos_zhuzhan/assets/scripts/level/UnityDrawSort.ts

193 lines
6.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 等距绘制排序(重设计)
*
* 单一全序标量,无成环、无特判互打:
* 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);
}