如何用CSS/HTML定位等距游戏实体并实现Z轴层级排序?
问题描述
我正在开发一款等距游戏大世界,当前已基于Entity-Component-System(ECS)模式实现仅支持XY坐标的移动系统(代码如下):
import type World from '../World'; export default class MovementSystem { constructor(private world: World) { } update() { for (let entity of this.world.entities) { let mv = entity.movable; if (mv != null && (mv.dx != 0 || mv.dy != 0) && entity.htmlElement != null) { entity.x += mv.dx; entity.y += mv.dy; let cancelledDX = false, cancelledDY = false; let rect = entity.rectangle; for (let entity2 of this.world.entities) { if (entity == entity2) continue; let rect2 = entity.rectangle; if (!cancelledDX && rect.horizontalHitTest(rect2)) { cancelledDX = true; entity.x -= mv.dx; } if (!cancelledDY && rect.verticalHitTest(rect2)) { cancelledDY = true; entity.y -= mv.dy; } } entity.htmlElement!.style.left = entity.x + 'px'; entity.htmlElement!.style.top = entity.y + 'px'; } } } }
现有系统仅实现XY坐标,我需要添加Z轴定位功能,游戏大世界有专门的<div/>容器(Scene类中overworldContainer属性)存放实体HTML元素,考虑使用CSS的z-index属性调整实体层级。实体定义如下:
export default class Entity { htmlElement: HTMLElement | null = null; x: number = 0; y: number = 0; rectWidth: number = 0; rectHeight: number = 0; constructor() { } get rectangle(): Rectangle { return new Rectangle(this.x, this.y, this.rectWidth, this.rectHeight); } get movable(): Movable | null { return null; } set movable(v) { } } export class Character extends Entity { private m_movable: Movable | null = new Movable(0, 0); constructor() { super(); } override get movable(): Movable | null { return this.m_movable; } override set movable(v) { this.m_movable = v; } }
请问是否有简便的实体重排方法,或是可借助的NPM工具来实现实体移动时的层级调整?
解决方案
一、自定义实体重排方法(无需依赖NPM包)
等距游戏的层级逻辑核心是实体的底部Y坐标越大,层级越高(等距视角中,位置越靠下的物体应在上方显示),直接基于此实现即可:
单实体实时更新层级
修改MovementSystem的update方法,在设置元素left和top后,加入z-index计算:// 原有设置left、top的代码之后 // 计算实体底部Y坐标(若为中心定位需调整计算逻辑) const bottomY = entity.y + entity.rectHeight; // 设置z-index,数值越大层级越高 entity.htmlElement!.style.zIndex = bottomY.toString();批量重排优化
若实体数量较多,单实体更新效率低,可在update末尾统一排序重排:update() { // ...原有移动逻辑代码 // 按实体底部Y坐标升序排序 this.world.entities.sort((a, b) => { const aBottom = a.y + a.rectHeight; const bBottom = b.y + b.rectHeight; return aBottom - bBottom; }); // 重新插入实体到容器,利用DOM插入顺序决定层级(后插入的元素层级更高) const container = this.world.scene.overworldContainer; this.world.entities.forEach(entity => { if (entity.htmlElement) { container.appendChild(entity.htmlElement); } }); }这种方式无需依赖z-index,利用DOM原生层级特性,性能更稳定。
二、可选NPM工具
如果不想自定义实现,可选择轻量工具:
z-index-manager:专门管理DOM元素z-index,支持自动排序、层级分组,适合复杂层级场景。dom-sort:基于自定义规则对DOM元素排序,可直接传入实体Y坐标作为排序依据。
不过对于等距游戏的基础层级需求,自定义实现足够简单高效,无需额外引入依赖。
内容的提问来源于stack exchange,提问作者Hydroper
相关产品推荐
相关产品推荐

