unify Left and Right to turn and forward backward to move
This commit is contained in:
parent
7da0dcf141
commit
cebad0459c
@ -17,7 +17,7 @@ pub trait DirectionalMovement: WithCommands {
|
||||
T: Into<Precision>,
|
||||
{
|
||||
let dist: Precision = distance.into();
|
||||
self.get_commands_mut().push(TurtleCommand::Forward(dist));
|
||||
self.get_commands_mut().push(TurtleCommand::Move(dist));
|
||||
self
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ pub trait DirectionalMovement: WithCommands {
|
||||
T: Into<Precision>,
|
||||
{
|
||||
let dist: Precision = distance.into();
|
||||
self.get_commands_mut().push(TurtleCommand::Backward(dist));
|
||||
self.get_commands_mut().push(TurtleCommand::Move(-dist));
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ pub trait Turnable: WithCommands {
|
||||
T: Into<Precision>,
|
||||
{
|
||||
let degrees: Precision = angle.into();
|
||||
self.get_commands_mut().push(TurtleCommand::Left(degrees));
|
||||
self.get_commands_mut().push(TurtleCommand::Turn(-degrees));
|
||||
self
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ pub trait Turnable: WithCommands {
|
||||
T: Into<Precision>,
|
||||
{
|
||||
let degrees: Precision = angle.into();
|
||||
self.get_commands_mut().push(TurtleCommand::Right(degrees));
|
||||
self.get_commands_mut().push(TurtleCommand::Turn(degrees));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,13 +6,11 @@ use crate::shapes::TurtleShape;
|
||||
/// Individual turtle commands
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TurtleCommand {
|
||||
// Movement
|
||||
Forward(Precision),
|
||||
Backward(Precision),
|
||||
// Movement (positive = forward, negative = backward)
|
||||
Move(Precision),
|
||||
|
||||
// Rotation
|
||||
Left(Precision), // degrees
|
||||
Right(Precision), // degrees
|
||||
// Rotation (positive = right/clockwise, negative = left/counter-clockwise in degrees)
|
||||
Turn(Precision),
|
||||
|
||||
// Circle drawing
|
||||
Circle {
|
||||
|
||||
@ -187,10 +187,7 @@ pub(crate) fn render_world_with_tween(
|
||||
|
||||
fn should_draw_tween_line(command: &crate::commands::TurtleCommand) -> bool {
|
||||
use crate::commands::TurtleCommand;
|
||||
matches!(
|
||||
command,
|
||||
TurtleCommand::Forward(..) | TurtleCommand::Backward(..) | TurtleCommand::Goto(..)
|
||||
)
|
||||
matches!(command, TurtleCommand::Move(..) | TurtleCommand::Goto(..))
|
||||
}
|
||||
|
||||
/// Draw arc segments for circle tween animation
|
||||
|
||||
@ -8,7 +8,7 @@ use macroquad::prelude::*;
|
||||
/// Execute a single turtle command, updating state and adding draw commands
|
||||
pub fn execute_command(command: &TurtleCommand, state: &mut TurtleState, world: &mut TurtleWorld) {
|
||||
match command {
|
||||
TurtleCommand::Forward(distance) => {
|
||||
TurtleCommand::Move(distance) => {
|
||||
let start = state.position;
|
||||
let dx = distance * state.heading.cos();
|
||||
let dy = distance * state.heading.sin();
|
||||
@ -31,34 +31,7 @@ pub fn execute_command(command: &TurtleCommand, state: &mut TurtleState, world:
|
||||
}
|
||||
}
|
||||
|
||||
TurtleCommand::Backward(distance) => {
|
||||
let start = state.position;
|
||||
let dx = -distance * state.heading.cos();
|
||||
let dy = -distance * state.heading.sin();
|
||||
state.position = vec2(state.position.x + dx, state.position.y + dy);
|
||||
|
||||
if state.pen_down {
|
||||
world.add_command(DrawCommand::Line {
|
||||
start,
|
||||
end: state.position,
|
||||
color: state.color,
|
||||
width: state.pen_width,
|
||||
});
|
||||
// Add circle at end point for smooth line joins
|
||||
world.add_command(DrawCommand::Circle {
|
||||
center: state.position,
|
||||
radius: state.pen_width / 2.0,
|
||||
color: state.color,
|
||||
filled: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TurtleCommand::Left(degrees) => {
|
||||
state.heading -= degrees.to_radians();
|
||||
}
|
||||
|
||||
TurtleCommand::Right(degrees) => {
|
||||
TurtleCommand::Turn(degrees) => {
|
||||
state.heading += degrees.to_radians();
|
||||
}
|
||||
|
||||
@ -175,7 +148,7 @@ pub fn add_draw_for_completed_tween(
|
||||
world: &mut TurtleWorld,
|
||||
) {
|
||||
match command {
|
||||
TurtleCommand::Forward(_) | TurtleCommand::Backward(_) | TurtleCommand::Goto(_) => {
|
||||
TurtleCommand::Move(_) | TurtleCommand::Goto(_) => {
|
||||
if start_state.pen_down {
|
||||
world.add_command(DrawCommand::Line {
|
||||
start: start_state.position,
|
||||
@ -281,7 +254,7 @@ mod tests {
|
||||
assert_eq!(state.heading, 0.0);
|
||||
|
||||
// Forward 100 - should move to (100, 0)
|
||||
execute_command(&TurtleCommand::Forward(100.0), &mut state, &mut world);
|
||||
execute_command(&TurtleCommand::Move(100.0), &mut state, &mut world);
|
||||
assert!(
|
||||
(state.position.x - 100.0).abs() < 0.01,
|
||||
"After forward(100): x = {}",
|
||||
@ -296,7 +269,7 @@ mod tests {
|
||||
|
||||
// Left 90 degrees - should face north (heading decreases by 90°)
|
||||
// In screen coords: north = -90° = -π/2
|
||||
execute_command(&TurtleCommand::Left(90.0), &mut state, &mut world);
|
||||
execute_command(&TurtleCommand::Turn(-90.0), &mut state, &mut world);
|
||||
assert!(
|
||||
(state.position.x - 100.0).abs() < 0.01,
|
||||
"After left(90): x = {}",
|
||||
@ -316,7 +289,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Forward 50 - should move north (negative Y) to (100, -50)
|
||||
execute_command(&TurtleCommand::Forward(50.0), &mut state, &mut world);
|
||||
execute_command(&TurtleCommand::Move(50.0), &mut state, &mut world);
|
||||
assert!(
|
||||
(state.position.x - 100.0).abs() < 0.01,
|
||||
"Final position: x = {} (expected 100.0)",
|
||||
|
||||
@ -117,10 +117,7 @@ impl TweenController {
|
||||
tween.start_state.heading + angle.to_radians() * progress
|
||||
}
|
||||
},
|
||||
TurtleCommand::Left(angle) => {
|
||||
tween.start_state.heading - angle.to_radians() * progress
|
||||
}
|
||||
TurtleCommand::Right(angle) => {
|
||||
TurtleCommand::Turn(angle) => {
|
||||
tween.start_state.heading + angle.to_radians() * progress
|
||||
}
|
||||
TurtleCommand::SetHeading(_) | _ => {
|
||||
@ -218,10 +215,7 @@ impl TweenController {
|
||||
fn command_creates_drawing(command: &TurtleCommand) -> bool {
|
||||
matches!(
|
||||
command,
|
||||
TurtleCommand::Forward(_)
|
||||
| TurtleCommand::Backward(_)
|
||||
| TurtleCommand::Circle { .. }
|
||||
| TurtleCommand::Goto(_)
|
||||
TurtleCommand::Move(_) | TurtleCommand::Circle { .. } | TurtleCommand::Goto(_)
|
||||
)
|
||||
}
|
||||
|
||||
@ -229,8 +223,8 @@ impl TweenController {
|
||||
let speed = speed.max(1) as f32;
|
||||
|
||||
let base_time = match command {
|
||||
TurtleCommand::Forward(dist) | TurtleCommand::Backward(dist) => dist.abs() / speed,
|
||||
TurtleCommand::Left(angle) | TurtleCommand::Right(angle) => {
|
||||
TurtleCommand::Move(dist) => dist.abs() / speed,
|
||||
TurtleCommand::Turn(angle) => {
|
||||
// Rotation speed: assume 180 degrees per second at speed 100
|
||||
angle.abs() / (speed * 1.8)
|
||||
}
|
||||
@ -255,20 +249,12 @@ impl TweenController {
|
||||
let mut target = current.clone();
|
||||
|
||||
match command {
|
||||
TurtleCommand::Forward(dist) => {
|
||||
TurtleCommand::Move(dist) => {
|
||||
let dx = dist * current.heading.cos();
|
||||
let dy = dist * current.heading.sin();
|
||||
target.position = vec2(current.position.x + dx, current.position.y + dy);
|
||||
}
|
||||
TurtleCommand::Backward(dist) => {
|
||||
let dx = -dist * current.heading.cos();
|
||||
let dy = -dist * current.heading.sin();
|
||||
target.position = vec2(current.position.x + dx, current.position.y + dy);
|
||||
}
|
||||
TurtleCommand::Left(angle) => {
|
||||
target.heading -= angle.to_radians();
|
||||
}
|
||||
TurtleCommand::Right(angle) => {
|
||||
TurtleCommand::Turn(angle) => {
|
||||
target.heading += angle.to_radians();
|
||||
}
|
||||
TurtleCommand::Circle {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user