7天3kB:在自定义字节码VM上制作游戏

Lobsters Hottest 新闻

摘要

作者详细介绍了在Langjam Gamejam中,用7天时间在自定义字节码VM上制作一款射击游戏,最终生成一个3kB的Windows可执行文件,并带有全屏像素着色器。

<p><a href="https://lobste.rs/s/he9kpd/making_game_on_custom_bytecode_vm_7_days">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/12 08:32

# 在自定义字节码 VM 上用 7 天和 3kB 制作一款游戏 来源:https://laurent.le-brun.eu/blog/making-a-game-on-a-custom-bytecode-vm-in-7-days-and-3kb 在过去的几天里,我制作了一款射击游戏(shoot ’em up),通过嵌入一个微型自定义字节码虚拟机,并使用全屏像素着色器渲染图形。结果是一个 3kB 的 Windows 可执行文件。 这是为 Langjam Gamejam(https://langjamgamejam.com/) 做的,一个 7 天挑战赛,要求你创造一种编程语言,然后用它来构建一款游戏。 这个项目结合了我的几个兴趣点:语言工具(https://laurent.le-brun.eu/blog/an-overview-of-starlark)、游戏开发(https://laurent.le-brun.eu/blog/designing-a-video-game-for-language-learners)、程序化图形,以及 demoscene 风格的大小限制(https://www.ctrl-alt-test.fr/2024/how-we-made-an-animated-movie-in-8kb/)。Game jam 的形式迫使我控制范围并探索新想法。而且,它很有趣! 和往常一样,[我的代码在 GitHub 上](https://github.com/laurentlb/shmup8);它也在 [itch.io](https://laurentlb.itch.io/shmup8) 上。为方便起见,这里有一个 YouTube 视频: ## 背景 当我第一次听说这个 game jam 时,我立刻产生了兴趣。我想了好几天,因为要找到一个能从新语言中受益的游戏概念并不容易(除了,嗯,像 TIS-100 这样的编程游戏)。 然后我想起了那些使用自定义字节码来缩小体积的 demoscene 作品。我想到的一个例子是 [Ikadalawampu](https://www.pouet.net/prod.php?which=54561),一个 2010 年在 Amiga 上运行的 4kB demo。我仍然有些怀疑:仅仅为了让实际代码更小,嵌入一个解释器真的值得吗?我必须试一试。 我的另一个灵感是 2004 年制作的第一人称射击游戏 [kkrieger](https://en.wikipedia.org/wiki/.kkrieger),它只有 96kB。从那以后,我们很少看到优秀的、以体积为编码目标的电子游戏。探索这个领域在我脑海中已存在一段时间了。 考虑到这些,我觉得这个 game jam 是一个做探索性工作的好借口。 ## 计划 - 设计一种语言。 - 使用 F# 实现一个编译器,将其编译为字节码。 - 使用 C++ 编写一个字节码解释器。 - 使用自定义语言创建一款射击游戏。 - 使用一个 GLSL 着色器渲染图形。 尽管这些设计选择是出于体积编码的考虑,但我也并不想花时间优化代码。我最初估计游戏会控制在 4 到 8kB,所以我把项目命名为 shmup8。最终可执行文件比预期的要小,但这也是因为我没有加入音乐或 3D 图形。和往常一样,着色器代码已[压缩](https://www.ctrl-alt-test.fr/2025/15-years-of-shader-minification/),可执行文件用 [Crinkler](https://github.com/runestubbe/Crinkler/) 压缩。 ## 实时编码工作流 当有即时视觉反馈时,编码会更有趣。我希望能够在不重新编译 C++ 代码的情况下编写整个游戏逻辑和视觉效果。我的想法是只运行一次可执行文件,然后通过实时重载进行完整的迭代。 每次我在 IDE 中编辑源代码时,自定义编译器都会被调用,并将字节码转储到文件中。然后 C++ 项目重新加载这个字节码,并在每一帧执行它。类似地,GLSL 着色器在编辑时也会自动重新加载。 早期开发截图:左上角是运行中的游戏,左下角是自定义语言,右下角是 GLSL 着色器,右上角是控制台日志。由于自定义语言会向着色器发送数据以供显示,因此同时拥有两个实时编码环境使得迭代非常容易。 Screenshot%202025-12-16%20000557 快速迭代是提高生产力的关键特性,尤其是在你很难预测什么效果会好的创意环境中。 ## 字节码设计 我很快决定,字节码和着色器之间的通信通过浮点数组进行。 本着极简主义,我决定只需要一种类型:float32。所有值都存储在数组中。想要一个局部变量?在浮点数组中选一个槽位来使用。如何索引数组?使用 float,解释器会将其转换为 int。如何编写条件?使用 float,如果它大于 0.5 就为真。 字节码只有两种语句:要么更新数组中的某个单元;要么跳转(可能带条件)到字节码中的另一个地址。 字节码还有表达式概念:因此当你更新一个单元时,该值可以是一个复杂的数学表达式,引用其他数组单元或函数(如正弦)。 0 到 255 之间的常量存储为一个字节。其他浮点数使用[我最喜欢的浮点技巧](https://www.ctrl-alt-test.fr/2018/making-floating-point-numbers-smaller/)存储为 2 个字节。 这种设计避免了栈、寄存器和类型标记之类的东西,从而使解释器和字节码都很紧凑。 [查看字节码元素列表](https://github.com/laurentlb/shmup8/blob/main/src/interp.cpp#L9) ## 语言设计 极简的字节码限制了我能在语言中支持的内容,但我仍然可以使用语法糖来让一些事情变得更优雅。 我使用类似 C 的语法,实现了对赋值、if 条件和 while 循环的支持。语法糖用于支持增广赋值和 for 循环。 每次编译器遇到一个变量,它都会在浮点数组中为它分配一个位置。当一个值需要与着色器共享时,我必须给它一个特定位置。例如,我决定用 state[5] 存储当前分数。为了提高可读性,我添加了对内容内联的支持。如下: `` inline score = state[5]; `` 现在我可以使用 `score` 来读取或写入 state[5]。 在迭代游戏的过程中,我有时不得不停下来补充缺失的功能。但在某些情况下,我也决定绕开这些限制;例如,在编写条件时,我用乘法代替了 &&。这其实是一样的……只要这些值只是 0 和 1。:) 我使用了一个名为 `missiles` 的数组来存储每颗导弹的位置。第一个单元表示屏幕上的导弹数量。如何在不写循环的情况下从数组中移除任意元素?交换它。 `` // 移除屏幕外的导弹 if (missiles[i*2 + 2] > 0.5) { // O(1) 移除:将元素与数组中的最后一个交换 missiles[i*2 + 1] = missiles[(missiles[0] - 1)*2 + 1]; // position.x missiles[i*2 + 2] = missiles[(missiles[0] - 1)*2 + 2]; // position.y missiles[0] -= 1; } `` (参见[文件其余部分](https://github.com/laurentlb/shmup8/blob/main/game.source)) ## 着色器图形 这与我们在 ShaderToy 中看到的非常相似。它只是根据游戏引擎提供的数据计算一个像素的颜色。 由于 game jam 时间有限,我让图形代码保持简单。 我使用了反馈效果(将上一帧与当前帧混合)来让视觉效果更有趣,并将该效果与一些噪声函数结合起来。 Screenshot%202025-12-16%20025758 ## 游戏设计 游戏设计也同样保持简单。游戏是无限循环的。一开始有三个敌人。每 7 秒增加一个敌人。敌人有三种,每种都有其特殊的行为和视觉效果。 与某些人可能认为的相反,敌人不会死亡。当导弹击中敌人时,它会被传送到屏幕外,并且能够重新回到游戏区域。 这种方法让代码非常简单,同时确保游戏内容越来越多。我最初的想法是创建敌人波次列表,但那样设计和平衡难度会更困难。 和《Super Hexagon》一样,我特别注重提供快速重启并鼓励玩家重玩。预计游戏时长在 30 到 60 秒之间。 ## 结论 快速迭代的工作流至关重要。并行设计字节码和游戏使得很难预先预测需要哪些功能,许多限制直到我开始编写游戏本身时才显现出来。 当然,还有一个问题……字节码真的比使用编译后的 C++ 更小吗?我把游戏逻辑移植到了 C++,去掉了字节码解释器,然后检查了体积。 C++ 版本比字节码版本大 90 字节。因此,使用字节码所节省的空间比解释器的大小更重要。有些人可能会说我移植的 C++ 引擎并没有真正优化;但解释器和字节码也没有优化。所以对这些数字不必太当真。 总的来说,这是一个有趣的项目。它比预期效果更好,我也学到了一些东西。我相信未来我会做更多游戏开发方面的探索。 (参见 [HackerNews 上的讨论](https://news.ycombinator.com/item?id=46325337))

相似文章