# 纯 CSS 实现 Doom:无需 Canvas 或 WebGL 即可渲染
开发者 Niels Lehner 发布了项目 cssDoom——这是一个经典游戏 Doom 的完整实现,所有图形均仅使用 CSS 渲染。游戏逻辑使用 JavaScript 实现,不依赖 canvas 或 WebGL。它基于 id Software 的原始 Doom 源代码,以 WAD 文件形式提供。该项目托管在 GitHub 上,采用 GPLv2 许可。
所有视觉元素——精灵、纹理墙壁、关卡、效果——均由 div 元素构成。它们使用 CSS 属性 transform 和 transform-style: preserve-3d 在 3D 空间中定位。JavaScript 不直接干预样式:相反,它根据 WAD 文件中的顶点几何数据设置自定义 CSS 属性。CSS 则独立使用三角函数计算宽度、高度及变换。
坐标适配与游戏循环
Doom 的坐标系统与 CSS 3D 不同:Doom 使用 2D 系统,其中 Y 轴向北递增,而 CSS 中 Y 轴向上,Z 轴朝向观察者。变换通过 translate3d(x, -z, -y) 实现。自定义属性以 Doom 坐标定义,由 CSS 解释。
JavaScript 中的游戏循环跟踪玩家的位置、输入、碰撞和敌人 AI。这是原代码的直接移植。分离严格:JS 仅更新如 --player-x、--player-y、--player-z、--player-angle 等关键属性。CSS 相对于玩家移动整个世界,模拟相机(CSS 无内置相机)。移动和视角仅需更新这四个属性。
支持第一人称视角,并可切换至地图概览。
场景构建的技术细节
过程从解析 WAD 文件开始:提取线定义、面定义和扇区参数。从中生成 div 元素,保留原始顶点几何。CSS 使用 calc() 进行计算:
- 元素宽度和高度由视野角度及距离决定。
- 变换考虑透视效果。
简化后的自定义属性结构示例:
:root {
--player-x: 0;
--player-y: 0;
--player-angle: 0;
}
.scene-element {
width: calc(var(--doom-width) * var(--perspective-factor));
height: calc(var(--doom-height) * var(--perspective-factor));
transform: translate3d(
calc(var(--doom-x)),
calc(-var(--doom-z)),
calc(-var(--doom-y))
) rotateY(var(--player-angle));
}
这种方法确保高性能:浏览器的 CSS 渲染器会在 GPU 上优化 3D 变换。
与其他实验的比较
cssDoom 延续了非传统 Doom 移植的传统。此前,Adam Rice 开发了 Doom Over DNS:游戏通过 Cloudflare DNS TXT 记录运行。WAD 文件压缩成约 1964 个记录,由 PowerShell 脚本实时解压。.NET DLL 加载到内存中而不写入磁盘。这展示了协议极限,但在视觉复杂度上不及 cssDoom。
| 方面 | cssDoom | Doom Over DNS |
|--------------|----------------------|---------------------|
| 渲染 | CSS 3D div | 标准(浏览器) |
| 逻辑 | JS(Doom 移植) | PowerShell + .NET |
| 依赖 | 仅 CSS/JS | DNS 查询 |
| 访问方式 | GitHub | 公共 Cloudflare 区域|
要点
- 纯 CSS 实现完整 Doom 渲染:3D 空间中的 div 模拟光线投射。
- 自定义属性 + calc() 根据 WAD 数据实现动态变换。
- JS(逻辑)与 CSS(视觉)的严格分离以优化性能。
- 通过轴反转将 Doom 坐标适配至 CSS 3D。
- 在 GitHub 上开源,GPLv2 许可。
该项目有助于研究 CSS3 在游戏开发中的极限,特别是实时场景下的 transform 动画和自定义属性。
— Editorial Team
暂无评论。