You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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坐标越大,层级越高(等距视角中,位置越靠下的物体应在上方显示),直接基于此实现即可:

  1. 单实体实时更新层级
    修改MovementSystem的update方法,在设置元素left和top后,加入z-index计算:

    // 原有设置left、top的代码之后
    // 计算实体底部Y坐标(若为中心定位需调整计算逻辑)
    const bottomY = entity.y + entity.rectHeight;
    // 设置z-index,数值越大层级越高
    entity.htmlElement!.style.zIndex = bottomY.toString();
    
  2. 批量重排优化
    若实体数量较多,单实体更新效率低,可在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:35:22