FASE 2: Spatial Hash Grid - Optimización O(n²) → O(n) para boids
Implementado sistema genérico de particionamiento espacial reutilizable que reduce drásticamente la complejidad del algoritmo de boids. **MEJORA DE RENDIMIENTO ESPERADA:** - Sin grid: 1000 boids = 1M comparaciones (1000²) - Con grid: 1000 boids ≈ 9K comparaciones (~9 vecinos/celda) - **Speedup teórico: ~100x en casos típicos** **COMPONENTES IMPLEMENTADOS:** 1. **SpatialGrid genérico (spatial_grid.h/.cpp):** - Divide espacio 2D en celdas de 100x100px - Hash map para O(1) lookup de celdas - queryRadius(): Busca solo en celdas adyacentes (máx 9 celdas) - Reutilizable para colisiones ball-to-ball en física (futuro) 2. **Integración en BoidManager:** - Grid poblado al inicio de cada frame (O(n)) - 3 reglas de Reynolds ahora usan queryRadius() en lugar de iterar TODOS - Separación/Alineación/Cohesión: O(n) total en lugar de O(n²) 3. **Configuración (defines.h):** - BOID_GRID_CELL_SIZE = 100.0f (≥ BOID_COHESION_RADIUS) **CAMBIOS TÉCNICOS:** - boid_manager.h: Añadido miembro spatial_grid_ - boid_manager.cpp: update() poblа grid, 3 reglas usan queryRadius() - spatial_grid.cpp: 89 líneas de implementación genérica - spatial_grid.h: 74 líneas con documentación exhaustiva **PRÓXIMOS PASOS:** - Medir rendimiento real con 1K, 5K, 10K boids - Comparar FPS antes/después - Validar que comportamiento es idéntico 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,8 @@ BoidManager::BoidManager()
|
||||
, state_mgr_(nullptr)
|
||||
, screen_width_(0)
|
||||
, screen_height_(0)
|
||||
, boids_active_(false) {
|
||||
, boids_active_(false)
|
||||
, spatial_grid_(800, 600, BOID_GRID_CELL_SIZE) { // Tamaño por defecto, se actualiza en initialize()
|
||||
}
|
||||
|
||||
BoidManager::~BoidManager() {
|
||||
@@ -30,11 +31,17 @@ void BoidManager::initialize(Engine* engine, SceneManager* scene_mgr, UIManager*
|
||||
state_mgr_ = state_mgr;
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
// Actualizar dimensiones del spatial grid
|
||||
spatial_grid_.updateWorldSize(screen_width, screen_height);
|
||||
}
|
||||
|
||||
void BoidManager::updateScreenSize(int width, int height) {
|
||||
screen_width_ = width;
|
||||
screen_height_ = height;
|
||||
|
||||
// Actualizar dimensiones del spatial grid (FASE 2)
|
||||
spatial_grid_.updateWorldSize(width, height);
|
||||
}
|
||||
|
||||
void BoidManager::activateBoids() {
|
||||
@@ -92,7 +99,17 @@ void BoidManager::update(float delta_time) {
|
||||
|
||||
auto& balls = scene_mgr_->getBallsMutable();
|
||||
|
||||
// FASE 2: Poblar spatial grid al inicio de cada frame (O(n))
|
||||
spatial_grid_.clear();
|
||||
for (auto& ball : balls) {
|
||||
SDL_FRect pos = ball->getPosition();
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
spatial_grid_.insert(ball.get(), center_x, center_y);
|
||||
}
|
||||
|
||||
// Aplicar las tres reglas de Reynolds a cada boid
|
||||
// FASE 2: Ahora usa spatial grid para búsquedas O(1) en lugar de O(n)
|
||||
for (auto& ball : balls) {
|
||||
applySeparation(ball.get(), delta_time);
|
||||
applyAlignment(ball.get(), delta_time);
|
||||
@@ -128,9 +145,11 @@ void BoidManager::applySeparation(Ball* boid, float delta_time) {
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
const auto& balls = scene_mgr_->getBalls();
|
||||
for (const auto& other : balls) {
|
||||
if (other.get() == boid) continue; // Ignorar a sí mismo
|
||||
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, BOID_SEPARATION_RADIUS);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue; // Ignorar a sí mismo
|
||||
|
||||
SDL_FRect other_pos = other->getPosition();
|
||||
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||
@@ -174,9 +193,11 @@ void BoidManager::applyAlignment(Ball* boid, float delta_time) {
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
const auto& balls = scene_mgr_->getBalls();
|
||||
for (const auto& other : balls) {
|
||||
if (other.get() == boid) continue;
|
||||
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, BOID_ALIGNMENT_RADIUS);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue;
|
||||
|
||||
SDL_FRect other_pos = other->getPosition();
|
||||
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||
@@ -229,9 +250,11 @@ void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
const auto& balls = scene_mgr_->getBalls();
|
||||
for (const auto& other : balls) {
|
||||
if (other.get() == boid) continue;
|
||||
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, BOID_COHESION_RADIUS);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue;
|
||||
|
||||
SDL_FRect other_pos = other->getPosition();
|
||||
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
|
||||
#include "../defines.h" // for SimulationMode, AppMode
|
||||
#include "../defines.h" // for SimulationMode, AppMode
|
||||
#include "../spatial_grid.h" // for SpatialGrid
|
||||
|
||||
// Forward declarations
|
||||
class Engine;
|
||||
@@ -98,6 +99,10 @@ class BoidManager {
|
||||
// Estado del modo boids
|
||||
bool boids_active_;
|
||||
|
||||
// Spatial Hash Grid para optimización O(n²) → O(n)
|
||||
// FASE 2: Grid reutilizable para búsquedas de vecinos
|
||||
SpatialGrid spatial_grid_;
|
||||
|
||||
// Métodos privados para las reglas de Reynolds
|
||||
void applySeparation(Ball* boid, float delta_time);
|
||||
void applyAlignment(Ball* boid, float delta_time);
|
||||
|
||||
Reference in New Issue
Block a user