历史与人物codeofhonor.com
星际争霸诞生路上的艰难时刻
Tough times on the road to Starcraft
2012 — 2022,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这是暴雪资深开发者 Patrick Wyatt 的回忆文章,讲述《星际争霸》开发过程中的艰难历程:引擎架构混乱、手写缓存列表引发的诡异 bug、性能瓶颈,以及最终如何一步步把这款传奇 RTS 打磨成型。文章既是一段游戏史,也是一份关于工程决策代价的第一手记录。
为什么经久不衰:它由亲历者写出,把“临期压力下不断打补丁”的工程困境讲得真实生动,对任何做过复杂系统的人都有共鸣,因此十年来反复登上 HN。
HN 评论精选
分享应对手工缓存列表失步 bug 的最佳实践:先朴素实现,再缓存并保留旧实现做调试对比。
手工维护列表是游戏开发中的常见陷阱。为了跑满 60fps,你往往需要缓存很多值,比如“所有正在移动的单位”或“某一方所有的单位”。最好的做法是先写安全保守、不做缓存的朴素函数,等性能分析发现瓶颈后,再手写一个持续更新特定列表的系统;关键是保留旧函数,在调试模式下偶尔对比两者结果(我通常每 100 次访问对比一次)。这样即使不知道缓存为何失步,至少能知道它失步了,而不是陷入那种让人想改行种地的、最绕最折磨人的 bug。
reitzensteinm查看英文原文
The part about hand maintained lists is a common pitfall in game development. When you're trying to push out frames at 60fps, you generally need to be caching quite a lot of values, for example, "Get all units that are moving" or "Get all units from side x". The absolute best way to handle this is to start off with safe, conservative functions, that don't cache at all - create a list, iterate over each entity, add whatever fits the condition. Then, after profiling to see what's slow, you hand roll a system that keeps a specific list updated continuously; and then importantly, keep around the old function, and in debug mode compare the lists occasionally (I usually do it every 100th access, so the game is still playable). After that, you may not know what's causing a cached value to go out of sync, but you can at least know it's happening, instead of getting some of the most convoluted and maddening bugs imaginable. The kind that make you want to take up farming (and I'd be a shitty farmer).
核心教训:数据结构的操作应集中管理,不要与应用逻辑混杂。
我从这篇文章得到的主要教训是:不要把数据结构和应用逻辑混在一起。这符合我的经验——复杂数据结构只要所有操作都集中在一处、可以单元测试(或至少仔细审查),就没问题;一旦操作散落各处或与其他逻辑混杂,就会非常糟糕。
jimrandomh查看英文原文
The main takeaway I got from this article is don't mix data structures and application logic. This matches my experience; complex data structures work fine if all the operations performed on them are in one place where they can be unit tested (or at least carefully inspected), but it works very badly if they're scattered or mixed with other things.
对比《魔兽争霸3》和《帝国时代》的确定性引擎与录像机制,指出星际保存全量状态的做法很浪费。
我完全不知道《星际争霸》保存的是整个游戏状态,太浪费了!我很好奇它的引擎是否是确定性的——如果不是,那为了实现录像和续玩功能就只能保存完整状态。而三年后推出的《魔兽争霸3》引擎是完全确定性的,录像文件只保存玩家输入,所以即使整局游戏的存档也极小。当年有很多网站可以下载别人的录像,包括著名对战。我和哥哥会通过邮件附件交换自己最精彩的录像,然后互相观看点评。据我所知,微软 1997 年的《帝国时代》一代就已经用了确定性引擎。
TacticalCoder查看英文原文
I had no idea StarCraft still saved the entire game state: what a gigantic waste! I wonder if the game engine was deterministic or not (if it wasn't there was no choice for save files: you had to save the full game state if you wanted to implement a replay or continue functionality). Now Warcraft III, which came out only three years later, had a fully deterministic game engine and, for replay files, only saved players inputs. Hence the Warcraft III save file, even for entire games, were tiny. And there were several websites where you could download and replay save files from other people, including from famous matchups. Fun times: I'd exchange my best games with my brother, as email attachments IIRC. We'd then watch each other's games and make comments. IIRC Microsoft's first Age of Empire, which came out in 1997, already used a deterministic game engine so there was already an AAA title who used that technique when StarCraft came out in 1998.
结合自身经历印证“临期打补丁导致长期痛苦”:维护期产品更应优先降低复杂度而非省钱糊补丁。
“因为离发售只有‘两个月’了,改进引擎的方案总是被搁置,转而对现有但不理想的方案打补丁,导致之后好几个月的痛苦”——我正遇到同样的问题。我们的一个产品即将不再卖给新客户(但仍有大量老客户),维护预算很小。很多人认为这意味着所有问题都该用最便宜的方式糊上胶带,哪怕代价是复杂度增加。我的想法恰恰相反:我们将被迫用极小的预算维护自己增加的任何复杂度,所以现在不应做任何增加复杂度的改动,理想情况下只做降低复杂度的改动,哪怕前期成本更高。但很难让别人理解这个逻辑。商人和开发者似乎以为活跃产品的预算大头在新功能开发,实际上恰恰相反。
kqr查看英文原文
> Since we were only “two months” from shipping, making changes to the engine for the better was regularly passed over for band-aiding existing but sub-optimal solutions, which led to many months of suffering I'm having a version of this problem right now. One of our products is not going to be sold to new customers at some point soon (but will continue to have plenty of existing customers), so it receives a small-ish budget for maintenance. A lot of people seem to believe that this means any problems should be patched over with duct tape at the cheapest possible up-front expense, even if it comes at the cost of increased complexity. I think of it the other way around: we are going to be forced to maintain whatever complexity we add to this with a very small budget, so at this point we shouldn't make any change that increases complexity. Ideally, we'd only make changes that decrease complexity! Even at higher up-front cost. But it's hard to get people to understand the logic of that. I might not be phrasing it well. It's a little like business people and developers think that most of the budget of an actively developed product goes to new development and only a small fraction is needed for maintenance, when in practise it seems to me to be the other way around.
历次讨论
同类还值得读
开发者无薪坚持完成 Mac 图形计算器:一个秘密项目的故事
Dev stays without pay to finish Mac Graphing Calculator as skunkworks project
苹果 Mac 图形计算器(Graphing Calculator)开发者的亲述:在项目被砍后,几位工程师在没有报酬、没有正式授权的情况下,以“地下项目”方式偷偷留在公司把软件做完…
历史与人物上首页 6 次 · 2009–2022pacifict.com理查德·费曼与 Connection Machine
Richard Feynman and the Connection Machine
长文回忆费曼晚年参与 Connection Machine 并行计算机项目的经历:他分析路由器、用自创的并行 Basic 编写 QCD 程序,也涉足细胞自动机等主题。
历史与人物上首页 5 次 · 2010–2021longnow.org编辑精选负 2000 行代码
-2000 Lines of Code
folklore.org 上 Andy Hertzfeld 记录的一则苹果 Macintosh 开发轶事:Bill Atkinson 被问到写了多少行代码时,回答“-2000 行…
历史与人物上首页 4 次 · 2014–2022folklore.org编辑精选Dennis Ritchie 的第一版 C 编译器(约 1972 年)
Dennis Ritchie’s first C compiler (c. 1972)
这个 GitHub 仓库保存了 Dennis Ritchie 约 1972 年编写的最早 C 编译器源码,是 C 语言和 Unix 早期历史的一手材料。
历史与人物上首页 4 次 · 2013–2025github.com一位破解赛马密码的赌徒
A Gambler Who Cracked the Horse-Racing Code (2018)
彭博社 2018 年的长篇特写,讲述数学家 Bill Benter 如何用统计模型和算法在赛马博彩中持续盈利、累计赢得近十亿美元的故事。
历史与人物上首页 4 次 · 2018–2024bloomberg.com