作者 | Kuber Mehta 編譯 | 蘇宓
出品 | CSDN(ID:CSDNnews)
自 1993 年問世以來,《DOOM》(毀滅戰(zhàn)士)早已超越了一款經(jīng)典射擊游戲的范疇,而是成為“極限移植”的代名詞。從烤面包機、MacBook Touch Bar、智能冰箱,到我們此前報道過的 、,它幾乎無處不在——“It Runs Doom”(萬物皆可跑 DOOM)也因此成為一代程序員的狂歡梗。
最近,這一狂歡再度升級:一位開發(fā)者竟然將一款可玩的《DOOM》風(fēng)格游戲完整封裝進一個二維碼中,掃碼即可在瀏覽器中直接啟動,無需下載,無需安裝。
整個開發(fā)僅耗時一周,旨在突破了二維碼在存儲和壓縮方面的極限,展示了將輕量級 Web 應(yīng)用完全托管于二維碼內(nèi)的全新可能。
而更令人驚訝的是——整個游戲大小還不到 3KB。
目前,此項目已在 GitHub 上開源:https://github.com/Kuberwastaken/backdooms。
值得注意的是,iPhone、Android 等智能手機無法直接掃描,其只適配于瀏覽器端,需要借助在線二維碼掃描器(https://scanqr.org/),掃描之后的游戲界面如下:
從荒誕構(gòu)想到技術(shù)落地
這個項目由開發(fā)者 Kuber Mehta 發(fā)起,挑戰(zhàn)是在不超過 3KB 的數(shù)據(jù)限制下,盡可能還原《DOOM》的游戲體驗。
為什么是 3KB?
Kuber Mehta 解釋說,這是二維碼所能容納的最大文本或二進制數(shù)據(jù)量。為了對比,原版《DOOM》中“機槍”(chaingun)貼圖就需要約 1.2KB,而這次項目的總?cè)萘款A(yù)算,僅為其兩倍多一點。時下,Kuber Mehta 要在這個限制內(nèi)完成整款游戲的邏輯與視覺呈現(xiàn),可謂是極限挑戰(zhàn)。
之所以會萌生這樣的想法,是由于幾年前Kuber Mehta 偶然刷到一位 YouTube 博主matttkc 發(fā)布的一條 YouTube 視頻,其曾提出一個瘋狂問題:“你能把一整個游戲塞進一個二維碼里嗎?”
這個設(shè)想從此深埋 Kuber Mehta 心底,但他一直沒付諸實踐——“因為我覺得自己可能不夠聰明。”Kuber Mehta 自嘲道。
直到不久前,這個想法再次浮現(xiàn),他決定不再猶豫,動手一試。可真正開始后,他很快發(fā)現(xiàn):網(wǎng)上幾乎找不到現(xiàn)成的 HTML 版本的 DOOM 實現(xiàn)可供復(fù)用。
資源有限的情況下,他退而求其次:“制作一個可玩的、受《Doom》啟發(fā)的游戲,其大小不超過三段純文本。”
正如他自己總結(jié)的:
“真的太難了,因為我的條件只有這些—— 沒有游戲引擎,只能寫原生 HTML/JS; 沒有素材資源,所有圖形都得代碼生成; 不能用任何庫,因為每個字節(jié)都彌足珍貴。 但也正因如此,我學(xué)到了太多。”
所以它其實并不是《Doom》本尊——但 Mehta 的游戲確實很有《Doom》的味道。除了從 1993 年原版射擊游戲中汲取靈感外,他還參考了迷因式的“迷離空間”恐怖故事 The Backrooms,于是他的項目被命名為“the backdooms”。
「這是不是一個愚蠢的決定?也許是。但結(jié)果酷不酷?毫無疑問——酷炸了!」,Kuber Mehta 說道。
極限代碼壓縮:每一個字節(jié)都算數(shù)
游戲是用 HTML 編寫的,Mehta 必須讓每個字符都物盡其用。
現(xiàn)實來看,要在二維碼的 2,953 字節(jié)容量(QR Code Version 40)內(nèi)嵌入一款游戲,他需要用到所謂的“壓縮技術(shù)”,更準(zhǔn)確說,是極限壓縮。
Kuber Mehta 以一段游戲代碼代碼為例,展示了他具體的做法:
html>
如果你沒看到 ,你可能都不敢相信這居然是 HTML。
再看一個例子,原始代碼:
function drawWall(distance) {
const height = 240 / distance;
context.fillRect(x, 120 - height/2, 1, height);
}
壓縮后:
h.fillRect(i,120-240/d/2,1,240/d)
其中變量名都被壓縮為單個字符,注釋也完全消失。“從最終的代碼看上去,有點像《Doom》里的惡魔挨了爆頭一樣令人震撼。”
地圖生成機制
在游戲設(shè)計方面,起初,Kuber Mehta 打算采用 16x16 或 8x8 的固定小地圖設(shè)計,這種尺寸在一個超小型游戲中本就算得上“合理”。但他并不滿足于此,更希望玩家能獲得“真正可玩”的體驗。
因此,他決定引入無限地圖生成,并輔以“種子(Seed)”機制。
這一做法與《Minecraft》中世界生成的思路類似:一個看似隨機的字符串,就能決定整個游戲世界的布局。
Kuber Mehta 利用了這一原理,讓玩家理論上可以通過特定種子值生成心儀的地圖,并在代碼中硬編碼,從而每次運行都得到一致的世界:
SEED = Math.random() * 100;
在圖形表現(xiàn)方面,Kuber Mehta 沒有采用 WebGL 或 Canvas 的高級圖形接口,而是回歸原點,用了《DOOM》早期版本(1992 年)使用的光線投射(Raycasting)技術(shù)。這種方法以極低的資源消耗,模擬出類似 3D 的視覺效果。
其實現(xiàn)方式是:對屏幕上每一列像素投出一條方向略有偏差的射線,并計算這條射線與墻體的交點距離。墻體越近,繪制的柱狀圖形就越高,最終呈現(xiàn)出縱深感。
簡版代碼如下:
for (let i = 0; i < 320; i++) {
const rayAngle = playerAngle + (i - 160) / 500;
let distance = 0;
while (!isWall(x + distance * cos(rayAngle), y + distance * sin(rayAngle))) {
distance += 0.1;
}
drawColumn(i, distance);
}
雖然這一邏輯只涉及基礎(chǔ)的三角函數(shù),但它在整個代碼體積中占據(jù)了相當(dāng)大的比重。Kuber Mehta 坦言,如果不是為了動態(tài)生成地圖,他可能早就選擇直接將 HTML 頁面 Base64 編碼后塞進 URL。但現(xiàn)在看來,這份堅持是值得的。
敵人機制
相比圖形渲染,敵人系統(tǒng)的實現(xiàn)則更加艱難。項目早期版本中,敵人數(shù)量固定,分布于地圖初始區(qū)域。玩家一旦走遠(yuǎn),地圖就變得空空如也——這在小地圖中還能接受,但在無限生成的大地圖中,問題立刻凸顯。
Kuber Mehta 回憶,這部分開發(fā)過程“非常頭痛”。在體積受限的前提下,想做出像樣的射擊反饋與敵人 AI,幾乎是不可能完成的任務(wù)。他也坦言自己并不是游戲開發(fā)出身:“我……確實不太會做游戲。”
起初,敵人是完全靜止的。后來,他陸續(xù)加入了簡單的追蹤機制,并最終實現(xiàn)了一個核心改進:玩家在移動時,系統(tǒng)會在其附近隨機生成敵人,從而讓整個地圖始終保持緊張感和挑戰(zhàn)性。
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表示,“制作游戲只是挑戰(zhàn)的一半,因為真正的挑戰(zhàn)是將其放入二維碼中。”
概念與可行性
標(biāo)準(zhǔn)最大的二維碼(Version 40)最多只能容納 2,953 字節(jié),也就是大約2.9KB。這個容量有多小?做個對比:
一個僅 1/15 秒的 Windows 音效文件,就已經(jīng)11KB
一張傳統(tǒng)軟盤(1.44MB)理論上可以存下將近 500 個這樣的二維碼
面對如此限制,Kuber Mehta 的首個版本大小達(dá)到了3.4KB,超標(biāo)嚴(yán)重。他的第一反應(yīng)是:“完蛋了。”
為了解決這個問題,他連續(xù)四天進行瘋狂壓縮與優(yōu)化,最終將游戲壓縮至2.4KB,雖然過程中做出了一些艱難但必要的取舍。
殊不知,一段折騰之后,更難的還在后面。
要知道二維碼只能存儲文本或二進制數(shù)據(jù),而 HTML 并不屬于這兩種類型。直接嵌入 HTML 代碼并不可行。
對此,不少開發(fā)者建議采用 Base64 編碼,但這帶來了33% 的體積開銷,幾乎會吃掉本就所剩無幾的存儲空間,意味著實際可用空間不到 1.9KB。
在反復(fù)嘗試后,Kuber Mehta 一度陷入絕望,甚至想要放棄。
后來,他連續(xù)兩天輪番咨詢 ChatGPT、DeepSeek 和 Claude 等 AI 模型,嘗試上百種提示詞,幾乎每次都得到建議:“干脆托管在網(wǎng)站上會更容易。”直到某次,ChatGPT隨口提到了一句:DecompressionStream。
這成了轉(zhuǎn)折點。
DecompressionStream 是一個現(xiàn)代瀏覽器支持的 Web API,能夠解壓 gzip 格式的數(shù)據(jù)流,簡而言之,相當(dāng)于瀏覽器內(nèi)置了“WinRAR”。
Kuber Mehta 形容自己當(dāng)時“仿佛被雷劈中”,豁然開朗。他確信:在嘗試了幾乎所有極限游戲優(yōu)化技巧后,這是當(dāng)前環(huán)境下唯一可行的解決方案。
整個游戲壓縮嵌入流程如下:
輸入 HTML 內(nèi)容
進行 Gzip 壓縮(最大壓縮等級)
將壓縮數(shù)據(jù)進行 Base64 編碼
嵌入一個自解壓的 HTML 包裝器
轉(zhuǎn)為 data:URI
嘗試生成二維碼(使用最高版本)
如果仍超出體積限制
→ 回頭繼續(xù)壓縮優(yōu)化
成功生成二維碼!
Kuber Mehta 為此還編寫了一個 Python 腳本自動化完成上述流程,期間測試了34 個不同版本,不斷調(diào)試壓縮策略,最終,二維碼成功誕生。
未來的可能性
受以上種種限制影響,the backdooms 的畫面非常有限,你只會在灰色墻壁之間躲避紅眼矩形,但它傳達(dá)的“感覺”是到位的。
在 Kuber Mehta 看來,這不僅是一個小游戲的誕生,更是一個技術(shù)可能性的證明。他將這個項目(現(xiàn)已開源在 GitHub,https://github.com/Kuberwastaken/backdooms)視為一種宣言:
只要壓縮得當(dāng),再加上 AI 助力,即便是在二維碼這種極限載體上,也能運行真正的交互式游戲。
盡管不適合開發(fā)復(fù)雜項目,但這個方向打開了許多令人興奮的應(yīng)用場景。Kuber Mehta 表示,這種想法也可以在未來應(yīng)用在更多場景中,如:
離線游戲傳播:可通過海報、傳單分享
極限編程展示(Demoscene):作為編程創(chuàng)意作品展示平臺
低帶寬環(huán)境下的教育小游戲:無需聯(lián)網(wǎng)即可運行,具備實用性與趣味性
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/
https://news.ycombinator.com/item?id=43729683
CSDN創(chuàng)始人蔣濤「對談」 浙大求是特聘教授方興東。作為中國互聯(lián)網(wǎng)30年的見證者,從鴻蒙操作系統(tǒng)的艱辛破曉之路,聊聊中國高科技的崛起大時代。華為數(shù)百人深度分享的技術(shù)傳奇《鴻蒙開物》來了!直播間抽福袋,領(lǐng)「限定簽章版」。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.