Compare commits

..

2 Commits

Author SHA1 Message Date
5f4e47f540
refactor and cleanup 2022-08-24 08:17:53 +02:00
f9a4c1d81a
Add more detail to geometry_tasks 2022-08-23 14:46:32 +02:00
12 changed files with 219 additions and 211 deletions

53
src/animation_step.rs Normal file
View File

@ -0,0 +1,53 @@
use bevy::prelude::{Commands, Query, Transform, With};
use bevy_tweening::Animator;
use crate::{
turtle::{TurtleCommands, TurtleGraphElement, TurtleShape},
turtle_movement::TurtleStep,
};
pub(crate) fn run_animation_step(
commands: &mut Commands,
tcmd: &mut TurtleCommands,
turtle: &mut Query<&mut Animator<Transform>, With<TurtleShape>>,
) {
loop {
match tcmd.get_next() {
Some(TurtleStep {
turtle_animation: Some(turtle_animation),
line_segment: Some(graph_element_to_draw),
line_animation: Some(line_animation),
}) => {
let mut turtle = turtle.single_mut();
turtle.set_tweenable(turtle_animation);
match graph_element_to_draw {
TurtleGraphElement::TurtleLine(line) => {
commands.spawn_bundle(line).insert(line_animation);
}
TurtleGraphElement::Noop => (),
TurtleGraphElement::TurtleCircle(circle) => {
commands.spawn_bundle(circle).insert(line_animation);
}
}
return;
}
// In case a rotation is performed the line drawing can be skipped
Some(TurtleStep {
turtle_animation: Some(turtle_animation),
line_segment: Some(_),
line_animation: None,
}) => {
let mut turtle = turtle.single_mut();
turtle.set_tweenable(turtle_animation);
return;
}
Some(_) => {
println!("without animation");
}
None => {
println!("nothing to draw");
return;
}
};
}
}

View File

@ -1,5 +1,3 @@
use std::f32::consts::PI;
use bevy::prelude::*; use bevy::prelude::*;
use bevy_prototype_lyon::prelude::*; use bevy_prototype_lyon::prelude::*;

View File

@ -4,6 +4,8 @@ use std::{
ops::{Add, Div, Mul, Neg, Rem, Sub}, ops::{Add, Div, Mul, Neg, Rem, Sub},
}; };
use crate::turtle::Precision;
#[derive(Inspectable, Copy, Clone, Debug, PartialEq, Eq)] #[derive(Inspectable, Copy, Clone, Debug, PartialEq, Eq)]
pub enum AngleUnit<T: Default> { pub enum AngleUnit<T: Default> {
Degrees(T), Degrees(T),
@ -43,7 +45,7 @@ impl<T: Default + Clone + Mul<T, Output = T>> Mul<T> for Angle<T> {
} }
} }
impl Angle<f32> { impl Angle<Precision> {
pub fn limit_smaller_than_full_circle(self) -> Self { pub fn limit_smaller_than_full_circle(self) -> Self {
match self.value { match self.value {
AngleUnit::Degrees(v) => Self { AngleUnit::Degrees(v) => Self {

View File

@ -1,4 +1,6 @@
use bevy_inspector_egui::Inspectable; use bevy_inspector_egui::Inspectable;
use crate::turtle::Precision;
#[derive(Inspectable, Default, Copy, Clone, Debug)] #[derive(Inspectable, Default, Copy, Clone, Debug)]
pub struct Length(pub f32); pub struct Length(pub Precision);

View File

@ -1,10 +1,10 @@
mod animation_step;
mod datatypes; mod datatypes;
mod debug; mod debug;
mod paths; mod paths;
mod primitives; mod primitives;
mod turtle; mod turtle;
mod turtle_movement; mod turtle_movement;
mod turtle_shapes;
use bevy::{prelude::*, window::close_on_esc}; use bevy::{prelude::*, window::close_on_esc};
use bevy_prototype_lyon::prelude::*; use bevy_prototype_lyon::prelude::*;

View File

@ -5,15 +5,24 @@ use crate::{
#[allow(dead_code)] #[allow(dead_code)]
pub fn geometry_task() -> Vec<TurtleCommand> { pub fn geometry_task() -> Vec<TurtleCommand> {
vec![ let mut before = vec![
TurtleCommand::Forward(Length(100.)), TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(90.)), TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Backward(Length(100.)), TurtleCommand::Backward(Length(100.)),
TurtleCommand::Right(Angle::degrees(90.)), TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(100.)), TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(45.)), TurtleCommand::Right(Angle::degrees(45.)),
//TurtleCommand::PenUp, ];
TurtleCommand::Forward(Length(100.)), for _ in 0..10 {
let mut dash = vec![
TurtleCommand::PenUp,
TurtleCommand::Forward(Length(5.)),
TurtleCommand::PenDown,
TurtleCommand::Forward(Length(5.)),
];
before.append(&mut dash);
}
let mut after = vec![
TurtleCommand::Right(Angle::degrees(90.)), TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(50.)), TurtleCommand::Forward(Length(50.)),
TurtleCommand::Right(Angle::degrees(90.)), TurtleCommand::Right(Angle::degrees(90.)),
@ -28,5 +37,7 @@ pub fn geometry_task() -> Vec<TurtleCommand> {
TurtleCommand::Forward(Length(100.)), TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(150.)), TurtleCommand::Right(Angle::degrees(150.)),
TurtleCommand::Forward(Length(100.)), TurtleCommand::Forward(Length(100.)),
] ];
before.append(&mut after);
before
} }

View File

@ -2,3 +2,4 @@ pub mod animation;
pub mod bundles; pub mod bundles;
pub mod components; pub mod components;
pub mod turtle_primitives; pub mod turtle_primitives;
pub mod turtle_shapes;

View File

@ -5,7 +5,7 @@ use bevy_prototype_lyon::{
}; };
use bevy_tweening::Lens; use bevy_tweening::Lens;
use crate::datatypes::angle::Angle; use crate::{datatypes::angle::Angle, turtle::Precision};
pub(crate) struct LineAnimationLens { pub(crate) struct LineAnimationLens {
start: Vec2, start: Vec2,
@ -29,8 +29,8 @@ pub(crate) struct CircleAnimationLens {
pub start_pos: Vec2, pub start_pos: Vec2,
pub center: Vec2, pub center: Vec2,
pub radii: Vec2, pub radii: Vec2,
pub start: Angle<f32>, pub start: Angle<Precision>,
pub end: Angle<f32>, pub end: Angle<Precision>,
} }
impl Lens<Path> for CircleAnimationLens { impl Lens<Path> for CircleAnimationLens {
@ -54,7 +54,7 @@ impl Lens<Path> for CircleAnimationLens {
pub(crate) struct CircleMovementLens { pub(crate) struct CircleMovementLens {
pub center: Vec2, pub center: Vec2,
pub start: Transform, pub start: Transform,
pub end: Angle<f32>, pub end: Angle<Precision>,
} }
impl Lens<Transform> for CircleMovementLens { impl Lens<Transform> for CircleMovementLens {

View File

@ -1,4 +1,5 @@
use bevy::prelude::{Bundle, Color, Component, Name, Transform, Vec2}; use bevy::prelude::{Bundle, Color, Component, Name, Transform, Vec2};
use bevy_inspector_egui::Inspectable;
use bevy_prototype_lyon::{ use bevy_prototype_lyon::{
entity::ShapeBundle, entity::ShapeBundle,
prelude::{DrawMode, FillMode, GeometryBuilder, PathBuilder, StrokeMode}, prelude::{DrawMode, FillMode, GeometryBuilder, PathBuilder, StrokeMode},
@ -7,18 +8,21 @@ use bevy_prototype_lyon::{
use crate::{ use crate::{
datatypes::angle::Angle, datatypes::angle::Angle,
turtle::{Colors, TurtleCommand, TurtleCommands}, turtle::{Colors, Precision, TurtleCommand, TurtleCommands},
}; };
#[derive(Bundle)] use super::turtle_shapes;
pub(crate) struct TurtleDrawLine {
#[derive(Bundle, Inspectable, Default)]
pub struct TurtleDrawLine {
#[bundle] #[bundle]
#[inspectable(ignore)]
line: ShapeBundle, line: ShapeBundle,
name: Name, name: Name,
marker: LineMarker, marker: LineMarker,
} }
#[derive(Component, Default)] #[derive(Component, Default, Inspectable)]
struct LineMarker; struct LineMarker;
impl TurtleDrawLine { impl TurtleDrawLine {
@ -38,23 +42,24 @@ impl TurtleDrawLine {
} }
} }
#[derive(Bundle)] #[derive(Bundle, Inspectable, Default)]
pub(crate) struct TurtleDrawCircle { pub struct TurtleDrawCircle {
#[bundle] #[bundle]
#[inspectable(ignore)]
line: ShapeBundle, line: ShapeBundle,
name: Name, name: Name,
marker: CircleMarker, marker: CircleMarker,
} }
#[derive(Component, Default)] #[derive(Component, Default, Inspectable)]
struct CircleMarker; struct CircleMarker;
impl TurtleDrawCircle { impl TurtleDrawCircle {
pub(crate) fn new( pub(crate) fn new(
center: Vec2, center: Vec2,
radii: Vec2, radii: Vec2,
angle: Angle<f32>, angle: Angle<Precision>,
index: u64, index: u64,
start: Vec2, start: Vec2,
end: Vec2, end: Vec2,
@ -89,6 +94,8 @@ pub struct Turtle {
colors: Colors, colors: Colors,
commands: TurtleCommands, commands: TurtleCommands,
name: Name, name: Name,
#[bundle]
shape: ShapeBundle,
} }
impl Default for Turtle { impl Default for Turtle {
@ -97,6 +104,14 @@ impl Default for Turtle {
colors: Colors::default(), colors: Colors::default(),
commands: TurtleCommands::new(vec![]), commands: TurtleCommands::new(vec![]),
name: Name::new("Turtle"), name: Name::new("Turtle"),
shape: GeometryBuilder::build_as(
&turtle_shapes::turtle(),
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
),
} }
} }
} }

View File

@ -3,31 +3,33 @@ use std::f32::consts::PI;
use bevy::prelude::Vec2; use bevy::prelude::Vec2;
use bevy_prototype_lyon::prelude::{Path, PathBuilder}; use bevy_prototype_lyon::prelude::{Path, PathBuilder};
use crate::turtle::Precision;
pub fn turtle() -> Path { pub fn turtle() -> Path {
let polygon = &[ let polygon: &[[Precision; 2]; 23] = &[
[-2.5f32, 14.0f32], [-2.5, 14.0],
[-1.25f32, 10.0f32], [-1.25, 10.0],
[-4.0f32, 7.0f32], [-4.0, 7.0],
[-7.0f32, 9.0f32], [-7.0, 9.0],
[-9.0f32, 8.0f32], [-9.0, 8.0],
[-6.0f32, 5.0f32], [-6.0, 5.0],
[-7.0f32, 1.0f32], [-7.0, 1.0],
[-5.0f32, -3.0f32], [-5.0, -3.0],
[-8.0f32, -6.0f32], [-8.0, -6.0],
[-6.0f32, -8.0f32], [-6.0, -8.0],
[-4.0f32, -5.0f32], [-4.0, -5.0],
[0.0f32, -7.0f32], [0.0, -7.0],
[4.0f32, -5.0f32], [4.0, -5.0],
[6.0f32, -8.0f32], [6.0, -8.0],
[8.0f32, -6.0f32], [8.0, -6.0],
[5.0f32, -3.0f32], [5.0, -3.0],
[7.0f32, 1.0f32], [7.0, 1.0],
[6.0f32, 5.0f32], [6.0, 5.0],
[9.0f32, 8.0f32], [9.0, 8.0],
[7.0f32, 9.0f32], [7.0, 9.0],
[4.0f32, 7.0f32], [4.0, 7.0],
[1.25f32, 10.0f32], [1.25, 10.0],
[2.5f32, 14.0f32], [2.5, 14.0],
]; ];
let mut turtle_path = PathBuilder::new(); let mut turtle_path = PathBuilder::new();
turtle_path.line_to(Vec2::new(1.0, 1.0)); turtle_path.line_to(Vec2::new(1.0, 1.0));

View File

@ -11,12 +11,10 @@ use bevy_tweening::{
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::paths::{circle_star::circle_star, geometry_task::geometry_task}; use crate::paths::{circle_star::circle_star, geometry_task::geometry_task};
use crate::{ use crate::{
animation_step::run_animation_step,
datatypes::{angle::Angle, length::Length}, datatypes::{angle::Angle, length::Length},
primitives::{ primitives::bundles::{Turtle, TurtleDrawCircle, TurtleDrawLine},
animation::{CircleAnimationLens, LineAnimationLens}, turtle_movement::TurtleStep,
bundles::{Turtle, TurtleDrawCircle, TurtleDrawLine},
},
turtle_shapes,
}; };
pub struct TurtlePlugin; pub struct TurtlePlugin;
@ -66,7 +64,7 @@ impl TurtleCommands {
} }
impl TurtleCommands { impl TurtleCommands {
fn get_next(&mut self) -> Option<(Option<Tween<Transform>>, Option<TurtleGraphElement>)> { pub(crate) fn get_next(&mut self) -> Option<TurtleStep> {
let index = self.state.index; let index = self.state.index;
let next_index = index + 1; let next_index = index + 1;
@ -86,11 +84,21 @@ impl TurtleCommands {
} }
TurtleCommand::PenUp => { TurtleCommand::PenUp => {
self.state.drawing = false; self.state.drawing = false;
(None, None)
TurtleStep {
turtle_animation: None,
line_segment: None,
line_animation: None,
}
} }
TurtleCommand::PenDown => { TurtleCommand::PenDown => {
self.state.drawing = true; self.state.drawing = true;
(None, None)
TurtleStep {
turtle_animation: None,
line_segment: None,
line_animation: None,
}
} }
TurtleCommand::Circle { radius, angle } => { TurtleCommand::Circle { radius, angle } => {
crate::turtle_movement::turtle_circle(&mut self.state, radius.0 as f32, *angle) crate::turtle_movement::turtle_circle(&mut self.state, radius.0 as f32, *angle)
@ -107,17 +115,8 @@ impl TurtleCommands {
#[derive(Inspectable, Default)] #[derive(Inspectable, Default)]
pub enum TurtleGraphElement { pub enum TurtleGraphElement {
TurtleLine { TurtleLine(TurtleDrawLine),
start: Vec2, TurtleCircle(TurtleDrawCircle),
end: Vec2,
},
TurtleCircle {
start: Vec2,
end: Vec2,
center: Vec2,
radii: Vec2,
angle: Angle<f32>,
},
#[default] #[default]
Noop, Noop,
} }
@ -159,17 +158,9 @@ fn setup(mut commands: Commands) {
)); ));
commands.spawn_bundle(Camera2dBundle::default()); commands.spawn_bundle(Camera2dBundle::default());
let mut turtle_bundle = Turtle::default(); let mut turtle_bundle = Turtle::default();
turtle_bundle.set_commands(geometry_task()); turtle_bundle.set_commands(circle_star());
commands commands
.spawn_bundle(turtle_bundle) .spawn_bundle(turtle_bundle)
.insert_bundle(GeometryBuilder::build_as(
&turtle_shapes::turtle(),
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
))
.insert(animator) .insert(animator)
.insert(TurtleShape); .insert(TurtleShape);
} }
@ -182,117 +173,26 @@ fn draw_lines(
) { ) {
for ev in query_event.iter() { for ev in query_event.iter() {
let mut tcmd = tcmd.single_mut(); let mut tcmd = tcmd.single_mut();
loop { run_animation_step(&mut commands, &mut tcmd, &mut turtle)
match tcmd.get_next() {
Some((Some(turtle_animation), Some(graph_element_to_draw))) => {
let mut turtle = turtle.single_mut();
turtle.set_tweenable(turtle_animation);
match graph_element_to_draw {
TurtleGraphElement::TurtleLine { start, end } => {
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(tcmd.state.speed),
LineAnimationLens::new(start, end),
));
commands
.spawn_bundle(TurtleDrawLine::new(start, end, tcmd.state.index))
.insert(line_animator);
}
TurtleGraphElement::Noop => println!("No drawing!"),
TurtleGraphElement::TurtleCircle {
center,
radii,
angle,
start,
end,
} => {
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(tcmd.state.speed),
CircleAnimationLens {
start_pos: start,
center,
radii,
start: Angle::degrees(0.),
end: angle,
},
));
commands
.spawn_bundle(TurtleDrawCircle::new(
center,
radii,
Angle::degrees(0.),
tcmd.state.index,
start,
end,
))
.insert(line_animator);
}
}
return;
}
Some((_, _)) => {
println!("without animation");
}
None => {
println!("nothing to draw");
return;
}
};
}
} }
} }
fn keypresses( fn keypresses(
mut commands: Commands, mut commands: Commands,
keys: Res<Input<KeyCode>>, keys: Res<Input<KeyCode>>,
mut qry: Query<&mut Animator<Transform>, With<TurtleShape>>,
mut tcmd: Query<&mut TurtleCommands>, mut tcmd: Query<&mut TurtleCommands>,
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
) { ) {
if keys.just_pressed(KeyCode::W) { if keys.just_pressed(KeyCode::W) {
let mut tcmd = tcmd.single_mut(); let mut tcmd = tcmd.single_mut();
tcmd.state = TurtleState { tcmd.state = TurtleState {
start: Vec2::ZERO, start: Vec2::ZERO,
heading: Angle::degrees(0.), heading: Angle::degrees(0.),
speed: 2000, speed: 500,
index: 0, index: 0,
drawing: true, drawing: true,
}; };
if let Some((Some(turtle_animation), Some(graph_element_to_draw))) = tcmd.get_next() {
let mut shap = qry.single_mut(); run_animation_step(&mut commands, &mut tcmd, &mut turtle);
shap.set_tweenable(turtle_animation);
match graph_element_to_draw {
TurtleGraphElement::TurtleLine { start, end } => {
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(tcmd.state.speed),
LineAnimationLens::new(start, end),
));
commands
.spawn_bundle(TurtleDrawLine::new(start, end, tcmd.state.index))
.insert(line_animator);
}
TurtleGraphElement::Noop => (),
TurtleGraphElement::TurtleCircle {
center,
radii,
angle,
start,
end,
} => {
commands.spawn_bundle(TurtleDrawCircle::new(
center,
radii,
angle,
tcmd.state.index,
start,
end,
));
}
}
};
} }
} }

View File

@ -1,78 +1,89 @@
use std::time::Duration; use std::time::Duration;
use bevy::prelude::{Quat, Transform, Vec2, Vec3}; use bevy::prelude::{Quat, Transform, Vec2, Vec3};
use bevy_prototype_lyon::prelude::Path;
use bevy_tweening::{ use bevy_tweening::{
lens::{TransformPositionLens, TransformRotateZLens}, lens::{TransformPositionLens, TransformRotateZLens},
EaseFunction, Tween, TweeningType, Animator, EaseFunction, Tween, TweeningType,
}; };
use crate::{ use crate::{
datatypes::angle::Angle, datatypes::angle::Angle,
primitives::animation::CircleMovementLens, primitives::{
turtle::{TurtleGraphElement, TurtleState}, animation::{CircleAnimationLens, CircleMovementLens, LineAnimationLens},
bundles::{TurtleDrawCircle, TurtleDrawLine},
},
turtle::{Precision, TurtleGraphElement, TurtleState},
}; };
pub fn turtle_turn( pub struct TurtleStep {
state: &mut TurtleState, pub turtle_animation: Option<Tween<Transform>>,
angle_to_turn: Angle<f32>, pub line_segment: Option<TurtleGraphElement>,
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) { pub line_animation: Option<Animator<Path>>,
}
pub fn turtle_turn(state: &mut TurtleState, angle_to_turn: Angle<Precision>) -> TurtleStep {
let start = state.heading; let start = state.heading;
let end = state.heading + angle_to_turn; let end = state.heading + angle_to_turn;
let animation = Tween::new( let animation = Tween::new(
// Use a quadratic easing on both endpoints
EaseFunction::QuadraticInOut, EaseFunction::QuadraticInOut,
TweeningType::Once, TweeningType::Once,
// Animation time
Duration::from_millis(state.speed), Duration::from_millis(state.speed),
// Rotate the turtle
TransformRotateZLens { TransformRotateZLens {
start: start.to_radians().value(), start: start.to_radians().value(),
end: end.to_radians().value(), end: end.to_radians().value(),
}, },
) )
.with_completed_event(state.index as u64); .with_completed_event(state.index as u64);
// Dont move and draw // Don't draw as the position does not change
let line = TurtleGraphElement::Noop; let line = TurtleGraphElement::Noop;
// Update the state // Update the state
state.heading = end.limit_smaller_than_full_circle(); state.heading = end.limit_smaller_than_full_circle();
(Some(animation), Some(line)) TurtleStep {
turtle_animation: Some(animation),
line_segment: Some(line),
line_animation: None,
}
} }
pub fn turtle_move( pub fn turtle_move(state: &mut TurtleState, length: Precision) -> TurtleStep {
state: &mut TurtleState,
length: f32,
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
let start = state.start; let start = state.start;
let end = state.start + (Vec2::from_angle(state.heading.to_radians().value()) * length); let end = state.start + (Vec2::from_angle(state.heading.to_radians().value()) * length);
let turtle_movement_animation = Tween::new( let turtle_movement_animation = Tween::new(
// accelerate and decelerate
EaseFunction::QuadraticInOut, EaseFunction::QuadraticInOut,
TweeningType::Once, TweeningType::Once,
// later to be controlled by speed
Duration::from_millis(state.speed), Duration::from_millis(state.speed),
// set the start and end of the animation
TransformPositionLens { TransformPositionLens {
start: start.extend(0.), start: start.extend(0.),
end: end.extend(0.), end: end.extend(0.),
}, },
) )
.with_completed_event(state.index as u64); .with_completed_event(state.index as u64);
// The line for animating and drawing
let line = if state.drawing { let line = if state.drawing {
TurtleGraphElement::TurtleLine { start, end } TurtleGraphElement::TurtleLine(TurtleDrawLine::new(start, end, state.index))
} else { } else {
TurtleGraphElement::Noop TurtleGraphElement::Noop
}; };
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
LineAnimationLens::new(start, end),
));
state.start = end; state.start = end;
(Some(turtle_movement_animation), Some(line)) TurtleStep {
turtle_animation: Some(turtle_movement_animation),
line_segment: Some(line),
line_animation: Some(line_animator),
}
} }
pub fn turtle_circle( pub fn turtle_circle(
state: &mut TurtleState, state: &mut TurtleState,
radius: f32, radius: Precision,
angle: Angle<f32>, angle: Angle<Precision>,
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) { ) -> TurtleStep {
let radius_tuple = Vec2::ONE * radius.abs(); let radii = Vec2::ONE * radius.abs();
let left_right = Angle::degrees(if radius >= 0. { 90. } else { -90. }); let left_right = Angle::degrees(if radius >= 0. { 90. } else { -90. });
let center = state.start let center = state.start
+ (Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle( + (Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
@ -80,12 +91,9 @@ pub fn turtle_circle(
))); )));
let turtle_movement_animation = Tween::new( let turtle_movement_animation = Tween::new(
// accelerate and decelerate
EaseFunction::QuadraticInOut, EaseFunction::QuadraticInOut,
TweeningType::Once, TweeningType::Once,
// later to be controlled by speed
Duration::from_millis(state.speed), Duration::from_millis(state.speed),
// set the start and end of the animation
CircleMovementLens { CircleMovementLens {
start: Transform { start: Transform {
translation: state.start.extend(0.), translation: state.start.extend(0.),
@ -97,23 +105,39 @@ pub fn turtle_circle(
}, },
) )
.with_completed_event(state.index as u64); .with_completed_event(state.index as u64);
// The line for animating and drawing
let line = if state.drawing {
TurtleGraphElement::TurtleCircle {
center,
radii: radius_tuple,
angle,
start: state.start,
end: state.start,
}
} else {
TurtleGraphElement::Noop
};
let end_pos = center let end_pos = center
+ Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle( + Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
(state.heading + angle - left_right).to_radians().value(), (state.heading + angle - left_right).to_radians().value(),
)); ));
let line = if state.drawing {
TurtleGraphElement::TurtleCircle(TurtleDrawCircle::new(
center,
radii,
Angle::degrees(0.),
state.index,
state.start,
end_pos,
))
} else {
TurtleGraphElement::Noop
};
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
CircleAnimationLens {
start_pos: state.start,
center,
radii,
start: Angle::degrees(0.),
end: angle,
},
));
state.start = end_pos; state.start = end_pos;
state.heading = state.heading + angle; state.heading = state.heading + angle;
(Some(turtle_movement_animation), Some(line)) TurtleStep {
turtle_animation: Some(turtle_movement_animation),
line_segment: Some(line),
line_animation: Some(line_animator),
}
} }