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