From 7a543685d3b1253b9dde40579b147ab299602234 Mon Sep 17 00:00:00 2001 From: Franz Dietrich Date: Fri, 19 Aug 2022 19:08:02 +0200 Subject: [PATCH] first circle try --- Cargo.lock | 91 ++++++++--------- src/bin/circle.rs | 32 ++++++ src/main.rs | 1 + src/primitives.rs | 110 +++++++++++++++++++++ src/turtle.rs | 216 ++++++++++++++++++++++------------------- src/turtle_movement.rs | 72 +++++++++++--- 6 files changed, 360 insertions(+), 162 deletions(-) create mode 100644 src/bin/circle.rs create mode 100644 src/primitives.rs diff --git a/Cargo.lock b/Cargo.lock index 5f70363..7b134d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" +checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" [[package]] name = "approx" @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ "concurrent-queue", "event-listener", @@ -422,9 +422,9 @@ dependencies = [ [[package]] name = "bevy_egui" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ab46f07c3f360507fae9bc3b9c000c583e0d67661f0dd6dd5a24a709775b1e" +checksum = "acbf44ff770566dca66b805a6829df783f64700bd01d35aec1034dff31b531a4" dependencies = [ "arboard", "bevy", @@ -875,7 +875,7 @@ checksum = "8bda6dada53e546845887ae7357eec57b8d547ef71627b716b33839b4a98b687" dependencies = [ "ahash", "getrandom", - "hashbrown 0.12.3", + "hashbrown", "instant", "tracing", "uuid", @@ -964,24 +964,24 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "bytemuck" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" +checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd2f4180c5721da6335cc9e9061cce522b87a35e51cc57636d28d22a9863c80" +checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9" dependencies = [ "proc-macro2", "quote", @@ -1119,9 +1119,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.4" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -1592,15 +1592,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" [[package]] name = "futures-lite" @@ -1778,13 +1778,13 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" +checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags", "gpu-descriptor-types", - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -1826,15 +1826,6 @@ dependencies = [ "syn", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1931,7 +1922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -1996,9 +1987,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "jni" @@ -2100,9 +2091,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libloading" @@ -2632,9 +2623,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "owned_ttf_parser" @@ -2774,9 +2765,9 @@ checksum = "a8815d101cfb4cb491154896bdab292a395a7ac9ab185a9941a2f5be0135900d" [[package]] name = "proc-macro-crate" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d50bfb8c23f23915855a00d98b5a35ef2e0b871bb52937bacadb798fbb66c8" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ "once_cell", "thiserror", @@ -2942,18 +2933,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7af873f2c95b99fcb0bd0fe622a43e29514658873c8ceba88c4cb88833a22500" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75743a150d003dd863b51dc809bcad0d73f2102c53632f1e954e738192a3413f" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", @@ -2962,9 +2953,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "itoa", "ryu", @@ -3263,9 +3254,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-normalization" @@ -3662,9 +3653,9 @@ dependencies = [ [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6" dependencies = [ "lazy_static", "libc", diff --git a/src/bin/circle.rs b/src/bin/circle.rs new file mode 100644 index 0000000..144b032 --- /dev/null +++ b/src/bin/circle.rs @@ -0,0 +1,32 @@ +use std::f32::consts::PI; + +use bevy::prelude::*; +use bevy_prototype_lyon::prelude::*; + +fn main() { + App::new() + .insert_resource(Msaa { samples: 4 }) + .add_plugins(DefaultPlugins) + .add_plugin(ShapePlugin) + .add_startup_system(setup_system) + .run(); +} + +fn setup_system(mut commands: Commands) { + let mut path_builder = PathBuilder::new(); + path_builder.move_to(Vec2::new(100., 0.)); + path_builder.arc( + 100.0 * Vec2::ZERO, + 100.0 * Vec2::ONE, + 90f32.to_radians(), + 0., + ); + let line = path_builder.build(); + + commands.spawn_bundle(Camera2dBundle::default()); + commands.spawn_bundle(GeometryBuilder::build_as( + &line, + DrawMode::Stroke(StrokeMode::new(Color::BLACK, 10.0)), + Transform::default(), + )); +} diff --git a/src/main.rs b/src/main.rs index 51fd67d..35405f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod debug; +mod primitives; mod turtle; mod turtle_movement; mod turtle_shapes; diff --git a/src/primitives.rs b/src/primitives.rs new file mode 100644 index 0000000..7f4bc33 --- /dev/null +++ b/src/primitives.rs @@ -0,0 +1,110 @@ +use bevy::prelude::{Bundle, Color, Component, Name, Transform, Vec2}; +use bevy_prototype_lyon::{ + entity::ShapeBundle, + prelude::{DrawMode, FillMode, GeometryBuilder, Path, PathBuilder, ShapePath, StrokeMode}, + shapes::{self, Line}, +}; +use bevy_tweening::Lens; + +use crate::turtle::Angle; + +pub(crate) struct LineAnimationLens { + start: Vec2, + end: Vec2, +} + +impl LineAnimationLens { + pub(crate) fn new(start: Vec2, end: Vec2) -> Self { + Self { start, end } + } +} + +impl Lens for LineAnimationLens { + fn lerp(&mut self, target: &mut Path, ratio: f32) { + let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio)); + *target = ShapePath::build_as(&line); + } +} + +#[derive(Bundle)] +pub(crate) struct TurtleDrawLine { + #[bundle] + line: ShapeBundle, + name: Name, + marker: LineMarker, +} + +#[derive(Component, Default)] +struct LineMarker; + +impl TurtleDrawLine { + pub(crate) fn new(start: Vec2, _end: Vec2, index: u64) -> Self { + Self { + line: GeometryBuilder::build_as( + &Line(start, start), + DrawMode::Outlined { + fill_mode: FillMode::color(Color::MIDNIGHT_BLUE), + outline_mode: StrokeMode::new(Color::BLACK, 1.0), + }, + Transform::identity(), + ), + name: Name::new(format!("Line {}", index)), + marker: LineMarker, + } + } +} + +pub(crate) struct CircleAnimationLens { + start: Vec2, + end: Vec2, +} + +impl Lens for CircleAnimationLens { + fn lerp(&mut self, target: &mut Path, ratio: f32) { + let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio)); + *target = ShapePath::build_as(&line); + } +} + +#[derive(Bundle)] + +pub(crate) struct TurtleDrawCircle { + #[bundle] + line: ShapeBundle, + name: Name, + marker: CircleMarker, +} + +#[derive(Component, Default)] +struct CircleMarker; + +impl TurtleDrawCircle { + pub(crate) fn new( + center: Vec2, + radii: Vec2, + angle: Angle, + index: u64, + start: Vec2, + end: Vec2, + ) -> Self { + let mut path_builder = PathBuilder::new(); + path_builder.move_to(start); + // The center point of the radius, then the radii in x and y direction, then the angle that will be drawn, then the x_rotation ? + path_builder.arc(center, radii, angle.0.to_radians(), 0.); + let line = path_builder.build(); + println!("Draw Circle: {} {} {:?}", center, radii, angle); + + Self { + line: GeometryBuilder::build_as( + &line, + DrawMode::Outlined { + fill_mode: FillMode::color(Color::rgba(0., 0., 0., 0.)), + outline_mode: StrokeMode::new(Color::BLACK, 1.0), + }, + Transform::identity(), + ), + name: Name::new(format!("Circle {}", index)), + marker: CircleMarker, + } + } +} diff --git a/src/turtle.rs b/src/turtle.rs index 8980593..e94abf9 100644 --- a/src/turtle.rs +++ b/src/turtle.rs @@ -2,13 +2,16 @@ use std::time::Duration; use bevy::prelude::*; use bevy_inspector_egui::{Inspectable, RegisterInspectable}; -use bevy_prototype_lyon::{entity::ShapeBundle, prelude::*, shapes::Line}; +use bevy_prototype_lyon::prelude::*; use bevy_tweening::{ - component_animator_system, lens::TransformPositionLens, Animator, EaseFunction, Lens, Tween, + component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween, TweenCompleted, TweeningPlugin, TweeningType, }; -use crate::turtle_shapes; +use crate::{ + primitives::{LineAnimationLens, TurtleDrawCircle, TurtleDrawLine}, + turtle_shapes, +}; pub struct TurtlePlugin; @@ -39,12 +42,26 @@ impl Default for Turtle { }, commands: TurtleCommands::new(vec![ TurtleCommand::Forward(Length(100.)), + TurtleCommand::Circle { + radius: Length(150.), + angle: Angle(180.), + }, TurtleCommand::Right(Angle(90.)), + TurtleCommand::Circle { + radius: Length(15.), + angle: Angle(180.), + }, TurtleCommand::Backward(Length(100.)), TurtleCommand::Right(Angle(90.)), TurtleCommand::Forward(Length(100.)), TurtleCommand::Right(Angle(45.)), + //TurtleCommand::PenUp, TurtleCommand::Forward(Length(100.)), + //TurtleCommand::PenDown, + TurtleCommand::Circle { + radius: Length(-30.), + angle: Angle(90.), + }, TurtleCommand::Right(Angle(90.)), TurtleCommand::Forward(Length(50.)), TurtleCommand::Right(Angle(90.)), @@ -94,6 +111,7 @@ pub struct TurtleState { pub start: Vec2, pub heading: f32, pub index: u64, + pub drawing: bool, } impl TurtleCommands { @@ -105,13 +123,14 @@ impl TurtleCommands { start: Vec2::ZERO, heading: 0f32.to_radians(), index: 0, + drawing: true, }, } } } impl TurtleCommands { - fn get_next(&mut self) -> Option<(Tween, TurtleGraphElement)> { + fn get_next(&mut self) -> Option<(Option>, Option)> { let index = self.state.index; let next_index = index + 1; @@ -129,9 +148,17 @@ impl TurtleCommands { TurtleCommand::Right(Angle(x)) => { crate::turtle_movement::turtle_turn(&mut self.state, -*x as f32) } - TurtleCommand::PenUp => todo!(), - TurtleCommand::PenDown => todo!(), - TurtleCommand::Circle => todo!(), + TurtleCommand::PenUp => { + self.state.drawing = false; + (None, None) + } + TurtleCommand::PenDown => { + self.state.drawing = true; + (None, None) + } + TurtleCommand::Circle { radius, angle } => { + crate::turtle_movement::turtle_circle(&mut self.state, radius.0 as f32, *angle) + } TurtleCommand::Pause => todo!(), }; self.state.index = next_index; @@ -148,6 +175,13 @@ pub enum TurtleGraphElement { start: Vec2, end: Vec2, }, + TurtleCircle { + start: Vec2, + end: Vec2, + center: Vec2, + radii: Vec2, + angle: Angle, + }, #[default] Noop, } @@ -161,10 +195,10 @@ pub struct Colors { fill_color: Color, } -#[derive(Inspectable, Default)] -pub struct Length(f64); -#[derive(Inspectable, Default)] -pub struct Angle(f64); +#[derive(Inspectable, Default, Copy, Clone, Debug)] +pub struct Length(f32); +#[derive(Inspectable, Default, Copy, Clone, Debug)] +pub struct Angle(pub f32); #[derive(Component, Inspectable, Default)] pub enum TurtleCommand { @@ -176,24 +210,20 @@ pub enum TurtleCommand { PenDown, #[default] Pause, - Circle, + Circle { + radius: Length, + angle: Angle, + }, } fn setup(mut commands: Commands) { let animator = Animator::new(Tween::new( - // Use a quadratic easing on both endpoints. EaseFunction::QuadraticInOut, - // Loop animation back and forth. TweeningType::PingPong, - // Animation time (one way only; for ping-pong it takes 2 seconds - // to come back to start). Duration::from_millis(500), - // The lens gives access to the Transform component of the Entity, - // for the Animator to animate it. It also contains the start and - // end values respectively associated with the progress ratios 0. and 1. - TransformPositionLens { - start: Vec3::ZERO, - end: Vec3::new(40., 40., 0.), + TransformScaleLens { + start: Vec3::new(1., 1., 0.), + end: Vec3::new(1.3, 1.3, 0.), }, )); commands.spawn_bundle(Camera2dBundle::default()); @@ -211,81 +241,61 @@ fn setup(mut commands: Commands) { .insert(TurtleShape); } -struct MyCustomLens { - start: Vec2, - end: Vec2, -} - -impl Lens for MyCustomLens { - fn lerp(&mut self, target: &mut Path, ratio: f32) { - let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio)); - *target = ShapePath::build_as(&line); - } -} - -#[derive(Bundle)] -struct TurtleDrawLine { - #[bundle] - line: ShapeBundle, - name: Name, - marker: LineMarker, -} - -#[derive(Component, Default)] -struct LineMarker; - -impl TurtleDrawLine { - fn new(start: Vec2, _end: Vec2, index: u64) -> Self { - Self { - line: GeometryBuilder::build_as( - &Line(start, start), - DrawMode::Outlined { - fill_mode: FillMode::color(Color::MIDNIGHT_BLUE), - outline_mode: StrokeMode::new(Color::BLACK, 1.0), - }, - Transform::identity(), - ), - name: Name::new(format!("Line {}", index)), - marker: LineMarker, - } - } -} - fn draw_lines( mut commands: Commands, mut tcmd: Query<&mut TurtleCommands>, mut turtle: Query<&mut Animator, With>, mut query_event: EventReader, // TODO: howto attach only to the right event? ) { - for _ev in query_event.iter() { + for ev in query_event.iter() { let mut tcmd = tcmd.single_mut(); - if let Some((turtle_animation, graph_element_to_draw)) = tcmd.get_next() { - 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( - // Use a quadratic easing on both endpoints. - EaseFunction::QuadraticInOut, - // Loop animation back and forth. - TweeningType::Once, - // Animation time (one way only; for ping-pong it takes 2 seconds - // to come back to start). - Duration::from_millis(500), - // The lens gives access to the Transform component of the Entity, - // for the Animator to animate it. It also contains the start and - // end values respectively associated with the progress ratios 0. and 1. - MyCustomLens { start, end }, - )); - commands - .spawn_bundle(TurtleDrawLine::new(start, end, tcmd.state.index)) - .insert(line_animator); + loop { + 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(500), + 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 circle_animator = todo!(); + commands.spawn_bundle(TurtleDrawCircle::new( + center, + radii, + angle, + tcmd.state.index, + start, + end, + )); + } + } + return; } - TurtleGraphElement::Noop => println!("No drawing!"), - } - } else { - println!("nothing to draw") - }; + Some((_, _)) => { + println!("without animation"); + } + None => { + println!("nothing to draw"); + return; + } + }; + } } } @@ -301,30 +311,40 @@ fn keypresses( start: Vec2::ZERO, heading: 0., index: 0, + drawing: true, }; - if let Some((turtle_animation, graph_element_to_draw)) = tcmd.get_next() { + if let Some((Some(turtle_animation), Some(graph_element_to_draw))) = tcmd.get_next() { let mut shap = qry.single_mut(); shap.set_tweenable(turtle_animation); match graph_element_to_draw { TurtleGraphElement::TurtleLine { start, end } => { let line_animator = Animator::new(Tween::new( - // Use a quadratic easing on both endpoints. EaseFunction::QuadraticInOut, - // Loop animation back and forth. TweeningType::Once, - // Animation time (one way only; for ping-pong it takes 2 seconds - // to come back to start). Duration::from_millis(500), - // The lens gives access to the Transform component of the Entity, - // for the Animator to animate it. It also contains the start and - // end values respectively associated with the progress ratios 0. and 1. - MyCustomLens { start, end }, + 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, + )); + } } }; } diff --git a/src/turtle_movement.rs b/src/turtle_movement.rs index d061806..b5a6c96 100644 --- a/src/turtle_movement.rs +++ b/src/turtle_movement.rs @@ -6,40 +6,40 @@ use bevy_tweening::{ EaseFunction, Tween, TweeningType, }; -use crate::turtle::{TurtleGraphElement, TurtleState}; +use crate::turtle::{Angle, TurtleGraphElement, TurtleState}; pub fn turtle_turn( state: &mut TurtleState, angle_to_turn: f32, -) -> (Tween, TurtleGraphElement) { +) -> (Option>, Option) { let start = state.heading; let end = state.heading + (angle_to_turn * PI / 180.); let animation = Tween::new( - // Use a quadratic easing on both endpoints. + // Use a quadratic easing on both endpoints EaseFunction::QuadraticInOut, - // Loop animation back and forth. TweeningType::Once, - // Animation time (one way only; for ping-pong it takes 2 seconds - // to come back to start). + // Animation time Duration::from_millis(500), - // The lens gives access to the Transform component of the Entity, - // for the Animator to animate it. It also contains the start and - // end values respectively associated with the progress ratios 0. and 1. + // Rotate the turtle TransformRotateZLens { start, end }, ) .with_completed_event(state.index as u64); + // Dont move and draw let line = TurtleGraphElement::Noop; + // Update the state state.heading = end % (2. * PI); - (animation, line) + (Some(animation), Some(line)) } -pub fn turtle_move(state: &mut TurtleState, length: f32) -> (Tween, TurtleGraphElement) { +pub fn turtle_move( + state: &mut TurtleState, + length: f32, +) -> (Option>, Option) { let start = state.start; let end = state.start + (Vec2::from_angle(state.heading) * length); let turtle_movement_animation = Tween::new( // accelerate and decelerate EaseFunction::QuadraticInOut, - // Loop animation back and forth. TweeningType::Once, // later to be controlled by speed Duration::from_millis(500), @@ -50,7 +50,51 @@ pub fn turtle_move(state: &mut TurtleState, length: f32) -> (Tween, T }, ) .with_completed_event(state.index as u64); - let line = TurtleGraphElement::TurtleLine { start, end }; + // The line for animating and drawing + let line = if state.drawing { + TurtleGraphElement::TurtleLine { start, end } + } else { + TurtleGraphElement::Noop + }; state.start = end; - (turtle_movement_animation, line) + (Some(turtle_movement_animation), Some(line)) +} + +pub fn turtle_circle( + state: &mut TurtleState, + radius: f32, + angle: Angle, +) -> (Option>, Option) { + let radius_tuple = Vec2::ONE * radius.abs(); + dbg!(state.start, radius_tuple); + let center = state.start + + (Vec2::new(radius, 0.).rotate(Vec2::from_angle((state.heading + 90.).to_radians()))); + dbg!(center); + let turtle_movement_animation = Tween::new( + // accelerate and decelerate + EaseFunction::QuadraticInOut, + TweeningType::Once, + // later to be controlled by speed + Duration::from_millis(500), + // set the start and end of the animation + TransformPositionLens { + start: center.extend(0.), + end: center.extend(0.), + }, + ) + .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 + 200., + } + } else { + TurtleGraphElement::Noop + }; + // TODO update end_position : state.start = end; + (Some(turtle_movement_animation), Some(line)) }