二维码也能跑游戏?开发者用3KB极限挑战复刻DOOM,曾一度崩溃后...ChatGPT救了场
创始人
2025-05-19 13:24:28
0

自 1993 年问世以来,《DOOM》(毁灭战士)早已超越了一款经典射击游戏的范畴,而是成为“极限移植”的代名词。从烤面包机、MacBook Touch Bar、智能冰箱,到我们此前报道过的、,它几乎无处不在——“It Runs Doom”(万物皆可跑 DOOM)也因此成为一代程序员的狂欢梗。

最近,这一狂欢再度升级:一位开发者竟然将一款可玩的《DOOM》风格游戏完整封装进一个二维码中,扫码即可在浏览器中直接启动,无需下载,无需安装。

整个开发仅耗时一周,旨在突破了二维码在存储和压缩方面的极限,展示了将轻量级 Web 应用完全托管于二维码内的全新可能。

而更令人惊讶的是——整个游戏大小还不到 3KB。

目前,此项目已在 GitHub 上开源:https://github.com/Kuberwastaken/backdooms。二维码如下:

值得注意的是,iPhone、Android 等智能手机无法直接扫描,其只适配于浏览器端,需要借助在线二维码扫描器(https://scanqr.org/),扫描之后的游戏界面如下:

从荒诞构想到技术落地

这个项目由开发者Kuber Mehta 发起,挑战是在不超过 3KB 的数据限制下,尽可能还原《DOOM》的游戏体验。

为什么是 3KB?

Kuber Mehta 解释说,这是二维码所能容纳的最大文本或二进制数据量。为了对比,原版《DOOM》中“机枪”(chaingun)贴图就需要约 1.2KB,而这次项目的总容量预算,仅为其两倍多一点。时下,Kuber Mehta 要在这个限制内完成整款游戏的逻辑与视觉呈现,可谓是极限挑战。

之所以会萌生这样的想法,是由于几年前Kuber Mehta 偶然刷到一位 YouTube 博主 matttkc 发布的一条 YouTube 视频,其曾提出一个疯狂问题:“你能把一整个游戏塞进一个二维码里吗?”

这个设想从此深埋Kuber Mehta 心底,但他一直没付诸实践——“因为我觉得自己可能不够聪明。”Kuber Mehta 自嘲道。

直到不久前,这个想法再次浮现,他决定不再犹豫,动手一试。可真正开始后,他很快发现:网上几乎找不到现成的 HTML 版本的 DOOM 实现可供复用。

资源有限的情况下,他退而求其次:“制作一个可玩的、受《Doom》启发的游戏,其大小不超过三段纯文本。”

正如他自己总结的:

“真的太难了,因为我的条件只有这些——

没有游戏引擎,只能写原生 HTML/JS;

没有素材资源,所有图形都得代码生成;

不能用任何库,因为每个字节都弥足珍贵。

但也正因如此,我学到了太多。”

所以它其实并不是《Doom》本尊——但 Mehta 的游戏确实很有《Doom》的味道。除了从 1993 年原版射击游戏中汲取灵感外,他还参考了迷因式的“迷离空间”恐怖故事 The Backrooms,于是他的项目被命名为“the backdooms”。

「这是不是一个愚蠢的决定?也许是。但结果酷不酷?毫无疑问——酷炸了!」,Kuber Mehta 说道。

极限代码压缩:每一个字节都算数

游戏是用 HTML 编写的,Mehta 必须让每个字符都物尽其用。

现实来看,要在二维码的 2,953 字节容量(QR Code Version 40)内嵌入一款游戏,他需要用到所谓的“压缩技术”,更准确说,是极限压缩

Kuber Mehta 以一段游戏代码代码为例,展示了他具体的做法:

html><html><head><metacharset="utf-8"><style>body{ margin: 0; overflow:hidden; background: #000; cursor:crosshair} canvas{ width: 100vw; height: 100vh} style>head><body><canvasid=c>canvas><> M= Math,c= document. getElementById( "c"),c. width= 320,c. height= 240,h=c. getContext( "2d"),x= 4,y= 4,a= 0,H= 100,am= 25,rc= 0,fl= 0; f= (i,j)=>( Math. abs(i- 4)< 4&& Math. abs(j- 4)< 4)? "0":((((i+ 1000)% 7)== 3||((j+ 1000)% 7)== 3)? "0":( Math. random< .05? "1": "0")); e=[{ x: 5, y: 4, h: 100},{ x: 4, y: 5, h: 100}],k={};onkeydown= e=>k[e. key]= 1;onkeyup= e=>k[e. key]= 0; onclick= _=>{ if(am){am--;fl= 2;rc= .2;e. forEach( o=>{d=M. hypot(o. x-x,o. y-y),r=M. atan2(o. y-y,o. x-x); if(d< 5&& Math. abs(r-a)< .3)o. h-= 50})}}; R= _=>{ rc= Math. max( 0,rc- .02);fl= Math. max( 0,fl- 1);e=e. filter( o=>o. h> 0); h. fillStyle= "#000";h. fillRect( 0, 0, 320, 240); k. ArrowLeft&&(a-= .1);k. ArrowRight&&(a+= .1);m= .1;

如果你没看到 ,你可能都不敢相信这居然是 HTML。

再看一个例子,原始代码:

functiondrawWall( distance) { constheight = 240/ distance; context. fillRect(x, 120- height/ 2, 1, height); }

压缩后:

h.fillRect(i, 120- 240/d/ 2, 1, 240/d)

其中变量名都被压缩为单个字符,注释也完全消失。“从最终的代码看上去,有点像《Doom》里的恶魔挨了爆头一样令人震撼。”

地图生成机制

在游戏设计方面,起初,Kuber Mehta 打算采用 16x16 或 8x8 的固定小地图设计,这种尺寸在一个超小型游戏中本就算得上“合理”。但他并不满足于此,更希望玩家能获得“真正可玩”的体验。

因此,他决定引入无限地图生成,并辅以“种子(Seed)”机制。

这一做法与《Minecraft》中世界生成的思路类似:一个看似随机的字符串,就能决定整个游戏世界的布局。

Kuber Mehta 利用了这一原理,让玩家理论上可以通过特定种子值生成心仪的地图,并在代码中硬编码,从而每次运行都得到一致的世界:

SEED= Math.random * 100;

在图形表现方面,Kuber Mehta 没有采用 WebGL 或 Canvas 的高级图形接口,而是回归原点,用了《DOOM》早期版本(1992 年)使用的光线投射(Raycasting)技术。这种方法以极低的资源消耗,模拟出类似 3D 的视觉效果。

其实现方式是:对屏幕上每一列像素投出一条方向略有偏差的射线,并计算这条射线与墙体的交点距离。墙体越近,绘制的柱状图形就越高,最终呈现出纵深感。

简版代码如下:

for( leti = 0; i < 320; i++) { constrayAngle = playerAngle + (i - 160) / 500; letdistance = 0; while(! isWall(x + distance * cos(rayAngle), y + distance * sin(rayAngle))) { distance += 0.1; } drawColumn(i, distance); }

虽然这一逻辑只涉及基础的三角函数,但它在整个代码体积中占据了相当大的比重。Kuber Mehta 坦言,如果不是为了动态生成地图,他可能早就选择直接将 HTML 页面 Base64 编码后塞进 URL。但现在看来,这份坚持是值得的。

敌人机制

相比图形渲染,敌人系统的实现则更加艰难。项目早期版本中,敌人数量固定,分布于地图初始区域。玩家一旦走远,地图就变得空空如也——这在小地图中还能接受,但在无限生成的大地图中,问题立刻凸显。

Kuber Mehta 回忆,这部分开发过程“非常头痛”。在体积受限的前提下,想做出像样的射击反馈与敌人 AI,几乎是不可能完成的任务。他也坦言自己并不是游戏开发出身:“我……确实不太会做游戏。”

起初,敌人是完全静止的。后来,他陆续加入了简单的追踪机制,并最终实现了一个核心改进:玩家在移动时,系统会在其附近随机生成敌人,从而让整个地图始终保持紧张感和挑战性。

if((k. ArrowUp|| k. w|| k. ArrowDown|| k. s|| k. ArrowLeft|| k. ArrowRight) && e. length< 10&& Math. random< .01) { t = Math. random* 6.283; Rdist= 1+ Math. random; X = x + M(t) * Rdist; Y = y + N(t) * Rdist; f(~~X, ~~Y) == "0"&& e. push({ x: X, y: Y, h: 100}); }

完成以上版块之后,Kuber Mehta表示,“制作游戏只是挑战的一半,因为真正的挑战是将其放入二维码中。”

概念与可行性

标准最大的二维码(Version 40)最多只能容纳 2,953 字节,也就是大约2.9KB。这个容量有多小?做个对比:

  • 一个仅 1/15 秒的 Windows 音效文件,就已经 11KB

  • 一张传统软盘(1.44MB)理论上可以存下将近 500 个这样的二维码

面对如此限制,Kuber Mehta 的首个版本大小达到了3.4KB,超标严重。他的第一反应是:“完蛋了。”

为了解决这个问题,他连续四天进行疯狂压缩与优化,最终将游戏压缩至2.4KB,虽然过程中做出了一些艰难但必要的取舍。

殊不知,一段折腾之后,更难的还在后面。

要知道二维码只能存储文本或二进制数据,而 HTML 并不属于这两种类型。直接嵌入 HTML 代码并不可行。

对此,不少开发者建议采用 Base64 编码,但这带来了33% 的体积开销,几乎会吃掉本就所剩无几的存储空间,意味着实际可用空间不到 1.9KB。

在反复尝试后,Kuber Mehta 一度陷入绝望,甚至想要放弃。

后来,他连续两天轮番咨询 ChatGPT、DeepSeek 和 Claude 等 AI 模型,尝试上百种提示词,几乎每次都得到建议:“干脆托管在网站上会更容易。”直到某次,ChatGPT随口提到了一句DecompressionStream

这成了转折点。

DecompressionStream是一个现代浏览器支持的 Web API,能够解压 gzip 格式的数据流,简而言之,相当于浏览器内置了“WinRAR”。

Kuber Mehta 形容自己当时“仿佛被雷劈中”,豁然开朗。他确信:在尝试了几乎所有极限游戏优化技巧后,这是当前环境下唯一可行的解决方案

整个游戏压缩嵌入流程如下:

  1. 输入 HTML 内容

  2. 进行 Gzip 压缩(最大压缩等级)

  3. 将压缩数据进行 Base64 编码

  4. 嵌入一个自解压的 HTML 包装器

  5. 转为 data:URI

  6. 尝试生成二维码(使用最高版本)

  7. 如果仍超出体积限制

    → 回头继续压缩优化

  8. 成功生成二维码!

Kuber Mehta 为此还编写了一个 Python 脚本自动化完成上述流程,期间测试了34 个不同版本,不断调试压缩策略,最终,二维码成功诞生。

未来的可能性

受以上种种限制影响,the backdooms的画面非常有限,你只会在灰色墙壁之间躲避红眼矩形,但它传达的“感觉”是到位的。

在 Kuber Mehta 看来,这不仅是一个小游戏的诞生,更是一个技术可能性的证明。他将这个项目(现已开源在 GitHub,https://github.com/Kuberwastaken/backdooms)视为一种宣言:

只要压缩得当,再加上 AI 助力,即便是在二维码这种极限载体上,也能运行真正的交互式游戏。

尽管不适合开发复杂项目,但这个方向打开了许多令人兴奋的应用场景。Kuber Mehta 表示,这种想法也可以在未来应用在更多场景中,如:

  • 离线游戏传播:可通过海报、传单分享

  • 极限编程展示(Demoscene):作为编程创意作品展示平台

  • 低带宽环境下的教育小游戏:无需联网即可运行,具备实用性与趣味性

来源:

https://github.com/Kuberwastaken/backdooms?tab=readme-ov-file

https://kuber.studio/blog/Projects/How-I-Managed-To-Get-Doom-In-A-QR-Code

https://www.pcgamer.com/hardware/behold-a-single-qr-code-containing-a-miniaturized-take-on-doom-literally-the-entire-game/

相关内容

热门资讯

一分钟介绍使用“金花房卡购买联... 微信游戏中心:怎么制作链接,打开微信,添加客服【44346008】,进入游戏中心或相关小程序,搜索“...
一分钟了解“金花链接房卡找谁买... 微信游戏中心:在哪充值,打开微信,添加客服【35100608】,进入游戏中心或相关小程序,搜索“微信...
一分钟介绍使用“微信好友一起玩... 微信游戏中心:货源渠道怎么找,打开微信,添加客服【86909166】,进入游戏中心或相关小程序,搜索...
一分钟介绍推荐“微信金花群怎么... 微信游戏中心:专卖店,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信炸...
重大通报“炸金花房卡链接建立步... 微信游戏中心:去哪买房卡,打开微信,添加客服【160470940】,进入游戏中心或相关小程序,搜索“...
一分钟介绍使用“微信上的斗牛怎... 微信游戏中心:房卡怎么获取,打开微信,添加客服【44346008】,进入游戏中心或相关小程序,搜索“...
秒懂百科“微信上金花房卡怎么来... 微信游戏中心:游戏制作链接,打开微信,添加客服【86909166】,进入游戏中心或相关小程序,搜索“...
全网内容“微信好友群玩炸金花链... 微信游戏中心:怎么买房间卡,打开微信,添加客服【86909166】,进入游戏中心或相关小程序,搜索“...
游戏指南“微信群金花房卡哪里可... 微信游戏中心:批发平台官网,打开微信,添加客服【44346008】,进入游戏中心或相关小程序,搜索“...
今日推荐“微信群平台金花游戏链... 微信游戏中心:批发平台,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信...
带你快速了解“正版金花房卡哪里... 微信游戏中心:批发市场,打开微信,添加客服【86909166】,进入游戏中心或相关小程序,搜索“微信...
一分钟介绍使用“微信斗牛牛房卡... 微信游戏中心:一张多少钱,打开微信,添加客服【160470940】,进入游戏中心或相关小程序,搜索“...
一分钟实测分享“微信拼三张金花... 微信游戏中心:代理,打开微信,添加客服【44346008】,进入游戏中心或相关小程序,搜索“微信炸金...
分享教程“微信金花房卡哪里买的... 微信游戏中心:平台充值,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信...
房卡必备教程“微信金花房卡招代... 微信游戏中心:房卡出售,打开微信,添加客服【35100608】,进入游戏中心或相关小程序,搜索“微信...
今日头条“微信金花房卡招代理”... 微信游戏中心:价格表,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信炸...
房卡全攻略“玩链接牛牛金花房卡... 微信游戏中心:代理出售,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信...
一分钟实测分享“金花链接房卡怎... 微信游戏中心:哪里来的,打开微信,添加客服【35100608】,进入游戏中心或相关小程序,搜索“微信...
游戏指南“炸金花房卡在哪有怎么... 微信游戏中心:哪里有卖,打开微信,添加客服【86909166】,进入游戏中心或相关小程序,搜索“微信...
秒懂教程“有没有玩金花房房卡购... 微信游戏中心:如何购买,打开微信,添加客服【15984933】,进入游戏中心或相关小程序,搜索“微信...