在C ++ 17中重新创建旧的DOS游戏

2016年,我开始从事一项业余项目,用于对游戏Duke Nukem II进行反向工程并从头开始重建其引擎。 该项目称为Rigel Engine,可在开源中使用( 其页面在GitHub上 )。 两年半以后的今天,在我的引擎上,您已经可以浏览原始游戏的整个共享软件集,并且具有与原始游戏几乎相同的游戏玩法。 这是第一级通过的视频:


他能做什么? Rigel Engine可以完全替代原始DOS二进制文件( NUKEM2.EXE )。 您可以将其复制到游戏目录,并考虑其中的所有数据,也可以将游戏数据的路径指定为命令行的参数。 该引擎是在Windows,Mac OS X和Linux下构建和执行的。 它基于SDL和OpenGL 3 / OpenGL ES 2,并使用C ++ 17编写。

它实现了Shareware情节中所有敌人和游戏机制的游戏逻辑,以及大多数菜单系统。 另外,您可以将保存的游戏和高分表从原始游戏导入到其中。

而且,该引擎比原始引擎具有优势:

  • 无需模拟器或旧硬件,无需设置
  • 没有加载屏幕-在菜单中选择“新游戏”,按Enter,然后立即开始游戏
  • 可以同时播放几种音效,这在原版中是不可能的
  • 对粒子,爆炸等同时作用的数量没有限制。
  • 保存每个播放器的文件和高分列表
  • 响应式菜单更多

到目前为止,我认为Rigel Engine并非完全“开箱即用”。 但这是发展的重要阶段,也是再次撰写有关引擎的好机会( 此处此处发布的旧文章)。 让我们开始看一下代码的当前状态,并找出我如何去实现它。

引擎中有多少代码?


在撰写本文时,RigelEngine由270个源文件组成,包含超过25,000行代码(无注释/空行)。 其中,有10个文件和2.5千行是单元测试。 空行和注释的详细分类可在此处获得

这些代码到底是什么? 一些通用的基础结构和支持功能,例如渲染之类的基本内容,以及一堆小逻辑块。 除了所有这些,最大的部分是:

  • 原始游戏中使用的14种不同文件格式的解析器/下载器-2000行代码(LOC)
  • 24个敌人/敌对对象的行为逻辑/游戏逻辑-3.8k LOC
  • 14种互动元素和游戏机制的游戏逻辑-2k LOC
  • 播放器控制逻辑-1.2k LOC
  • 154个配置条目(每个敌人的健康值,所收集物品的得分等)-1k LOC
  • 31种破坏效果的规范(破坏敌人或其他可破坏物体而触发的效果)-254 LOC
  • 相机控制代码-159 LOC
  • 游戏菜单描述语言译员/过场动画-643 LOC
  • HUD和其他UI代码为818 LOC
  • 菜单外有5个屏幕/模式,例如初始动画,奖金屏幕等。 -789个

当然,所有这些代码都需要编写,这将导致我们进入下一个问题。

它做了多少工作?


尽管自项目开始以来已经过去了两年半,但我一直都没有为此工作。 几个月以来,我根本没有做任何项目,在另一些项目中,我只花了几个小时。 但是有时候我会非常积极地使用Rigel Engine。 查看Github上的提交时间表,您可以大致了解我的工作如何随时间分配:


根据时间表,我们看到对master分支进行了1081次提交。 但是,即使在创建存储库之前,我仍在进行一个封闭的工作,其中有247个以上的提交,总共给了我们1328个提交。 另外,我有几个原型分支用于研究和实验,但从未与主要分支结合使用。 另外,在合并之前,我有时将大型提交故事压缩为较短的提交故事。

我还必须说代码编写不是项目的唯一部分-逆向工程是另一个重要部分。 我花了好几个小时研究Ida Pro (免费版)中原始可执行文件的反汇编代码,做笔记,编写伪代码,并计划实现该版本的元素。 此外,我还积极测试了原始游戏,并在DOSBox和原始设备(在eBay上购买了其他机器386和486)上运行了该游戏。 我收集了用于分别观察特定敌人和研究游戏机制的测试级别,使用DOSBox录制了视频剪辑,并逐帧浏览以确认我在研究汇编代码时所得出的结论。 在意识到敌人或游戏机制之后,我通常会记录我的版本的视频剪辑,并将其与原始视频进行逐帧比较,以确认实现的准确性。

这是我的笔记的一些照片:


反向工程摄像机控制代码。 较大的矩形表示屏幕。 虚线表示玩家无需移动相机即可移动的区域。 如果您有兴趣,可以在此处找到相机控制代码本身。


一般说明可帮助您理解汇编代码。 左侧是高级更新原始游戏的过程。 右边是指示某些游戏对象状态的位字段上的注释。


将汇编程序代码转录为伪代码。 通常,我会足够机械地进行操作,在不考虑代码在做什么的情况下进行转录,然后使用伪代码中的版本来理解底层的逻辑。 在此基础上,我已经提出了实现方案。 此处查看完成的代码。


清除后的敌人逻辑版本的伪代码 标头指示状态机的状态,下面的代码说明在各个状态下应发生的情况。 它是根据通过转录汇编代码获得的原始伪代码创建的。 准备好的代码可以在这里找到。

最后,该项目的工作非常令人兴奋,我从中学到了很多东西:逆向工程,16位x86汇编器,低级VGA编程,90年代初期PC游戏开发人员必须面对的严格限制; 此外,我还发现了有关原始游戏的内部功能以及其中某些功能的实现是多么奇怪和怪异的许多发现-这个主题本身值得一连串发表。

接下来是什么


除了添加最后剩下的功能并最终完成对注册版本的支持外,我还有几个想法可以改进和扩展Rigel Engine的功能,更不用说清理和重构代码了-通常,创建软件体系结构的最佳方法只有在完成此软件的创建后才能显现。

至于将来的改进,以下是我考虑实现的一些要点:

  • 插补平滑运动。 游戏每秒大约更新15次逻辑,在原始游戏中,它也是渲染的帧速率。 另一方面,Rigel引擎可以轻松以60 FPS或更高的频率工作。 目前,这些附加框架没有任何优势,但我认为可以将它们用于中间框架,以实现对象的平滑滚动和移动。 游戏的逻辑仍将以相同的速度运行,但是对象将平滑移动,并且不会像现在那样以8像素的增量“跳跃”。 早些时候,我创建了这样一个系统的原型,尽管需要改进,但它看起来很棒。
  • 游戏手柄支持。 在原始游戏中,有对操纵杆的支持,DosBox可以在现代游戏手柄上模拟操纵杆,但是它们的设置可能很困难-需要准备游戏中的配置和校准。 更不用说并非所有控制器按钮都受支持,但是要使用菜单,您仍然必须带键盘。 因此,我相信对本机控制器的支持将大大改善游戏玩法。
  • 声音增强。 当前,所有声音效果具有相同的音量。 产生声音的物体(例如,力场)在撞击屏幕时变得清晰可闻,并突然破裂。 我很好奇,如果远处的效果逐渐减弱,它们的声音会如何。 例如,当力场尚未出现在屏幕上时,我们几乎听不到,而接近时力场会变大。
  • 远程摄像头/查看大部分关卡。 游戏不是为此设计的,因此这种可能性可能会破坏游戏玩法-玩家将开始看到在屏幕外未处于活动状态的敌人,等等。 但是我仍然想知道它的外观和播放方式。 最后,玩家经常抱怨这款游戏无法看到关卡的足够部分。 添加选项以关闭HUD或使用透明度最小的HUD替换将是很有趣的。
  • 增加图形分辨率。 经常在许多游戏端口/休闲游戏中找到此功能,在此添加它会很棒。 该引擎已经可以让您用自己的图像替换精灵图形,但是到目前为止,它们不能具有更高的分辨率,因为所有内容都会渲染到较小的缓冲区中,并且随后会扩大比例。 首先,您需要替换此方法,以便可以对单个对象执行缩放。

我没有未来的路线图,因此我可以按任何顺序实施这些要点。 但是在此之前,下一步将是整合Dear ImGui,以进一步组装选项菜单,而这在游戏中还没有。 此外,它将启用或禁用上述改进。 最后,我要说的是,感谢您在GitHub上的工作

Source: https://habr.com/ru/post/zh-CN454570/


All Articles