Franz Dietrich 25753b47ce Initial macroquad version for compiletime reasons
```rust
// Movement
plan.forward(100);
plan.backward(50);

// Rotation
plan.left(90);    // degrees
plan.right(45);

// Circular arcs
plan.circle_left(50.0, 180.0, 36);   // radius, angle (degrees), segments
plan.circle_right(50.0, 180.0, 36);  // draws arc to the right

// Pen control
plan.pen_up();
plan.pen_down();

// Appearance
plan.set_color(RED);
plan.set_pen_width(5.0);
plan.hide();
plan.show();

// Turtle shape
plan.shape(ShapeType::Triangle);
plan.shape(ShapeType::Turtle);    // Default classic turtle shape
plan.shape(ShapeType::Circle);
plan.shape(ShapeType::Square);
plan.shape(ShapeType::Arrow);

// Custom shape
let custom = TurtleShape::new(
    vec![vec2(10.0, 0.0), vec2(-5.0, 5.0), vec2(-5.0, -5.0)],
    true  // filled
);
plan.set_shape(custom);

// Chaining
plan.forward(100).right(90).forward(50);
```
2025-10-09 09:12:16 +02:00

114 lines
2.6 KiB
Rust

//! Turtle state and world state management
use crate::general::{Angle, Color, Coordinate, Precision, Speed};
use crate::shapes::TurtleShape;
use macroquad::prelude::*;
/// State of a single turtle
#[derive(Clone, Debug)]
pub struct TurtleState {
pub position: Coordinate,
pub heading: Precision, // radians
pub pen_down: bool,
pub color: Color,
pub fill_color: Option<Color>,
pub pen_width: Precision,
pub speed: Speed,
pub visible: bool,
pub shape: TurtleShape,
}
impl Default for TurtleState {
fn default() -> Self {
Self {
position: vec2(0.0, 0.0),
heading: 0.0, // pointing right (0 radians)
pen_down: true,
color: BLACK,
fill_color: None,
pen_width: 2.0,
speed: 100, // pixels per second
visible: true,
shape: TurtleShape::turtle(),
}
}
}
impl TurtleState {
pub fn set_speed(&mut self, speed: Speed) {
self.speed = speed.max(1);
}
pub fn heading_angle(&self) -> Angle {
Angle::radians(self.heading)
}
}
/// Drawable elements in the world
#[derive(Clone, Debug)]
pub enum DrawCommand {
Line {
start: Coordinate,
end: Coordinate,
color: Color,
width: Precision,
},
Circle {
center: Coordinate,
radius: Precision,
color: Color,
filled: bool,
},
Arc {
center: Coordinate,
radius: Precision,
rotation: Precision, // Start angle in degrees
arc: Precision, // Arc extent in degrees
color: Color,
width: Precision,
sides: u8, // Number of segments for quality
},
FilledPolygon {
vertices: Vec<Coordinate>,
color: Color,
},
}
/// The complete turtle world containing all drawing state
pub struct TurtleWorld {
pub turtle: TurtleState,
pub commands: Vec<DrawCommand>,
pub camera: Camera2D,
pub background_color: Color,
}
impl TurtleWorld {
pub fn new() -> Self {
Self {
turtle: TurtleState::default(),
commands: Vec::new(),
camera: Camera2D {
zoom: vec2(1.0 / screen_width() * 2.0, 1.0 / screen_height() * 2.0),
target: vec2(0.0, 0.0),
..Default::default()
},
background_color: WHITE,
}
}
pub fn add_command(&mut self, cmd: DrawCommand) {
self.commands.push(cmd);
}
pub fn clear(&mut self) {
self.commands.clear();
self.turtle = TurtleState::default();
}
}
impl Default for TurtleWorld {
fn default() -> Self {
Self::new()
}
}