# CppCon 2014 学习: Quick game development with C++11/C++14
这是一个关于游戏开发与现代 C++(尤其是 C++11/C++14)结合的技术分享或讲座的概要,结构清晰、内容分为几个部分:
About This Talk — 内容结构
1. 导言部分(Introductory part)
介绍为什么选择游戏开发作为主题,可能从以下角度展开:
- 游戏开发对性能和架构的要求高,是验证语言特性的良好场景;
- 游戏项目具有高度模块化,适合演示抽象、封装、面向对象与泛型编程;
- 吸引力强、反馈直观,有助于学习者保持兴趣。
2. 为什么选择 C++?(Why C++?)
可能会提到:
- 高性能:几乎没有运行时开销;
- 精细控制:对内存管理、线程、对象生命周期等有绝对掌控;
- 巨大的生态(如 SDL、SFML、Unreal、Unity/C++ plugin);
- 跨平台开发能力强。
3. 为什么选择 C++11/C++14?(Why C++11/C++14?)
强调现代 C++ 的优势:
- 更简洁:
auto
、range-for
、lambda
函数; - 更安全:
nullptr
、类型推导、RAII 更易用; - 更强大:
move semantics
、std::function
、std::thread
; - 现代标准库功能增强:
<chrono>
、<unordered_map>
、智能指针。
4. 现场编码部分(Live Coding Part)
Preparation:
- 明确目标:构建一个可运行的、简单的小游戏(比如:贪吃蛇、打砖块、跳跃游戏等);
- 工具链准备:C++14 编译器(如 Clang、GCC、MSVC)、构建系统(CMake?)、编辑器(VSCode/CLion);
- 使用资源:图形库(SDL2、SFML)、音频、输入处理、游戏循环。
实录内容:
- 分阶段展示游戏的设计和实现;
- 讲解架构设计(实体组件系统?);
- 使用现代 C++ 特性重构或优化部分模块;
- 最终展示一个 完整可玩的小游戏。
本次讲座的核心目标(Goals of this talk):
Talk Goals
1. 鼓励大家尝试游戏开发
Encouraging everyone to try game development
- 说明游戏开发并不高不可攀;
- 通过一个简单示例激发兴趣;
- 展示游戏开发带来的乐趣、成就感和技能提升。
2. 展示 C++(特别是新标准)如何简化游戏开发
Demonstrating how C++ and its newer standards make game development a breeze
- 使用 C++11/C++14 提供的现代语法和特性:
auto
、lambda
、range-based for
提高代码可读性;smart pointers
提升资源管理安全性;std::function
、std::bind
提高接口灵活性;move semantics
优化性能;constexpr
与模板改进提升可复用性;
- 目标是让观众认识到现代 C++ 并不复杂,反而可以写出简洁、高效、优雅的游戏代码。
这是关于“为什么选择游戏开发(Game development: why?)”的内容核心:
为什么要做游戏开发?
1. 游戏开发需要多领域的知识与技能
Game development – Requires knowledge and skills in multiple areas
- 你必须掌握的不仅是编程,还有逻辑、图形、物理、音频、用户体验等;
- 是对综合技术实力的全面挑战;
- 帮助你成长为全栈工程师(或更高层次的通才)。
2. 游戏开发促进与玩家社区互动
Involves the programmer with the community
- 你编写的不只是代码,而是直接影响玩家体验;
- 开发过程中可以快速得到反馈、建议、甚至热情的粉丝;
- 游戏开发让你成为创作者,同时也拥有观众。
3. 游戏开发涵盖大量专业的编程主题
Touches a vast number of specific programming topics
包含但不限于以下方向(每一个都是深水区):
领域 | 内容示例 |
---|---|
Mechanics | 核心玩法规则与反馈 |
Design | 关卡设计、平衡性、美术风格 |
Implementation | 动作、输入、逻辑、动画等系统代码 |
Resources | 管理图像、音效、材质、字体等资源 |
Style and Feel | 操作流畅性、反馈、细节打磨 |
Story and Concept | 世界观、剧情走向、角色设计 |
Engine and Architecture | 引擎模块化、数据驱动、插件系统 |
Scripting and Customization | Lua、Python、可扩展事件系统 |
Porting and Distribution | 多平台支持(PC/手机/主机)、打包、部署 |
Graphics | 渲染管线、图形 API(OpenGL/Vulkan/DirectX) |
Music | 背景音乐、动态切换 |
Sounds | 音效反馈、3D 声场、节奏设计 |
总结:
游戏开发是一个 高度综合、极具挑战、同时又非常 有成就感和乐趣 的编程方向。
你不仅在写代码,也在讲故事、打造世界、创造体验。
这是对“为什么游戏开发选择 C++?(Game development: why C++?)”的核心解释:
为什么游戏开发用 C++?
1. 高效:零成本抽象 + 低层控制能力
Efficient: zero-cost abstractions and “low-level” code
- C++ 提供接近底层硬件的控制:内存管理、位操作、SIMD 等;
- 同时拥有高级抽象能力(模板、RAII、STL)——如果你不用,就不会付出任何运行时代价(zero-cost abstraction);
- 非常适合对性能要求极高的实时场景(如图形渲染、物理模拟、AI、音频等);
- Unreal Engine 就是 C++ 写的;Unity 的核心也是用 C++ 实现的。
2. 可移植性强:标准代码可跨平台
Portable: standard-compliant code can target many architectures
- 遵循 C++ 标准的代码可在不同平台之间轻松迁移:
- Windows / Linux / macOS / Android / iOS / 各类主机平台;
- 大型游戏往往需要支持多个平台,C++ 是主流跨平台解决方案;
- 各大游戏引擎也为 C++ 提供良好的跨平台支持。
3. 生态丰富:大量成熟库和资源
Widespread: huge number of libraries and resources available
- C++ 拥有几十年的开发历史,积累了大量稳定且高性能的第三方库:
- 图形:OpenGL、Vulkan、DirectX、SDL
- 物理:Box2D、Bullet、PhysX
- 音频:OpenAL、FMOD、SoLoud
- 脚本集成:Lua、Python(通过 bindings)
- 网络:Boost.Asio、ENet、RakNet
- 教程、开源代码、Stack Overflow 问题数量巨大,学习和调试成本低。
总结:
优势 | 说明 |
---|---|
性能 | 高效、可优化、接近硬件 |
控制力 | 允许手动控制内存和资源 |
可移植 | 一套代码跨多个平台 |
生态 | 工具、引擎、库、文档齐全 |
C++ 可能不易入门,但它是专业级游戏开发中经得起时间考验的首选语言。 |
这部分内容解释了 C++11 / C++14 在游戏开发中的优势。以下是对每一类内容的详细分解和说明:
为什么选择 C++11 / C++14?
现代 C++ 为游戏开发带来了更方便、更安全、更有表现力的语言特性。
便利性、安全性、表达力增强(Convenience, safety and expressiveness)
特性 | 用途 |
---|---|
initializer_list 、统一初始化 {} | 更直观、统一的构造语法 |
auto | 减少冗长类型,提高可读性 |
range-based for | 更简洁遍历容器 |
lambda | 定义临时函数、回调、事件处理等 |
variadic templates | 支持不定参数模板,如事件系统 |
decltype | 获取表达式类型,模板中更灵活 |
override / final | 防止错误重写,提高代码安全性 |
enum class | 强类型枚举,避免命名冲突 |
explicit | 防止隐式转换,减少 bug |
nullptr | 类型安全的空指针 |
现代内存管理工具(Memory management)
工具 | 用途 |
---|---|
std::unique_ptr / std::shared_ptr | 自动释放资源,避免内存泄露 |
offsetof | 获取成员偏移,可用于序列化或反射 |
工厂函数(factory functions) | 统一资源创建和管理 |
实体管理(entity management) | ECS(实体组件系统)构建更方便、安全 |
可能的性能提升(Possible performance improvements)
特性 | 用途 |
---|---|
constexpr | 编译时计算,减少运行时代价 |
std::move | 避免不必要的复制,提高效率 |
noexcept | 函数不会抛异常,编译器可优化调用路径 |
其他增强特性(Other improvements/additions)
特性 | 用途 |
---|---|
多线程支持(thread, async, mutex 等) | 支持并行计算、任务调度等 |
<tuple> | 多返回值、结构化数据处理 |
变参宏(variadic macros) | 更灵活的调试工具或日志接口 |
<random> / <chrono> | 随机数生成器、时间测量(如游戏循环 timing) |
泛型 lambda(C++14) | 更简洁处理不同类型的回调 |
lambda 捕获表达式 | 更安全、灵活地捕获变量 |
auto 函数返回值 | 简化返回值类型声明 |
更宽松的 constexpr | 可用于更复杂的编译期逻辑 |
std::tuple::get<...> | 模板化访问结构数据 |
应用场景举例
- 游戏循环 timing:用
<chrono>
精确测量 delta time; - 事件系统:用 lambda 和 variadic templates 定义任意事件;
- 资源管理:用
shared_ptr
加factory
构建资源池; - 组件系统(ECS):利用 tuple、decltype 管理组件集合;
- AI/行为树:使用 lambda 组合行为逻辑;
- 粒子系统、图形缓冲区:用
constexpr
做静态优化; - 多线程加载资源:用
std::thread
/async
实现异步资源加载;
Live Coding 目标说明
- 目标游戏类型:Arkanoid / Breakout(打砖块游戏)克隆版
- 实现方式:几乎从零开始编写代码
- 演示形式:一步一步展示游戏开发过程
- 目标代码量:控制在 约 200 行左右,展示简单但完整的 可玩游戏
目的总结:
- 向大家展示:C++ 也可以快速开发一个小游戏
- 即使是复杂看起来的“游戏开发”,在现代 C++(尤其 C++11/14)加持下,也能变得简单直接
- 通过打砖块这样的经典小游戏作为例子,涵盖游戏开发的多个方面(窗口、渲染、输入、逻辑、碰撞等)
这是关于 Game Loop(游戏主循环) 的介绍:
游戏主循环的核心概念:
游戏运行时,程序不断执行一个循环,直到游戏结束。每一帧(frame)都按照以下步骤运行:
Game Loop 的三个阶段:
-
Input(输入)
- 获取玩家操作,例如键盘、鼠标、手柄等输入
-
Update(更新逻辑)
- 根据输入和游戏状态更新游戏世界
- 处理物理碰撞、AI、得分、状态变更等
-
Draw(绘制)
- 渲染场景,将游戏实体绘制到屏幕上
这种结构让游戏逻辑和渲染分离、清晰有序,是所有游戏开发中最基本也最重要的模式。
SFML(Simple and Fast Multimedia Library)的坐标系统原点(0,0)在窗口的左上角。
- X 轴 向右增加
- Y 轴 向下增加
这是典型的屏幕坐标系,和大多数2D图形库一致。
球的移动原理就是每一帧更新球的位置:
position = position + velocity * delta_time;
这里的 velocity
是一个二维向量(x和y分量),代表球在水平方向和垂直方向的速度。
每次更新位置时,将当前速度向量加到球的位置上,球就看起来“动”起来了。
velocity
可以是正(向右/向下)或负(向左/向上)。delta_time
是帧间时间,用于让速度和时间同步,保证运动平滑且和帧率无关。
球与窗口边界的碰撞检测,就是判断球的位置是否超出了窗口的边界。
比如,水平方向上:
- 右边界检测:
if (ball.x + ball.radius >= window.width) {// 球碰到右边界,做反弹处理,比如反转水平速度ball.velocity.x = -ball.velocity.x;
}
- 左边界检测:
if (ball.x - ball.radius <= 0) {// 球碰到左边界,反弹ball.velocity.x = -ball.velocity.x;
}
同理,垂直方向:
- 下边界:
if (ball.y + ball.radius >= window.height) {// 碰到下边界,反弹或者处理游戏结束等逻辑ball.velocity.y = -ball.velocity.y;
}
- 上边界:
if (ball.y - ball.radius <= 0) {// 碰到上边界,反弹ball.velocity.y = -ball.velocity.y;
}
ball.radius
是球的半径,使用半径判断碰撞是为了用球的中心点坐标加减半径,准确检测球体边缘是否超出窗口。
AABB(Axis-Aligned Bounding Box,轴对齐包围盒)碰撞检测:
两个矩形是否相交,主要判断它们在水平方向和垂直方向上是否有重叠。
假设有两个矩形 A 和 B:
-
A 左边界:A.left
-
A 右边界:A.right
-
A 上边界:A.top
-
A 下边界:A.bottom
同理,B 也有对应的边界。
碰撞条件:
两个矩形碰撞,必须满足: -
水平方向重叠:
A.right > B.left
且A.left < B.right
-
垂直方向重叠:
A.bottom > B.top
且A.top < B.bottom
如果这两个条件都满足,就说明矩形 A 和矩形 B 有交集(碰撞)。
计算重叠量:
- 水平重叠量 =
min(A.right, B.right) - max(A.left, B.left)
- 垂直重叠量 =
min(A.bottom, B.bottom) - max(A.top, B.top)
通常在碰撞检测后,这些重叠量用来做响应,比如调整物体位置、反弹方向等。
球和挡板碰撞的要点:
- 当球碰到挡板时,不只是简单地反弹(Y方向速度反向),
- 还根据球击中挡板的位置调整X方向的速度,控制球的左右方向。
例如: - 如果球碰到了挡板的左半部分,球的X速度变为向左(负值)
- 碰到右半部分,X速度变为向右(正值)
这样做可以让球的运动更有趣,玩家可以用挡板的不同部分“控制”球的方向。
球与砖块碰撞时的速度变化逻辑:
- 根据球碰撞砖块的方向(是从左、右、上还是下碰撞)来决定改变球的速度分量(X或Y方向)。
- 如果球从砖块左边或右边撞上,反转X方向速度。
- 如果球从砖块上方或下方撞上,反转Y方向速度。
通常会通过计算重叠区域(overlapRight、overlapLeft、overlapTop、overlapBottom)来判断具体是哪个方向的碰撞,从而调整速度。
游戏里各种对象的关系:
- Entity 是基类,所有游戏对象都继承自它。
- Rectangle 和 Circle 是 mix-in 类,用来给实体赋予形状特征(矩形或圆形)。
- 具体游戏对象类如 Paddle(挡板)、Brick(砖块)、Ball(球)继承自 Entity,并可能混入 Rectangle 或 Circle。
游戏代码的整体架构:
- Game:游戏主控类,负责游戏的整体流程和状态管理。
- Manager:负责管理实体,比如创建、更新、销毁游戏对象。
- Entities:游戏中的所有实体对象,如球、挡板、砖块等。
- Grouped entities:实体的分组管理,方便批量操作,比如所有砖块在一个组里。