wine源码分析(IndieDevStory独立开发经历复盘)
wine源码分析(IndieDevStory独立开发经历复盘)我计划在一个月内做完这款游戏,但我的工作很忙,每周都要加班到夜里11点。最终,我利用晚上或凌晨上床睡觉前时的1到2个小时,大约用了两个月完成了游戏。这还是很不容易的,因为这个时间我已经很累了,有时候你需要一些时间去进入状态。然而,同时我觉得在其他方面来说这也是有益的。每次我开始的时候,我会玩游戏,并清醒地记下可以使游戏整体更好的地方(音效,UI,动画等等)。我经常会在一些费时费力的大改动之前先做一些小的变化当作有趣的热身。时间表Indie Dev Story是一款独立开发者点击冒险游戏,就像是我和其他人一些经历的传记,例如睡在地下室的地板上来获得办公空间并最终得以在Steam上发布游戏。游戏中的角色基于与我一起工作的团队里的同事,你所购买的所有物品都与我的经历有关!为什么是点击类题材?我想要的疯狂的感觉,是独立和努力平衡一切,在你的游戏中工作,支付账单,睡个好觉,保持身体健康和开放社交。我
文/James Rowbotham
译/喝喝喝水
我叫James,是一名独立游戏开发者。目前我在与朋友一起建立的工作室做些大型游戏,同时在空闲时间自己独立制作一些小游戏。我享受这种在团队中制作大型游戏的挑战,也会在独立小型游戏中寻找乐趣,通过更短的开发周期来学习提升及保持动力。这是我第一篇项目回顾,或许对别的开发者来说会有趣,同时也能帮助我回顾整个过程。
Indie Dev Story是什么?
Indie Dev Story是一款独立开发者点击冒险游戏,就像是我和其他人一些经历的传记,例如睡在地下室的地板上来获得办公空间并最终得以在Steam上发布游戏。游戏中的角色基于与我一起工作的团队里的同事,你所购买的所有物品都与我的经历有关!
为什么是点击类题材?
我想要的疯狂的感觉,是独立和努力平衡一切,在你的游戏中工作,支付账单,睡个好觉,保持身体健康和开放社交。我曾经玩过Cookie Clicker和Clicker Heros,我喜欢他们的难度,但是我注意到当玩家深入游戏的时候会逐渐失去兴趣。所以在Indie Dev Story里我想做一个短暂又甜蜜的关系,目的是通过大约八分钟的时间玩家从一个地下室开始创业到上线你的游戏。
时间表
我计划在一个月内做完这款游戏,但我的工作很忙,每周都要加班到夜里11点。最终,我利用晚上或凌晨上床睡觉前时的1到2个小时,大约用了两个月完成了游戏。这还是很不容易的,因为这个时间我已经很累了,有时候你需要一些时间去进入状态。然而,同时我觉得在其他方面来说这也是有益的。每次我开始的时候,我会玩游戏,并清醒地记下可以使游戏整体更好的地方(音效,UI,动画等等)。我经常会在一些费时费力的大改动之前先做一些小的变化当作有趣的热身。
下图是我在火车上写下的最初想法。
引擎以及艺术风格
我用过虚幻4引擎,因为我知道它确实很好,它强大的功能和预设对不懂C 的人来说真的很棒!至于美术风格,我想要尝试一些新的东西,所以我选择了体素风格,因为我认为它干净简约的风格与游戏简单的操作比较搭调。
下图是我参考过的风格。
建模
我考察了很多体素建模软件并最终选择了MagicaVoxel,你可以在这里下载它。我在MagicaVoxel中建模然后把它们保存为obj,然后导入3DS Max稍加调整。我把它们转成可编辑多边形,把顶点焊接在一起,并应用了粗糙角平滑组。我在想要不同颜色的地方设置了不同材料ID的多边形。我发现我可以基于其位置用UVW展开来选择多边形组,然后折叠UVW修改器并选中多边形,从展开中的选择会依然存在(这比手选每个多边形更快),接着从这设置材料ID。接着我把mash导入到虚幻引擎里,并在引擎中用材料着色。我创建了一个简单的主材料,用于更改基本颜色,然后再创建材料实例。我使用这种方法在游戏中使用纯色进行网格化,而不必进行任何解包。这允许我可以在引擎运行时更改颜色,而不是重新导入和花时间去鼓捣纹理。我也想到添加一个基本颜色的不透明纸张纹理,但我最终不这么做,因为我不得不解开一切才能用另一个UV通道。
动画
角色是用同样方式制作的。在MagicaVoxel建模,在3DS Max里绑定骨骼设置关键帧。一般来说,在10帧里我做了3或4个关键帧,Frame1和10是相同的用来循环,然后根据动画,围绕Frame4和6设置关键帧。我试过为了重叠和期望加帧,但是动画很快很鬼畜。在一些动画中,我在一些姿势上停留几帧来强调运动,例如举重健身动画。如果没有停顿看起来就不真实。我也试了阶梯插值但是更喜欢在自动样条曲线运动上改一点用。
我在一个max文件里试着用Biped骨骼图层来保证动画条理清晰。首先创建一个基本空闲动作图层例如FitnessIdle01,导出它,接着在顶部创建另一个图层,在顶部为实际运动添加一些简单的键,可以命名为FitnessAnima01,完成后,关闭这些图层的可见,并重复重新开始一个新的。为了适应我想在引擎中播放动画的方式我做了两个独立的动画。在虚幻引擎里,我通过动画蓝图来移动动画,使用1维混合空间,从Idle空闲状态到循环的移动的动画。我可以通过动画蓝图状态机完成任务动画,但我觉得会很混乱,所以我改用了蒙太奇,我会播放动画,然后让它进入循环的空闲状态动画。
以下两张图为1维混合空间示例以及蒙太奇设置。
虚幻蓝图
在游戏程序这块,我用了虚幻引擎的蓝图系统(像一种可视化代码),虽然它看起来很乱,但是对于不熟悉C 的人例如我来说真的是太棒了。在这我很难显示代码,因为跨越了很多地方和功能,几张图说不清楚。所以,我试着解释一下我怎么做以及做了什么功能,和一些我发现的有用的东西。我写的代码核心是:Player Controller,Player Character,HUD,购买部分,End Screen Widget游戏结算,以及AI部分。
Player Controller
角色控制器是最重要的部分。它包括所有的时间日期控制的功能,是我储存我最重要的变量的地方。它控制着游戏的核心:游戏状态,UI商店刷新,灯光开关,AI自由职业者来来往往的运动,租金账单,成就部分等等。
Player Character
我用Player Character处理绑定到控件的各种事情,例如填写任务条值告诉所有AI该放什么动画了(通过蒙太奇)。通常,Player Character把信息传给Player Controller来储存,或者把信息直接发送给要显示的UI控件。
HUD设计以及End Screen Widget游戏结算部分
HUD是统筹代码的另一个重要的部分,因为它是前端显示并与玩家之间直接交互。很多信息借此反复传递,例如Player Controller和Player Character。我试图限制这里的功能,而是让它更多地处理数据,使得对玩家来说一目了然。举一个例子,就是用append方法把值连接在一起,使它们更清晰,例如加一个£到金钱上使你可以看的见(注意你只能通过字符串调用append)。End Screen Widget就有更多的功能。创建它时,它从Player Controller和Player Character那里抓取它需要的值,结算分数并显示出来,我不确定,但我觉得这不太好,我觉得如果是在Player Controller那里调用会更容易访问,但是它只被调用一次,所以我觉得还是可以的。
购买部分Buyable Widget
由于游戏中每个可购买的项目都需要一个单独的小部件,如果我为每个可购买项都做一个小部件,那么当我想改动某些东西的时候就简直是噩梦。我在游戏场景里一直用的小技巧是,每当我有一个部件将被使用两次以上时,我就做一个“子部件”。最初设置这些时可能有点麻烦,但当运行时它意味着你只需要改动父部件即可,它会影响到下属的所有实例。在可购买的小部件中,我创建一个可被外部调用的int变量(通过单击眼睛图标)。然后使用这个值来驱动窗口部件中的功能。在部件外观的关闭部分我用int值开关控制。关闭按钮我也做了同样的事情,通过int值控制开关来反馈正确的功能,例如首先执行一个简单的检查,看看你是否有足够的钱。
创建你想要的新的Widget。
添加一个可外部调用的int变量(眼睛图标),然后关掉并设置你的小部件的外观。
在按钮点击中使用相同的int值作为开关(我在购买功能里有一个基于int值的开关)。
Ai Characters
玩家控制的角色,他的朋友,以及所有自由职业者都以相同的方式工作,只是主要角色稍微复杂一些。我没有用行为树,只是用了Ai Move To node移动到节点。主角的朋友以及自由职业者由Player Controller统一生成,我用他们的event事件开始播放驱动他们的大部分功能。它们会抓取世界上当前适当的位置,然后使用Ai Move To node导航到那里。完成这一步后,我再将他们旋转到正确的方向,然后开始检查他们的功能以及循环播放动画。当他们离开的时候,Player Controller会检查当前所有世界上的AI,告诉他们完成了工作,然后他们回到起始位置,并成功销毁自己。
下图为Ai Characters功能实例。
定时器
我发现的一个很酷的并且我也用了很多次的东西就是定时器()。最初我用tick,bool,以及do-onces来运行循环功能,但是我在很多地方读到应该尽量避免用tick,可能有潜在的危险。使用定时器功能,你可以设置它在X时间之后调用自定义事件(也可以是循环),这使得更加高效。我在游戏中的许多地方都使用它,例如左下角玩家的心情值。开始时我先把这些关闭来连续循环播放。你也可以暂停计时器,我发现的唯一问题就是,你不能通过他们提供变量,但我挺需要这个,所以我选择仅仅得到信息,而不是直接反馈给自定义事件。
玩家心情值中运用定时器功能的示例。
我想要调用的自定义事件的示例。
未完待续……