作者NDark (溺於黑暗)
看板GameDesign
标题[心得] 容易被遗忘的游戏设计模组(3)
时间Fri Feb 5 18:20:22 2010
作者:NDark
时间﹔201001
http://wp.me/pBAPd-a4
"容易被遗忘的游戏设计模组"之三:Resource/Stage Paragraphing
http://blog.zhieng.com/wp-content/uploads/2009/10/warcfrat_loading.jpg

我想大家都看过进游戏之前,或是从游戏大厅进入战斗时的读取状态跟读取条。
不知道有没有人想过,为什麽不在程式开始的时候就把所有东西读进来。
这样游戏过程不就不用等待了吗?
也许这个问题太笨了。
OK,
以关卡制为例,我们不用在第一关开始的时候就把第二关的场景读进来。
(这样做造成了第一关开始要读入的资料变少了。只是把资料读取延後到第二关。)
以MMORPG为例,还没有跨到下一区的时候也没必要读入那一区的场景。
因为那对於主记忆体都是一个浪费,
不如把资源省下来给目前正在使用的场景让他有更多的多样性。
一定有人想过MMORPG在快接近第二区的时候就开始偷偷预先读资料的设计。
避免游戏中的停顿是非常重要的设计,
有时候差那个几秒,对使用者来说就会累积不耐烦。
因此有些人在读取资料的时候用动画,用读取条来"安慰"使用者。
或是先读入小部分的资料,用预先设计好的即时动画,或飞览来让使用者再多等一下。
这边不是要讨论如何制造这些安慰剂。
而是用几个事实说明分段的重要性。
.如果把资料全部在一开始读入,那麽程式开始可能要读10分钟。这恐怕是个灾难。
但是如果分成3分3分4分读入,使用者也许就能接受。
.只让主记忆体塞满目前要用的资料为目标,那麽这空间就很可观,
可以让你的场景丰富起来。意思是同一时间能呈现的多变性够多。
.资源是有限的,让尽量多的使用者的电脑都能玩是一件重要的事情。
无论使用者的主记忆体与显示卡有多low。
确认了分段的重要性
那麽,确实来说要怎麽分段?
大部分的游戏都包含这样的结构
主选单模式:还没进入游戏,大部分是让你选择要继续上次的进度还是新游戏。
资源与游戏模式是几乎豪无相关。
游戏模式:主要的场景,大部分的游戏时间在的模式。
战场模式:或是次游戏模式,从主游戏切换至的游戏模式,
场景与主游戏不相关,但是资料是相关的。
注:有时会只分两段,也就是主选单-游戏
因此我们的游戏应该怎麽执行?
1)-读取主选单的资源-主选单模式-释放主选单的资源-进入2
2)-读取游戏模式的资源-游戏模式-释放游戏模式的资源-进入1/3
3)-读取战场模式的资源-战场模式-释放战场模式的资源-回到2
延伸思考
如果考量到"安慰剂"的话上面的状况会变成怎样?
意思是在真的开始大量读取资源之前一定有一些事情要作吧。
注:这边我定义的资源与资料有点不太一样。应该不用我多作说明了吧。
到此所讨论的东西我把他称之为Resource Paragraphing,
主要是为了资源分配最大化(後述)为考量的。
我在沙漠商旅C的时候用的stage稍微细一点,分别是:
system initalization:程式开始,将游戏系统初始化中,把主选单的资源读进来。
system pre-main menu:游戏系统已经读入了基本的元件,或是已经初始化完毕。
在主选单前会有一些必要的东西。
请思考一下这段使用者看到什麽。
main menu:主选单,举凡列出读档清单与新游戏挑选角色。
load level:读取关卡资源,开始进入游戏模式了。
game starting:游戏开始中。
game playing:游戏进行中,请思考一下跟starting有什麽不一样。
load battle:读取战场资源,进入战场模式
game battling:游戏战斗中。
back to play:自战场回到游戏模式。这是第二种进入游戏模式的方法。
back to main:自游戏模式回到主选单。大量的资源被释放了,
这是第二种进入主选单模式的方法。
pausing:暂停状态。
exiting:从主选单或是从任何状态离开程式的时候,连游戏系统的物件都被释放了。
延伸思考
暂停状态是什麽暂停了?什麽没暂停?
如果主选单太久没动作会自动播放动画,那麽要怎麽修改?
战斗之後的结算画面应该是哪个stage?或是额外的stage?
注:沙漠商旅C的结构是
平台程式承载游戏系统物件 游戏系统物件再承载游戏资料如图:
http://ndark.files.wordpress.com/2010/01/caravaneerclone-system-graph.jpg
但平台程式负责将游戏资料绘出
且平台程式负责互动处理。恩...大概很像是MVC的架构。
(没听过这个的後述)
注:这些分段如果大部分的游戏都存在这样的设计,
是否我们可以在每个游戏设计专案开始之初建立一个架构?
这也是我写这几篇文章的起始动机。
曾经有位非游戏界的软体工程师问我,multi-thread在游戏程式设计中有没有用。
我回答他:"有用,但不是最重要的。因为游戏设计开始之初,都是单执行绪的。"
当然随着时代进步,开始有多工软硬体环境(如Sony PS3就是多工硬体),
但是那都是加强运算的能力,而非加强游戏程式设计的本质。
我们接下来都先假设我们只有单执行绪。
再进一步讨论之前,
我要先介绍codeproject.com的一篇文章。
SK Genius 的 "Game Programming - One"
http://www.codeproject.com/KB/game/skgameone.aspx
他介绍了一个十分简单却重要的游戏流程。
请翻到"It's All About Timing"下方的程式码。
我们可以看到,在一个单执行绪的流程中,游戏是一直反覆着在作相同的几个步骤。
GetInput()
PerformLogic()
DrawGraphics()
这三步骤基本上涵盖了游戏程式设计的主要工作:控制,资料/流程,绘图
也就是Control,Model,View。
(与一般视窗软体不同的是,
游戏进行中即使不输入,流程本身也是一直在进行控制=改变的。)
当然复杂一点的游戏流程会作比较多的步骤。以沙漠商旅C为例,依序为
1.FPS计算,
2.网路处理(未完成预留),
3.3D动画(未完成预留),
4.更新位置,
5.2D动画(未完成预留),
6.输入事件,
7.碰撞侦测,
8.环境变化(读档,游戏事件处理,更新3D视野,更新2D选单),
9.人工智能,
10.绘图前处理(未完成预留),
11.绘图(设定3D视野,画3D物件,设定平面视野,画2D选单)
注:这些流程的顺序当然并非一定得这样排,而且一定可以找到更好的排法。
很希望未来有机会可以跟各位讨论这个问题。
因此,我们有主要流程,每个画格都作一样的事情-执行了1,2,3...的步骤流程。
再加上还有一开始讨论的stage,就是不同的阶段下我们的流程应该作不同的事情。
那麽这两个该怎麽组合在一起?
最Naive的做法当然就是把各个阶段当作不同的游戏,甚至是不同的程式。
毕竟它们的流程是真的不一样。因此这样的主流程会像这样:
-以Stage(阶段)为经,以Process(流程)为纬
MainLoop
{
switch( StageNow )
{
case system initalization :
GameLoopSysInit() ;
case game playing :
GameLoopGamePlaying() ;
...
}
}
但是,
我们会发现其实每个阶段中都会有相同的工作要作,
这一种方式简直就是把同样的事情重复作好几次。完全不符合程式设计偷懒的本质。
因此接下来我们就要跟各位讨论本篇主题的第二个部分Stage Paragraphing。
-以Process(流程)为经,以Stage(阶段)为纬
我们的流程变成这样
MainLoop
{
InputHandling() ;
...
EnvironmentChanging() ;
...
DisplayMain()
}
MainLoop里面的各子函式就都可以变成这种形式
(*)SubFunc()
{
switch( stage )
{
case game playing :
...
break ;
case game battling :
...
break ;
}
}
这样作的好处是有时候 相同的流程可以用在不同的阶段。
譬如说
主选单模式的stage,游戏模式的stage,与战场模式的stage都有画选单的流程
而且这些流程基本上是做相同的事情-画出目前需要的选单。
因此在画选单函式就可以合并成这样。
RenderMenu
{
switch( stage )
{
case main menu :
case game playing :
case game battling :
DrawAllValidMenu() ;
break ;
}
}
坏处是,结构改变的时候,
a) 当原本合并的两个stage要分开,或是
b) 原先没有必要进行因此忽略的stage突然需要,却忘记修正这个分段结构。
就会造成除错的风险。(A)
简单来讲,如果开发团队没办法完全掌控好这结构就容易造成维护上的困扰。
分段结构造成的影响是
a) 极大化同样的程式-若是相近的流程运作,却因为小处的不同而刻了两段类似的程式
,反而会造成未来维护上的更大危机。
b) 强迫游戏开发者去开发通用(robust)的元件,来符合这个分段结构。
注:这边的"更大"指得是相较於上述(A) "忘记修正这个分段结构"
讲了这麽多,最後作总结。
虽然有点抽象,但请试着想像一下
一个好的分段就像一个"压缩率"的比例,同时压缩资源/程式码/风险
这个分段的做法保持了一个原则:
"将相同的事情变成同一件事,将不同的事情尽量分开"。
(刚好符合程式设计模式的大概念。)
假设优秀的分段可以让效能发挥到0.3的压缩率。
而没有分段时压缩率为1.0。
当硬体进步时100分的硬体等於塞进了100个未压缩的物体
有分段的结构就是塞进了100/0.3=333个物体。
当硬体效能1000的时候,比值就是 1000比3333
高压缩率的设计方式可以让在同等硬体平台同样的人力工时运作"开发"这件事情的时候,
获得超越对手的(虚拟)硬体/游戏内容。
这听起来既模糊又显而易见。
事实上就是一个永无止尽的军备竞赛-游戏开发工厂的输入与输出。
输入的是code或是PG的工时,输出的是游戏效能。
质的改变最终造成量的改变。
--
"May the Balance be with U"(愿平衡与你同在)
视窗介面游戏设计教学(
http://0rz.tw/V28It ),讨论,分享。欢迎来信。
视窗程式设计(Windows CLR Form)游戏架构设计(Game Application Framework)
游戏工具设计(Game App. Tool Design )
电脑图学架构及研究(Computer Graphics)论文代读(含投影片制作)
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.96.77.176
※ 编辑: NDark 来自: 140.96.77.176 (02/05 18:20)
※ 编辑: NDark 来自: 140.96.77.176 (02/05 18:20)
1F:推 silveriii:头推!! 受益良多 02/05 18:34
2F:推 elfkiller:这篇超重要 大推 02/05 18:56
3F:推 ddavid:推! 02/05 19:08
4F:推 scornn:推~ 超棒的~ 02/05 20:23
5F:推 linjack:推! 02/05 21:01
6F:推 marksswy:谢谢~~~~ 获益良多阿 02/05 21:02
7F:推 zzzdeath:推!几个月前把游戏放在360上时也卡这问题卡许久Q_Q 02/05 21:11
8F:→ adxis:一点想法 我觉得分段有一部分是为了较有弹性的资料驱动方式 02/05 22:20
9F:推 chrisho:感谢分享一系列的文章, 我可以拜一下吗? >< 02/06 12:34
10F:→ kenzou:thanks for your share. 02/08 02:27
11F:推 zxcmoney:推 03/11 19:47