```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);
```
114 lines
2.6 KiB
Rust
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()
|
|
}
|
|
}
|