hanjie zou,C++的子集 阅读原文 恬不知耻地,拿一个我自己写着玩的项目来举例吧~ tprpix,一个我自己做着玩的,用 「C++ 徒手撸的」 自娱自乐级游戏项目 项目仍在推进中,很多部分甚至尚未开工(还是脚手架状态)。不过我已经把它开源到了 GitHub ,欢迎大佬们去拍砖~ 与你的问题相似,tprpix 的诞生,也是为了动手实践下:「用 C++ 徒手搭建一个游戏,是个怎么样的体验」。在开启这个项目之前,我只用 C++ 实践过一两个 2000 行级的迷你项目。(更早之前,则是在用 C 和一点点汇编,跟着教程搭一个 类 unix 操作系统内核(玩具级))确切地说,tprpix 就是我的第一个 C++ 项目。在开工的头几个月里,我始终处于:边翻书学习新用法,边重写原有模块的状态。 tprpix 中的绝大多数模块都是徒手撸出来的,包括但不限于: 基于 OpenGL 的画面渲染层,和一个简易的帧动画播放器 一个轻量级 移动碰撞检测模块 一个基于 Perlin Noise 的地图生成器 一个“蓝图”系统,读取 json 文件,用来定制不同生态的地景分配规则 水域系统(已被改设定为:“源自异星的生物汤“...(中二... 基于 SQLite3 数据库的 自动读档存档 基于 glfw 的 游戏手柄支持(Xbox360-Style) 跨平台,支持 Win10 / MacOSX / Linux(Ubuntu) 编译 如上述细节所提,我也使用到了第三方库,比例: OpenGL 方面的库:GLM,glfw,glad 小型数据库: SQLite3 json 解析库:RapidJSON debug 库:fmt,spdlog enum 库:magic_enum 目前的 tprpix 只为试玩者提供了非常有限的功能:你可以操纵一只鸡,遍历这个世界。不管朝任何方向走,地图都会自动生成 / 销毁。在这个世界中,运用一套规则(perlin noise+ 蓝图)来自动在游戏世界中分布景物和人造物(草,树,墙壁篝火等.... 类似于 MineCraft 的地图生成机制... ) 更多功能还在编写中,更多生物也在制作中... 废话完毕进入正题: 「从零开始,搭建一个游戏项目,到底该怎么做?」 我觉得可以分为: 学习如何搭建 C++ 项目 选择图形库 主函数 和 主循环 游戏模块 在实践的过程中强化 「bypass」 思维 "能跑的轮子就是好轮子" 以下是展开: 1 .学习如何搭建 C++ 项目 这其实是所有 C/C++ 玩家都要面临的问题。遗憾的是,绝大多数语法书都不会提及这块。这导致很多玩家在学习了一段时间语法后,仍然只能捏着一个 .h, 两个 .cpp 文件(一个 main.cpp, 一个 test.cpp)来构建项目,非常凄惨。 如果你的项目只想支持 win平台,那不妨直接学习如何在 VS中创建项目。如果你想要跨平台,那或许该学习下 CMake 的使用。往深了说就是: 学习使用 有组织的 目录,文件(.h, .cpp, .hpp, .vs, .fs, .json, .png.... )再配合一个构建工具,来管理一个项目。 对于这件事,我的建议很粗暴:抄!去找一个别人写的迷你项目,照着对方的格式,搭建自己的项目。比方说 这个: 这是一个大佬使用 C/OpenGL/Cmake 复刻 MineCraft 的项目。在某些方面,它做得挺屎,比如它会在单个 main.c 文件里堆上 30 来个函数,这些函数之间相互关联,难以解耦(也可能是大佬想把它快快做完,好赶去玩别的~)。但另一方面,它在目录规划上挺值得借鉴( 你甚至还可以学一学它的 CMakeLists.txt 文件的写法... ) 抄到合适的项目格式后,可以先停顿一下,拿这个项目框架,去编写几个小工具。在实践中,加深对项目格式的理解。不出所料的话,你很可能会遭遇 编译链接 方面的问题,这其实也是一个暗坑: 链接(Linking)著名三不管地区~ 语法书们觉得这玩意儿不属于语法,所以不讲。环境库的书觉得这种东西你应该懂,所以也不讲。再加上它本来就有点神秘,如果之前的你都是在几个很小的 .h .cpp 文件里堆代码。相信我,当遭遇链接问题时,你会一脸懵逼。 这种时刻,最好的办法就是看书查资料,比如《深入理解计算机系统》(3th) 中的第七章。或者: Linkers and Loaders 当然,如果你为了跨平台而投奔 cmake,那将是另一段磨难... (鉴于知乎 cmake大佬太多,而我在这方面又特菜,就不摆弄了... 最后的最后,如果你特别懒,并不想去琢磨别人的项目到底是怎么搭出来的,不妨去 GitHub 搜索关键词:「cpp empty project」(或类似的词)。其实 已经存在很多现成的模板。在这里,我也提供一份我自己的: Cpp_Empty_Project (夹带私货时间~) 这是一个 基于 cmake/C++17 的跨平台空项目。从上面那个游戏项目 tprpix 整理抽取而来。你可以在这个空项目基础上,搭建出你自己的跨平台程序。(具体食用方式已经写在项目中,在此略过... 2.选择图形库 游戏的一个核心模块就是 画面呈现。你可以直接使用功能便捷的图形界面框架,比如 QT。或者底层的图形库,比如 OpenGL, DirectX。不管选择哪一种,这些图形库的使用方式,都会影响你的主函数,主循环的编写格式。 所以,请在项目开始的第一阶段,确定好自己使用的图形库。 在这里,我以 OpenGL 为例。你可以直接根据这个教程来入门图形学。顺带学习如何搭建一个 OpenGL 视觉交互程序: LearnOpenGL 英文版中文版 图形库方面的代码有个特点,就是它们的编写格式往往是固定的。直白地说就是:你在项目前期劳烦下,把这些代码理解透,然后封装进你自己写的模块中、排布进你的游戏主循环中,然后就不大需要改动它们了(唯一需要开放出来,以便时刻添新的就是 shader 代码了)。也许,未来某天,当你领悟了更好的设计方法,你会回来重构。但整体上,你应该在游戏制作的前期,就把这些东西确定下来。 如果你希望你的游戏有惊人的画面表现,也许你该停下来,深入挖掘下图形学方面的知识。不过,做出一个游戏需要投入的的方面有很多,视觉只是它的一部分。 3.主函数 和 主循环 游戏的本质就是一个时刻等待玩家输入的交互程序: 游戏程序启动,优先执行各个模块的初始化。然后跌入一个巨型的 while 循环中,以每秒 60 帧(或更多)的速度,反复执行 while 体内的代码。直到某一刻,玩家的某个输入触发 exit 事件。然后正式退出 while 循环。在执行一系列收尾工作后,彻底关闭游戏进程。 这么一看,一旦搞定了 主函数 和 主循环。游戏框架似乎就出来了。我的建议是,项目前期请使用最简单粗暴的方式来实现,比如: intmain(intargc,char*argv[]){// // init modules// ...// // Main Loop while(!exit()){//...}// // end everything// ...} 要么照着图形库教程传授你的格式去搭,也是完全够用了。或者说,这也许是更值得推荐的方法。如果你真的跟着那些图形库教程一路走下去,你会发现,它们已经教会你如何去搭建一个合格的 视觉交互程序。在这个交互程序的基础上,再往前多走两步,将它塑造成一款游戏,是件自然而然的事。 回到 主函数 和 主循环。如果你想把这部分做得更考究的话,不妨阅读下这两篇文章: http://gameprogrammingpatterns.com/game-loop.htmlhttps://dewitters.com/dewitters-gameloop/ 4.游戏模块 一个游戏,到底该被划分成哪些模块呢? 此时不妨去看看 正经的游戏引擎是怎么设计的,比如 unity3D。你可以借鉴一下它的设计思路,结合自己的游戏内容,设计一组功能相似的模块。(可以是简化版,合并版,只要能满足你的游戏就行~) 好吧,这一段我讲得有点敷衍。但怎么讲呢:为自己的游戏,亲手实现一些功能性模块,其实是非常快乐的过程。如果说,在处理上文提及的图形渲染方面的代码时,你还有点畏手畏脚的话(毕竟大家都是第一次)。那么现在,当你开始写功能性代码时,你就可以像对待一个纯粹的程序那样,去组织,去实现它了。用上你在 C++ 和其他书里学到的所有知识:放开脑洞,埋头填坑,停下总结,然后再翻工重写... 5.在实践的过程中强化 「bypass」 思维 好吧我承认,这个概念是我自己编的。若有发现更专业的描述,还请告诉我... 当你正式开工,并且推进了一段时间后。你可能会失落地发现,有些模块的制作工期实在太长了。有些模块则相互依赖,在所有依赖模块都完成之前,你就是无法看见你的程序运行的样子。这种体验使人沮丧,在你撑到最后一刻之前,你的意志力已经被消费光了。我的建议就是:搭建微型的 旁路系统(bypass) 怎么讲呢,假设你正在写一个模块 A,而 A 还依赖于另一个模块 B。而这个 B,你其实一行代码都没写呢。传统的方法当然是把两个都写完整后再跑。但这个依赖关系可能很长,不只是 A 和 B 这么简单。 此时的你不妨尝试:搭建一个空架子的 B,它暂时什么也不干。但它的一些接口函数,切切实实联通到了大流程中。(就像原初设计的那样) 然后就拿着这个看起来像是被故意短路了的程序,去测一测跑一跑了。(当然,并不是真的短路到没法运行,而是功能上的短路) 随时随地的反馈是很有必要的,它是你坚持下去的动力源 当然,以上只是一个很简陋的例子。放大了讲,万物皆可被 bypass。以各种灵活的方式。 6.「能跑的轮子就是好轮子」 这其实也是 bypass 思维的一个变种:一个简陋的,但能正常运行的模块,就是好模块。不要担心第一套方案设计得不够完善。随着项目的推进,经验的积累,你还可以回来重写嘛~(捂脸) 阅读原文