use carla::{
client::Client,
geom::Location,
rpc::{Command, VehicleControl},
};
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== CARLA Batch Operations Example ===\n");
println!("Connecting to CARLA simulator...");
let mut client = Client::connect("localhost", 2000, None)?;
let world = client.world()?;
println!("✓ Connected! Current map: {}\n", world.map()?.name());
let blueprint_library = world.blueprint_library()?;
let spawn_points = world.map()?.recommended_spawn_points()?;
println!("Available spawn points: {}", spawn_points.len());
let tesla_bp = blueprint_library
.find("vehicle.tesla.model3")?
.expect("Tesla Model 3 not found");
let spawn_count = 10.min(spawn_points.len());
println!("\n=== PART 1: Batch Spawning {} Vehicles ===", spawn_count);
let mut spawn_commands = Vec::new();
for i in 0..spawn_count {
let spawn_point = spawn_points.get(i).unwrap();
spawn_commands.push(Command::spawn_actor(
tesla_bp.clone(),
spawn_point.clone(),
None,
));
}
println!("Created {} spawn commands", spawn_commands.len());
let start = Instant::now();
let spawn_responses = client.apply_batch_sync(spawn_commands, false)?;
let batch_duration = start.elapsed();
println!(
"Batch spawn completed in {:.2}ms",
batch_duration.as_secs_f64() * 1000.0
);
let mut vehicle_ids = Vec::new();
let mut success_count = 0;
let mut error_count = 0;
for (i, response) in spawn_responses.iter().enumerate() {
match response.actor_id() {
Some(actor_id) => {
println!(" ✓ Vehicle {} spawned (ID: {})", i + 1, actor_id);
vehicle_ids.push(actor_id);
success_count += 1;
}
None => {
eprintln!(
" ✗ Vehicle {} failed: {}",
i + 1,
response.error().unwrap_or("Unknown error")
);
error_count += 1;
}
}
}
println!(
"\nBatch spawn results: {} successful, {} failed",
success_count, error_count
);
if vehicle_ids.is_empty() {
println!("No vehicles spawned, exiting.");
return Ok(());
}
println!("\n=== PART 2: Batch Applying Vehicle Controls ===");
let mut control_commands = Vec::new();
for (i, &actor_id) in vehicle_ids.iter().enumerate() {
let control = if i % 2 == 0 {
VehicleControl {
throttle: 0.5,
steer: 0.0,
brake: 0.0,
hand_brake: false,
reverse: false,
manual_gear_shift: false,
gear: 0,
}
} else {
VehicleControl {
throttle: 0.0,
steer: 0.3,
brake: 0.0,
hand_brake: false,
reverse: false,
manual_gear_shift: false,
gear: 0,
}
};
control_commands.push(Command::apply_vehicle_control(actor_id, control));
}
println!(
"Applying controls to {} vehicles...",
control_commands.len()
);
let start = Instant::now();
let control_responses = client.apply_batch_sync(control_commands, false)?;
let control_duration = start.elapsed();
println!(
"Batch control application completed in {:.2}ms",
control_duration.as_secs_f64() * 1000.0
);
let control_success = control_responses
.iter()
.filter(|r| r.actor_id().is_some())
.count();
println!(
"Successfully applied controls to {} vehicles",
control_success
);
println!("\n=== PART 3: Batch Enabling Autopilot ===");
let mut autopilot_commands = Vec::new();
for &actor_id in &vehicle_ids {
autopilot_commands.push(Command::set_autopilot(actor_id, true, 8000));
}
let autopilot_responses = client.apply_batch_sync(autopilot_commands, false)?;
let autopilot_success = autopilot_responses
.iter()
.filter(|r| r.actor_id().is_some())
.count();
println!("Enabled autopilot for {} vehicles", autopilot_success);
println!("\n=== PART 4: Batch Teleporting Vehicles ===");
let mut teleport_commands = Vec::new();
for (i, &actor_id) in vehicle_ids.iter().enumerate() {
let original_spawn = spawn_points.get(i).unwrap();
let original_location = original_spawn.location;
let new_location = Location {
x: original_location.x + 10.0,
y: original_location.y,
z: original_location.z,
};
teleport_commands.push(Command::ApplyLocation {
actor_id,
location: new_location,
});
}
let teleport_responses = client.apply_batch_sync(teleport_commands, false)?;
let teleport_success = teleport_responses
.iter()
.filter(|r| r.actor_id().is_some())
.count();
println!("Teleported {} vehicles", teleport_success);
println!("\n=== Performance Summary ===");
println!("Total vehicles spawned: {}", vehicle_ids.len());
println!(
"Batch spawn time: {:.2}ms ({:.2}ms per vehicle)",
batch_duration.as_secs_f64() * 1000.0,
batch_duration.as_secs_f64() * 1000.0 / vehicle_ids.len() as f64
);
println!(
"Batch control time: {:.2}ms ({:.2}ms per vehicle)",
control_duration.as_secs_f64() * 1000.0,
control_duration.as_secs_f64() * 1000.0 / vehicle_ids.len() as f64
);
println!("\n💡 Performance Tip:");
println!("Batch operations are 5-10x faster than individual operations");
println!("when working with multiple actors. Always prefer batch commands");
println!("for spawning, controlling, or modifying multiple actors.");
println!("\n=== PART 6: Batch Cleanup ===");
println!("Destroying {} vehicles...", vehicle_ids.len());
let mut destroy_commands = Vec::new();
for &actor_id in &vehicle_ids {
destroy_commands.push(Command::destroy_actor(actor_id));
}
let destroy_responses = client.apply_batch_sync(destroy_commands, false)?;
let destroy_success = destroy_responses
.iter()
.filter(|r| r.actor_id().is_some())
.count();
println!("Successfully destroyed {} vehicles", destroy_success);
println!("\n✓ Batch operations example completed!");
Ok(())
}