From d49aef8c0f14aa2d99d7656b869ab6af3eabc546 Mon Sep 17 00:00:00 2001 From: SepComet <2428390463@qq.com> Date: Thu, 11 Jun 2026 15:27:57 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20LightGame=20=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E7=A2=B0=E6=92=9E=E4=B8=8E=E9=97=A8=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LightPlatform / ShadowPlatform:移除单向板碰撞逻辑,改为完整 tile 碰撞体 - Door:碰撞箱从 32x64 改为 32x32,与单 tile 素材匹配 - 修复 game_engine_tests 编译:补全 LevelData 初始化字段,增加缺失的 include path --- CMakeLists.txt | 2 ++ README.md | 21 ++++++++++++++++++- src/Apps/LightGame/src/engine/LevelLoader.cpp | 2 +- src/Apps/LightGame/src/engine/Physics2D.cpp | 18 ---------------- tests/game_engine_tests.cpp | 2 ++ 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aab60d..ea91965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,8 @@ if(BUILD_TESTING AND NOT USE_FRAMEBUFFER) target_include_directories(game_engine_tests PRIVATE src/Apps/LightGame/src/engine src/Apps/LightGame/src/systems + src/Apps/LightGame/src/levels + src/Apps/LightGame/generated ${CORE_INCLUDE_DIRS} ) diff --git a/README.md b/README.md index f925527..42a61ad 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ - **Linux x86 编译**:验证代码在 GCC/Clang 下有无警告、CMake 配置是否跨平台、系统 SDL2 依赖是否正确。很多嵌入式工具链的问题在 x86 Linux 上就能提前暴露。 - **ARM 交叉编译**:最终在 IMX6U 上跑。若目标板使用 SDL2,则 SDL2 仅作为显示/输入适配层,时间由独立 `Platform::ITimeSource` 提供,核心渲染仍按 CPU framebuffer + 一次性提交设计;如需极简依赖,也保留 `/dev/fb0` 后端作为对照。 - ## 开发规范与性能红线 IMX6U 运行时性能预算较紧,后续开发必须遵守 `docs/DEVELOPMENT_GUIDELINES.md`。如果目标板使用 SDL2,仍然要把 SDL2 限制在平台适配层,核心逻辑和渲染热路径不直接依赖 SDL: @@ -62,22 +61,26 @@ cmake --build build-win --config Release ``` 只构建某个 App: + ```bash cmake --build build-win --config Release --target IMX6U-Game cmake --build build-win --config Release --target IMX6U-Demo ``` 构建 `IMX6U-Game` 时会自动重新生成 Tom 的 atlas 头文件;也可以单独执行: + ```bash cmake --build build-win --config Release --target GenerateTomAtlasHeader ``` 运行: + ```bash ./build-win/Release/IMX6U-Game.exe ``` 可选帧率档位: + ```bash ./build-win/Release/IMX6U-Game.exe --fps 30 ./build-win/Release/IMX6U-Game.exe --fps 45 @@ -95,23 +98,27 @@ sudo apt-get install libsdl2-dev libsdl2-image-dev cmake g++ ``` 构建: + ```bash cmake -B build-linux . cmake --build build-linux ``` 只构建某个 App: + ```bash cmake --build build-linux --target IMX6U-Game cmake --build build-linux --target IMX6U-Demo ``` 构建 `IMX6U-Game` 时会自动重新生成 Tom 的 atlas 头文件;也可以单独执行: + ```bash cmake --build build-linux --target GenerateTomAtlasHeader ``` 运行: + ```bash ./build-linux/IMX6U-Game ``` @@ -130,6 +137,7 @@ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf - **Framebuffer 后端**:作为极简依赖和显示通路对照测试。 构建(Framebuffer 对照后端): + ```bash cmake -B build-arm-fb \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-linux-gnueabihf.cmake \ @@ -142,6 +150,7 @@ cmake --build build-arm-fb 注意:Tom 的 atlas 头文件生成工具是主机侧离线工具,依赖 PC/Linux 主机上的 SDL2_image;主机构建 `IMX6U-Game` 时会自动执行,ARM 交叉编译过程不会执行它。如果修改了 `src/Apps/Game/assets/raw/` 里的 PNG,必须先在 Windows 或 Linux x86 构建目录执行 `GenerateTomAtlasHeader` 或构建一次 `IMX6U-Game`,再进行 ARM 交叉编译。ARM 构建只消费已经生成好的 `src/Apps/Game/generated/tom_atlas.h`。 构建(SDL2 后端,要求工具链/sysroot 可找到目标板 SDL2 开发库): + ```bash cmake -B build-arm-sdl \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-linux-gnueabihf.cmake \ @@ -150,6 +159,7 @@ cmake --build build-arm-sdl ``` 部署到开发板: + ```bash scp build-arm-sdl/IMX6U-Game root@imx6u:/tmp/ # 或部署 framebuffer 对照版本: @@ -157,6 +167,7 @@ scp build-arm-fb/IMX6U-Game root@imx6u:/tmp/ ``` 板子上运行: + ```bash /tmp/IMX6U-Game ``` @@ -315,9 +326,11 @@ IMX6U-Game/ ## 模块说明 ### Draw2D + - **DrawContext**:统一绘制入口,封装 FrameBuffer、DepthBuffer、Rasterizer、TriangleRasterizer,对外提供 `clear`、`clear_color`、`clear_depth`、`draw_line`、`draw_triangle`、`draw_sprite`、`draw_sprite_ex`、`draw_text`、`draw_tilemap`、`fill_rect`、`present` 接口 ### RenderData + - **Image**:通用图像数据结构,持有 `const void* pixels` 和 `PixelFormat`(当前统一 `RGBA5551`),支持 color_key 透明跳过 - **Sprite**:描述 atlas 中的子区域,通过 `const Image* atlas` 引用源图,是对外 sprite 绘制单位 - **Tilemap**:使用 `uint16_t` tile id 引用 atlas 中的固定大小 tile,`EmptyTile` (`0xFFFF`) 表示空 tile @@ -325,20 +338,24 @@ IMX6U-Game/ - **Color**:RGBA8888 颜色值,用于绘制接口参数和调试;sprite 运行时像素格式仍为 RGBA5551 ### Core + - **FrameBuffer**:CPU 侧 RGB565 颜色缓冲,渲染结果先写在这里 - **DepthBuffer**:深度测试用 Z-buffer - **Renderer**:渲染器辅助工具 - **Timer**:整数毫秒固定步长 tick 生成器,支持 30/45/60 FPS 档位和每帧剩余时间计算 ### Math + - 通用数学类型:`Vector2/3/4`、`Matrix4x4` - 纯头文件实现,无动态分配 ### Rasterizer + - **Rasterizer**:Bresenham 线段光栅化,入口做快速全屏可见性检查,屏幕内走 `set_pixel_unsafe` 快路径,屏幕外走 Cohen-Sutherland 裁剪 - **TriangleRasterizer**:扫描线三角形填充 + 定点深度插值(增量式整数边缘函数,内层循环无 float 运算) ### Platform + - **IDisplay**:显示后端抽象,解耦渲染与输出 - **SDLDisplay**:SDL2 后端,PC 调试和 IMX6U SDL2 目标路径共用这一类适配思想 - **FBDisplay**:`/dev/fb0` 对照后端,用于极简显示通路验证 @@ -366,6 +383,7 @@ IMX6U-Game/ ## 当前状态与后续 **已完成:** + - 可旋转立方体的 3D 渲染(MVP 变换、背面剔除、扫描线填充、深度测试) - 双平台显示后端(SDL2 / Framebuffer) - 离线资源转换工具:PNG sprite -> RGBA5551 C++ 头文件,像素字体 -> bitmap atlas/header @@ -376,6 +394,7 @@ IMX6U-Game/ - CMake 跨平台构建 **待完成(按优先级):** + 1. FrameBuffer / FBDisplay 性能优化(目标像素格式 backbuffer、dirty rect、专用 tile/sprite 快路径、NEON) 2. 应用层拆分(Launcher / GameA / GameB / Shared)和统一 `IApp` 主循环 3. SDL2 输入抽象(键盘/触摸/按键状态快照) diff --git a/src/Apps/LightGame/src/engine/LevelLoader.cpp b/src/Apps/LightGame/src/engine/LevelLoader.cpp index 33ebd92..9065566 100644 --- a/src/Apps/LightGame/src/engine/LevelLoader.cpp +++ b/src/Apps/LightGame/src/engine/LevelLoader.cpp @@ -84,7 +84,7 @@ namespace LightGame case GameObjectType::Door: obj.collider = RenderData::BoundingBox2D( - Math::Vector2Int(0, 0), Math::Vector2Int(ts, ts * 2)); + Math::Vector2Int(0, 0), Math::Vector2Int(ts, ts)); obj.solid = true; obj.light_threshold = LightThreshold(spawn.light_min, spawn.light_max); obj.sprite = &spr_door_closed; diff --git a/src/Apps/LightGame/src/engine/Physics2D.cpp b/src/Apps/LightGame/src/engine/Physics2D.cpp index 5c6692e..3cb0bb0 100644 --- a/src/Apps/LightGame/src/engine/Physics2D.cpp +++ b/src/Apps/LightGame/src/engine/Physics2D.cpp @@ -143,9 +143,6 @@ namespace LightGame continue; } - const bool is_one_way = (other.type == GameObjectType::LightPlatform || - other.type == GameObjectType::ShadowPlatform); - const RenderData::BoundingBox2D other_world = other.get_world_collider(); world_collider = obj.get_world_collider(); @@ -154,21 +151,6 @@ namespace LightGame continue; } - if (is_one_way) - { - const int32_t obj_bottom = world_collider.max.y; - const int32_t other_top = other_world.min.y; - const int32_t prev_bottom = obj_bottom - move_y; - - if (prev_bottom > other_top || obj.velocity.y <= 0) - { - continue; - } - - obj.position.y = other_top - (obj.collider.max.y - obj.collider.min.y); - obj.velocity.y = 0; - } - else { const int32_t overlap_left = world_collider.max.x - other_world.min.x; const int32_t overlap_right = other_world.max.x - world_collider.min.x; diff --git a/tests/game_engine_tests.cpp b/tests/game_engine_tests.cpp index c217305..c9ec62d 100644 --- a/tests/game_engine_tests.cpp +++ b/tests/game_engine_tests.cpp @@ -392,6 +392,8 @@ namespace 0, spawns, 2, + nullptr, + 0, Math::Vector2Int(16, 16), 0, 0,