自研引擎二三事

酝酿了许久,想仔细回忆一下故事从哪里说起——我想,关于游戏开发和造轮子这件事,大致在初高中时便埋下了种子。那会儿自己和周围的同学们都是资深老二刺猿,有一部动漫经典作品叫《刀剑神域》,关于完全沉浸式VR的幻想以及使用游戏为媒介创造出一个完全虚拟的世界这种东西,对于青春热血的理工科少年来说简直有着难以想象的诱惑力,于是乎,中二病爆破的年纪便把在动漫里面缔造这一切的角色茅场晶彦作为了自己的偶像,幻想着自己也能有朝一日成为这种天才程序员,用代码模拟出一个亦真亦幻的世界。

真正有机会接触代码学习的时候,其实已经是脱离“做题家”身份的大学时代了,那时候想学编程但是求学无门,市面上成体系的教学课程太贵,刚开始使用互联网学习的自己又不知道从何下手搜索学习资料,于是乎,便歪打正着从一贴吧老哥那里求得了有偿的“自学辅导”。自学辅导的意思大概就是说,他作为码农前辈,给制定学习路线,提供学习资料,日常答疑解惑,但是你的主要学习过程,是要自己去学习钻研的,而不是培训课程那样的填鸭式教育。虽然这位老哥提供的学习资料其实都是免费的,但是对于一开始搜刮情报能力极低的自己,这无疑是莫大的帮助。 这个过程自然是有偿的,不过经过一番讨价还价,那位老哥大概是本着副业从小本生意做起的原则,同意我对一共3K的学费分10期付完,这样固定每月300的学习费用便由我自己从生活费里面挤出来。

那段时间的学习是从Java入手的,倒也合理,那些年市面上热度最高的行业大多都是在Java的基石上运转起来的,资料自然也是最多的。但是,慢慢地在学习过程中发现,Java后端,H5前端,Node.js,Android开发……自己的学习路线似乎与想要创造一个“虚拟世界”的初心越来越远。没办法,既然师傅不能提供这些资料,自己便尝试着用现有的技术知识去制作一个虚拟的世界。

那时候接触到的编程知识都是空洞抽象的数据,自然而然,这个项目便在仅有“数据内核”的情况下开始了设计和开发,他更像是大多数同学在初学编程时接触到的“XXX管理系统”之流的控制台程序,只有通过System.out.println产生的终端输出,而没有任何具象的画面吗,程序的体量也不大,甚至大部分内容都是在寒假回家的高铁上完成的。

CivilizationSimulationLibrary 配置文件

这个项目事实上几乎已经终结了我在这个阶段的探索,这让我第一次意识到,尽管自己已经对Java的语法和概念熟记于心,但就算是一个如此简单的纯数据逻辑程序,我却在代码的组织上无从下手,如何设计类,如何设计接口,如何抽象数据、封装逻辑……没有项目经验的加持,就算是对画面一无所知,想要仅通过数据来做一个自娱自乐的小玩具,也是举步维艰。

既然有了Java编程的功底,那就不妨去探索学习一下其他语言。一个偶然的机会我遇到了C#这门看起来和Java很像的语言,紧接着认识到的是他竟然借助.NetFramework等一系列魔法在Windows上轻而易举地创造图形化界面。“有画面了!”,这是我对WPF的第一个印象。

那时候玩的最多的游戏是Minecraft,各种登录器五花八门眼花缭乱,于是乎我便尝试着模仿MC登录器,制作了一个文明模拟虚拟世界的登录器。这个程序只有界面,而没有任何实质性的功能,是在元旦晚上完成的他,像是打开了一个新世界的我按捺不住喜悦之情,豪言壮语地发了个动态,说自己希望能在新的一年,让这个登录器点击之后出现绚丽的画面。

Cardinal 系统登录器

能做有画面的程序了!那时的我便感觉无所不能,老二刺猿之魂还没有燃尽,那段时间连着推了几部Galgame,便萌生了那时的我也能做Galgame的错觉。其实现在来看,AVG类游戏用GUI框架去做虽然有点剑走偏锋,但是实现上确实应该不是问题。尽管如此,那时候的自己却被“如何将图片打包到exe”中这种问题给卡住了,在查阅各方资料好不容易解决之后,又被”如何动态读取图片文件渲染“这种问题难住了。那时的我才意识到,WPF这种东西虽然在可视化编辑器的加持下看起来上手轻松,但是在它和蔼可亲的面孔背后,是深不可测的机制与概念,尝试着使用GUI库来做游戏的念头便再次被破了冷水。

那时候碰巧参加的“虚拟仿真”协会举办了几次关于Unity的培训沙龙,Unity这个强大且精妙的工具便再次回到了我的视野中。其实对于Unity的学习早在Java求学之前就有了解,毕竟时至今日,任何人想要通过搜索引擎之流的互联网途径查阅游戏开发相关的内容,都会看到Unity的大名名列榜首;但是无奈当初的自己并没有编程基础,眼花缭乱的界面操作又对涉世未深的自己造成了极大的畏难情绪。所以,与Unity的交锋,这时才算正式开始。

UGUI的强大加持和Unity作为游戏引擎在设计上特有的优势,让我在AVG游戏的开发上无往不利。在遇到问题时,可以随时到协会的办公室里面请教大佬学长们,虽然“在我电脑上没问题怎么到你这里运行不了”的这些情况时有出现,但是最终,一个依托于UGUI系统的AVG短篇《Recollection》便制作完成了,并成功打包到了安卓平台上;虽然由于水平有限,在布局和锚点定位上不尽完善,在不同屏幕尺寸的设备上经常会露出丑陋的马脚,但是至少,一个相对完整的游戏作品便被制作完成了。

Recollection 游戏截图

那时候的自己便信心爆棚,虽然似乎与一开始的虚拟世界模拟的初衷有所偏离,但是至少有了自己的第一个作品,成就感是难以言说的。觉察到自己力量在成长,便迫不及待地准备开始了新的挑战,也就是这个时候,我与小伙伴们一起创立了逆光游戏工作室(BacklightStudio),以现实中的戒网瘾学校的故事为蓝本,准备创造一款带有较强观点输出的青春热血向AVG作品《逆光》。

《逆光》游戏 CG 概念图

十分幸运的是,参与到这个项目中来与我一起的小伙伴们也都是那个学生时代能力与行动力爆棚的人,丹水墨银老师和他的朋友们也就是在那个时候认识的,他们一起为这部作品精心设计了人物立绘和众多细节,制作了精美的CG,参与到配音制作中的小伙伴们也都尽可能地做到了业余水平中的巅峰。

可是就在这时,一个足以改变我后续发展轨迹的抉择出现了——自己参与的创业团队将以我不能首尾相顾为由将我踢出局。此创业团队并非我的AVG游戏制作团队,而是我与大一届的学长们一起发起的“新概念”传媒公司,概念有多新呢——从终端设备到软件系统都是由我们自己设计完成的。虽然,我当时的技术能力并不能让我在团队中像学长们一样充当顶梁柱一般的中坚力量,但是至少在团队注册成为公司前,我们是最初的一批行动者和支持者,最原始的股东。而这时,就在事业稍有起色的情形下,我们却成为了兔死狗烹的那群人,在某些成员一言堂的设计下,我被迫提出放弃几乎全部股权和与项目相关的所有比赛荣誉和可能的保研机会,取而代之的是暂留其名充当团队吉祥物的角色。

自主研发的自助打印传媒终端

现在来看,我愿称之为我的游戏开发求知这条主线任务之上的一个小插曲,但是,在当时的很长一段时间后,我的手机壁纸和屏保以及聊天记录背景等所有目力可及之处,都设置成了我“自愿”放弃这一切时的耻辱对话截图,它无时无刻不在提醒我,自己的一腔热血和奋斗,是如何被算计和 被“利益最大化” 的,自己对于游戏的热爱,是付出了何种的现实代价的。

愤愤不平的情绪总是需要一个积极的发泄口的,创业团队没有我或许也可以继续进行下去,但是由我发起的AVG游戏工作室,离开了我恐怕要举步维艰。虽然那时的自己并无类似团队的组织经验,但是我相对清晰地认识到,在大家都相对业余的工作中,将自己所负责的内容做得专业,就是最大的保底。于是乎,没有故步自封满足于Unity制作的《Recollection》,我便开始了对于业界通用的AVG游戏制作工具进行了探索。从Steam上昂贵且难用的AVG Maker,到大名鼎鼎但是年代久远的Krkr(吉里吉里)引擎,再到由此发展起来的BKEngine,一直到新一代的开源引擎Renpy。直到遇到Renpy,我才似乎柳暗花明起来,原来现代化的AVG游戏制作,是这样的理念,Renpy全声明式的设计思想让我受益匪浅,甚至仅用了半个小时左右,就用Renpy复刻了当时用Unity折磨了数周的《Recollection》。美中不足的是Renpy没有可视化编辑器,于是乎我便试着用Unity制作了Renpy的可视化编辑工具,奈何自己对于Renpy的高阶知识了解较浅,可视化编辑器这个项目也就不了了之。

Renpy 可视化编辑器

由于学业繁忙外加团队进度管理经验不足等原因,《逆光》项目企划便渐渐凉了下来,以至于后续大家都十分默契地将资料封存了起来,不再进行制作有关的推进工作。这时的我,回头看来却没有丝毫沮丧,大学时代的团队大抵如此,有热血有干劲儿,但是能力有限经验不足,传统意义的成败已经不足以来评价这些事情,在这期间认识的朋友们,增长的技术和视野,远不是我墨守成规地求学所能企及的。

新冠元年网课的一学期,让我接触到了COC跑团这个神奇的TRPG玩法,在游戏制作上的怠慢让我对Web的兴趣灰复燃了起来,恰逢猫爷TRPG平台正在小范围公测,使用起来有诸多不方便,于是乎便动用了自己搭建TRPG跑团平台的想法,无奈受限于学生款服务器性能无法支持流畅的语音大厅等功能的落地,便逐渐搁置了起来。

在线 TRPG 平台

也几乎在同时,狸子Neazle老师的活字引擎刚刚开始萌动,这个本是用来制作跑团Replay的工具勾起了我在AVG游戏引擎探索上的回忆,同期RimoChan大佬的Librian引擎也给了我十分坚定的方向,想要从文字形式的台本,快速地产出AVG游戏作品,使用更接近文本的声明式脚本语言是必要的,只局限于使用引擎原生的静态开发语言(如C#)对文本进行硬编码,在灵活性和效率上都是很大的问题。一不做二不休,于是乎,我手中第一个可以称得上是“引擎”的产品,便在稀里糊涂的尝试中诞生了出来——BacklightEngine

BacklightEngine基于Unity开发,内置了一套自有标准的语法解释器,引擎脚本的语法和台本这种纯文本的形式十分相似,对资源加载、音乐播控、立绘定位、分支跳转和跨文件链接等功能都做了支持,甚至对脚本不规范使用导致的运行时异常捕获也进行了处理。就像下面这一小段脚本,便可以实现动图所示的游戏效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@showbg = school_moring.png
@showfg_mid = lifa.png 400 1200 0 -4
@playmusic = オムニバス.wav
[莉法] 能在VisualNovel的世界里见到你真的太好了~
[莉法] 接下来就让我们开始愉快的创作之旅吧!
[莉法] 首先让我们来测试一下分支指令
@tag = selections
<#flag_1> 这里是分支选择一
<#flag_2> 这里是分支选择二
<#flag_3> 这里是分支选择三
@tag = flag_1
[莉法] 你选择了分支一,记住最多只能由三个分支同时存在哦~
[莉法] 接下来我们回到重新选择分支的地方,试一下其他选择~
@jumpto = #selections
@tag = flag_2
... ...

BacklightEngine 画面效果

或许我会一直这样下去,依托于Unity这个庞大且完备的平台,将自己的游戏梦和虚拟世界梦与这个大家伙绑定在一起。但是,恰恰在这时,我遇到了一些原始的、但是闪烁着神圣光芒的东西——

起因是一位痴迷于硬件的大佬学长,决定制作自己的游戏掌机,当然是从硬件到软件一条龙设计和开发,那在Windows平台上的调试便需要大家喜闻乐见的“模拟器”,可是自己的掌机软件也是自己写的怎么办,那“模拟器”便也自己手搓一个!这不由得让我想到了那时在B站刷到的一位国外大佬,“自由”的精神也是极其相似。

不满足于Unity渲染效果自己写引擎的国外大佬

话说回来,这位学长在软件上的工作倒没有这么离谱,他专注的是硬件,那软件层面,便是一切以能用为标准的使用风格了,我想这多半也是考虑到嵌入式掌机这种受限系统吧。这位学长研发的掌机系统内核自然由C语言制作,开发脚本选择了使用Lua,在Windows平台上的模拟器程序在渲染接口的使用上便选择了EasyX(本质是GDI)。是的!就是这看似云淡风轻的交流,让我打开了全新的世界!

首先是Lua,从BacklightEngine以来,我一直寻求一种方便的、快捷的脚本来替代C#/C++这种静态语言的逻辑,而Lua的出现让我茅塞顿开,它如此的轻巧,如此的便携,如此的优雅,简直就是梦境中都没有胆量去幻想的事情! 这种惊叹现在看来似乎是有些夸张的,但是对于那时候绞尽脑汁四处碰壁的我来说,那确实是让人赞叹不已的完美解决方案;其次是EasyX,虽然在翅膀稍硬之后,我不止一次地表示,将它和游戏开发的概念挂边应该算是国内技术环境的耻辱,但是客观来讲,对于像那时的我一样的萌新,能够摆脱Unity这种大家伙,真正通过代码去一点点控制自己的渲染和一丝一缕的游戏逻辑,这不仅是神奇的,更是引人入胜的,它将带领着我走入探索游戏引擎底层逻辑的大门。

掌机模拟器 -《欧陆商人》

这才是“真正地做有画面的游戏”,之前的WPF之流都是什么歪门邪道!

于是乎,在几乎没有使用美术素材的情况下,仅通过矢量绘图硬编码制作了一款几乎没有任何玩法的回合制小游戏。正如下图所示,是的,你没有看错,“Another World”这个纯色的标题,并不是使用诸如outtextxy这类文本渲染函数输出的,而是通过线段和填充一点点绘制出来的,这并不是我对于美术素材或者的使用或是文字渲染这种东西毫无概念,更多的,我想是一种对于获得对程序细节绝对支配后的狂喜,我可以操纵每一个像素!世界,就在我眼前!我逐渐理解一切!

AnotherWorld 游戏截图

而对Lua的实践起源于我模仿着学长的掌机模拟器,在C语言层面封装了一套对Lua的EasyX渲染接口——EasyGame,尽管后面更名为了EasyDraw,仅用来处理绘图,但这个Lua库充分暴露了我对C语言和Lua交互的浅薄理解,在这个库里面,接口设计一塌糊涂,甚至存在内存泄漏的问题。虽然如此,EasyDraw的设计让我第一次对跨语言交互有了相对清晰的认知。

EasyX解决了绘图和按键交互的问题,但是游戏音乐播放的解决方案还是没有出现。在不断求索的过程中,我接触到了SDL2这个神奇的玩意儿。他不仅有SDL_mixer,SDL_ttf这些全家桶套餐,更是提供了更进阶渲染途径,随着深入了解,我才意识到自己是多么得接近行业专业的解决方案,原来有那么多游戏在SDL这个基石之上搭建起来的(如《消逝的光芒》),一个比EasyX更强大且通用的开源项目,让我第一次真正地将目光看向更远的世界。

封装是最好的学习途径!有了之前EasyGame系列库的经验,这次使用SDL2作为“引擎”内核的Lua扩展库有了全新的升级,除去渲染、交互、音频播控这些功能以外,还提供了获取操作系统内存大小和剪切板操作等系统级别的工具接口,我把这个项目叫做QGame,取Quick Game和Cute Game之意。引擎的运行时压缩后仅有2MB左右,借助图灵完备的Lua脚本,几乎可以说是无所不能——至少在那时候我看来是这样的。所谓三十年河东三十年河西,那时的我已经成为了学校虚拟仿真协会的技术部部长了,例行的技术沙龙会该分享点什么呢?那就讲如何用QGame制作Galgame游戏引擎吧!

QGame 制作 Galgame 游戏引擎教程文档截图

QGame可以说是自己第一次在GitHub上试着正式地去维护一个项目,VisualDust快乐的老鼠宝宝这两位素未相识的网友给我在GitHub的项目组织上提供了莫大的帮助,时至今日QGame的历史仓库的Readme等文档还留有他们协作过的身影XD。

QGame只有简单的图形接口,没有GUI组件怎么办?不慌,既然图形接口都手搓了,GUI框架也不差这一点半点了。NiceGUI便应运而生了,虽然GitHub仓库中现存的一版是给EtherEngine使用的,但是这套GUI风格的接口一开始是QGame系列之下的。有了GUI的支持,制作稍微复杂点的游戏界面便轻而易举了,譬如下图所示的半成品游戏《大灾变:最后避难所》截图。

NiceGUI 示例程序

《大灾变:最后避难所》游戏截图

但是我总是闲不住的,尽管QGame的质量已经决定了它不会被更广泛的社区使用,但我从自己的使用体验中便觉察到了诸多不便,其中一点便是动态链接库的形式,QGame始终将自己处于扩展地位的设计,让它的运行不得不拖拽着一个Launcher.exe,以及随着我对SDL2等库的深入实践,我越来越发觉这个项目的重构价值远大于在其💩山不断堆砌。碰巧朋友说一起制作一款类饥荒的奇幻风格荒岛求生游戏,QGame这种相对顶层的API设计在面对瓦片地形系统这种需要高度特化的功能就显得有些乏力了,我们那时把游戏名暂定为《Ether》(以太),那么新的游戏引擎就自然而然地叫EtherEngine了,谁也没有想到,这又会是一个“一眼万年”的庞大工程

其实EtherEngine还没开工多久,Ether游戏的企划便了无音讯了,对于程序主导的制作组来说,策划先于程序消逝是再寻常不过的事情了,毕竟人要吃饭,要睡觉,要应付百无聊赖的大学课程,没有利益驱使的大学生在这种事情上,即使是最亲密的伙伴,也会因为懈怠和拖延逐渐忘记出发时的目标,仅剩的,大概只有我对于“下一代”游戏引擎EtherEngine开发的执念了。

在EtherEngine初具眉目的时候,基于EtherEngine的项目DreamFramework视觉小说开发框架便也已经在筹备中了。这个项目的灵感来自于实习时导师的一句话:“游戏引擎的角色更像是给大家协作的平台。”。这话让我醍醐灌顶,一直专注于程序的我,对于引擎的认知仅局限于其程序层面封装的功能,以为只要能够简化程序开发的工作量足矣。有了之前AVG游戏开发的经验,DreamFramework设计时功能便尝试兼顾AVG项目组所有成员角色的身份,剧本演出美术程序可以各司其职。虽然想法是好的,但是最终由于接下来大四的忙碌,这个项目便也被搁置了起来。只有当年使用DreamFramework给老鼠宝宝的制作组制作的SplashScreen还诉说着当年的记忆。

DreamFramework Logo

DreamFramework SplashScreen

这时使用专门的框架设计的动画效果,相较于之前在C++层面直接将数据硬编码的开屏动画,明显丝滑了很多。

《镜语人》SplashScreen

大学时期的女朋友上进心很强,作为翘课大王的我总不能窝在宿舍暗无天日地写一天程序而让人家一个人孤零零地上课,虽然不至于这么惨但是心里总是有点过不去的,于是乎,我便带着笔记本到教室写代码,推进EtherEngine的开发,可是用了两三年的拯救者不争气啊,尤其是使用VisualStudio这种怪物级的IDE的时候,不外接电源供电甚至都撑不过两节课,也就是一节大课。但是教室里面供电位置有限,甚至插座时好时坏该怎么办呢?办法总比困难多,于是我便从淘宝买了一块电动车可用的小型蓄电池,塞在书包里,早八从宿舍出发前充满电,笔记本电池快撑不下去的时候便掏出来插上,等电池的电量耗完,电脑差不多以及接近满电了,这会儿再去找个位置把蓄电池冲上,循环下来甚至可以支撑一上午的开发使用。这块蓄电池在我毕业离开的最后一天,还在纠结如何将它邮寄回家的时候,伴随着一阵焦糊味的白烟结束了自己的生命,也算是功德圆满了。

EtherEngine开发背后的蓄电池

人总是现实的,就像大学生活总是短暂的一样。时间一晃来到了大三的寒冬,没有保研的希望,是考研还是工作,再次摆在了我的面前。虽然我有为了热爱和梦想再次放手一搏的勇气,但是左右你抉择的永远不只是你自己一个人。我希望日后能够从事游戏开发,并以此谋生,便需要向他人证明,我有这个能力——而到目前为止,我的工作重心,似乎并没有足够的说服力,我急切地需要一份完整的游戏作品,无论是应付简历,抑或是应对家里人的质疑。

其实美术素材的创作一直是我的心头之痛,相信这是很多人程序起手的游戏制作同好所共同面对的问题,虽然我也尝试过专门拿出时间去学习尝试一些较为简单的美术风格,但是无奈自己的双手已经离开画笔太久了,画出的作品虽然没有做到半点形似,但是神韵上也总是能够有所“创新”。

大佬的教程范例 & 我的绘画作品

要想在相对较短的时间内快速地产出一部游戏作品,只靠我自己的美术实力大致是没有希望了,于是我再次拨通了丹水墨银老师的电话。从《逆光》企划搁浅后,我们基本上便各自为战忙活儿自己充实的大学生活,就算是有这种再次合作的机会,之前的失败也总还是有所愧疚的。但是这次,我还是厚下脸皮,十分隐晦的表达了自己对于“这部作品”的利害关系。简单两句后,他便说让我等一下消息。再次接起电话,他便告诉我已经和家里沟通好寒假来我家一起工作的准备了。当时的我是有些懵的,在传统观念里面,回家过年似乎是理所应当的事情,就因为我这个八字没一撇的合作请求,就直接决定和我一起来到寒冷的北方一起工作,这种果断和坦率是让我一时有点难以接受。

既然可以,那就直接来吧!

新的游戏企划《杀死乔治》便在回家的高铁上酝酿而生了,一个像素风的暗杀游戏,讲述克系背景下主角三位一体的跨时空刺杀任务。背景设计、关卡设计、美术风格确定,一切都紧锣密鼓地安排着。《杀死乔治》将使用全新的EtherEngine引擎,十年磨一剑,这将是真正交锋的时刻。

Bilibili 动态详情截图

一切似乎都在向好发展,但是成长总是要从失败的骨灰中趟过去的,我对于自己的开发能力过于乐观了,对底层封装的娴熟并不代表着我在Gameplay上游刃有余,再加上EtherEngine并未提供较高层级的封装,一开始没有考虑好架构的话随着体量增大将会是灾难性的崩塌,拆东墙补西墙所带来的工作量将远大于新内容的推进所需要的工作;同理,美术的工作虽然快我一步,但是体量也并非一开始预估的那般容易。

没有可视化编辑器同样也是造成效率低下的问题之一,所谓磨刀不误砍柴工,起步时对于开发工具的轻视必然会化作一颗定时炸弹,当你在濒临崩溃的悬崖边上时在你脚下爆炸。在速览相关概念后,我对结构化场景搭建进行了第一个尝试——EasyDrawXML,虽然我知道,根据XML内容进行场景实例化并不是可视化编辑的全部,但是至少,这是它的数据前置条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>

<EDX>
<Config>
<Window Title="CustomizeWindow" Width="1280" Height="720" Color="0, 255, 255, 100" />
<Resource Type="Font" Path="STKAITI.TTF" />
<Resource Type="Icon" Path="bug.png" />
</Config>

<Body>
<Circle IsFilled="True" Radius="350" Color="#db8449">
<Ellipse X="400" Y="400" RadiusX="475" RadiusY="200" Color="#ffffff" />
<Rectangle X="500" Y="500" Width="1000" Height="500" IsFilled="True" Color="255, 0, 0, 100" />
</Circle>
<Triangle PointAX="100" PointAY="100" PointBX="200" PointBY="300" PointCX="700" PointCY="900" IsFilled="True" Color="255, 255, 0">
<Line StartX="0" StartY="0" EndX="1280" EndY="720" Width="5" Color="#69d9ff" />
<Text Content="左上角的二维码可以跳转至我的一个无聊项目" X="450" Y="360" />
<Image Path="qrcode.png" Alpha="175" />
</Triangle>
</Body>
</EDX>

上述 XML 对应的渲染效果

没能做出让自己或他人信服的作品,想要通过游戏开发养活自己这条路似乎就显得有些渺茫了,在大三下学期开始时,便接受了宿命一般,开始切实准备考研的事情。但是,考研的路总是难走的,我已经“远离”考试太久了,纯粹的理论学习让人忍不住抓狂,要不顾一切地当逃兵吗?

我说,我想试一试,就试一次,看看能不能找到工作,如果没有结果,我再死心塌地回来考研……

那是最焦虑的一段时间,海投简历——尽管那时大部分游戏大厂的暑期实习网投时间已过,过往的一切都像走马灯一样历历在目,我不是计算机或是软工的科班出身,一切兴趣热爱驱动的我,要去补基础,要去背八股,虽然我有相对充足的项目经历,但是这是最后一次,我不能输的赌注,我放弃了很多东西,但是这一次,可能是我最后一次不甘平庸证明自己的机会。

  • 鹅厂首战的败北反而让我没有那么紧张了,但是接下来……
  • 某易原定半小时的面试,在与面试官愈聊愈热的对话中,延长到了1.5个小时……
  • 米哈游顺利通过初筛进入下一轮……
  • 西山居面试官几近当场给出暑期实习的承诺……
  • 字节跳动在后续的半年时间里,换了3个HR给我打电话……
  • 已经在某易实习的我再次收到了鹅厂的电话,询问是否考虑光子工作室面试……

我不清楚如果我没有卖掉考研复习资料去放手一搏,现在的处境是否会有变化,但是,这次,在仅有的几次赌注中,我还是赌赢了……

三方签署

借助《杀死乔治》开发期间直播的热度,EtherEngine也吸引了几位小伙伴一起来参与到相关作品的制作,EtherWorkCollection里面囊括了一部分大家的作品,以及那时候正值高考的hsz小同志,在高考结束后便用EtherEngine制作了一款泰拉瑞亚视角的MC同人沙盒游戏。

hsz 的聊天记录

hsz 使用 EtherEngine 制作的沙盒游戏

在大厂上班总是好的,时至今日,同事们之间的工作氛围我回忆起来都十分怀念,但是自己身处窗明几净的办公室内时,总感觉少了点什么。在通宵达旦的工作之余,我开始重新审视自己,编程是我的技能,是我的工作,是我的本分,但是我是否能够做好一颗在庞大工业化机器上运转的小螺丝钉?这样的工作我能否真正胜任?我是工程师,还是艺术家,骨子里面的是循规蹈矩的技术探索,还是以技术为媒介的创作表达?

在压力巨大的实习期间,夜晚和同事们从大排档走出来,广州的夜景是很美的,虽然我们身处郊区,但是至少玻璃大厦的幕墙上还有打工人燃烧的生命之光在熠熠生辉。我们互相讨论说着近在咫尺的未来,我说,如果,如果,如果我没能转正,去做独立游戏呢?

我已经忘记那时候同事们的笑谈中到底作了如何的回复,但是我自己认为,在这个就业世界中人人自危的年代,这绝对是自寻短见,但是,这个念头,却在我脑海中愈加清晰。

  • 我还有多久,还有多少年才能实现我最初的梦想?
  • 从虚拟世界的模拟,到工业化的游戏作品开发,是越来越近还是越来越远……

在转正双选会的前一天晚上,我翻出了行李箱中跨越大半个中国的一沓笔记,那是高中时和朋友们一起在错题汇集簿上写下的满满4本RPG游戏策划,纸页已经泛黄,边角也卷了起来,彩色的便签胶纸已经干燥得嗦嗦作响,我打电话给那时的朋友们,我说,还记得,要做吗,等我回去……

我曾经奋力到达的地方,现在却要决断地逃离它。

在相对顺利地辞职之后,有了先前EtherEngine痛苦开发的经验,可视化编辑器的开发被提到了日程之上,集成新一代EtherEngine内核的引擎IDE便逐渐有头绪起来了。游戏引擎理论相关的书籍摆了厚厚一摞,日常下饭菜是Games104,或许这些系统的专业知识早该补充,但是现在,想必也为时不晚。

EtherStudio 启动界面

EtherStudio GUI 示例

那时将自己的技术与行业内正处于应用阶段的技术相比,还是有些相形见绌的。尤其是图形学方面,在对《Inmost》游戏的体验中,我真真切切地被他在2D像素世界中塑造的美学艺术给震撼到了,于是乎,有了标杆,EtherStudio在光照方向的重构便有了明确的目标。

《Inmost》游戏截图

2D 灯光烘焙测试

一个时代的结束总是要伴随着锣鼓喧天的热闹抑或是凄厉的悲鸣,疫情解封的那会儿人人都以为可以靠“躲”来熬过这个寒冬,但是无奈新冠更像是一种无形的诅咒,在尚且健康的赌徒头顶摇着骰子,又像是悬着的达摩克利斯之剑,总会有斩下来的那刻。阳康后的我第一次感觉到了工作上的有心无力,无法集中注意力对引擎这种繁琐逻辑的开发有着致命的debuff,开发这种庞大的系统,每次着手编写代码之前的预热便要启动许久,而那时的精力根本不能撑到让我真正开始编写有实际进展的代码。不止一次地,我对自研引擎之于现阶段的意义开始产生了怀疑。

EtherStudio 帧动画编辑器 & 组件编辑器

既然决定了不顾一切地投身独立游戏,全局项目进展的必要性必然是优先于局部的技术探索的。于是乎,在万般无奈的斟酌之下,我再次请出了Unity这位老朋友,时隔多年,如同游遍山河重返故乡的旧友相叙,可能也是个人技术能力有所成长,很多之前彼此生疏的领域,也有了交谈的可能。虽然游戏类型不同,第一次试水难免磕磕绊绊,但是总体而言,在Unity的协助之下,还是有所进展的。

《MyLost》游戏开发阶段画面

此时的EtherEngine又退回到了最初的模样,化身为EtherTK这个动态链接库,在集成了Dear ImGui等库后,它的工具属性更加明确,已经成为我日常开发时的辅助工具库,还是一样的Lua,多年的战友依然在这个自研引擎的黄昏阶段陪在我身边。

EasyGL - 矢量绘图代码生成工具(左)/ Emake - Lua 代码静态编译工具(右)

可就在这时,hsz引领开发的下一代游戏引擎StardustEngine捷报频传,借助反射和自动绑定等现代化技术的“Modern Cpp Game Engine”已经初具雏形,这不由得再次点燃了我们的自研引擎之火。虽然当下的开发任务繁重,引擎的工作主要由Godot来承担,但是对于自研引擎的探索和追寻,或许永远不会停下。

Stardust Engine Logo

总有人会问我,明明有那么多功能强大的游戏引擎,为什么执迷于自研造轮子?
我想,这篇博客就是答案,自研引擎是一首诗,我在用生命和代码追求这种赛博田园式的艺术……

BacklightEngine Readme 自述

作者

Voidmatrix

发布于

2023-11-21

更新于

2023-11-22

许可协议

评论