From 21f9436c41a8397fca64438b57477396992b4eb4 Mon Sep 17 00:00:00 2001 From: Ziyu Date: Sat, 10 Jan 2026 21:11:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E6=B8=85=E7=90=86=E5=B7=B2=E6=A0=87=E8=AE=B0=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E7=9A=84=E6=B8=B8=E6=88=8F=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_web | 2 +- src/engine/scene/scene.cpp | 36 ++++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/build_web b/build_web index 0e87798..15dc550 160000 --- a/build_web +++ b/build_web @@ -1 +1 @@ -Subproject commit 0e877989471abe35ea3331e8220e8a3eb7758fdd +Subproject commit 15dc5506585579cb7d9fb75bb28be59e04d0bf05 diff --git a/src/engine/scene/scene.cpp b/src/engine/scene/scene.cpp index 5ddc035..f2b849c 100644 --- a/src/engine/scene/scene.cpp +++ b/src/engine/scene/scene.cpp @@ -30,33 +30,41 @@ void Scene::init() { void Scene::update(float delta_time) { if (!is_initialized_) return; + // 先移除上一帧已经标记删除的对象,避免物理更新产生的碰撞事件持有悬空指针 + bool need_remove = false; // 设定一个标志,用于判断是否需要移除对象 + for (auto& obj : game_objects_) { + if (!obj) { + need_remove = true; + spdlog::warn("场景 '{}' 中存在空的游戏对象指针,将在本帧清理。", scene_name_); + continue; + } + if (obj->isNeedRemove()) { + need_remove = true; + obj->clean(); + } + } + if (need_remove) { + // NOTE: 需要先 clean 再 erase,确保组件(如 PhysicsComponent)能正确反注册 + std::erase_if(game_objects_, [](const std::unique_ptr& obj) { + return !obj || obj->isNeedRemove(); + }); + } + // 只有游戏进行中,才需要更新物理引擎和相机 if (context_.getGameState().isPlaying()){ context_.getPhysicsEngine().update(delta_time); context_.getCamera().update(delta_time); } - bool need_remove = false; // 设定一个标志,用于判断是否需要移除对象 - // 更新所有游戏对象,先略过需要移除的对象 for (auto& obj : game_objects_) { if (obj && !obj->isNeedRemove()) { obj->update(delta_time, context_); - } else { - need_remove = true; - if (obj) obj->clean(); // 如果对象需要移除,则先调用clean方法 - else spdlog::warn("尝试更新一个空的游戏对象指针。"); + } else if (!obj) { + spdlog::warn("尝试更新一个空的游戏对象指针。"); } } - if (need_remove) { - // 使用C++20新添加的erase_if删除需要移除的对象,比使用erase - remove_if更简洁 - // NOTE: 用此语句则没有机会调用clean方法,因此要在update中先调用clean方法 - std::erase_if(game_objects_, [](const std::unique_ptr& obj) { - return !obj || obj->isNeedRemove(); - }); - } - // 更新UI管理器 ui_manager_->update(delta_time, context_);