improve speed to have one single point of truth.
This commit is contained in:
parent
cebad0459c
commit
5799d2aa07
@ -13,20 +13,23 @@ async fn main() {
|
|||||||
plan.set_color(RED);
|
plan.set_color(RED);
|
||||||
plan.set_pen_width(0.5);
|
plan.set_pen_width(0.5);
|
||||||
plan.left(90.0);
|
plan.left(90.0);
|
||||||
|
plan.set_speed(999);
|
||||||
plan.circle_left(100.0, 540.0, 72); // partial circle to the left
|
plan.circle_left(100.0, 540.0, 72); // partial circle to the left
|
||||||
|
|
||||||
plan.forward(150.0);
|
plan.forward(150.0);
|
||||||
|
plan.set_speed(100);
|
||||||
plan.set_color(BLUE);
|
plan.set_color(BLUE);
|
||||||
plan.circle_right(50.0, 270.0, 72); // partial circle to the right
|
plan.circle_right(50.0, 270.0, 72); // partial circle to the right
|
||||||
|
// Set animation speed
|
||||||
|
plan.set_speed(20);
|
||||||
plan.forward(150.0);
|
plan.forward(150.0);
|
||||||
|
|
||||||
|
plan.set_speed(700);
|
||||||
plan.set_color(GREEN);
|
plan.set_color(GREEN);
|
||||||
plan.circle_left(50.0, 180.0, 36); // Half circle to the left
|
plan.circle_left(50.0, 180.0, 36); // Half circle to the left
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Create turtle app with animation (speed = 100 pixels/sec)
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 100.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -8,14 +8,15 @@ async fn main() {
|
|||||||
// Create a turtle plan
|
// Create a turtle plan
|
||||||
let mut plan = create_turtle();
|
let mut plan = create_turtle();
|
||||||
|
|
||||||
|
// Set animation speed
|
||||||
|
plan.set_speed(50);
|
||||||
plan.right(45.0);
|
plan.right(45.0);
|
||||||
plan.forward(100.0);
|
plan.forward(100.0);
|
||||||
plan.right(45.0);
|
plan.right(45.0);
|
||||||
plan.forward(100.0);
|
plan.forward(100.0);
|
||||||
//plan.circle_left(100.0, 90.0, 72); // Full circle to the left
|
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Create turtle app with animation (speed = 100 pixels/sec)
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 10.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -23,22 +23,23 @@ async fn main() {
|
|||||||
let mut plan = create_turtle();
|
let mut plan = create_turtle();
|
||||||
|
|
||||||
// Position turtle
|
// Position turtle
|
||||||
plan.set_speed(10);
|
|
||||||
plan.pen_up();
|
plan.pen_up();
|
||||||
plan.backward(150.0);
|
plan.backward(150.0);
|
||||||
|
|
||||||
plan.pen_down();
|
plan.pen_down();
|
||||||
|
plan.set_speed(10000);
|
||||||
|
|
||||||
// Draw Koch snowflake (triangle of Koch curves)
|
// Draw Koch snowflake (triangle of Koch curves)
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
koch(4, &mut plan, 300.0);
|
koch(4, &mut plan, 300.0);
|
||||||
plan.right(120.0);
|
plan.right(120.0);
|
||||||
|
plan.set_speed(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
plan.hide(); // Hide turtle when done
|
plan.hide(); // Hide turtle when done
|
||||||
|
|
||||||
// Create app with animation
|
// Create app with animation
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 1000.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
clear_background(WHITE);
|
clear_background(WHITE);
|
||||||
|
|||||||
@ -58,8 +58,8 @@ async fn main() {
|
|||||||
|
|
||||||
nikolaus(&mut plan, 100.0);
|
nikolaus(&mut plan, 100.0);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Create turtle app with animation
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 100.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -31,8 +31,11 @@ async fn main() {
|
|||||||
plan.shape(ShapeType::Arrow);
|
plan.shape(ShapeType::Arrow);
|
||||||
plan.forward(100.0);
|
plan.forward(100.0);
|
||||||
|
|
||||||
|
// Set animation speed
|
||||||
|
plan.set_speed(50);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec for slower animation)
|
// Create turtle app with animation (speed = 100 pixels/sec for slower animation)
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 700.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -14,8 +14,11 @@ async fn main() {
|
|||||||
plan.forward(100.0).right(90.0);
|
plan.forward(100.0).right(90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Set animation speed
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 100.0);
|
plan.set_speed(50);
|
||||||
|
|
||||||
|
// Create turtle app with animation
|
||||||
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -18,8 +18,11 @@ async fn main() {
|
|||||||
plan.circle_left(10.0, 72.0, 1000);
|
plan.circle_left(10.0, 72.0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set animation speed
|
||||||
|
plan.set_speed(300);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Create turtle app with animation (speed = 100 pixels/sec)
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build(), 100.0);
|
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -25,8 +25,11 @@ async fn main() {
|
|||||||
t.pen_down();
|
t.pen_down();
|
||||||
t.circle_right(8.0, 360.0, 12);
|
t.circle_right(8.0, 360.0, 12);
|
||||||
|
|
||||||
|
// Set animation speed
|
||||||
|
t.set_speed(1000);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
// Create turtle app with animation (speed = 100 pixels/sec)
|
||||||
let mut app = TurtleApp::new().with_commands(t.build(), 100.0);
|
let mut app = TurtleApp::new().with_commands(t.build());
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
//! Builder pattern traits for creating turtle command sequences
|
//! Builder pattern traits for creating turtle command sequences
|
||||||
|
|
||||||
use crate::commands::{CommandQueue, TurtleCommand};
|
use crate::commands::{CommandQueue, TurtleCommand};
|
||||||
use crate::general::{Color, Precision};
|
use crate::general::{AnimationSpeed, Color, Precision};
|
||||||
use crate::shapes::{ShapeType, TurtleShape};
|
use crate::shapes::{ShapeType, TurtleShape};
|
||||||
|
|
||||||
/// Trait for adding commands to a queue
|
/// Trait for adding commands to a queue
|
||||||
@ -106,8 +106,11 @@ impl TurtlePlan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_speed(&mut self, speed: u32) -> &mut Self {
|
/// Set animation speed
|
||||||
self.queue.push(TurtleCommand::SetSpeed(speed));
|
/// - Values >= 999 = instant mode (no animation)
|
||||||
|
/// - Values < 999 = animated mode with specified pixels/second
|
||||||
|
pub fn set_speed(&mut self, speed: impl Into<AnimationSpeed>) -> &mut Self {
|
||||||
|
self.queue.push(TurtleCommand::SetSpeed(speed.into()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Turtle commands and command queue
|
//! Turtle commands and command queue
|
||||||
|
|
||||||
use crate::general::{Color, Coordinate, Precision};
|
use crate::general::{AnimationSpeed, Color, Coordinate, Precision};
|
||||||
use crate::shapes::TurtleShape;
|
use crate::shapes::TurtleShape;
|
||||||
|
|
||||||
/// Individual turtle commands
|
/// Individual turtle commands
|
||||||
@ -28,7 +28,7 @@ pub enum TurtleCommand {
|
|||||||
SetColor(Color),
|
SetColor(Color),
|
||||||
SetFillColor(Option<Color>),
|
SetFillColor(Option<Color>),
|
||||||
SetPenWidth(Precision),
|
SetPenWidth(Precision),
|
||||||
SetSpeed(u32),
|
SetSpeed(AnimationSpeed),
|
||||||
SetShape(TurtleShape),
|
SetShape(TurtleShape),
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
|
|||||||
@ -5,6 +5,9 @@ use crate::commands::TurtleCommand;
|
|||||||
use crate::state::{DrawCommand, TurtleState, TurtleWorld};
|
use crate::state::{DrawCommand, TurtleState, TurtleWorld};
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::general::AnimationSpeed;
|
||||||
|
|
||||||
/// 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 {
|
||||||
@ -129,17 +132,6 @@ pub fn execute_command(command: &TurtleCommand, state: &mut TurtleState, world:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute all commands immediately (no animation)
|
|
||||||
pub fn execute_all_immediate(
|
|
||||||
queue: &mut crate::commands::CommandQueue,
|
|
||||||
state: &mut TurtleState,
|
|
||||||
world: &mut TurtleWorld,
|
|
||||||
) {
|
|
||||||
while let Some(command) = queue.next() {
|
|
||||||
execute_command(command, state, world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add drawing command for a completed tween (state transition already occurred)
|
/// Add drawing command for a completed tween (state transition already occurred)
|
||||||
pub fn add_draw_for_completed_tween(
|
pub fn add_draw_for_completed_tween(
|
||||||
command: &TurtleCommand,
|
command: &TurtleCommand,
|
||||||
@ -228,7 +220,7 @@ mod tests {
|
|||||||
pen_width: 1.0,
|
pen_width: 1.0,
|
||||||
color: Color::new(0.0, 0.0, 0.0, 1.0),
|
color: Color::new(0.0, 0.0, 0.0, 1.0),
|
||||||
fill_color: None,
|
fill_color: None,
|
||||||
speed: 100,
|
speed: AnimationSpeed::Animated(100.0),
|
||||||
visible: true,
|
visible: true,
|
||||||
shape: TurtleShape::turtle(),
|
shape: TurtleShape::turtle(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,8 +17,61 @@ pub type Coordinate = Vec2;
|
|||||||
/// Visibility flag for turtle
|
/// Visibility flag for turtle
|
||||||
pub type Visibility = bool;
|
pub type Visibility = bool;
|
||||||
|
|
||||||
/// Speed of animations (higher = faster, >= 999 = instant)
|
/// Execution speed setting
|
||||||
pub type Speed = u32;
|
/// - Instant: No animation, commands execute immediately
|
||||||
|
/// - Animated(speed): Smooth animation at specified pixels/second
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum AnimationSpeed {
|
||||||
|
Instant,
|
||||||
|
Animated(f32), // pixels per second
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimationSpeed {
|
||||||
|
/// Check if this is instant mode
|
||||||
|
pub fn is_instant(&self) -> bool {
|
||||||
|
matches!(self, AnimationSpeed::Instant)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the speed value (returns a high value for Instant)
|
||||||
|
pub fn value(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
AnimationSpeed::Instant => 9999.0,
|
||||||
|
AnimationSpeed::Animated(speed) => *speed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create from a raw speed value (>= 999 becomes Instant)
|
||||||
|
pub fn from_value(speed: f32) -> Self {
|
||||||
|
if speed >= 999.0 {
|
||||||
|
AnimationSpeed::Instant
|
||||||
|
} else {
|
||||||
|
AnimationSpeed::Animated(speed.max(1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create from a u32 value for backward compatibility
|
||||||
|
pub fn from_u32(speed: u32) -> Self {
|
||||||
|
Self::from_value(speed as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AnimationSpeed {
|
||||||
|
fn default() -> Self {
|
||||||
|
AnimationSpeed::Animated(100.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for AnimationSpeed {
|
||||||
|
fn from(speed: f32) -> Self {
|
||||||
|
AnimationSpeed::from_value(speed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for AnimationSpeed {
|
||||||
|
fn from(speed: u32) -> Self {
|
||||||
|
AnimationSpeed::from_u32(speed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Color type re-export from macroquad
|
/// Color type re-export from macroquad
|
||||||
pub use macroquad::color::Color;
|
pub use macroquad::color::Color;
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
//! let mut plan = create_turtle();
|
//! let mut plan = create_turtle();
|
||||||
//! plan.forward(100.0).right(90.0).forward(100.0);
|
//! plan.forward(100.0).right(90.0).forward(100.0);
|
||||||
//!
|
//!
|
||||||
//! let mut app = TurtleApp::new().with_commands(plan.build(), 100.0);
|
//! let mut app = TurtleApp::new().with_commands(plan.build());
|
||||||
//!
|
//!
|
||||||
//! loop {
|
//! loop {
|
||||||
//! clear_background(WHITE);
|
//! clear_background(WHITE);
|
||||||
@ -37,7 +37,7 @@ pub mod tweening;
|
|||||||
// Re-export commonly used types
|
// Re-export commonly used types
|
||||||
pub use builders::{CurvedMovement, DirectionalMovement, Turnable, TurtlePlan, WithCommands};
|
pub use builders::{CurvedMovement, DirectionalMovement, Turnable, TurtlePlan, WithCommands};
|
||||||
pub use commands::{CommandQueue, TurtleCommand};
|
pub use commands::{CommandQueue, TurtleCommand};
|
||||||
pub use general::{Angle, Color, Coordinate, Length, Precision, Speed};
|
pub use general::{Angle, AnimationSpeed, Color, Coordinate, Length, Precision};
|
||||||
pub use shapes::{ShapeType, TurtleShape};
|
pub use shapes::{ShapeType, TurtleShape};
|
||||||
pub use state::{DrawCommand, TurtleState, TurtleWorld};
|
pub use state::{DrawCommand, TurtleState, TurtleWorld};
|
||||||
pub use tweening::TweenController;
|
pub use tweening::TweenController;
|
||||||
@ -48,7 +48,7 @@ use macroquad::prelude::*;
|
|||||||
pub struct TurtleApp {
|
pub struct TurtleApp {
|
||||||
world: TurtleWorld,
|
world: TurtleWorld,
|
||||||
tween_controller: Option<TweenController>,
|
tween_controller: Option<TweenController>,
|
||||||
mode: ExecutionMode,
|
speed: AnimationSpeed,
|
||||||
// Mouse panning state
|
// Mouse panning state
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
last_mouse_pos: Option<Vec2>,
|
last_mouse_pos: Option<Vec2>,
|
||||||
@ -56,46 +56,31 @@ pub struct TurtleApp {
|
|||||||
zoom_level: f32,
|
zoom_level: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ExecutionMode {
|
|
||||||
Immediate,
|
|
||||||
Animated,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TurtleApp {
|
impl TurtleApp {
|
||||||
/// Create a new turtle application with default settings
|
/// Create a new TurtleApp with default settings
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
world: TurtleWorld::new(),
|
world: TurtleWorld::new(),
|
||||||
tween_controller: None,
|
tween_controller: None,
|
||||||
mode: ExecutionMode::Immediate,
|
speed: AnimationSpeed::default(),
|
||||||
is_dragging: false,
|
is_dragging: false,
|
||||||
last_mouse_pos: None,
|
last_mouse_pos: None,
|
||||||
zoom_level: 1.0,
|
zoom_level: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add commands to the turtle with specified speed
|
/// Add commands to the turtle
|
||||||
|
///
|
||||||
|
/// Speed is controlled by SetSpeed commands in the queue.
|
||||||
|
/// Use `set_speed()` on the turtle plan to set animation speed.
|
||||||
|
/// Speed >= 999 = instant mode, speed < 999 = animated mode.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `queue` - The command queue to execute
|
/// * `queue` - The command queue to execute
|
||||||
/// * `speed` - Animation speed in pixels/sec (>= 999.0 = instant, 0.5-999.0 = animated)
|
pub fn with_commands(mut self, queue: CommandQueue) -> Self {
|
||||||
pub fn with_commands(mut self, queue: CommandQueue, speed: f32) -> Self {
|
// The TweenController will switch between instant and animated mode
|
||||||
if speed <= 0.5 || speed.is_infinite() || speed.is_nan() {
|
// based on SetSpeed commands encountered
|
||||||
// Compiler error speed should be between 0.5 and 1000.0
|
self.tween_controller = Some(TweenController::new(queue, self.speed));
|
||||||
panic!("Speed must be greater than 0.5 and less than 1000.0");
|
|
||||||
}
|
|
||||||
if speed >= 999.0 {
|
|
||||||
// Immediate mode - execute all commands instantly
|
|
||||||
self.mode = ExecutionMode::Immediate;
|
|
||||||
let mut state = TurtleState::default();
|
|
||||||
let mut queue_mut = queue;
|
|
||||||
execution::execute_all_immediate(&mut queue_mut, &mut state, &mut self.world);
|
|
||||||
self.world.turtle = state;
|
|
||||||
} else {
|
|
||||||
// Animated mode - tween between states
|
|
||||||
self.mode = ExecutionMode::Animated;
|
|
||||||
self.tween_controller = Some(TweenController::new(queue, speed));
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Turtle state and world state management
|
//! Turtle state and world state management
|
||||||
|
|
||||||
use crate::general::{Angle, Color, Coordinate, Precision, Speed};
|
use crate::general::{Angle, AnimationSpeed, Color, Coordinate, Precision};
|
||||||
use crate::shapes::TurtleShape;
|
use crate::shapes::TurtleShape;
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub struct TurtleState {
|
|||||||
pub color: Color,
|
pub color: Color,
|
||||||
pub fill_color: Option<Color>,
|
pub fill_color: Option<Color>,
|
||||||
pub pen_width: Precision,
|
pub pen_width: Precision,
|
||||||
pub speed: Speed,
|
pub speed: AnimationSpeed,
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub shape: TurtleShape,
|
pub shape: TurtleShape,
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ impl Default for TurtleState {
|
|||||||
color: BLACK,
|
color: BLACK,
|
||||||
fill_color: None,
|
fill_color: None,
|
||||||
pen_width: 2.0,
|
pen_width: 2.0,
|
||||||
speed: 100, // pixels per second
|
speed: AnimationSpeed::default(),
|
||||||
visible: true,
|
visible: true,
|
||||||
shape: TurtleShape::turtle(),
|
shape: TurtleShape::turtle(),
|
||||||
}
|
}
|
||||||
@ -35,8 +35,8 @@ impl Default for TurtleState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TurtleState {
|
impl TurtleState {
|
||||||
pub fn set_speed(&mut self, speed: Speed) {
|
pub fn set_speed(&mut self, speed: AnimationSpeed) {
|
||||||
self.speed = speed.max(1);
|
self.speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn heading_angle(&self) -> Angle {
|
pub fn heading_angle(&self) -> Angle {
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::circle_geometry::{CircleDirection, CircleGeometry};
|
use crate::circle_geometry::{CircleDirection, CircleGeometry};
|
||||||
use crate::commands::{CommandQueue, TurtleCommand};
|
use crate::commands::{CommandQueue, TurtleCommand};
|
||||||
|
use crate::general::AnimationSpeed;
|
||||||
use crate::state::TurtleState;
|
use crate::state::TurtleState;
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use tween::{CubicInOut, TweenValue, Tweener};
|
use tween::{CubicInOut, TweenValue, Tweener};
|
||||||
@ -46,7 +47,7 @@ impl From<TweenVec2> for Vec2 {
|
|||||||
pub struct TweenController {
|
pub struct TweenController {
|
||||||
queue: CommandQueue,
|
queue: CommandQueue,
|
||||||
current_tween: Option<CommandTween>,
|
current_tween: Option<CommandTween>,
|
||||||
speed: f32, // pixels per second (or degrees per second for rotations)
|
speed: AnimationSpeed,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CommandTween {
|
pub(crate) struct CommandTween {
|
||||||
@ -61,20 +62,52 @@ pub(crate) struct CommandTween {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TweenController {
|
impl TweenController {
|
||||||
pub fn new(queue: CommandQueue, speed: f32) -> Self {
|
pub fn new(queue: CommandQueue, speed: AnimationSpeed) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue,
|
queue,
|
||||||
current_tween: None,
|
current_tween: None,
|
||||||
speed: speed.max(1.0),
|
speed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_speed(&mut self, speed: f32) {
|
pub fn set_speed(&mut self, speed: AnimationSpeed) {
|
||||||
self.speed = speed.max(1.0);
|
self.speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the tween, returns (command, start_state) if command completed
|
/// Update the tween, returns (command, start_state) if command completed
|
||||||
pub fn update(&mut self, state: &mut TurtleState) -> Option<(TurtleCommand, TurtleState)> {
|
pub fn update(&mut self, state: &mut TurtleState) -> Option<(TurtleCommand, TurtleState)> {
|
||||||
|
// In immediate mode, execute all remaining commands instantly
|
||||||
|
if self.speed.is_instant() {
|
||||||
|
loop {
|
||||||
|
let command = match self.queue.next() {
|
||||||
|
Some(cmd) => cmd.clone(),
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let start_state = state.clone();
|
||||||
|
|
||||||
|
// Handle SetSpeed command to potentially switch modes
|
||||||
|
if let TurtleCommand::SetSpeed(new_speed) = &command {
|
||||||
|
state.set_speed(*new_speed);
|
||||||
|
self.speed = *new_speed;
|
||||||
|
// If speed dropped below instant, switch to animated mode
|
||||||
|
if !self.speed.is_instant() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute command immediately
|
||||||
|
let target_state = self.calculate_target_state(state, &command);
|
||||||
|
*state = target_state.clone();
|
||||||
|
|
||||||
|
// Return drawable commands for rendering
|
||||||
|
if Self::command_creates_drawing(&command) {
|
||||||
|
return Some((command, start_state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process current tween
|
// Process current tween
|
||||||
if let Some(ref mut tween) = self.current_tween {
|
if let Some(ref mut tween) = self.current_tween {
|
||||||
let elapsed = (get_time() - tween.start_time) as f32;
|
let elapsed = (get_time() - tween.start_time) as f32;
|
||||||
@ -160,6 +193,19 @@ impl TweenController {
|
|||||||
// Start next tween
|
// Start next tween
|
||||||
if let Some(command) = self.queue.next() {
|
if let Some(command) = self.queue.next() {
|
||||||
let command_clone = command.clone();
|
let command_clone = command.clone();
|
||||||
|
|
||||||
|
// Handle SetSpeed command specially
|
||||||
|
if let TurtleCommand::SetSpeed(new_speed) = &command_clone {
|
||||||
|
state.set_speed(*new_speed);
|
||||||
|
self.speed = *new_speed;
|
||||||
|
// If switched to immediate mode, process immediately
|
||||||
|
if self.speed.is_instant() {
|
||||||
|
return self.update(state); // Recursively process in immediate mode
|
||||||
|
}
|
||||||
|
// For animated mode speed changes, continue to next command
|
||||||
|
return self.update(state);
|
||||||
|
}
|
||||||
|
|
||||||
let speed = state.speed; // Extract speed before borrowing self
|
let speed = state.speed; // Extract speed before borrowing self
|
||||||
let duration = self.calculate_duration(&command_clone, speed);
|
let duration = self.calculate_duration(&command_clone, speed);
|
||||||
|
|
||||||
@ -219,8 +265,8 @@ impl TweenController {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_duration(&self, command: &TurtleCommand, speed: u32) -> f64 {
|
fn calculate_duration(&self, command: &TurtleCommand, speed: AnimationSpeed) -> f64 {
|
||||||
let speed = speed.max(1) as f32;
|
let speed = speed.value();
|
||||||
|
|
||||||
let base_time = match command {
|
let base_time = match command {
|
||||||
TurtleCommand::Move(dist) => dist.abs() / speed,
|
TurtleCommand::Move(dist) => dist.abs() / speed,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user