|
作者:Herman Tulleken
在2013年11月份,我和两个同事制作了30款游戏。虽然我之前做过一些游戏原型,但在如此短暂的时间内制作这么多游戏还是让我获得了之前所没有的收获。正如我对好友所说的,这就好像在数天内看完一部电视连续剧,而不是每周定期看一集——你会有不同的体会。
我在以建议的形式综合了自己的一些观察和心得。我想也许有不少读者已经看过《如何在7天内快速创造游戏原型》这篇文章。从某些方面来说,本文是该文章所呈现理念的一个编程扩展版(如果想了解更多创建原型的文章,还可以看看《如何在30天内制作了30款游戏》这篇文章)。
proto2(from gamasutra)
A.快速是一种心理状态
极为快速地制作内容有许多乐趣。日常开发可以是缓慢的过程,因为离最终的产品成型还有数月(甚至数年)时间呢。在你的闲暇时间捣鼓一个理念,可以让你获得一些见解,但其结果却不甚明朗。
快速创造原型可以让你获得即时的满足感。它让你专注,让你投入精力并加快速度。
但你应该摆脱开发模式,以及捣鼓模式。你得知道自己将会把作品抛置一边,并浪费一些精力。你得知道有时候你并不需要最佳决策——你只要直接让它成型即可。你得摆脱完美主义和细节情结。
你得抓住核心。
了解和记住目标
创造原型的原因多种多样,以下是其中的几例:
*为在固定时间前完成一款游戏(例如游戏开发大赛)
*为找到有趣的游戏核心(例如在项目的预开发阶段)
*为从一系列选择中找到最佳理念
*为测试某一理念的技术可行性(游戏邦注:这个理念可以是关于整款游戏的理念,也可以是某项图像技术或AI算法)
最好的方法是根据这个目标来制作和制定决策。要明确这个目标是什么,并时时自我提醒。
如果某项任务并没有让你离目标更近,那就不要动手了。
找到你理念的实质,并为此安排足够的时间。
这个实质可能是一个机制,一种风格,一个主题,一个设定,一种情感体验。要找到它,然后将其从其他支持元素中区分出来。
当你安排项目进程时,要据此分配时间。如果你的实质是一种新机制,你就会希望拥有足够的时间来探索它,因为你不想把自己所有的时间用来创建关卡或编写着色器。
接受创意冒险,但要避免技术风险
如果游戏原型失败了,那应该是因为它很无趣,而不应该是技术问题(当然,当你的目标是技术原型时例外)。你想让自己的原型完工,并允许你和团队探索其实质,并其此传递给玩家。
*避免棘手、复杂的数据结构和算法
*避免复杂的系统和结构
*避免试图让制作速度更快
*避免无助于提升玩法的技术性特征
B.规划和过程
考虑内容
问问自己你的游戏为呈现一种感觉需要哪些内容:
*你需要创造多少内容?
*你将如何注入多样性?
*应该在哪个开发阶段注入多样性?
*如果你耗尽了所有时间,拥有一个注入实质内容的计划,那该使用哪些折衷方法?这会让boss成为关卡敌人的软弱版本吗?
计划
*制定一个粗糙的计划,写下统计时间。
*根据目标检查你的计划,并移除那些无法让你更接近目标的计划。
*根据你的游戏理念的实质检查计划,并核实你是否为探索该实质而分配了足够的时间。
*确定你估计最可能完成的环节。牢记折衷想法,考虑减少他们的影响/角色/复杂性。想想占位符策略。
遵从一个执行策略,但要根据创意过程进行灵活调整。
以下就是我建议你遵从的次序。要谨记其中的相关性。
1.让屏幕显示一些东西
2.执行头个关卡游戏
3.执行用户控制方式
4.执行一个极简化关卡
5.执行一个玩具逻辑
6.执行游戏目标
7.执行AI
8.执行反馈
9.润色
创造原型并不只是编写一个规格,记住这里会有一个不成功的开端,你得及时调整。在必要情况下要更改计划和更新日程安排。
proto3(from gamasutra)
清楚和避免时间流失
有些事情就是会占用大量时间。要认识到这一点,并确保你安排了足够的时间,留有折衷办法,保持其简单性(通常的时间耗损当然与游戏类型有关)。
控制方式:在动作游戏中,控制方式可能需要投入长期时间才会具有可玩性。
平衡:在模拟游戏中,平衡很费时间。要保持系统低数量,保持低变量。并留下足够的时间进行平衡。
GUI:在信息密集型的游戏中,GUI可能耗尽你所有的时间。找到合适的音频需要很长时间——所以除非有必要,或者你已经拥有了所需的音频,否则就不要添加音频。
动画:动画可能吸收大量时间,要考虑使用捕捉姿势,或者进行合适的滑动。
程序生成内容:针对内容生成调整算法可能非常费时。与其他算法不一样的是,内容生成算法的技术参数很难制作对象。
考虑到使用系列开发(编程管道)
对于拥有不止一名程序员的团队来说,将项目划分为多个环节,并为每名程序员指派任务,以便大家平行工作是一种普通做法。
还有另一种方法不妨一试,看看它是否适合你们团队。
这种方法要求多数代码以错列的方式经手所有程序员。首个程序员将执行项目的大致框架,下一个程序员将开始填充细节,如此反复。每名程序员不只是编写一部分代码,每位程序员在一定的时间片段都要接手整个项目(当然,这些时间片段可能有所重叠)。如果你使用大量占位符,它就尤其管用。
这一方法的好处在于,减少了界面的讨论。在你的时间空档中,如果你需要更改一个界面,就可以立即更改。这不会破坏其他程序员的代码,因为你就是唯一的程序员(即使是在重叠性的时间片段也仍然管用,只是你需要更加小心,以及相关计划)。
当然其负面效果就是你所得到的设计可能非常糟糕。但这没有关系,因为设计并不重要。这看起来有点浪费,因为总有些时候某些程序员并不需要编程。
(当然,这意味着要划分编程任务:如果是同其他创意工作一同展开这项任务,那就太遗憾了。在许多创造原型的项目中,程序员同时也是游戏设计师,但这并不适用于设计师)
不要陷入僵局
有些事情可能会让你觉得受到阻碍:漏洞、难以执行的代码,不具可用性和棘手的控制方式,内容数量,关卡设计等。
当你身陷泥淖时,一定要想法脱身,并继续前进。以下是你陷入僵局时可以采用的一些做法:
*忽略那些不会破坏玩法的棘手漏洞
*砍削有问题的功能,减少内容
*使用简单的占位符算法或近似值
*使用强力检查——这是在消耗一定内存,以及在主循环(甚至是游戏)之外投入的额外时间这一情况下设计正确、快速算法的有效方法。
*伪装。那些能够响应玩家的怪物看起来就比不具响应性的怪物更智能,无论它们实际上有多智能。
*硬码。一个冗长的怪物系列比一个复杂的造波算法更容易编码。
*隐藏。
C.代码设计和执行
使用占位符代码
在任何可行的地方使用占位符代码,这样你就可以更早地转向核心玩法。当你确定玩法后,就可以有组织地用代码来替换占位符代码。这种方法的好处在于,当你所有的系统都到位,并制作核心玩法时,就更容易根据玩法影响来划分任务的主次顺序了。
以下就是占位符的一些通常候选对象。
控制:在一些游戏中,控制方式尤其重要。但如果二级控制方式不会影响玩家体验,并且更快执行,那就要先执行二级控制方式。例如,在许多滑行益智游戏中,最佳控制方式允许玩家使用鼠标(或手指)来滑动对象。这可能是一种很难执行的方法。换句话说,带有方向键或按钮的鼠标选择执行很快,能够让你更快进入其他玩法元素。
反馈:反馈很重要,它负责提供信息以及优化体验。但首先要做一些简单的操作:对话和信息,换色,闪光或喧哗声。
AI:AI很困难,我们很难预测哪种战略会奏效。以下是你执行最终算法之前可用于AI占位符的一些做法:
*随机AI
*使用简单启发法的AI可以取代预见性的AI,反之亦然,哪种方法更简便就用哪一种。
*贪婪算法(游戏邦注:这是一种不追求满意解,只希望得到较为满意解的方法)。
*无法执行所有可以操作的AI。
程序生成内容:如果你的游戏依赖程序生成内容,你可以使用以下类型的替代方法。
*固定内容
*纯随机内容
近似值:粗糙的近似值通常可能非常管用。以下就是其中例子:
*使用碰撞球体而非碰撞网眼。
*为曲线使用线性近似值。
使用设计捷径
(要慎用)在制作代码中你应该避免“万能”类,但原型中,它们可以替你节省大量时间。你不需要从作用物延伸而来的怪物或玩家,而是将所有代码导入作用物,并使用相似的切换法而非多态性。
不要相信任何比动态列表更复杂的数据结构,尤其是在你需要自己执行的时候。专注于简单、安全和便于理解的数据结构和算法。
避免错误的设计捷径
*命名规则和原型组织不变。
*不必要地暴露数据(使用公共域)即使是在短暂的一两天中也会让你受害。因为要记住将命值调整为0是否就会杀死怪物,或者你是不是还需要亲手了结它,这并不是一件容易的事。
*状态机(或任何追踪状态的东西)所需的声明远超过你的想象。如果你试图使用捷径,而不是合理的抽象法,那就很可能陷入漏洞百出的混乱代码中。
管理你的可调整内容
*让游戏在某个地方保持可调整状态,以便更容易地微调游戏。
*并非每个值都需要调整:不要害怕将其变为常量。但要让它们处于中间位置。不要使用幻数。
*谨慎命名你的可调整内容。
*当你设计一个可调整系统时,确保其中暴露的变量拥有明确而线性的作用。模糊不清的可调整内容最好要隐藏起来。最好制作一个清晰易懂,但却无法彻底控制的系统。
proto4(from gamasutra)
编写可读代码
一次性的代码不应该用最高标准来编写。
但是,它仍然要能够服务于传达你的意图,尤其是当你在团队中工作时。混乱不堪的代码会浪费大量时间。快速开发时编写代码的最有效方法就是:
*正确命名
*富有组织性
*避免深度分层和复杂的依赖性
*保持方法的简单性
*限制“智能”类的数量。智能类是处理游戏逻辑的方法。在小型、不稳定的项目中,最好是集中化逻辑,并保存用于展示的助手类。这更易于制作快速调整。只要你保持方法的简短性。
使用执行模式
执行模式是一种做事的标准方法。例如,以下这个游戏主要文件的执行模式:- public void Start()
- {
- Reset()
- }
- public void ResetGame()
- {
- currentLevel = 0;
- ResetLevel();
- }
- public void ResetLevel()
- {
- DestroyObjectsFromPreviousPlay()
- InitialiseVariables()
- BuildLevel()
- InitGameState()
- }
- public void Update()
- {
- ProcessGameFlowInput(); //Reset or next level
- if(gameOver) return;
- ProcessGamplayInput(); //player controls
- UpdateContinuousGameState(); //movement, AI, etc.
- gameState = GetGameState();
- if(gameState == GameState.Win) WinGame();
- if(gameState == GameState.Loose) LooseGame();
- }
- private void NextLevel()
- {
- currentLevel++;
- ResetLevel();
- }
- private WinGame()
- {
- ShowMessage(“You win”);
- EndGame();
- }
- private LooseGame()
- {
- ShowMessage(“You loose”);
- EndGame();
- }
- private EndGame()
- {
- gameOver = true;
- }
复制代码 通过使用标准,你将减少用于思考,以及争辩替代性方案的时间。执行模式对制作代码也很有用,但创造原型模式却有所不同:它们强调简单性和明确性,而不是面向对象编程的重用和有效性。
你可以经常设置像模版一样的模式,这样你就可以在创造原型时使用。
另举一例,以下是一个随着时间发展更改一个变量值的执行模式:- private IEnumerator ChangeSomething(thingToChange, initialState, finalState)
- {
- float timePassed = 0;
- Set(thingToChange, originalState);
- bool finalStateReached = false;
- DoThingsAtStartOfChange();
- while(!finalStateReached)
- {
- timePassed += Time.deltaTime;
- if(timePassed >= time)
- {
- timePassed = time;
- finalStateReached = true;
- }
- Set(thingToChange, Lerp(originalState, finalState, timePassed / totalTime);
- yield return null;
- }
- DoThingsAtEndOfChange();
- }
复制代码 D.之前,之后,之间
如果你经常创造原型,你就可以利用这一优势,在创造原型的空隙做一些事情。
反思
在你完成一个原型时,做一份事后分析报告,并鉴别其中的好坏经验。在你开启下个原型项目时简短地回顾其中的要点。
创造一个促进快速创造原型的代码库
这不同于制作项目的库。你可以使用有点低端的技术,或者制定一些平台假设,或者使用其他你无法正常使用制作代码的技术。
例如,我们在自己的许多游戏中通过利用像素纹理来,而不是使用精灵来渲染网格。这个方法适用于创造原型,但对最终成品来说太慢了。
确定执行模式,漏洞模式和时槽
在一些原型之后,你可能就会开始看出一些模式。制定一个列表,以此来指导你的库需要什么内容。
你能够在自己的以来中像模板一样编纂执行模式吗?你能否设计更好的数据结构来避免一些代码漏洞模式?你能否在一个时槽中,通过添加库的内容而让自己获得有利的开端?
翻译:游戏邦
|
|