Adam Djellouli 2 months ago
parent
commit
aeda796ea0
2 changed files with 47 additions and 121 deletions
  1. 47 0
      game/systems/command_service.cpp
  2. 0 121
      game/systems/movement_system.cpp

+ 47 - 0
game/systems/command_service.cpp

@@ -879,6 +879,53 @@ void CommandService::process_path_results(Engine::Core::World &world) {
         Point const current_grid = world_to_grid(member_transform->position.x,
                                                  member_transform->position.z);
 
+        // Check if unit is currently on an invalid cell (pushed there during combat)
+        bool const current_cell_invalid =
+            request_info.unit_radius <= kUnitRadiusThreshold
+                ? !s_pathfinder->is_walkable(current_grid.x, current_grid.y)
+                : !s_pathfinder->is_walkable_with_radius(
+                      current_grid.x, current_grid.y, request_info.unit_radius);
+
+        if (current_cell_invalid) {
+          // Unit is on invalid cell - find nearest walkable point and move there
+          constexpr int kNearestPointSearchRadius = 5;
+          Point const nearest = Pathfinding::find_nearest_walkable_point(
+              current_grid, kNearestPointSearchRadius, *s_pathfinder,
+              request_info.unit_radius);
+
+          if (!(nearest == current_grid)) {
+            // Found a valid nearby cell - teleport with jitter
+            QVector3D safe_pos = grid_to_world(nearest);
+
+            thread_local std::random_device rd;
+            thread_local std::mt19937 gen(rd());
+            std::uniform_real_distribution<float> dist(-kJitterDistance,
+                                                       kJitterDistance);
+
+            float const jitter_x = dist(gen);
+            float const jitter_z = dist(gen);
+
+            member_transform->position.x = safe_pos.x() + jitter_x;
+            member_transform->position.z = safe_pos.z() + jitter_z;
+          } else {
+            // No walkable cell found nearby - apply random jitter as last resort
+            thread_local std::random_device rd;
+            thread_local std::mt19937 gen(rd());
+            std::uniform_real_distribution<float> dist(-kJitterDistance,
+                                                       kJitterDistance);
+
+            member_transform->position.x += dist(gen);
+            member_transform->position.z += dist(gen);
+          }
+
+          movement_component->has_target = false;
+          movement_component->vx = 0.0F;
+          movement_component->vz = 0.0F;
+
+          return;
+        }
+
+        // Fallback: all surrounding cells invalid (completely trapped)
         if (are_all_surrounding_cells_invalid(current_grid, *s_pathfinder,
                                               request_info.unit_radius)) {
 

+ 0 - 121
game/systems/movement_system.cpp

@@ -18,12 +18,6 @@ namespace Game::Systems {
 
 static constexpr int max_waypoint_skip_count = 4;
 static constexpr float repath_cooldown_seconds = 0.4F;
-static constexpr int kNearestPointSearchRadius = 5;
-
-static constexpr float kStuckDetectionThreshold = 0.1F;
-static constexpr float kStuckTimeThreshold = 2.0F;
-static constexpr float kUnstuckCooldown = 1.5F;
-static constexpr float kUnstuckOffsetRadius = 1.0F;
 
 namespace {
 
@@ -85,121 +79,6 @@ auto is_segment_walkable(const QVector3D &from, const QVector3D &to,
   return true;
 }
 
-auto try_unstuck_unit(Engine::Core::World &world, Engine::Core::Entity *entity,
-                      Engine::Core::TransformComponent *transform,
-                      Engine::Core::MovementComponent *movement,
-                      float unit_radius, float delta_time) -> bool {
-
-  auto &terrain = Game::Map::TerrainService::instance();
-  bool const on_bridge =
-      terrain.is_initialized() &&
-      terrain.is_on_bridge(transform->position.x, transform->position.z);
-
-  float const stuck_threshold = on_bridge ? 1.0F : kStuckTimeThreshold;
-  float const unstuck_cooldown = on_bridge ? 0.8F : kUnstuckCooldown;
-
-  float const dx = transform->position.x - movement->last_position_x;
-  float const dz = transform->position.z - movement->last_position_z;
-  float const distance_moved = std::sqrt(dx * dx + dz * dz);
-
-  if (distance_moved < kStuckDetectionThreshold && movement->has_target) {
-    movement->time_stuck += delta_time;
-  } else {
-    movement->time_stuck = 0.0F;
-  }
-
-  movement->last_position_x = transform->position.x;
-  movement->last_position_z = transform->position.z;
-
-  if (movement->unstuck_cooldown > 0.0F) {
-    movement->unstuck_cooldown -= delta_time;
-  }
-
-  if (movement->time_stuck > stuck_threshold &&
-      movement->unstuck_cooldown <= 0.0F && movement->has_target) {
-    bool const had_target = movement->has_target;
-    QVector3D const goal_pos(movement->goal_x, 0.0F, movement->goal_y);
-
-    Pathfinding *pathfinder = CommandService::get_pathfinder();
-    if (pathfinder != nullptr) {
-
-      Point const current_grid = CommandService::world_to_grid(
-          transform->position.x, transform->position.z);
-
-      Point const nearest = Pathfinding::find_nearest_walkable_point(
-          current_grid, kNearestPointSearchRadius, *pathfinder, unit_radius);
-
-      if (!(nearest == current_grid)) {
-
-        QVector3D safe_pos = CommandService::grid_to_world(nearest);
-
-        thread_local std::random_device rd;
-        thread_local std::mt19937 gen(rd());
-        std::uniform_real_distribution<float> dist(-kUnstuckOffsetRadius,
-                                                   kUnstuckOffsetRadius);
-
-        float const offset_x = dist(gen);
-        float const offset_z = dist(gen);
-
-        QVector3D const offset_pos(safe_pos.x() + offset_x, safe_pos.y(),
-                                   safe_pos.z() + offset_z);
-
-        if (is_point_allowed(offset_pos, entity->get_id(), unit_radius)) {
-          safe_pos = offset_pos;
-        }
-
-        transform->position.x = safe_pos.x();
-        transform->position.z = safe_pos.z();
-
-        movement->time_stuck = 0.0F;
-        movement->unstuck_cooldown = unstuck_cooldown;
-
-        movement->clear_path();
-        movement->path_pending = false;
-        movement->pending_request_id = 0;
-        movement->has_target = false;
-        movement->vx = 0.0F;
-        movement->vz = 0.0F;
-        movement->repath_cooldown = 0.0F;
-
-        if (had_target) {
-          CommandService::MoveOptions opts;
-          opts.clear_attack_intent = false;
-          opts.allow_direct_fallback = false;
-          std::vector<Engine::Core::EntityID> const ids = {entity->get_id()};
-          std::vector<QVector3D> const targets = {goal_pos};
-          CommandService::move_units(world, ids, targets, opts);
-        }
-
-        return true;
-      }
-    }
-
-    movement->time_stuck = 0.0F;
-    movement->unstuck_cooldown = unstuck_cooldown;
-    movement->clear_path();
-    movement->path_pending = false;
-    movement->pending_request_id = 0;
-    movement->has_target = false;
-    movement->vx = 0.0F;
-    movement->vz = 0.0F;
-    movement->repath_cooldown = 0.0F;
-
-    if (had_target) {
-      CommandService::MoveOptions opts;
-      opts.clear_attack_intent = false;
-      opts.allow_direct_fallback = false;
-      std::vector<Engine::Core::EntityID> const ids = {entity->get_id()};
-      std::vector<QVector3D> const targets = {goal_pos};
-      CommandService::move_units(world, ids, targets, opts);
-    }
-
-    return true;
-  }
-
-  return false;
-}
-
 } // namespace
 
 void MovementSystem::update(Engine::Core::World *world, float delta_time) {