Skip to content

Commit 09dcead

Browse files
committed
Track user-facing docs and ignore IDE directories
- .gitignore: keep /docs/* excluded but whitelist the six usage documents (engine tutorial, feature list, maintenance log, rendering contract, application runtime guide, physics guide); plan drafts stay local. - ignore /.idea/ so CLion project data cannot be committed by accident.
1 parent cd89a57 commit 09dcead

7 files changed

Lines changed: 1281 additions & 1 deletion

‎.gitignore‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ CMakeUserPresets.json
1111
/runtime/examples/
1212
/runtime/_legacy/
1313
# 设计草稿与本机工具数据,不属于仓库内容。
14-
/docs/
14+
# 文档默认不入库:只放行面向使用者的说明,计划类草稿保留在本地。
15+
/docs/*
16+
!/docs/引擎入门教程.md
17+
!/docs/项目功能清单.md
18+
!/docs/维护优化记录.md
19+
!/docs/渲染接口约定.md
20+
!/docs/应用运行层使用说明.md
21+
!/docs/物理系统说明.md
1522
/.workbuddy/
23+
# IDE 工程目录与工具数据。
24+
/.idea/
1625
/后续设计相关-不放git上.md
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# 如何使用Application
2+
3+
## 从哪里开始看
4+
5+
先看 `examples/application_template/main.cpp`,这是能直接编译的空白模板。
6+
再看 `examples/color_triangle/main.cpp`:它只增加了资源创建、一个物体和移动回调。
7+
最后看 `src/core/Application.cpp`,就能看到这些回调在什么时候被调用。
8+
9+
这轮新增的不是绘制能力,而是统一“怎样使用引擎”。无需学习类继承、虚函数或单例。
10+
11+
## 三个容易混淆的名字
12+
13+
- Application:管理一次应用运行,拥有窗口、输入、摄像机、渲染器和场景。
14+
- Scene:管理物体。Application每帧调用它更新和绘制。
15+
- GameObject:场景中的一个物体,保存身份、Transform、启用状态和可选的运动回调;它通过Renderable组件组合网格、材质和透明排序参考点。
16+
17+
`runExample`是示例层的辅助函数,不是引擎API。它统一资源目录、日志、Escape和`--smoke-test`。
18+
自己的游戏可以直接使用Application,也可以先复制空白示例再修改。
19+
20+
## 资源应该放哪里
21+
22+
在初始化回调里创建GPU资源,此时OpenGL上下文已经就绪:
23+
24+
```cpp
25+
auto shader = std::make_shared<Shader>(directory / "shaders/color.vert", directory / "shaders/color.frag");
26+
auto mesh = std::make_shared<Mesh>(vertices);
27+
auto material = std::make_shared<Material>(shader);
28+
auto &object = application.scene().createObject("角色");
29+
object.setRenderable(mesh, material);
30+
```
31+
32+
`setRenderable`仍是最简洁的兼容入口;需要直接操作渲染组件时,也可以写成:
33+
34+
```cpp
35+
object.renderable().setSortOrigin({0.0f, 0.0f, 0.0f});
36+
```
37+
38+
Renderable只组合Mesh和Material,不复制网格数据,也不接管Transform或对象更新逻辑。
39+
40+
对于磁盘上的Shader和Texture,推荐通过Application提供的ResourceManager加载:
41+
42+
```cpp
43+
auto shader = application.resources().loadShader(
44+
directory / "shaders/color.vert", directory / "shaders/color.frag");
45+
auto texture = application.resources().loadTexture(directory / "assets/checker.ppm");
46+
```
47+
48+
ResourceManager会按规范化路径缓存文件型资源。同一个Application中重复请求同一组Shader或同一张Texture时,
49+
会返回同一个 `shared_ptr`,避免重复编译和上传。程序生成的Mesh、Material以及没有文件路径的运行时图片,
50+
仍然由应用自己创建;ResourceManager不负责把它们强行纳入同一种缓存。
51+
52+
这里的 `shared_ptr` 是“共享持有”:初始化回调结束后,局部变量不再持有资源,但物体继续持有Mesh和Material,Material又持有Shader和Texture。所以它们不会提前消失。
53+
54+
不要在初始化函数里用局部 `Mesh mesh(...)` 和 `Material material(...)` 然后传给借用接口。局部对象会在函数返回时销毁,留下无效引用。借用接口仍可用于生命周期明确的低层测试,不是新应用的首选。
55+
56+
Application正常退出和异常退出都会清空自己的场景,窗口最后销毁。不要把GPU资源保存在比Application活得更久的全局变量中;`shared_ptr`并不会延长OpenGL上下文的生命。
57+
58+
## 场景保存和加载
59+
60+
`SceneSerializer`适合保存关卡中的基础结构:对象名称、启用状态、局部Transform、父子层级、透明排序参考点以及Mesh/Material文件引用。
61+
文件是带版本号的可读文本,加载前会验证对象数量、数值、父索引和循环关系;验证失败不会修改目标Scene。
62+
63+
```cpp
64+
SceneSerializer::save(application.scene(), "level.scene");
65+
SceneSerializer::load(application.scene(), "level.scene", application.resources());
66+
```
67+
68+
场景文件使用版本4格式时,`MESH`和`MATERIAL`字段保存相对于场景文件的路径,基础几何额外保存`PRIMITIVE`参数。
69+
版本3格式时,`MESH`和`MATERIAL`字段保存相对于场景文件的路径。带资源引用的场景必须通过
70+
`ResourceManager`加载;它会缓存OBJ、Material以及材质依赖的Shader和Texture。加载函数返回新对象的ID列表,
71+
应用仍需根据这些ID重新绑定不会被文件保存的 `setUpdateCallback` 行为。版本1/2的无资源场景仍可读取。
72+
73+
加载采用“临时场景提交”规则:OBJ、Material、父子关系全部成功后才替换目标Scene;中途失败不会清空旧场景。
74+
资源加载失败前已经进入ResourceManager的缓存项可以被后续请求复用,但不会进入目标Scene。
75+
76+
## 输入动作映射
77+
78+
Application提供可选的 `ActionMap`,把多个具体按键或鼠标按钮组合成稳定的动作名称:
79+
80+
```cpp
81+
application.actions().createAction("move_forward");
82+
application.actions().bindKey("move_forward", Key::W);
83+
application.actions().bindKey("move_forward", Key::Up);
84+
85+
if (application.actions().isDown("move_forward", application.input()))
86+
{
87+
// W或上方向键按住时执行移动。
88+
}
89+
```
90+
91+
动作映射只保存名称和绑定关系,输入状态仍由Window/Input每帧采集。一个动作可以绑定多个键或鼠标按钮,
92+
查询使用OR语义;未知动作和非法绑定会报告错误。它不包含轴值、手柄或配置文件热重载,这些留到真正需要时再扩展。
93+
94+
## 每帧逻辑写在哪里
95+
96+
对象自己的运动用 `object.setUpdateCallback`:
97+
98+
```cpp
99+
object.setUpdateCallback([](GameObject &self, float deltaTime)
100+
{
101+
// 旋转单位为弧度,deltaTime单位为秒。
102+
self.transform.rotateEuler({0.0f, deltaTime, 0.0f});
103+
});
104+
```
105+
106+
按键持续移动用 `isKeyDown`;一次性动作如开关用 `wasKeyPressed`。旧 `isKeyPressed` 为兼容保留,含义仍是“按住”。
107+
对象回调中不能增删/清空Scene;需要增删时使用ApplicationCallbacks的update阶段,或先记录请求,下一轮应用update再处理。删掉对象后,其引用不能继续使用,长期记录请保存ObjectId并重新查找。
108+
109+
应用回调的顺序是:initialize只运行一次;之后每轮收集事件,执行onEvents,若可绘制则执行update、Scene::update、清屏、Scene::render、afterRender、交换缓冲。每个阶段结束后检查退出,不中断当前正在执行的回调或Scene遍历。
110+
111+
## 时间和暂停
112+
113+
- 初始化结束后才开始计时,首个更新dt为0。
114+
- 最小化或帧缓冲为零:只处理事件,暂停更新和绘制;使用最多50毫秒的事件等待避免空转。
115+
- 暂停恢复首帧dt为0,后续恢复正常。
116+
- 平常卡顿时运动dt最多0.1秒,可通过ApplicationConfig::maximumDeltaTime修改。
117+
- 真实时间通过frameTime().realDeltaTime / realElapsedTime读取;模拟时间通过deltaTime / simulationTime读取。真实时间包含暂停,模拟时间不包含暂停和被截断的部分。
118+
- onEvents在本轮时间采样前执行,适合退出和窗口事件,不适合依赖本轮dt的运动。
119+
- 失焦但没最小化时不自动暂停;隐藏测试窗口不等于最小化窗口。
120+
121+
## 运行与验证
122+
123+
```powershell
124+
E:/msys64/ucrt64/bin/cmake.exe --build --preset msys2-ucrt64-debug
125+
E:/msys64/ucrt64/bin/ctest.exe --preset msys2-ucrt64-debug
126+
./runtime/examples/application_template/application_template.exe
127+
```
128+
129+
空白模板显示蓝灰色背景是预期行为,不代表绘制失败。加入物体后把模板最后的ClearOnly改为DrawnScene,现有简单冒烟检查会要求窗口中点有区别于清屏的像素;若新示例的中点本来没有物体,需要为它设计对应的检查位置。
130+
131+
自动测试使用隐藏窗口和直接馈入的GLFW回调验证暂停接线,不模拟用户桌面操作。实机验收时请运行scene_objects:检查WASD、窗口缩放、最小化再恢复、Escape,以及关闭窗口;恢复后物体不应突然跳动。此项人工交互验收与自动测试分开记录。
132+
133+
`scene_objects` 的自由摄像机属于示例层控制器,文件位于 `examples/common/FreeCameraController.h`,没有进入 `src/` 框架层。WASD控制水平移动,Space/Ctrl控制升降,Shift临时加速;按住鼠标右键移动可以改变观察方向,R恢复初始位置。右键刚按下时会丢弃已有鼠标位移,失焦或暂停恢复时也会重置鼠标基准,避免摄像机突然跳转。

0 commit comments

Comments
 (0)