作者zabiak (zabiak)
看板StarCraft
标题Re: [新闻] StarCraft 的开发历史
时间Mon Sep 10 22:41:10 2012
首先感谢LCamel分享这篇有趣的文章,我尝试翻译了这包含星海争霸的由来、开发
过程、软体工程及程式开发等面向的故事,与大家分享,其中的翻译错误,也请大家不吝
指正,谢谢
原文连结:
http://www.codeofhonor.com/blog/tough-times-on-the-road-to-starcraft
原文及翻译:
Tough times on the road to Starcraft
那段迈向"星海争霸之道"的艰苦时光
by Patrick Wyatt
I've been writing about the early development of Warcraft, but a recent blog
post I read prompted me to start scribbling furiously, and the result is this
three-part, twenty-plus page article about the development of StarCraft, along
with my thoughts about writing more reliable game code. I'll be posting the
latter parts over the next several days.
This post: Why StarCraft crashed frequently during development
Part 2: How we could have fixed the most common causes
Part 3: Explaining the implementation details of the fix
我已经写了一些关於魔兽争霸早期开发的相关文章,但是最近我读到一篇部落格文章,促
使我振笔疾书,结果就是这分成三部分、二十多页关於开发星海争霸的文章,并包含一些
我对於撰写可靠游戏程式码的想法。我将在接下来的几天发表其余的部分
此篇文章:为什麽星海争霸在开发阶段频繁的死当
第二部分:我们如何修正时常造成死当的原因
第三部分:详述关於修正的实作细节
The beginnings of StarCraft
During the development of StarCraft, a two and a half year slog with over a
year of crunch time prior to launch, the game was as buggy as a termite nest.
While its predecessors (Warcraft I and II) were far more reliable games than
their industry peers, StarCraft crashed frequently enough that play-testing
was difficult right up until release, and the game continued to require ongoing
patching efforts post-launch.
Why? There were sooooo many reasons.
星海争霸之始
在星海争霸推出前的开发阶段(包含两年半长时间的艰苦工作以及超过一年的收尾),游戏
中的臭虫多到像是白蚁巢穴一样。相比於运作稳定度剩过其他同业的前作(魔兽争霸及魔兽
争霸二),星海争霸实在太常死当,甚至直到释出前的试玩测试都难以进行,在推出後更需
要持续不断的补丁修正。
为什麽?有太太太太太多原因了。
Orcs in space
StarCraft was originally envisioned as a game with modest goals that could fit
into a one-year development cycle so that it could be released for Christmas,
1996.
The project leadership was comprised of the same folks who had started
Shattered Nations (video), a turn-based strategy game along the lines of X-COM
that Blizzard announced in May 1995 but canceled some months later.
The team members were regrouped to build something that could reach market
quickly so Blizzard wouldn’t have a long gap between game launches.
Q4 1994 - Warcraft
Q4 1995 - Warcraft II
Q4 1996 - planned ship date for StarCraft
Q2 1998 - actual ship date for StarCraft
The decision to rush the game’s development seems ludicrous in retrospect, but
Allen Adham, the company’s president, was under pressure to grow revenue.
While Blizzard’s early games had been far more successful than expected, that
just raised expectations for future growth.
Given a short timeframe and limited staff, the StarCraft team’s goal was to
implement a modest game - something that could best be described as "Orcs in
space". A picture from around the time of the E3 game show in Q2 1996 shows the
path the game team originally chose:
But a higher priority project overshadowed StarCraft and stole its developers
one by one. Diablo, a role-playing game being developed by Condor Studios in
Redwood City California, was in need of additional help. Condor, a company
formed by Dave Brevik along with Max Schaefer and his brother Erich Schaefer,
was given a budget of only $1.2 million - ridiculously small even in those
days.
The Condor team had no hope of making the game they aspired to build, but
they did such ground-breaking work in developing something fun that it made
sense for Blizzard to acquire Condor, rename it Blizzard North, and start
pouring in the money and staff the game really deserved.
Initially Collin Murray, a programmer on StarCraft, and I flew to Redwood City
to help, while other developers at Blizzard "HQ" in Irvine California worked on
network "providers" for battle.net, modem and LAN games as well as the
user-interface screens (known as "glue screens" at Blizzard) that performed
character creation, game joining, and other meta-game functions.
As Diablo grew in scope eventually everyone at Blizzard HQ - artists,
programmers, designers, sound engineers, testers - worked on the game until
StarCraft had no one left working on the project. Even the project lead was
co-opted to finish the game installer that I had half-written but was too busy
to complete.
After the launch of Diablo at the end of 1996, StarCraft development was
restarted, and everyone got a chance to see where the game was headed, and it
wasn’t pretty. The game was dated, and not even remotely impressive,
particularly compared to projects like Dominion Storm, which looked great in
demos at E3 six months before.
The massive success of Diablo reset expectations about what Blizzard should
strive for: StarCraft became the game that defined Blizzard’s strategy of
not releasing games until they were ready. But a lot of pain had to occur along
the way to prove out this strategy.
太空兽族
星海争霸的初始预想是相当简单的,符合一年的开发周期,并可在1996年的圣诞档期推出
。
专案负责人是由"破碎的国度(影片)"团队成员组成, 破碎的国度是暴雪在1995年5月发表
的回合制战略游戏,此专案在几个月之後被腰斩。
团队成员则进行重组,预计可在短时间内作出些什麽并推出,使得暴雪不会在各游戏的上
市日期之间有太大的空窗期。
1994年第4季 - 魔兽争霸
1995年第4季 - 魔兽争霸2
1996年第4季 - 预计的星海争霸出货日期
1998年第2季 - 实际的星海争霸出货日期
现在回想起来,加快游戏的开发脚步似乎荒唐可笑,但是公司总裁Allen adham承受着增
加公司营收的压力,尤其是当暴雪早先推出的游戏出乎预期的成功,更加深了对於公司未
来成长的期待。
在紧凑的时间表以及有限的人力下,星海争霸团队的目标是实作出一个简单的游戏 - 一
个称之为"太空兽族"的游戏。一张於1996年第2季左右的E3展览会发布图片可以看出游戏
团队最初决定的走向。
但是一个更高优先权的专案凌驾於星海争霸之上,并把开发成员一个接一个"偷"走了。暗
黑破坏神,一个由位於加州Redwood市Condor Studio所开发的角色扮演游戏,正处於需要
额外帮助的状态。Condor,一家由Dave Brevik、Max Shaefer以及Erich Schaefer兄弟创
立的公司,仅编列120万美元的预算 - 即使在那时候,也可以说是少得可怜。
Condor团队并没有办法作出他们想要作出的游戏,但是他们仍作出一些具开创性且有趣的
东西,促使暴雪收购它,更名为Blizzard North,并开始投入开发此游戏实际上需要的资
金及人力。
最初,我跟Collin Murray(星海争霸的程式设计师)飞到Redwood市去帮忙,後来,包括
加州Irvine暴雪总部的battle.net网路服务提供人员,数据机及区域网路游戏人员,以及
图型使用者介面(在暴雪称之为"glue-screen")人员(包括创造角色,加入游戏以及其他
meta-game的功能),都投入到这个游戏的开发行列。
暗黑破坏神的开发规模越来越大,最後暴雪总部的每一个人 - 美术人员、程式设计师、
设计师、音效工程师、测试人员,都陆续投入暗黑破坏神的开发工作,最後,没有任何人
在进行星海争霸专案的开发工作。甚至连专案负责人都被指派来完成我已经写到一半,但
忙到无法完成的游戏安装程式。
在暗黑破坏神於1996年末推出後,星海争霸的开发工作才重启,每一个人得到机会检视游
戏的走向,结论是相当糟糕。这游戏已经过时,甚至无法留下深刻印象,尤其是与像是
Dominion Storm等专案进行比较,其於六个月前的E3进行展示,看起来相当棒。
因为暗黑破坏神的巨大成功,暴雪重新订定他们所追求的目标:暴雪的策略是,星海争霸
不应该在没有准备好的情况下发行。为了达到这个目标,我们可是吃足了苦头。
Something to prove
With everyone looking critically at StarCraft, it was clear that the project
needed to be vastly more ambitious than our previous ground-breaking efforts
in defining the future of the real-time strategy (RTS) genre with the first two
Warcraft games.
At the time of the StarCraft reboot, according to Johnny Wilson, then Editor
in Chief of Computer Gaming World, the largest-distribution gaming magazine
of that time, there were over eighty (80!!) RTS games in development. With so
many competitors on our heels, including Westwood Studios, the company that
originated the modern RTS play-style, we needed to make something that kicked
ass.
And we were no longer an underdog; with the successes of Warcraft and Diablo
continuing to fill the news we sure wouldn’t be getting any slack from
players or the gaming press. In the gaming world you’re only ever as good as
your last game. We needed to go far beyond what we’d done previously, and that
required taking risks.
需要证明的东西
在每一个人严苛地检视下,很明显星海争霸专案需要有更大的雄心壮志,即超过我们之前
两款魔兽争霸游戏(其定义了即时战略游戏未来)的开创性成就。
在星海争霸专案重启的当下,根据Computer Gaming World(当时发行量最大的游戏杂志)
总编Johnny Wilson所言,当时有超过80款即时战略游戏正在进行开发,有这麽多的竞争
者,包括Westwood Studios(首创即时战略游戏类型的公司),我们需要作出些什麽对对手
迎头痛击。
我们已非昔日的无名小卒;我们确信我们并未因报章杂志充斥着魔兽争霸及暗黑破坏神的
成功,而怠慢了玩家及游戏媒体。在游戏产业,你的评价只来自於你上一个推出的游戏,
我们需要远远超过之前所作,而这代表我们需要冒险。
New faces
Warcraft II had only six core programmers and two support programmers; that
was too few for the larger scope of StarCraft, so the dev team grew to include
a cadre of new and untested game programmers who needed to learn how to write
game code without much mentoring.
Our programming leadership was weak: we hadn't yet learned how essential it is
to provide guidance to less experienced developers early in the project so they
learn much-needed lessons before the game launches, so it was very much a
sink-or-swim proposition for new Padawans. A big part of the problem was just
how thin we were on the ground - every programmer was coding like mad to meet
goals, with no time for reviews, code-audits, or training.
And not only were there inexperienced junior members on the team, the leader of
the StarCraft programming effort had never architected a shipping game engine.
Bob Fitch had been programming games for several years with great results but
his previous efforts were game ports, where he worked within an existing
engine, and feature programming for Warcraft I and II, which didn't require
large-scale engine design. And while he had experience as the tech lead for
Shattered Nations, that project was canceled, therefore no validation of its
architectural decisions was possible.
The team was incredibly invested in the project, and put in unheard of efforts
to complete the project while sacrificing personal health and family life. I've
never been on a project where every member worked so fiercely. But several key
coding decisions in the project, which I’ll detail presently, would haunt the
programming team for the remainder of the project.
新面孔
魔兽争霸2只有6个核心程式设计师以及2个支援程式设计师;对於星海争霸较大的规模来
说,实在是太少了,所以开发团队增加了新的且未经试用的游戏程式设计师,这些程式设
计师需要在得不到太多指导的情况下,学习如何写出游戏程式码。
我们的程式设计领导环节相当薄弱:在专案早期,我们还不知道提供缺乏经验的开发者开
发指南是必需的,导致他们在游戏推出前的这段时间,学到大量的教训,就像是对於新的
帕达瓦接受溺水或学会游泳的课题一样。很大一部分的问题出在时程紧迫 - 导致每一个
程式设计师疯狂地撰写程式码好达到目标,根本没时间进行检视、程式码稽核或是教育训
练。
不只是团队中具有没有经验的新成员,星海争霸专案的负责人也没有商用游戏引擎架构设
计的经验。Bob Fitch有多年游戏程式设计经验,并伴随着成功的结果,但是他之前的经
验为游戏移植,使用已存在的游戏引擎,进行魔兽争霸及魔兽争霸2的功能程式撰写,这些
都不需要大型的引擎设计经验。当他作为破碎的国度主程式设计师时,这个专案後来被腰
斩了,因此并没有机会验证他对於架构的决策是否正确。
团队为这个专案投入令人难以置信,甚至为了完成专案牺牲了个人健康及家庭生活。我从
来没经历过一个专案,其中的成员如此的鞠躬尽瘁。但是专案中的几个主要的程式设计决
策,却在专案的余下部分,困扰着程式设计团队。
Some things have changed
After spending months working to launch Diablo, and further months of cleanup
effort and patching afterwards, I returned to help with the reboot of
StarCraft. I wasn't looking forward to diving into another bug-fest, but that's
exactly what happened.
I thought it would be easy to jump back into the project because I knew the
Warcraft code so well - I'd literally worked on every component. I was instead
terrified to discover that many components of the engine had been thrown away
and partially rewritten.
The game's unit classes were in the process of being rewritten from scratch,
and the unit dispatcher had been thrown out. The dispatcher is the mechanism I
created to ensure that each game unit gets time to plan what it wants to do.
Each unit periodically asks: "what should I do now that I finished my current
behavior?", "should I re-evaluate the path to get where I'm going?", "is there
a better unit to attack instead of the one that I'm targeting now?", "did the
user give me a new command?", "I'm dead, how do I clean up after myself?, and
so forth.
There are good reasons code needs to be rewritten, but excising old code comes
with risks as well. Joel Spolsky said it most eloquently in Things You Should
Never Do, Part I:
It's important to remember that when you start from scratch there is absolutely
no reason to believe that you are going to do a better job than you did the
first time. First of all, you probably don't even have the same programming
team that worked on version one, so you don't actually have "more experience".
You're just going to make most of the old mistakes again, and introduce some
new problems that weren't in the original version.
The Warcraft engine had taken months of programming effort to get right, and
while it needed rework for new gameplay features, a fresh programming team
was now going to spend a great deal of time relearning lessons about how and
why the engine was architected the way it was in the first place.
那些改变的事情
在为了暗黑破坏神上市工作了几个月,以及之後几个月的收尾及後来的补丁,我重返岗位
回到星海争霸重启的计画。我没有预料到我会掉入另一个臭虫宴会,但它就是发生了。
我以为回到专案工作是容易的,因为我对於魔兽争霸的程式码的理解相当透彻 - 事实上
,我可以对每一个元件进行开发工作。取而代之的是,我吓了一大跳,因为许多游戏引擎
的元件已经被弃之如屣或经过部分改写。
游戏的单位类别被重新改写,而单位调度机制则已被丢弃。调度机制是由我创造,使得每
一个游戏单位取得时间并计画它想要作什麽。每一单位周期性地询问:"我已经完成我现在
的行为,现在该作些什麽?","我需要重新评估路径以到达我要去的地方吗?","有比目
前我瞄准的单位更好的攻击目标吗?","玩家有给我新的命令吗?""我已经死了,我该怎
麽把自己清除呢?" 等等
有合理的理由说明程式码需要被改写,但是除去旧的程式码同样具有风险。Joel Spolsky
在"你绝对不应该作的事之一"文章中大声疾呼:
"你一定要记住,想要从头开始时,请不要抱着这次会做得比第一次好的想法。首先,你
的程式团队根本不可能和当初相同,所以并不会真的有"更多的经验"。其实只会把大部分
的旧错误重新再犯一次,并且再多增加一些旧版本所没有的新问题。" (注)
注:摘录自"约尔趣谈软体(Joel On Software) Joel Spolsky 着 梅普华 译
悦之文化 出版
魔兽争霸引擎花了几个月的工作量才使得它正常运作,并需要额外的工作增加崭新的游戏
功能。现在,新的程式设计团队需要先花好大一番功夫重新了解,游戏引擎如何及为什麽
如此的建构。
Game engine architecture
I wrote the original Warcraft engine for Microsoft DOS in C using the Watcom
Compiler. With the switch to releasing on Microsoft Windows, Bob chose to use
the Visual Studio compiler and re-architected the game engine in C++. Both were
reasonable choices but for the fact that - at that point - few developers on
the team had experience with the language and more especially with its many
pitfalls.
Though C++ has strengths it is easy to misuse. As Bjarne Stroustrup, the
language’s creator, so famously said: "C makes it easy to shoot yourself in
the foot; C++ makes it harder, but when you do it blows your whole leg off."
History tells us that programmers feel compelled to try every feature of their
new language during the first project, and so it was with class inheritance in
StarCraft. Experienced programmers will shudder when seeing the inheritance
chain that was designed for the game’s units:
CUnit < CDoodad < CFlingy < CThingy
CThingy objects were sprites that could appear anywhere on the game map, but
didn't move or have behaviors, while CFlingys were used for creating particles;
when an explosion occurred several of them would spin off in random directions.
CDoodad - after 14 years I think this is the class name - was an uninstantiated
class that nevertheless had important behaviors required for proper functioning
of derived classes. And CUnit was layered on top of that. The behavior of units
was scattered all throughout these various modules, and it required an
understanding of each class to be able to accomplish anything.
And beyond the horror of the class hierarchy, the CUnit class itself was an
unholy mess defined across multiple header files:
class CUnit ... {
#include "header_1.h"
#include "header_2.h"
#include "header_3.h"
#include "header_4.h"
};
Each of those headers was several hundred lines, leading to an overall class
definition that could at best be called amusing.
It wasn't until many years later that the mantra "favor composition over
inheritance" gained credence among programmer-kind, but those who worked on
StarCraft learned the hard way much earlier.
游戏引擎架构
我使用微软DOS平台、C语言及Watcom编译器来撰写原本的魔兽世界引擎。为了释出到到微
软视窗作业系统的转变,Bob选择使用Visual Studio编忆器,并使用C++重新架构游戏引擎
。这两者皆是合理的选择,但在那个时候,事实上,团队中只有少数的开发者具有使用此
种语言进行开发的经验,更遑论此语言中蕴含的许多陷阱。
C++有其长处,但也容易被误用。就像C++之父Bjarne Stroustrup的名言:
"使用C语言,很容易就搬起石头砸自己的脚;使用C++,变得没这麽容易,但是一旦你这
麽作,你整条腿都要报销"
历史告诉我们,程式设计师在使用新的语言进行第一个专案开发时,觉得有必要尝试新语
言的每一个特徵,这体现在星海争霸的类别继承。有经验的程式设计师在看到为了游戏单
位设计的继承链时,会感到不寒而栗。
CUnit < CDoodad < CFlingy < CThingy
CThingy物件在游戏地图中无所不在,但并不移动或具有行为。CFlingy用在创造微粒,当
爆炸发生时,许多CFlingy以随机方向分散开来。CDoodad - 在过了14年之後,我想这是
一个类别名称 - 是一个未具现化类别。CUnit则是最高层级的类别。单位的行为被分散在
这些各种不同的模祖中,这需要对每一个类别都有深刻的了解,才能够完成任何事情。
除了这恐怖的类别阶层,CUnit类别本身简直是乱七八糟,搞得天怒人怨,其定义包含了
多个标头档:
class CUnit ... {
#include "header_1.h"
#include "header_2.h"
#include "header_3.h"
#include "header_4.h"
};
其中的每一个标头档都有好几百行,导致整个类别定义就像是整人大爆笑。
在多年之後,有一句在程式设计师间口耳相传的口诀如是说"优先使用组合而非继承",但
对於在暴雪工作的程式设计师来说,早就已经体验过"震撼教育"的洗礼了。
We're only two months from launch
With its troubled early history, after the reboot the development team was
pressured to finish up, and so schedules were bandied about that showed the
game could be launched in two months.
Given the number of game units and behaviors that needed to be added, the
changes necessary to switch from top-down to isometric artwork, a completely
new map editor, and the addition of Internet play over battle.net, it was
inconceivable that the game actually could ship in that time, even assuming
that the art team, designers, sound engineers, game-balancers and testers
could finish their end of the bargain. But the programming team continually
worked towards shipping in only two months for the next fourteen months!
The entire team worked long hours, with Bob working stretches of 40 hours, 42
hours, even 48 hours programming. As I recall no one else attempted these sorts
of masochistic endeavors, though everyone was putting in massive, ridiculous
hours.
My experiences developing Warcraft, with frequent all-nighters coding, and
later Diablo, where I coded fourteen-plus hour days seven days a week for
weeks at a time, suffered me to learn that there wasn’t any point in
all-nighters. Any code submissions [ha! what an appropriate word] written
after a certain point in the evening would only be regretted and rewritten in
the clear light of following days.
Working these long hours made people groggy, and that's bad when trying to
accomplish knowledge-based tasks requiring an excess of creativity, so there
should have been no surprises about the number of mistakes, misfeatures and
outright bugs.
Incidentally, these sorts of crazy hours weren't mandated - it was just the
kind of stuff we did because we wanted to make great games. In retrospect it
was foolish - we could have done better work with more reasonable efforts.
One of my proudest accomplishments was to ship four Guild Wars campaigns in a
two-year window without leading the development team down that dark path.
离推出只有两个月
其多灾多难的早期历史,以及自计画重启後开发团队就面临早日完工的压力,所以时程规
划也是急就章,要在两个月内让游戏上市。
增加大量的游戏单位及其行为,需要从鸟瞰图变成立体投影图,全新的地图编辑器,可以
透过battle.net进行网路对战,在在都凸显准时上市是不可能的任务,这还是在没有把跟
美术团队、设计师、音效工程师、游戏平衡制定人员以及测试人员的"吵架大会"列入考虑
的情况下。但是程式设计团队仍持续不断地工作,想要在短短的两个月内推出这款游戏,
但最终我们花了14个月才达到这个目标。
整个团队工时过长,Bob不间断地撰写程式整整40小时、40小时,甚至48小时。在我的回
忆里,没有其他人像他如此地燃烧小宇宙,但是每一个人的工时都长得离谱。
在我开发魔兽争霸以及暗黑破坏神的经验里(频繁的通宵达旦地撰写程式,每天工作超过
14小时,每周工作7天),让我知道彻夜工作是毫无意义的。所有在深夜完成的"鬼斧神工"
,在接下来的日子里都会现出原形,而需要砍掉重练。
长时间的工作会使人们脑筋不清楚,这对於需仰赖大量创造力的脑力密集型工作来说,简
直是糟糕透顶,所以产生大量错误,功能缺失,以及显而易见的臭虫,也就不令人意外了
。
顺带一提,这种疯狂的工时是不必要的,之所以这麽作的原因,是因为我们想要作出好游
戏。回顾过去,我们当时真是犯傻,只有在合理的工时下,才可以完成品质更好的作品。
我一生最骄傲的事,就是激战在推出游戏及三款资料片这为期两年的时间中,我没有引领
开发团队再次走上那充满荆棘的道路。
The most common cause of StarCraft game crashes
While I implemented some important features in StarCraft, including fog-of-war,
line-of-sight, flying unit pathing-repulsion, voice-chat, AI reinforcement
points, and others, my primary job gravitated to fixing bugs.
Wait: voice-chat! In 1998?!? Yeah: I had it all working in December 1997. I
used a 3rd-party voice-to-phoneme compressor, and wrote the code to send the
phonemes across the network, decompress them, and then play them back on the
other seven players' computers.
But every single sound-card in our offices required a driver upgrade to make
it work, if the sound card was even capable of full-duplex sound (simultaneous
recording and playback of sounds), so I regretfully made the recommendation to
scrap the idea. The tech-support burden would have been so high that we would
have spent more money on game support than we would have made selling the game.
So anyway I fixed lots of bugs. Some of my own, sure, but mostly the elusive
bugs written by other tired programmers. One of the best compliments I've
received came just a few months ago, when Brian Fitzgerald, one of two best
programmers I've had occasion to work with, mentioned a code-review of
StarCraft; they were blown away by how many changes and fixes I had made over
the entire code-base. At least I got some credit for the effort, if only well
after the fact!
Given all the issues working against the team, you might think it was hard to
identify a single large source of bugs, but based on my experiences the
biggest problems in StarCraft related to the use of doubly-linked linked
lists.
Linked lists were used extensively in the engine to track units with shared
behavior. With twice the number of units of its predecessor - StarCraft had
a maximum of 1600, up from 800 in Warcraft 2 - it became essential to optimize
the search for units of specific types by keeping them linked together in
lists.
Recalling from distant memory, there were lists for each player's units and
buildings, lists for each player's "power-generating" buildings, a list for
each Carrier's fighter drones, and many many others.
All of these lists were doubly-linked to make it possible to add and remove
elements from the list in constant time - O(1) - without the necessity to
traverse the list looking for the element to remove - O(N).
Unfortunately, each list was "hand-maintained" - there were no shared
functions to link and unlink elements from these lists; programmers just
manually inlined the link and unlink behavior anywhere it was required. And
hand-rolled code is far more error-prone than simply using a routine that's
already been debugged.
Some of the link fields were shared among several lists, so it was necessary
to know exactly which list an object was linked into in order to safely
unlink. And some link fields were even stored in C unions with other data
types to keep memory utilization to a minimum.
So the game would blow up all the time. All the time.
造成星海争霸死当的原凶
我实作星海争霸中一些重要的功能,包括视野范围限制、视野、飞行单位的路径互斥、语
音聊天、人工智能集节点,以及其他功能,但我最主要的工作其实是修正臭虫。
等一下,在1988年实作语音聊天功能?没错,一切都在1997年12月大功告成。我使用第三
方开发的声音-音素转换压缩工具,并撰写了在网路上传输音素的程式码,以及解
压缩功能,接着在其他七位玩家的电脑播放。
但是我们办公室的每一张支援全双工(同时录音并播放声音)的音效卡,都需要更新驱动程
式才可以使用这项功能,只能说遗憾,这点子只得被束之高阁。因为提供技术支援的金钱
负担将会相当巨大,超过我们卖出游戏的营收所得。
我修正了相当多的臭虫,一些当然是我造成的,但是大部分难以发现的臭虫是由其他疲惫
不堪的程式设计师所撰写的。几个月前,Brian Fitzgerald(他是我合作过的程式设计师中
最好的两位其中之一)对星海争霸进行程式码检视後,给予我极高的赞誉,可以说是我这辈
子所得到最好的。我对整个程式码经过许多变更及修正,臭虫被一网打尽。至少我的努力
得到肯定,而事实也是如此!
由於横亘在开发团队面前的所有问题,你可能认为在庞大的程式码中很难找出臭虫,但是
根据我的经验,星海争霸最大的问题其实来自於使用了双向链结串列。
链结串列在引擎中被广泛地始用,用来记录单位及其共享行为。魔兽争霸2的单位数目有
800个,但星海争霸最多有1600个,整整增加了一倍。这使得我们必需对寻找特定类型的单
位这件事进行优化,方法是将他们链结在一起存放於串列中。
回顾遥远的记忆,有很多用来储存玩家的单位及建筑的串列,很多用来储存每个玩家"发
电"建筑的串列,一个储存每一架航空母舰无人战斗机的串列,以及其他很多很多其他的串
列。
所有的串列都是双向链结的,使得我们可以在常数时间(O(1))里新增及移除节点,而不需
要搜寻整个串列找到欲移除的节点(O(N))。
不幸的是,每个串列都是"手工维护"的 - 没有共用的函式去链结及取消链结这些串列,程
式设计师全凭手动在需要链结及取消链结的地方加入行内函式。手工程式码远比使用已经
过除错的常式来的容易出错。
有些链结栏位是由多个串列共享,所以必须要确切知道这个物件被哪些串列链结,好安全
地移除链结。一些链结栏位使用C语言的union型别储存,可以最小化记忆体的使用。
总的来说,这个游戏总是死当,履试不爽。
But why did you do it that way?
Tragically, there was no need for these linked-list problems to exist. Mike
O'Brien, who, along with Jeff Strain, cofounded ArenaNet with me, wrote a
library called Storm.DLL, which shipped with Diablo. Among its many features,
storm contained an excellent implementation of doubly-linked lists using
templates in C++.
During the initial development of StarCraft, that library was used. But early
in the development the team ripped out the code and hand-rolled the linked-lists
, specifically to make writing save-game files easier.
Let me talk about save games for a second to make this all clearer.
但是为什麽你们要这麽作呢?
一切都是悲剧阿!其实这些链结串列问题根本就不该存在。我跟Mike O’Brien及Jeff
Strain(後来共同成立ArenaNet公司)撰写了一个叫作Storm.DLL的函式库,与暗黑破坏神一
起出货。在Storm众多的功能中,有一个卓越的双向链结串列的实作,是我们使用C++中的
范本功能撰写出来的。
在星海争霸最初的开发阶段,我们使用这个函式库。但是在早期开发阶段,开发团队将这
程式码删去,并手工处理链结串列,为的是让游戏存档时的写档比较容易。
让我们接着谈谈游戏存档好让一切明朗。
Save games
Many games that I played before developing Warcraft had crappy save-game
functionality. Gamers who played any game created by Origin will remember how
looooooong it took to write save-game files. I mean sure, they were written
by slow microprocessors onto hard-drives that - by today's standards - are
as different as tricycles and race cars. But there was no reason for them to
suck, and I was determined that Warcraft wouldn't have those problems.
So Warcraft did some tricks to enable it to write large memory blocks to disk
in one chunk instead of meandering through memory writing a bit here and
there. The entire unit array (600 units times a few hundred bytes per unit)
could be written to disk in one chunk. And all non-pointer-based global
variables could similarly be written in one chunk, as could each of the
game-terrain and fog-of-war maps.
But oddly enough, this ability to write the units to disk in one chunk wasn't
essential to the speed of writing save game files, though it did drastically
simplify the code. But it worked primarily because Warcraft units didn't
contain "pointer" data.
StarCraft units, which as mentioned previously contained scads of pointers in
the fields for linked lists, was an entirely different beast. It was necessary
to fixup all the link pointers (taking special care of unioned pointer fields)
so that all 1600 units could be written at once. And then unfixup the link
pointers to keep playing. Yuck.
储存游戏
在我开发魔兽争霸之前,我玩过许多游戏,他们的游戏存档功能都很糟糕。玩家玩任何由
Origin出品的游戏,都会记得他们需要花费多久的时间存档。我的意思是,他们使用速度
慢的微处理器对硬碟进行写入的动作,以现在的标准来看,就像是拿三轮车与赛车作比较
。但是,仍然没有理由会烂成这样,所以我暗自决定,这些问题绝不会出现在魔兽争霸里
。
魔兽争霸使用了一些小技巧,让他可以一次将一大块记忆体区块写入硬碟,而不是缓慢地
透过记忆体一个bit一个bit的进行写入。整个单位阵列(600个单位乘上几百个byte),可以
一次写入硬碟。所有非指标的全域变数,像是每一个游戏地形及视野范围限制地图,可以
用类似的方法一次写入。
奇怪的是,这个将单位一次写入硬碟的能力,并不是提升游戏存档写档速度的决定性因素
,但仍显着地简化了程式码。而魔兽争霸单位并不包含指标资料,透过一次写入,效果则
相当明显。
如前所述,星海争霸单位储存於具有指标的链结串列栏位中,完全是不同的挑战。必须要
修复所有的链结指标(使用特别手法处理union类型指标栏位),使得所有1600单位可以一次
写入。接着反修复这些链结指标,使得可以继续进行游戏。啐!
Change back!
So after fixing many, many linked list bugs, I argued vehemently that we should
switch back to using Storm's linked lists, even if that made the save-game code
more complicated. When I say "argued vehemently", I should mention that was
more or less the only way we knew how to argue at Blizzard - with our youthful
brashness and arrogant hubris, there was no argument that wasn't vehement
unless it was what was for lunch that day, which no one much wanted to decide.
I didn't win that argument. 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, so much that it affected my approach to coding (for the better) ever
since, which is what I'll discuss in part two of this article.
给我改回来!
在修正了相当多的链结串列臭虫後,我激烈地争论我们应该回头使用Storm的链结串列,
纵使这会让游戏储存的程式码更加复杂。当我说"激烈地争论",我应该或多或少提一下,
在暴雪里进行争论的唯一已知方法,就是凭藉着年轻人的自以为是以及傲慢自大。唯一不
激烈的争论是,讨论当天午餐该吃些什麽,因为没人想作决定。
我并没有赢得这场争论。因为我们距离出货只剩"两个月",对引擎进行变更比较好的方法
是,经常对现有但并不完美的解决方案贴OK蹦,这导致多个月的水深火热,并造就我使用
更好的方法来撰写程式,我将在本文的第二部分进行讨论。
More Band-Aids: path-finding in StarCraft
I wanted to mention one more example of patching over bugs instead of fixing
the underlying problem: when StarCraft switched from top-down artwork to
isometric artwork, the background tile-graphics rendering engine, which dated
back to code I had written in 1993/4, was left unchanged.
Rendering isometric-looking tiles using a square tile engine isn't hard, though
there are difficulties in getting things like map-editors to work properly
because laying down one map tile on another requires many "edge fixups" since
the map editor is trying to place diagonally-shaped images drawn in square
tiles.
While rendering isn't so bad, isometric path-finding on square tiles was very
difficult. Instead of large (32x32 pixel) diagonal tiles that were either
passable or impassable, the map had to be broken into tiny 8x8 pixel tiles -
multiplying the amount of path-searching by a factor of 16 as well as creating
difficulties for larger units that couldn't squeeze down a narrow path.
Had Brian Fitzgerald not been a stellar programmer, the path-finding problem
would have prevented the game from launching indefinitely. As it was pathing
was one of the problems that was only finalized at the end of the project. I
plan to write more about path-finding in StarCraft because there are lots
interesting technical and design bits.
更多的OK蹦: 星海争霸的路径搜寻
我想再举一个例子关於宁可使用补丁修正臭虫,也不要尝试去修正底下的问题。当星海争
霸从鸟瞰图喘变成立体投影图,背景的砌块式图像绘图引擎可追溯至我在1993/1994年撰
写的程式码,分毫未改。
使用方型砌块绘出立体投影的砌块并不困难,但要让地图编辑器正常运作仍有相当的难度
,因为将一地图砌块放在另一个砌块上面,需要大量的"边缘修复",因为地图编辑器尝试
将对角线形状的图像绘於方型砌块上。
绘图没那麽糟糕,在方型砌块上的立体投影路径搜寻非常困难。不使用分成可通过及不可
通过大的(32x32像素)对角线砌块,地图是以小的8x8像素组成 - 使得路径搜寻以16倍的
数量级成长,而且造成较大的单位没有办法挤进狭窄的路径。
要不是Brian Fitzgerald是一位一流的程式设计师,本来路径搜寻的问题将使得这款游戏
永远无法上市,路径问题直到专案收尾阶段才解决。我计画写更多有关星海争霸的路径搜
寻的内容,因为在技术上或设计上都相当有趣。
End of part 1
So you've heard me whine a bit about how difficult it was to make StarCraft,
largely through poor choices made at every level of the company about the
game's direction, technology and design.
We were fortunate to be a foolhardy but valiant crew, and our perspicacity
carried the day. In the end we buckled down and stopped adding features long
enough to ship the game, and players never saw the horror show underneath.
Perhaps that's another benefit of compiled languages over scripted ones like
JavaScript - end users never see the train wreck!
In part two of this article I'm going to get even more technical and talk
about why most programmers get linked lists wrong, then propose an alternative
solution that was used successfully for Diablo, battle.net and Guild Wars.
And even if you don't use linked-lists, the same solutions carry over to more
complex data structures like hash tables, B-trees and priority queues.
Moreover, I believe the underlying ideas generalize well to all programming.
But let's not get ahead of ourselves; that's another article.
Thanks for reading this far, and sorry I haven't yet discovered how to write
concisely.
filed under: game design, programming tagged with: starcraft
第一部分的结尾
关於制作星海争霸有多困难这件事,你已经听我大吐苦水,很大一部分是因为公司的每一
个层级对於游戏方向、科技以及设计,作了错误的选择。
我们很幸运我们是一支铁头又强悍的团队,且我们的洞察力让我们赢得最後的胜利。在收
尾阶段,我们继续埋头苦干,并停止增加新功能,确定游戏时间够长,可以推出了。玩家
绝不会发现底下发生的恐怖事情,或许这是编译式语言另一个胜过像是Javascript这种脚
本语言的地方 - 终端使用者绝不会看见火车失事!
在这篇文章的第二部分,我将会谈论更多技术性的话题,并讲述为什麽大部份的程式设计
师总是把链结串列搞砸了,接着提出成功使用於暗黑破坏神、battle.net以及激战的另一
种解决方案。
即使你不使用链结串列,相同的解决方案甚至会使用更复杂的资料结构,像是杂凑表、
B树以及优先伫列。我相信基本思想足以概括所有的程式设计面向。但让我们慢慢来,那属
於另一篇文章的内容。
谢谢你读到这里,很抱歉我还不知道如何写得简单扼要。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 111.251.232.70
※ 编辑: zabiak 来自: 111.251.232.70 (09/10 22:42)
1F:推 dl4303:推 09/10 22:42
2F:推 std94003:推推 09/10 22:47
3F:推 doom3:END推 09/10 22:50
4F:推 KYPKYPKYP:学过程式推 好猛阿~ 09/10 22:51
5F:推 justastupid:好神 英文也太好了 09/10 22:53
6F:推 Vett:看到linked list的死当 真是妙到一个不行 09/10 22:54
7F:推 huggie:赞赞赞!! 09/10 22:55
8F:推 suwilliam:人家是这样坚持品质(烧钱)反观国内......难怪被韩国超车 09/10 22:56
9F:推 OSDim:楼上那是员工自主卖命阿,哪有烧钱 09/10 22:59
10F:→ OSDim:感动 09/10 22:59
11F:推 bbyan:所以在世界末日之前玩不到虫心了吗 QQ 09/10 23:01
12F:推 moongloaming:不解释了~ 09/10 23:03
13F:推 derswarm:推 翻得真好 09/10 23:05
14F:→ dakkon:虫心也才刚beta,就算不用六个月.四个月也总是要的 09/10 23:06
15F:推 cji4284503:这麽认真翻译只能推了QQ 大感谢!!! 09/10 23:07
16F:推 ck321:好强喔 真想看他们写的程式 TAT 09/10 23:07
17F:推 Sechslee:不推不行 09/10 23:09
18F:推 crazymagic00:英文推推推推推推推推推推!!! 09/10 23:09
19F:推 PTTco:CS的只能推了 09/10 23:10
20F:推 imunknown: 09/10 23:10
21F:推 VenceYen:同为RD只能泪推... 09/10 23:12
22F:推 MaySnow2010:写得很好,翻译也很棒!!值得鼓励,大推!! 09/10 23:13
23F:→ VenceYen:不过现在开发应该会更容易 09/10 23:13
24F:推 Sechslee:"只有在合理的工时下,才可以完成品质更好的作品。" 09/10 23:18
25F:推 hahahaha5438:星海争霸之始---> 稳定度"剩"过其他同业的前作 09/10 23:19
26F:推 zseineo:推 09/10 23:19
27F:推 nilson847552:"只有在合理的工时下,才可以完成品质更好的作品。" 09/10 23:20
28F:推 oscarss07:这麽长的翻译只能推了 09/10 23:20
29F:推 Puser: 09/10 23:20
30F:推 jhunfong:推翻译!!!! 09/10 23:23
31F:推 wtao: 原来Diablo 太成功 让SC1完整了才敢上架@_@ 09/10 23:27
32F:→ wtao: 果真成也Diablo 败也Diablo 09/10 23:27
33F:推 Lioli:大推翻译官 09/10 23:29
34F:推 paul81611:推高品质翻译! 09/10 23:35
35F:推 CaTkinGG:推!看到错误的设计方向让之後的臭虫只能贴OK绷心有戚戚焉 09/10 23:41
36F:推 always123x:专业推 09/10 23:43
37F:推 FAlin:翻译专业推!! 09/10 23:45
38F:推 Infernity:超扯!! 09/11 00:01
39F:推 aCCQ:推~ 09/11 00:05
40F:推 bobjohns:我觉得SC1做的比SC2好 光 音效跟图 就赢了 09/11 00:19
41F:推 only1032:感谢翻译 09/11 00:22
42F:→ wtao: BZ 以往的音乐都很用心 几乎都很有特色独创 09/11 00:29
43F:推 yuiweq1999:大推翻译~翻得好好看噢QQ 09/11 00:39
44F:推 Emerson158:"想要从头开始时,请不要抱着这次会做得比第一次好的想 09/11 01:30
45F:→ Emerson158:法。" ...有深刻体会过 09/11 01:31
46F:→ Emerson158:话说这才是有料的工程师阿... 09/11 01:32
47F:推 jackalin2002:让我一直想起八挂那篇 讲德国人精神跟台湾人精神... 09/11 01:42
48F:推 rssai:SC1真是难以跨越的巨墙~~SC2目前也难以超越 09/11 04:23
49F:→ photopanda:里面提到的两家游戏公司/工作室都被EA吃掉了,回不来了 09/11 04:52
50F:→ photopanda:万恶EA还我Origin跟西木头啊! 09/11 04:52
51F:推 LZong:原来SC1的程式设计上是这麽可怕的东西... 09/11 07:43
52F:推 PanXPan:推! 09/11 10:02
53F:推 oceanocean:太不简单啦~推推 09/11 13:44
54F:推 little76d:推翻译 09/11 14:00
55F:推 carlk:推翻译太强大了= = 09/11 14:37
56F:→ OpenSolaris:同是RD帮推,虽然有些还不是看得懂。 09/11 15:57
57F:推 onelife:好文推~ 原po愿不愿意也转录到GameDesign版? 09/11 19:55
58F:→ zabiak:忘了说 大家可以随意转录 进行交流 但这篇文章应该会被 09/11 21:05
59F:→ zabiak:疯狂吐槽 因为我没有任何开发游戏的经验 对於电脑绘图理 09/11 21:06
60F:→ zabiak:论也是一窍不通 XD 09/11 21:07
61F:推 losesong:很详实的心路历程 推! 09/12 11:40
62F:推 Falldog:推 09/12 16:00
63F:推 onelife:感谢同意转录~ 09/12 21:32
※ onelife:转录至看板 GameDesign 09/12 21:32
64F:推 LCamel:辛苦罗 ~~ ^^ 09/14 13:23
65F:推 uluvu0:大型专案总是有这些教训,而人们总是学不会教训。 09/14 23:27
66F:推 godead236:专业翻译!! 09/15 12:36
67F:→ j9145:吵架大会跟决定吃午餐真得是程式都不想面对的事情XD 12/11 18:33
68F:推 lucien13:推~~ 06/29 12:22