使用了SDL等库和CMake和C++语言和AI大模型辅助,从零开始写了一个小游戏雏形,用时大约4个月。
里面进入游戏后是一个GAME CLICK TO play 的场景,然后使用鼠标点击后进入主菜单场景,主菜单目前有两个场景堆叠成的一个画面,一个是背景和 play settings exit 按钮场景,一个是点击settings 后弹出来的独立的设置场景。点击play进入世界场景,里面是两个场景堆叠成的一个画面,一个是瓦片地图和玩家和粒子效果的场景,一个是UI场景,场景间任何事件可以被消费掉。
可玩性欠缺,目前仅仅测试引擎运行和效果等等,后续会陆续加入可玩性。
实现了一个基本的2D游戏框架,内部有场景切换功能,模拟重力的物理,瓦片地图系统,角色帧动画,对象池粒子系统,基本UI系统,场景事件消费。使用了C++20和现代C++的特性,使用了对象池和启动时预加载的功能实现了运行时无内存分配开销,并且退出程序时使用了RAII特性进行了内存清理来防止内存泄露程序崩溃等等问题。
RAII:使用了现代C++的特性进行开发,使用智能指针std::unique_ptr进行启动时预加载对象分配,const T*观察指针和引用&进行运行时对象引用。清理时使用了模块化单例化设计,每一个模块单例管理自己的内存。
场景系统:场景系统SceneManager就是一个管理栈型数据结构的类封装,场景Scene是基本单位。并且Scene为顶级父类,Scene继承下来的类如 class WorldScene : public Scene 是世界场景等等。
事件消费:事件消费使用了场景系统SceneManager来实现。场景系统SceneManager就是一个管理栈型数据结构的类封装,场景Scene是基本单位,最后堆叠渲染成一个画面。把事件先传给最上层场景,如果场景有能力对事件做出反应,就把事件消费,如果没有能力消费事件,就传下去给下层场景。
UI:UI系统就是使用事件消费和基本AABB检查鼠标在不在框内实现的。比如点击UI场景的事件不会传给世界场景。当然也可以选择允许不消费,也就是UI不消费事件,把事件传给世界场景等等
。包含一个Widget基类和各种如 class ControlButton : public Widget 的继承类。
并且UI事件消费的事件处理对于高频使用的按钮是直接访问对象内存地址的方式进行信号发送,因为这是最快的。如果高频使用的按钮是使用EventBus进行信号发送,而不是直接写内存,会比较慢并且有堵塞风险。但是也有一个EventBus进行低频率的信号发送,比如菜单按钮,玩家相比移动按钮更少按下,就可以使用低频EventBus进行信号发送。
渲染:渲染器使用了SDL_Renderer进行基本2D渲染,并且也封装了底层SDL_gpu配合HLSL着色器语言和SDL_shadercross着色器跨平台编译器和SPIRV-Cross进行编写基本跨平台的2D渲染管线。但是目前发现了SDL_Renderer无法和SDL_gpu + 着色器语言配合使用,所以说只能取舍。方案是最后全部采用SDL_gpu进行跨平台GPU渲染。
SPIRV-Cross 配合 DXC 使用HLSL编写的着色器可以进行跨平台着色器编译。比如HLSL → DXIL支持DX12,HLSL → SPIR-V支持 Vulkan,HLSL → SPIR-V → MSL支持苹果的Metal,HLSL → SPIR-V → GLSL支持老OpenGL,等等。