最近想学游戏开发... 说起来很早以前就想做游戏的, 但是误入歧途了(也许吧). 最近利用空余时间尝试写一下游戏, 目标是先做一个 demo, 熟悉之后再设计一个自己的游戏

技术栈与工具链

此前没有接触过游戏开发, 只在大学的时候学过一点点 OpenGL. 我打算从较为原始的方式开始, 先不用游戏引擎, 由于我本身不会 C++, 用 C# 的话不如直接上 Unity, 于是便选择了 C + raylib 来写

raylib 对应的还有一个库叫 raygui, 这是一个 UI 库, 我打算用这个库来画按钮等

构建工具我打算选择 CMake + Make, 并且不需要包管理器, 手动管理依赖

由于我在 macOS 上开发, 编译器的话自然就选择 clang 了, 版本为 21.1.8 (macOS 上自带的版本为 17.0.0)

工具链: clang (21.1.8), CMake (4.2.2), Make (4.4.1)

技术栈: C (23), raylib (latest), raygui (latest)

编辑工具: nvim

raylib 安装:

brew install raylib

raygui 下载: https://github.com/raysan5/raygui, 直接下载头文件即可

项目结构

我打算将游戏逻辑和渲染层分开

core: 游戏核心逻辑

client: 游戏渲染

lib: 通用库

third_party: 第三方依赖

build: 构建产物

然后头文件都放在各个模块的 include 文件夹下, 源码放在 src 文件夹下

项目结构就是这样:

game_project
     ├─build
     ├─client
     |   ├─include
     |   └─src
     ├─core
     |   ├─include
     |   └─src
     ├─lib
     |   └─lib_1
     |       ├─include
     |       └─src
     └─third_party
         └─raygui

依赖关系:

┌───── lib
|    ↗     ↖
|   core ← client
|    ↓      ↙   
└→ third_party

core 作为一个库给 client 使用

项目初始化

项目的根目录放一个 CMakeLists.txt, 在每个子模块下面也放一个 CMakeLists.txt, 并在顶层将模块包含进去

game_project
     ├─client
     |   ├─include
     |   ├─src
     |   └─CMakeLists.txt
     ├─core
     |   ├─include
     |   ├─src
     |   └─CMakeLists.txt
     ├─lib
     |   ├─lib_1
     |   |   ├─include
     |   |   ├─src
     |   |   └─CMakeLists.txt
     |   └─CMakeLists.txt
     ├─third_party
     └─CMakeLists.txt

game_project/CMakeLists.txt:

cmake_minimum_required(VERSION 3.30)
 project(game_project C)
 ​
 set(CMAKE_C_STANDARD 23)
 set(CMAKE_C_STANDARD_REQUIRED ON)
 ​
 if(MSVC)
   add_compile_options(/W4)
 else()
   add_compile_options(-Wall -Wextra -Wpedantic)
 endif()
 ​
 add_subdirectory(core)
 add_subdirectory(client)
 add_subdirectory(lib)

game_project/client/CMakeLists.txt:

set(RAYLIB_VERSION 5.5)
 find_package(raylib ${RAYLIB_VERSION} REQUIRED)
 if(NOT raylib_FOUND)
   include(FetchContent)
   FetchContent_Declare(
     raylib
     DOWNLOAD_EXTRACT_TIMESTAMP OFF
     URL https://github.com/raysan5/raylib/archive/refs/tags/${RAYLIB_VERSION}.tar.gz
   )
   FetchContent_GetProperties(raylib)
   if(NOT raylib_POPULATED)
     set(FETCHCONTENT_QUIET NO)
     FetchContent_MakeAvailable(raylib)
   endif()
 endif()
 ​
 file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c")
 ​
 add_executable(client ${SOURCES})
 ​
 target_include_directories(
   client
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${PROJECT_SOURCE_DIR}/third_party/stb/include
   PRIVATE ${PROJECT_SOURCE_DIR}/third_party/raygui/include)
 ​
 if(APPLE)
   target_link_libraries(client PRIVATE "-framework IOKit" "-framework Cocoa"
                                           "-framework OpenGL")
 elseif(UNIX AND NOT APPLE)
   target_link_libraries(client PRIVATE m)
 endif()
 ​
 target_link_libraries(client PRIVATE raylib xlog core)
 ​
 target_compile_options(client PRIVATE $<$<CONFIG:Release>:-O3 -DNDEBUG>)

game_project/core/CMakeLists.txt:

file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c")
 ​
 file(GLOB_RECURSE TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test/*.c")
 ​
 add_executable(core_main ${SOURCES} ${TEST_SOURCES})
 ​
 add_library(core ${SOURCES})
 ​
 target_include_directories(
   core
   PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${PROJECT_SOURCE_DIR}/third_party/stb/include)
 ​
 target_include_directories(
   core_main
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${PROJECT_SOURCE_DIR}/third_party/stb/include)

Makefile:

BUILD_DIR := build
DEBUG_DIR := $(BUILD_DIR)/debug
RELEASE_DIR := $(BUILD_DIR)/release

CC ?= clang

CMAKE := cmake
CMAKE_PRESET ?= ninja

CMAKE_FLAGS ?= -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

ifneq ($(CC),)
CMAKE_FLAGS += -DCMAKE_C_COMPILER=$(CC)
endif

all: debug

debug: CMakeLists.txt
	$(CMAKE) --preset=$(CMAKE_PRESET) -S . -B $(DEBUG_DIR) \
		$(CMAKE_FLAGS) -DCMAKE_BUILD_TYPE=Debug
	$(CMAKE) --build $(DEBUG_DIR)
	cp $(DEBUG_DIR)/compile_commands.json compile_commands.json

release: CMakeLists.txt
	$(CMAKE) --preset=$(CMAKE_PRESET) -S . -B $(RELEASE_DIR) \
		$(CMAKE_FLAGS) -DCMAKE_BUILD_TYPE=Release
	$(CMAKE) --build $(RELEASE_DIR)

clean:
	rm -rf $(BUILD_DIR)

.PHONY: all debug release clean

CMakePresets.json:

{
   "version": 8,
   "configurePresets": [
     {
       "name": "ninja",
       "generator": "Ninja",
       "displayName": "Default Ninja Config",
       "description": "Using generator: Ninja"
     },
     {
       "name": "make",
       "generator": "Unix Makefiles",
       "displayName": "Default Make Config",
       "description": "Using generator: Make"
     },
     {
       "name": "xcode",
       "generator": "Xcode",
       "displayName": "Default Xcode Config",
       "description": "Using generator: Xcode"
     }
   ]
 }

暂时就这么写吧, 也许得找一个现成的项目学一下