A high-performance 3D boids flocking simulation with multiple rendering backends and neighbor search algorithms.
swarm-sim/
├── scripts/
│ └── run_sim.py # Main entry point script
├── src/swarm_sim/
│ ├── main.py # CLI entry point
│ ├── simulation/
│ │ ├── world.py # Main simulation world
│ │ ├── integrator.py # Physics integrators
│ │ └── boundary.py # Boundary conditions
│ ├── behaviors/
│ │ └── boids.py # Boids flocking behavior
│ ├── neighbors/
│ │ ├── brute_force.py # O(n²) neighbor search
│ │ └── spatial_hash.py # O(n) neighbor search
│ └── render/
│ ├── matplotlib_3d.py # Matplotlib renderer
│ └── vispy_3d.py # High-performance Vispy renderer
├── configs/
│ └── boids_3d.yaml # Simulation configuration
└── tests/
└── test_spatial_hash.py # Unit tests
# Clone or navigate to the project
cd swarm-sim
# Install required dependencies
pip install numpy matplotlib pyyaml
# Optional: Install Vispy for high-performance rendering
pip install vispy# Run with default configuration (2000 boids, matplotlib renderer)
python scripts/run_sim.py
# Run with custom number of steps
python scripts/run_sim.py --steps 500
# Run without visualization (faster)
python scripts/run_sim.py --no-render
# Run and render every 5th frame (better performance)
python scripts/run_sim.py --render-interval 5
# Using the main module
python -m src.swarm_sim.main --config configs/boids_3d.yamlEdit configs/boids_3d.yaml to customize the simulation:
seed: 42 # Random seed for reproducibility
simulation:
num_agents: 2000 # Number of boids
dt: 0.02 # Time step
steps: 5000 # Total simulation steps
world:
bounds: [50.0, 50.0, 50.0] # World size (x, y, z)
wrap: true # Wrap around boundaries (true) or bounce (false)
boids:
vision_radius: 4.0 # Neighborhood search radius
separation_radius: 1.2 # Close neighbor radius
max_speed: 3.0 # Maximum boid velocity
max_accel: 1.5 # Maximum acceleration
weight_separation: 1.8 # Separation rule weight
weight_alignment: 1.0 # Alignment rule weight
weight_cohesion: 0.9 # Cohesion rule weight
weight_noise: 0.05 # Random noise weight
render:
backend: matplotlib # 'matplotlib' or 'vispy'
fps: 30 # Target FPS
trail_length: 0 # Show boid trails (0 = no trails)- Brute Force (O(n²)): Good for ≤10k boids, simple and accurate
- Spatial Hash (O(n)): For large swarms (10k+ boids), much faster
- Matplotlib: Simple, interactive, good for small-medium swarms (≤1000 boids)
- Vispy: GPU-accelerated, handles 10k+ boids smoothly, requires installation
- Reduce render frequency: Use
--render-interval 5or higher - Disable rendering: Use
--no-renderfor benchmark tests - Use Vispy: For large swarms or high FPS requirements
- Adjust simulation parameters:
- Smaller vision_radius = fewer neighbors = faster
- Fewer boids = obviously faster
- Larger world = fewer boids per region
- Separation: Avoid crowding nearby flockmates
- Alignment: Steer towards the average heading of neighbors
- Cohesion: Steer to move toward the average location of neighbors
- Euler Integration: Fast, simple O(n) update
- Velocity Verlet: More stable, better energy conservation
- Semi-implicit Euler: Good balance of stability and performance
- Wrapping: Toroidal world (enter one side, exit the opposite)
- Bouncing: Entities reflect off walls with damping
- Cylindrical: 3D cylindrical world with wrapping on z-axis
from src.swarm_sim.simulation.world import World
# Create simulation
world = World('configs/boids_3d.yaml')
# Run for 100 steps with rendering
world.run(num_steps=100, render=True, render_interval=1)
# Print statistics
world.print_statistics()
# Or manually step through simulation
for step in range(100):
world.step()
if step % 10 == 0:
world.render_frame()
# Reset and run again
world.reset()
world.run(num_steps=100)Typical performance on a modern laptop:
| Boids | Backend | Neighbor Search | FPS |
|---|---|---|---|
| 100 | Matplotlib | Brute Force | 30 |
| 500 | Matplotlib | Brute Force | 10 |
| 2000 | Matplotlib | Brute Force | 2-3 |
| 2000 | Vispy | Spatial Hash | 60+ |
| 10000 | Vispy | Spatial Hash | 30-40 |
python test_system.py- Boids class: Implements flocking rules and neighbor queries
- World class: Main simulation loop, integrates all components
- Integrator classes: Handle physics time stepping
- Boundary classes: Enforce domain constraints
- Neighbor search: Find nearby boids efficiently
- Renderers: Display the simulation
- Obstacles and predators
- Different boid types/groups
- GPU-accelerated neighbor search
- Advanced rendering effects (trails, particle systems)
- Parameter optimization/tuning UI
- Multi-threaded simulation
- Real-time performance profiling
MIT
- Boids original paper: http://www.red3d.com/cwr/boids/
- Flocking algorithms: https://en.wikipedia.org/wiki/Flocking_(behavior)