turtle/turtle-lib/examples/game_logic_demo.rs

107 lines
3.3 KiB
Rust

//! Example: Game Logic in Separate Thread
//!
//! This example demonstrates how to run game logic in a separate thread
//! while keeping the render loop responsive on the main thread.
//!
//! The main thread handles rendering and animation, while game logic
//! threads can perform blocking operations (like fetching data) and
//! send turtle commands via channels.
use std::thread;
use std::time::Duration;
use turtle_lib::*;
#[macroquad::main("Game Logic Threading")]
async fn main() {
let mut app = TurtleApp::new();
// Create two turtles and get their command senders
let turtle1_tx = app.create_turtle_channel(100);
let turtle2_tx = app.create_turtle_channel(100);
// Spawn first game logic thread
let _thread1 = thread::spawn({
let tx = turtle1_tx.clone();
move || {
// Simulate some blocking work (e.g., network request, calculation)
println!("Thread 1: Starting work...");
thread::sleep(Duration::from_millis(500));
// Now send turtle commands
let mut plan = create_turtle_plan();
plan.set_pen_color(BLUE)
.forward(100.0)
.right(90.0)
.forward(100.0)
.right(90.0)
.forward(100.0)
.right(90.0)
.forward(100.0);
tx.send(plan.build())
.expect("Failed to send commands for turtle 1");
println!("Thread 1: Commands sent!");
// Send more commands in a loop
for i in 0..10 {
thread::sleep(Duration::from_millis(300));
let mut step = create_turtle_plan();
step.right(36.0).forward(50.0);
let _ = tx.try_send(step.build());
println!("Thread 1: Step {} sent", i + 1);
}
}
});
// Spawn second game logic thread
let _thread2 = thread::spawn({
let tx = turtle2_tx.clone();
move || {
// Different timing than thread1
println!("Thread 2: Starting work...");
thread::sleep(Duration::from_millis(1000));
// Draw a circle with turtle2
let mut plan = create_turtle_plan();
plan.set_pen_color(RED).circle_left(75.0, 360.0, 72);
tx.send(plan.build())
.expect("Failed to send commands for turtle 2");
println!("Thread 2: Circle sent!");
}
});
// Main render loop
let mut frame_count = 0;
loop {
// Check for quit
if macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Escape)
|| macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Q)
{
break;
}
// Clear background
macroquad::prelude::clear_background(WHITE);
// Process incoming commands from game logic threads
// This drains all pending commands from turtle channels
app.process_commands();
// Update animation state (tweening, etc.)
app.update();
// Render the turtles
app.render();
frame_count += 1;
if frame_count % 60 == 0 {
println!("Rendered {} frames", frame_count);
}
macroquad::prelude::next_frame().await;
}
println!("Finished!");
}