From fe2beb01ed8c8c6c65809e995ea8748a5fff9aba Mon Sep 17 00:00:00 2001 From: Franz Dietrich Date: Sun, 12 Oct 2025 19:39:09 +0200 Subject: [PATCH] remove the bevy turtle --- Cargo.toml | 17 -- turtle-lib/Cargo.toml | 21 -- turtle-lib/LICENSE | 9 - turtle-lib/NotesWhileUpgradingBevy.md | 240 ----------------- turtle-lib/src/builders.rs | 255 ------------------ turtle-lib/src/commands.rs | 202 -------------- turtle-lib/src/debug.rs | 14 - turtle-lib/src/drawing.rs | 19 -- turtle-lib/src/drawing/animation.rs | 242 ----------------- .../src/drawing/animation/circle_lens.rs | 51 ---- turtle-lib/src/drawing/animation/line_lens.rs | 21 -- turtle-lib/src/drawing/immediate.rs | 159 ----------- turtle-lib/src/drawing/line_segments.rs | 99 ------- turtle-lib/src/drawing/run_step.rs | 58 ---- turtle-lib/src/events.rs | 4 - turtle-lib/src/general.rs | 9 - turtle-lib/src/general/angle.rs | 212 --------------- turtle-lib/src/general/length.rs | 19 -- turtle-lib/src/lib.rs | 145 ---------- turtle-lib/src/shapes.rs | 15 -- turtle-lib/src/shapes/turtle.rs | 46 ---- turtle-lib/src/state.rs | 71 ----- turtle-lib/src/turtle_bundle.rs | 104 ------- 23 files changed, 2032 deletions(-) delete mode 100644 turtle-lib/Cargo.toml delete mode 100644 turtle-lib/LICENSE delete mode 100644 turtle-lib/NotesWhileUpgradingBevy.md delete mode 100644 turtle-lib/src/builders.rs delete mode 100644 turtle-lib/src/commands.rs delete mode 100644 turtle-lib/src/debug.rs delete mode 100644 turtle-lib/src/drawing.rs delete mode 100644 turtle-lib/src/drawing/animation.rs delete mode 100644 turtle-lib/src/drawing/animation/circle_lens.rs delete mode 100644 turtle-lib/src/drawing/animation/line_lens.rs delete mode 100644 turtle-lib/src/drawing/immediate.rs delete mode 100644 turtle-lib/src/drawing/line_segments.rs delete mode 100644 turtle-lib/src/drawing/run_step.rs delete mode 100644 turtle-lib/src/events.rs delete mode 100644 turtle-lib/src/general.rs delete mode 100644 turtle-lib/src/general/angle.rs delete mode 100644 turtle-lib/src/general/length.rs delete mode 100644 turtle-lib/src/lib.rs delete mode 100644 turtle-lib/src/shapes.rs delete mode 100644 turtle-lib/src/shapes/turtle.rs delete mode 100644 turtle-lib/src/state.rs delete mode 100644 turtle-lib/src/turtle_bundle.rs diff --git a/Cargo.toml b/Cargo.toml index 3c0edc1..acb2c14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,23 +9,6 @@ members = [ ] [workspace.dependencies] -# Pin Bevy across the workspace -bevy = { version = "0.17.1" } - -# Bevy ecosystem crates compatible with Bevy 0.17 -# Lyon: main branch targets latest Bevy (0.17 at time of writing) -bevy_prototype_lyon = { git = "https://github.com/pindash-io/bevy_prototype_lyon.git", branch = "bevy-0.17" } - -# Tweening: pin to a recent commit on main that states compatibility with latest Bevy -# If this still pulls Bevy 0.16, we'll revisit and temporarily gate tweening. -bevy_tweening = { git = "https://github.com/djeedai/bevy_tweening.git", rev = "8b3cad18a090078d9055d77a632be44e701aecc7" } - -# Inspector: main branch adds support for newer Bevy, use git until 0.17 release is published -bevy-inspector-egui = { git = "https://github.com/jakobhellermann/bevy-inspector-egui.git" } - -# Shared utility crates -num-traits = "0.2" -rand = "0.8" # Enable a small amount of optimization in debug mode diff --git a/turtle-lib/Cargo.toml b/turtle-lib/Cargo.toml deleted file mode 100644 index b7e1936..0000000 --- a/turtle-lib/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "turtle-lib" -version = "0.1.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bevy = { workspace = true } -bevy_prototype_lyon = { workspace = true } -bevy-inspector-egui = { workspace = true, optional = true } -bevy_tweening = { workspace = true, optional = true } -num-traits = { workspace = true } - -[features] -default = [] -# Enable debug inspector UI (bevy-inspector-egui) -inspector = ["dep:bevy-inspector-egui"] -# Enable animations (bevy_tweening) -tweening = ["dep:bevy_tweening"] diff --git a/turtle-lib/LICENSE b/turtle-lib/LICENSE deleted file mode 100644 index 2071b23..0000000 --- a/turtle-lib/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/turtle-lib/NotesWhileUpgradingBevy.md b/turtle-lib/NotesWhileUpgradingBevy.md deleted file mode 100644 index 5689079..0000000 --- a/turtle-lib/NotesWhileUpgradingBevy.md +++ /dev/null @@ -1,240 +0,0 @@ -# Turtle Lib Bevy Upgrade Guide - -## Goal and Scope -- upgrade path: `bevy` 0.10.x → 0.16.1 -- crates covered: `turtle-lib`, example app(s), supporting tooling -- audience: maintainers comfortable with Rust & Bevy internals - -## Dependency Targets -- `bevy` 0.10.x → 0.16.1 -- `bevy_inspector_egui` 0.18 → 0.33 -- `bevy_tweening` 0.6→0.13 -- `bevy_prototype_lyon` 0.8 → 0.13 - -## Bevy relevant changes for the turtle-lib crate -src: https://bevy.org/news/ - -### 0.10 → 0.11 -- Schedule-first API (mandatory): replace all add_system/add_startup_system calls with schedule-scoped add_systems - - In `turtle-lib/src/lib.rs::TurtlePlugin::build`: - - `.add_startup_system(setup)` → `.add_systems(Startup, setup)` - - `.add_system(keypresses)` → `.add_systems(Update, keypresses)` - - `.add_system(component_animator_system::)` → `.add_systems(Update, component_animator_system::)` - - `.add_system(close_on_esc)` → `.add_systems(Update, close_on_esc)` - - `.add_system(draw_lines)` → `.add_systems(Update, draw_lines)` - - Source: 0.10→0.11 “Schedule-First: the new and improved add_systems” - -- Plugin API: `add_plugin` deprecated → use `add_plugins` (single items or tuples) - - In `TurtlePlugin::build`: - - `.add_plugin(debug::DebugPlugin)` → `.add_plugins(debug::DebugPlugin)` - - `.add_plugin(ShapePlugin)` → `.add_plugins(ShapePlugin)` - - `.add_plugin(TweeningPlugin)` → `.add_plugins(TweeningPlugin)` - - Source: 0.10→0.11 “Allow tuples and single plugins in add_plugins, deprecate add_plugin” - -- Window configuration moved from `WindowDescriptor` to `Window` on `WindowPlugin` - - In `TurtlePlugin::build` replace: - - `DefaultPlugins.set(WindowPlugin { window: WindowDescriptor { title, width, height, present_mode, ..Default::default() }, ..default() })` - - with `DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { title, resolution: (width, height).into(), present_mode, ..default() }), ..default() })` - - Notes: PresentMode variants are unchanged here; title now takes `String` via `.into()`; width/height become `resolution`. - - Source: Bevy 0.11 window API (examples/docs) - -- Events must derive Event - - In `turtle-lib/src/events.rs`: add `#[derive(Event)]` to `DrawingStartedEvent`. - - Ensure `app.add_event::()` remains in `TurtlePlugin::build`. - - Source: 0.10→0.11 “Require #[derive(Event)] on all Events” - -- Reflect derives: `FromReflect` is auto-derived by `#[derive(Reflect)]` - - In `turtle-lib/src/commands.rs`, many enums/structs derive both `Reflect` and `FromReflect`. - - You can remove explicit `FromReflect` derives unless you provide a manual impl; if you keep a manual impl, disable auto via `#[reflect(from_reflect = false)]`. - - Source: 0.10→0.11 “FromReflect Ergonomics Implementation” - -### 0.11 → 0.12 -- EventReader API rename: `iter()` → `read()` - - In `turtle-lib/src/lib.rs::draw_lines` change: - - `for _ev in query_event.iter() { ... }` → `for _ev in query_event.read() { ... }` - - Also, `&mut EventReader` no longer implements `IntoIterator`; prefer `.read()`. - - Source: 0.11→0.12 “Refactor EventReader::iter to read” and “Remove IntoIterator impl for &mut EventReader” - -- Unified `configure_sets` API (FYI only) - - If you later configure system sets, prefer `app.configure_sets(ScheduleLabel, …)`. Turtle-lib doesn’t currently call this, so no change. - - Source: 0.11→0.12 “Replace IntoSystemSetConfig with IntoSystemSetConfigs” and “Unified configure_sets API” - -- Present mode/Window tweaks (FYI only) - - `PresentMode::Fifo` still valid; an additional `FifoRelaxed` variant exists—no change required. - - Hot reloading workflow changed to feature flag `bevy/file_watcher`; turtle-lib doesn’t configure `AssetPlugin`, so no change. - - Source: 0.11→0.12 windowing and assets notes - -### 0.12 → 0.13 -- Scheduling and plugin API are unchanged from 0.12 for turtle-lib - - Existing schedule-first usage and `add_plugins` continue to work. No changes needed in `TurtlePlugin::build` for scheduling semantics. - -- WindowPlugin: primary window field naming consistency - - If you already use the 0.11+ style (recommended earlier): - - `WindowPlugin { primary_window: Some(Window { title, resolution, present_mode, ..default() }), ..default() }` continues to be the correct pattern. - - If any code still uses `WindowPlugin { window: WindowDescriptor { .. } }`, migrate per 0.10→0.11 notes above (crate currently uses `WindowDescriptor` and needs that migration anyway). - -- Camera clear color configuration remains valid - - `Camera2dBundle { camera_2d: Camera2d { clear_color: ClearColorConfig::Custom(Color::BEIGE) }, ..default() }` remains correct. No change needed. - -- Input API is stable - - `Res>` and `keys.just_pressed(KeyCode::W)` continue to work without changes. - -- Events ergonomics (carry-over from 0.11) - - Ensure custom events derive `#[derive(Event)]` and are registered with `app.add_event::()`. This remains required and stable in 0.13. - - `EventReader::read()` introduced in 0.12 continues to be the correct method in 0.13; prefer `for ev in reader.read()` over the removed `iter()`. - -- Bevy Inspector Egui (debug) still uses plugin as-is - - `WorldInspectorPlugin` continues to be added via `add_plugins` in debug builds; no API change affecting `turtle-lib` at this hop. - -### 0.13 → 0.14 -- Color API refinements (no code change needed for current usage) - - Named colors like `Color::BEIGE`, `Color::MIDNIGHT_BLUE`, `Color::BLACK` remain valid. No renames impacting `turtle-lib` in this hop. - - Type-safe color constructors improved, but we don’t currently construct custom colors beyond constants. - -- Windowing migrated to winit 0.30 (FYI) - - No direct use of backend-specific window APIs in `turtle-lib`; existing `Window { title, resolution, present_mode }` remains valid. - - If examples or downstream apps interact with window events, check their migrations separately; not applicable in this crate. - -- Events are always updated in minimal apps (FYI) - - Bevy 0.14 guarantees events update even in minimal setups; `turtle-lib` already uses `DefaultPlugins` and explicit `add_event::()` so no action required. - -- Scheduling/UI/Camera - - `Camera2dBundle` stays stable in this hop; our use of `ClearColorConfig::Custom(Color::BEIGE)` continues to be correct. - - `close_on_esc` remains available via `bevy::window::close_on_esc` with the same call pattern. - -### 0.14 → 0.15 -- Query::single family migrated to `Single` (N/A) - - `turtle-lib` does not call `Query::single()`/`single_mut()`; no migration needed here. - -- State-scoped events (FYI) - - 0.15 introduces state-scoped events; `turtle-lib` uses a global `DrawingStartedEvent` and doesn’t scope events to states. No change required. - -- Color, camera, and window remain compatible - - Existing use of `Color::BEIGE`, `Camera2dBundle`, and `Window { resolution, present_mode }` remains valid; no API renames affecting our code in this hop. - -- Scheduling order clarifications (FYI) - - 0.15 tightened ambiguities in system ordering; `turtle-lib` doesn’t rely on ambiguous ordering between systems, and uses default sets. No action needed. - -### 0.15 → 0.16 -- ECS Relationships replace `Parent`/`Children` (N/A) - - `turtle-lib` doesn’t use hierarchy components directly; no migration required. - -- Improved spawn ergonomics (N/A) - - The new `children!`/`related!` helpers don’t affect current code; we spawn via bundles without parent-child APIs. - -- Unified ECS error handling (optional) - - Systems and commands can return `Result` in 0.16+. `turtle-lib` systems currently return `()`. You may adopt `Result` for clearer error paths later, but no change is required to compile. - -- Window/Input/Camera remain compatible - - `close_on_esc`, `Input`, `Camera2dBundle`, and `ClearColorConfig::Custom(Color::BEIGE)` continue to work. No API renames in these areas affecting current usage. - -- Tweening and Lyon plugins - - API incompatibilities, if any, are tracked in their dedicated sections below. No direct Bevy-0.16-specific change required in our calls (`Animator`, `Tween`, `Path`). - -## Bevy_inspector_egui relevant changes for the turtle-lib crate -src: https://github.com/jakobhellermann/bevy-inspector-egui/blob/main/docs/CHANGELOG.md -src: https://github.com/jakobhellermann/bevy-inspector-egui/blob/main/docs/MIGRATION_GUIDE_0.15_0.16.md - -- Version alignment across Bevy upgrades - - 0.12 → 0.13: use bevy_inspector_egui ≥ 0.21 (changelog shows 0.21 updated to Bevy 0.12; 0.23 to Bevy 0.13). Our target path ends at 0.33 for Bevy 0.16. - - 0.14: use ≥ 0.25 (changelog: 0.25.0 updated to Bevy 0.14). - - 0.15: use ≥ 0.28 (changelog: 0.28.0 updated to Bevy 0.15). - - 0.16: use ≥ 0.31 (changelog: 0.31.0 updated to Bevy 0.16). Latest at time of writing is 0.33.x. - -- WorldInspectorPlugin path and construction (0.15 → 0.16) - - The old `WorldInspectorPlugin` moved to `bevy_inspector_egui::quick::WorldInspectorPlugin`. - - In `turtle-lib/src/debug.rs`, ensure we import from `quick`: - - `use bevy_inspector_egui::quick::WorldInspectorPlugin;` - - Continue to add it conditionally in debug: - - `app.add_plugins(WorldInspectorPlugin);` (use `add_plugins`, not `add_plugin`). - - The removed `WorldInspectorParams` is not used in this crate, so no action is required. - -- Reflect-driven inspector (0.15 → 0.16 rewrite) - - The inspector is centered on `Reflect` and type registration. We already register types we care about (`TurtleColors`, `TurtleCommands`). No additional registration is necessary for using the world inspector itself. - - If we later add per-resource inspectors (e.g., `ResourceInspectorPlugin`), derive `Reflect` for `T` and call `app.register_type::()`. - -- Schedules/ambiguity fixes in quick plugins - - The crate’s quick plugins run in their own schedule to avoid system ambiguity since ~0.25. No overrides needed by `turtle-lib`. - -- Known guardrails - - 0.18.4 added a guard for missing `PrimaryWindow`; our app defines a primary window via `DefaultPlugins.set(WindowPlugin { … })`, so the inspector will work in debug. - -## Bevy_tweening relevant changes for the turtle-lib crate -src: https://github.com/djeedai/bevy_tweening/blob/main/CHANGELOG.md - -- Version alignment with Bevy - - Bevy 0.10 → bevy_tweening 0.7 - - Bevy 0.11 → bevy_tweening 0.8 - - Bevy 0.12 → bevy_tweening 0.9 - - Bevy 0.13 → bevy_tweening 0.10 - - Bevy 0.14 → bevy_tweening 0.11 - - Bevy 0.15 → bevy_tweening 0.12 - - Bevy 0.16 → bevy_tweening 0.13 - -- Custom Lens signature change (bevy_tweening 0.11 for Bevy 0.14) - - Impacted files: `turtle-lib/src/drawing/animation/line_lens.rs`, `turtle-lib/src/drawing/animation/circle_lens.rs`. - - Update `Lens::lerp(&mut self, target: &mut T, ratio: f32)` → `Lens::lerp(&mut self, target: &mut dyn Targetable, ratio: f32)`. - - Code using `target` can remain unchanged because `dyn Targetable` implements `Defer`/`DeferMut` and derefs like `&mut T`. - - This change is required when moving to Bevy 0.14 (bevy_tweening 0.11+) and remains compatible up to 0.13. - -- EaseFunction source update (bevy_tweening 0.12 for Bevy 0.15) - - `interpolation::EaseFunction` was replaced by `bevy_math::EaseFunction` and re-exported by bevy_tweening. - - Our code imports `bevy_tweening::EaseFunction`, which continues to work. Alternatively, import `bevy_math::EaseFunction` directly. - -- Animator systems and Path animations - - Continue adding `TweeningPlugin` to the app. - - Continue registering `component_animator_system::` in `Update` to animate `Animator` (still required up to bevy_tweening 0.13). - - Note: The removal of `component_animator_system` is planned in a future bevy_tweening 0.14 (unreleased at the time of writing) and does not apply to our 0.13 target. - -- Completion events - - `TweenCompleted` event remains available through 0.13. Our use of `.with_completed_event(state.segment_index() as u64)` is valid up to 0.13. - - If migrating beyond 0.13 later, the API changes (no `user_data`, new event types) will require adjustments; out of scope for Bevy 0.16 + bevy_tweening 0.13. - -- Bevy 0.12 EventReader change applies here too - - When listening to `TweenCompleted`, use `EventReader::read()` (not `iter()`), as documented in the Bevy 0.11→0.12 section above. - -## Bevy_prototype_lyon relevant changes for the turtle-lib crate -src: https://github.com/Nilirad/bevy_prototype_lyon/blob/master/CHANGELOG.md - -- Version alignment with Bevy - - Bevy 0.10 → lyon 0.8 - - Bevy 0.11 → lyon 0.9 - - Bevy 0.12 → lyon 0.10 - - Bevy 0.13 → lyon 0.11 - - Bevy 0.14 → lyon 0.12 - - Bevy 0.15 → lyon 0.13 - - Bevy 0.16 → lyon 0.14 - -- 0.8: Fill/Stroke rename - - `FillMode`/`StrokeMode` renamed to `Fill`/`Stroke` and became Components. - - In `turtle-lib/src/turtle_bundle.rs`, if still using the old names, update: - - `DrawMode::Outlined { fill_mode: FillMode::color(c), outline_mode: StrokeMode::new(c2, w) }` - - to the current API for your target lyon version (≤0.13 still supports DrawMode; in 0.14 see below). - -- 0.13: `ShapeBundle` composition change (FYI) - - Deprecated `SpatialBundle` was removed from `ShapeBundle`; `Transform` and `Visibility` are added separately internally. - - We construct shapes via `GeometryBuilder::build_as(...)` returning `ShapeBundle`; we don’t access its fields—no code change required. - -- 0.14 (Bevy 0.16): Major API rework affecting turtle-lib - - Path component renamed to `Shape`; `Shape` now includes fill and stroke data. - - `Fill` and `Stroke` are no longer `Component`s; they’re part of `Shape` data. - - `GeometryBuilder` and `PathBuilder` removed. Use `ShapeBuilder` and `ShapePath`: - - Build shapes: `ShapeBuilder::with(&geometry).fill(color).stroke((color, width)).build()`. - - `ShapePath` now implements `Geometry` and replaces direct `PathBuilder` usage. - - `ShapeBundle` is deprecated and no longer exported from `prelude`. - - Impacted code and migration sketch for 0.14: - - Imports in `turtle-lib/src/lib.rs` and lenses: - - Replace `use bevy_prototype_lyon::prelude::{Path, ShapePlugin};` with `use bevy_prototype_lyon::prelude::{Shape, ShapePath, ShapeBuilder, ShapePlugin};` - - Animator and systems: - - `Animator` → `Animator` - - `component_animator_system::` → `component_animator_system::` - - Lenses (`drawing/animation/line_lens.rs`, `circle_lens.rs`): - - `impl Lens for ...` → `impl Lens for ...` - - Replace `PathBuilder` usage with creating/updating a `ShapePath` geometry and attaching it to the `Shape` target per the new API. - - Spawn/build (`turtle_bundle.rs`): - - Replace `GeometryBuilder::build_as(&shapes::turtle(), DrawMode::Outlined { ... }, Transform::IDENTITY)` and `ShapeBundle` - - with `ShapeBuilder::with(&shapes::turtle()).fill(Color::MIDNIGHT_BLUE).stroke((Color::BLACK, 1.0)).build()`. - -Notes: -- If you stop at lyon 0.13 (Bevy 0.15), you don’t need the 0.14 rework yet. If you upgrade to Bevy 0.16, adopt lyon 0.14 and apply the above migrations. \ No newline at end of file diff --git a/turtle-lib/src/builders.rs b/turtle-lib/src/builders.rs deleted file mode 100644 index de71746..0000000 --- a/turtle-lib/src/builders.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::ops::Neg; - -use crate::{ - commands::{DrawElement, MoveCommand, TurtleSegment}, - general::{angle::Angle, length::Length, Precision}, -}; - -#[derive(Default, Debug)] -pub struct TurtlePlan { - /** - * A turtle Plan contains the segments of a turtle drawing. - * The segments in turn contain the commands to draw the graph. - */ - commands: Vec, -} - -pub trait WithCommands { - fn get_mut_commands(&mut self) -> &mut Vec; - fn get_commands(self) -> Vec; -} - -impl WithCommands for TurtlePlan { - fn get_mut_commands(&mut self) -> &mut Vec { - &mut self.commands - } - - fn get_commands(self) -> Vec { - self.commands - } -} - -impl TurtlePlan { - pub fn new() -> TurtlePlan { - TurtlePlan { commands: vec![] } - } -} - -pub trait DirectionalMovement: WithCommands { - fn forward(&mut self, length: IntoDistance) -> &mut Self - where - Length: From, - { - let length: Length = length.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Draw( - crate::commands::MoveCommand::Forward(length), - ))); - self - } - fn backward(&mut self, length: IntoDistance) -> &mut Self - where - Length: From, - { - let length: Length = length.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Draw( - crate::commands::MoveCommand::Backward(length), - ))); - self - } -} - -impl DirectionalMovement for TurtlePlan {} - -pub trait Turnable: WithCommands { - fn right(&mut self, angle: IntoAngle) -> &mut Self - where - Angle: From, - { - let angle: Angle = angle.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Orient( - crate::commands::OrientationCommand::Right(angle), - ))); - self - } - fn left(&mut self, angle: IntoAngle) -> &mut Self - where - Angle: From, - { - let angle: Angle = angle.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Orient( - crate::commands::OrientationCommand::Left(angle), - ))); - self - } -} - -impl Turnable for TurtlePlan {} - -pub trait CurvedMovement: WithCommands { - fn circle( - &mut self, - radius: IntoDistance, - extend: IntoAngle, - ) -> &mut Self - where - Angle: From, - Length: From, - { - let angle: Angle = extend.into(); - let radius: Length = radius.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Draw( - MoveCommand::Circle { radius, angle }, - ))); - self - } - fn circle_right>( - &mut self, - radius: IntoDistance, - extend: IntoAngle, - ) -> &mut Self - where - Angle: From, - Length: From, - { - self.circle(-radius, extend); - println!("Warning: circle with right arc not working yet..."); - self - } -} - -impl CurvedMovement for TurtlePlan {} - -pub trait StopLine -where - T: WithCommands, -{ - fn pen_up(self) -> InvisibleLinesPlan; -} - -impl StopLine for TurtlePlan { - fn pen_up(self) -> InvisibleLinesPlan { - { - InvisibleLinesPlan { - before: self, - commands: vec![], - } - } - } -} - -pub trait StartLine { - fn pen_down(self) -> T; -} - -impl StartLine for InvisibleLinesPlan -where - T: WithCommands, -{ - fn pen_down(mut self) -> T { - self.before.get_mut_commands().append(&mut self.commands); - self.before - } -} - -pub struct InvisibleLinesPlan { - before: T, - commands: Vec, -} - -impl WithCommands for InvisibleLinesPlan -where - T: WithCommands, -{ - fn get_mut_commands(&mut self) -> &mut Vec { - &mut self.commands - } - - fn get_commands(self) -> Vec { - self.commands - } -} - -impl InvisibleLinesPlan -where - T: WithCommands, -{ - pub fn new(before: T) -> Self { - InvisibleLinesPlan { - before, - commands: vec![], - } - } -} - -impl Turnable for InvisibleLinesPlan {} - -impl DirectionalMovement for InvisibleLinesPlan -where - T: WithCommands, -{ - fn forward(&mut self, length: IntoDistance) -> &mut Self - where - Length: From, - { - let length: Length = length.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Move( - crate::commands::MoveCommand::Forward(length), - ))); - self - } - - fn backward(&mut self, length: IntoDistance) -> &mut Self - where - Length: From, - { - let length: Length = length.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Move( - crate::commands::MoveCommand::Backward(length), - ))); - self - } -} - -impl CurvedMovement for InvisibleLinesPlan -where - T: WithCommands, -{ - fn circle( - &mut self, - radius: IntoDistance, - extend: IntoAngle, - ) -> &mut Self - where - Angle: From, - Length: From, - { - let angle: Angle = extend.into(); - let radius: Length = radius.into(); - self.get_mut_commands() - .push(TurtleSegment::Single(DrawElement::Move( - MoveCommand::Circle { radius, angle }, - ))); - self - } - - fn circle_right>( - &mut self, - radius: IntoDistance, - extend: IntoAngle, - ) -> &mut Self - where - Angle: From, - Length: From, - { - self.circle(-radius, extend); - println!("Warning: circle with right arc not working yet..."); - self - } -} diff --git a/turtle-lib/src/commands.rs b/turtle-lib/src/commands.rs deleted file mode 100644 index 0de3ae2..0000000 --- a/turtle-lib/src/commands.rs +++ /dev/null @@ -1,202 +0,0 @@ -use bevy::{prelude::Component, reflect::Reflect}; - -use crate::{ - builders::WithCommands, - drawing::TurtleGraphElement, - general::{angle::Angle, length::Length, Coordinate, Precision, Speed}, - state::TurtleState, -}; - -#[cfg(feature = "tweening")] -use crate::drawing::animation::{ - draw_circle_segment, draw_straight_segment, move_straight_segment, turtle_turn, - ToAnimationSegment, TurtleAnimationSegment, -}; -/** - * All the possibilities to draw something with turtle. All the commands can get the position, heading, - * color and fill_color from the turtles state. - */ -#[derive(Component, Reflect, Debug, Clone)] -pub enum MoveCommand { - Forward(Length), - Backward(Length), - Circle { - radius: Length, - angle: Angle, - }, - Goto(Coordinate), -} - -impl Default for MoveCommand { - fn default() -> Self { - Self::Forward(Length(100.)) - } -} -/// Different ways to drop breadcrumbs on the way like a dot or a stamp of the turtles shape. - -#[derive(Component, Reflect, Default, Debug, Clone)] -pub enum Breadcrumb { - Dot, - #[default] - Stamp, -} - -/// Different ways that change the orientation of the turtle. -#[derive(Component, Reflect, Debug, Clone)] -pub enum OrientationCommand { - Left(Angle), - Right(Angle), - SetHeading, - LookAt(Coordinate), -} - -impl Default for OrientationCommand { - fn default() -> Self { - Self::Right(Default::default()) - } -} - -/// A combination of all commands that can be used while drawing. -#[derive(Component, Reflect, Debug, Clone)] -pub enum DrawElement { - Draw(MoveCommand), - Move(MoveCommand), - Orient(OrientationCommand), - Drip(Breadcrumb), -} - -impl Default for DrawElement { - fn default() -> Self { - Self::Draw(Default::default()) - } -} - -#[cfg(feature = "tweening")] -impl ToAnimationSegment for DrawElement { - fn to_draw_segment( - &self, - state: &mut TurtleState, - ) -> crate::drawing::animation::TurtleAnimationSegment { - match self { - DrawElement::Draw(e) => match e { - MoveCommand::Forward(length) => draw_straight_segment(state, length.0), - MoveCommand::Backward(length) => draw_straight_segment(state, -length.0), - MoveCommand::Circle { radius, angle } => { - draw_circle_segment(state, *radius, *angle) - } - MoveCommand::Goto(coord) => todo!(), - }, - DrawElement::Move(e) => match e { - MoveCommand::Forward(length) => move_straight_segment(state, length.0), - MoveCommand::Backward(length) => move_straight_segment(state, -length.0), - MoveCommand::Circle { radius, angle } => todo!(), - MoveCommand::Goto(coord) => todo!(), - }, - DrawElement::Orient(e) => match e { - OrientationCommand::Left(angle_to_turn) => turtle_turn(state, -*angle_to_turn), - OrientationCommand::Right(angle_to_turn) => turtle_turn(state, *angle_to_turn), - OrientationCommand::SetHeading => todo!(), - OrientationCommand::LookAt(_) => todo!(), - }, - DrawElement::Drip(_) => todo!(), - } - } -} - -#[derive(Component, Reflect, Debug, Clone)] -pub enum TurtleSegment { - Single(DrawElement), - Outline(Vec), - Filled(Vec), -} - -impl Default for TurtleSegment { - fn default() -> Self { - Self::Single(Default::default()) - } -} - -#[cfg(feature = "tweening")] -impl ToAnimationSegment for TurtleSegment { - fn to_draw_segment( - &self, - state: &mut TurtleState, - ) -> crate::drawing::animation::TurtleAnimationSegment { - match self { - Self::Single(e) => e.to_draw_segment(state), - Self::Outline(_) => todo!(), - Self::Filled(_) => todo!(), - } - } -} -#[derive(Component, Reflect, Debug)] -pub struct TurtleCommands { - animation_state: usize, - commands: Vec, - lines: Vec, - state: TurtleState, -} - -impl TurtleCommands { - pub fn new(commands: Vec) -> Self { - let mut state = TurtleState::default(); - state.set_speed(200); - Self { - animation_state: 0, - commands, - lines: vec![], - state, - } - } - pub fn push(&mut self, segment: TurtleSegment) { - self.commands.push(segment) - } - pub fn extend(&mut self, segments: Vec) { - self.commands.extend(segments.into_iter()) - } - pub fn set_speed(&mut self, speed: Speed) { - self.state.set_speed(speed); - } - - // Public accessors for immediate drawing - pub(crate) fn animation_state(&self) -> usize { - self.animation_state - } - pub(crate) fn animation_state_mut(&mut self) -> &mut usize { - &mut self.animation_state - } - pub(crate) fn commands(&self) -> &[TurtleSegment] { - &self.commands - } - pub(crate) fn state_mut(&mut self) -> &mut TurtleState { - &mut self.state - } -} - -#[cfg(feature = "tweening")] -impl Iterator for TurtleCommands { - type Item = TurtleAnimationSegment; - - fn next(&mut self) -> Option { - let index = self.animation_state; - let next_index = index + 1; - - if let Some(command) = self.commands.get(self.animation_state) { - let res = command.to_draw_segment(&mut self.state); - self.animation_state = next_index; - Some(res) - } else { - None - } - } -} - -impl WithCommands for TurtleCommands { - fn get_mut_commands(&mut self) -> &mut Vec { - &mut self.commands - } - - fn get_commands(self) -> Vec { - self.commands - } -} diff --git a/turtle-lib/src/debug.rs b/turtle-lib/src/debug.rs deleted file mode 100644 index 92c6dd9..0000000 --- a/turtle-lib/src/debug.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bevy::prelude::Plugin; -#[cfg(feature = "inspector")] -use bevy_inspector_egui::quick::WorldInspectorPlugin; - -pub struct DebugPlugin; - -impl Plugin for DebugPlugin { - fn build(&self, _app: &mut bevy::prelude::App) { - if cfg!(debug_assertions) { - #[cfg(feature = "inspector")] - app.add_plugins(WorldInspectorPlugin::default()); - } - } -} diff --git a/turtle-lib/src/drawing.rs b/turtle-lib/src/drawing.rs deleted file mode 100644 index 0b77305..0000000 --- a/turtle-lib/src/drawing.rs +++ /dev/null @@ -1,19 +0,0 @@ -use bevy::reflect::Reflect; - -pub use self::line_segments::{TurtleDrawCircle, TurtleDrawLine}; - -#[cfg(feature = "tweening")] -pub mod animation; -#[cfg(not(feature = "tweening"))] -pub(crate) mod immediate; -mod line_segments; -#[cfg(feature = "tweening")] -pub(crate) mod run_step; - -#[derive(Reflect, Default, Debug)] -pub enum TurtleGraphElement { - TurtleLine(TurtleDrawLine), - TurtleCircle(TurtleDrawCircle), - #[default] - Noop, -} diff --git a/turtle-lib/src/drawing/animation.rs b/turtle-lib/src/drawing/animation.rs deleted file mode 100644 index 8b92921..0000000 --- a/turtle-lib/src/drawing/animation.rs +++ /dev/null @@ -1,242 +0,0 @@ -mod circle_lens; -mod line_lens; - -use bevy::prelude::{Quat, Transform, Vec2, Vec3}; -use bevy_prototype_lyon::prelude::Shape; -use bevy_tweening::{ - lens::{TransformPositionLens, TransformRotateZLens}, - Animator, EaseFunction, Tween, -}; - -use crate::{ - general::{angle::Angle, length::Length, Coordinate, Precision}, - state::TurtleState, -}; - -use self::{ - circle_lens::{CircleAnimationLens, CircleMovementLens}, - line_lens::LineAnimationLens, -}; - -use super::{TurtleDrawCircle, TurtleDrawLine, TurtleGraphElement}; - -pub struct TurtleAnimationSegment { - pub turtle_animation: Option>, - pub line_segment: Option, - pub line_animation: Option>, -} - -pub trait ToAnimationSegment { - fn to_draw_segment( - &self, - state: &mut TurtleState, - ) -> crate::drawing::animation::TurtleAnimationSegment; -} - -pub fn turtle_turn( - state: &mut TurtleState, - angle_to_turn: Angle, -) -> TurtleAnimationSegment { - let start = state.heading(); - let end = state.heading() + angle_to_turn; - let animation = Tween::new( - EaseFunction::QuadraticInOut, - state.animation_duration(), - TransformRotateZLens { - start: start.to_radians().value(), - end: end.to_radians().value(), - }, - ) - .with_completed_event(state.segment_index() as u64); - // Don't draw as the position does not change - let line = TurtleGraphElement::Noop; - // Update the state - state.set_heading(end.limit_smaller_than_full_circle()); - TurtleAnimationSegment { - turtle_animation: Some(animation), - line_segment: Some(line), - line_animation: None, - } -} - -pub fn move_straight_segment(state: &mut TurtleState, length: Precision) -> TurtleAnimationSegment { - let animation = MoveStraightTurtleAnimation::new(state, length); - - state.set_position(animation.end); - TurtleAnimationSegment { - turtle_animation: Some(animation.animation), - line_segment: None, - line_animation: None, - } -} - -pub fn draw_straight_segment(state: &mut TurtleState, length: Precision) -> TurtleAnimationSegment { - let animation = MoveStraightTurtleAnimation::new(state, length); - let line_animation = MoveStraightLineAnimation::new(state, length, &animation); - - state.set_position(animation.end); - TurtleAnimationSegment { - turtle_animation: Some(animation.animation), - line_segment: Some(TurtleGraphElement::TurtleLine(line_animation.line)), - line_animation: Some(Animator::new(line_animation.animation)), - } -} - -pub fn draw_circle_segment( - state: &mut TurtleState, - radius: Length, - angle: Angle, -) -> TurtleAnimationSegment { - let animation = MoveCircleTurtleAnimation::new(state, radius, angle); - let line_animation = MoveCircleLineAnimation::new(state, radius, angle); - state.set_position(animation.end); - state.set_heading(animation.end_heading); - TurtleAnimationSegment { - turtle_animation: Some(animation.animation), - line_segment: Some(TurtleGraphElement::TurtleCircle(line_animation.line)), - line_animation: Some(Animator::new(line_animation.animation)), - } -} - -struct MoveStraightLineAnimation { - _start: Coordinate, - _end: Coordinate, - line: TurtleDrawLine, - animation: Tween, -} - -impl MoveStraightLineAnimation { - fn new( - state: &TurtleState, - _length: Precision, - turtle_animation: &MoveStraightTurtleAnimation, - ) -> Self { - let line = TurtleDrawLine::new(turtle_animation.start, turtle_animation.end); - let line_animation = Tween::new( - EaseFunction::QuadraticInOut, - state.animation_duration(), - LineAnimationLens::new(turtle_animation.start, turtle_animation.end), - ) - /* .with_repeat_strategy(RepeatStrategy::MirroredRepeat) - .with_repeat_count(RepeatCount::Infinite)*/; - Self { - _start: turtle_animation.start, - _end: turtle_animation.end, - line, - animation: line_animation, - } - } -} - -struct MoveStraightTurtleAnimation { - start: Coordinate, - end: Coordinate, - animation: Tween, -} -impl MoveStraightTurtleAnimation { - fn new(state: &TurtleState, length: Precision) -> Self { - let start = state.position(); - let end = - state.position() + (Vec2::from_angle(state.heading().to_radians().value()) * length); - let turtle_movement_animation = Tween::new( - EaseFunction::QuadraticInOut, - state.animation_duration(), - TransformPositionLens { - start: start.extend(0.), - end: end.extend(0.), - }, - ) - .with_completed_event(state.segment_index() as u64); - Self { - start, - end, - animation: turtle_movement_animation, - } - } -} - -struct MoveCircleLineAnimation { - _start: Coordinate, - _end: Coordinate, - line: TurtleDrawCircle, - animation: Tween, -} - -impl MoveCircleLineAnimation { - fn new(state: &TurtleState, radius: Length, angle: Angle) -> Self { - let radii = Vec2::ONE * radius.0.abs(); - let start = state.position(); - let left_right = Angle::degrees(if radius.0 >= 0. { 90. } else { -90. }); - let center = state.position() - + (Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - ((state.heading() + left_right).to_radians()).value(), - ))); - let end_pos = center - + Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - (state.heading() + angle - left_right).to_radians().value(), - )); - - let line = - TurtleDrawCircle::new(center, radii, Angle::degrees(0.), state.position(), end_pos); - let line_animator = Tween::new( - EaseFunction::QuadraticInOut, - state.animation_duration(), - CircleAnimationLens { - start_pos: state.position(), - center, - radii, - start: Angle::degrees(0.), - end: if radius.0 > 0. { angle } else { -angle }, - }, - ); - Self { - _start: start, - _end: end_pos, - line, - animation: line_animator, - } - } -} - -struct MoveCircleTurtleAnimation { - _start: Coordinate, - end: Coordinate, - end_heading: Angle, - animation: Tween, -} - -impl MoveCircleTurtleAnimation { - fn new(state: &TurtleState, radius: Length, angle: Angle) -> Self { - let start = state.position(); - let left_right = Angle::degrees(if radius.0 >= 0. { 90. } else { -90. }); - let center = state.position() - + (Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - ((state.heading() + left_right).to_radians()).value(), - ))); - let end_heading = state.heading() + if radius.0 > 0. { angle } else { -angle }; - let end_pos = center - + Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - (state.heading() + angle - left_right).to_radians().value(), - )); - let turtle_movement_animation = Tween::new( - EaseFunction::QuadraticInOut, - state.animation_duration(), - CircleMovementLens { - start: Transform { - translation: state.position().extend(0.), - rotation: Quat::from_rotation_z(state.heading().to_radians().value()), - scale: Vec3::ONE, - }, - end: if radius.0 > 0. { angle } else { -angle }, - center, - }, - ) - .with_completed_event(state.segment_index() as u64); - Self { - _start: start, - end: end_pos, - end_heading, - animation: turtle_movement_animation, - } - } -} diff --git a/turtle-lib/src/drawing/animation/circle_lens.rs b/turtle-lib/src/drawing/animation/circle_lens.rs deleted file mode 100644 index 0e297bf..0000000 --- a/turtle-lib/src/drawing/animation/circle_lens.rs +++ /dev/null @@ -1,51 +0,0 @@ -use bevy::prelude::{Quat, Transform, Vec2}; -use bevy_prototype_lyon::{path::ShapePath, prelude::*, self as lyon_crate}; -use lyon_crate::entity::Shape; -use bevy_tweening::Lens; - -use crate::general::{angle::Angle, Precision}; - -pub(crate) struct CircleAnimationLens { - pub start_pos: Vec2, - pub center: Vec2, - pub radii: Vec2, - pub start: Angle, - pub end: Angle, -} - -impl Lens for CircleAnimationLens { - fn lerp(&mut self, target: &mut Shape, ratio: f32) { - let mut path = ShapePath::new(); - path = path.move_to(self.start_pos); - // 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 = path.arc( - self.center, - self.radii, - (self.start + ((self.end - self.start) * ratio)) - .to_radians() - .value(), - 0., - ); - *target = Shape::from(path); - } -} - -pub(crate) struct CircleMovementLens { - pub center: Vec2, - pub start: Transform, - pub end: Angle, -} - -impl Lens for CircleMovementLens { - fn lerp(&mut self, target: &mut Transform, ratio: f32) { - let angle = self.end * ratio; - let mut rotated = self.start; - - rotated.rotate_around( - self.center.extend(0.), - Quat::from_rotation_z(angle.to_radians().value()), - ); - - *target = rotated; - } -} diff --git a/turtle-lib/src/drawing/animation/line_lens.rs b/turtle-lib/src/drawing/animation/line_lens.rs deleted file mode 100644 index 0c92763..0000000 --- a/turtle-lib/src/drawing/animation/line_lens.rs +++ /dev/null @@ -1,21 +0,0 @@ -use bevy::prelude::Vec2; -use bevy_prototype_lyon::{prelude::{Shape, ShapePath}, shapes}; -use bevy_tweening::Lens; - -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 Shape, ratio: f32) { - let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio)); - *target = Shape::from(ShapePath::build_as(&line)); - } -} diff --git a/turtle-lib/src/drawing/immediate.rs b/turtle-lib/src/drawing/immediate.rs deleted file mode 100644 index 0ff78fe..0000000 --- a/turtle-lib/src/drawing/immediate.rs +++ /dev/null @@ -1,159 +0,0 @@ -use bevy::prelude::{Commands, Query, Quat, Transform, Vec2, With}; - -use crate::{ - commands::{DrawElement, MoveCommand, OrientationCommand, TurtleCommands, TurtleSegment}, - general::angle::Angle, - shapes::TurtleShape, -}; - -use super::line_segments::{TurtleDrawCircle, TurtleDrawLine}; - -/// Executes all turtle commands immediately without animation -pub fn run_all_commands_immediately( - commands: &mut Commands, - tcmd: &mut TurtleCommands, - turtle: &mut Query<&mut Transform, With>, -) { - if let Ok(mut turtle_transform) = turtle.single_mut() { - // Execute all commands - loop { - let idx = tcmd.animation_state(); - if idx >= tcmd.commands().len() { - break; - } - - let segment = tcmd.commands()[idx].clone(); - match segment { - TurtleSegment::Single(element) => { - execute_draw_element(commands, &element, tcmd, &mut turtle_transform); - } - TurtleSegment::Outline(elements) => { - for element in elements { - execute_draw_element(commands, &element, tcmd, &mut turtle_transform); - } - } - TurtleSegment::Filled(elements) => { - for element in elements { - execute_draw_element(commands, &element, tcmd, &mut turtle_transform); - } - } - } - *tcmd.animation_state_mut() += 1; - } - } -} - -fn execute_draw_element( - commands: &mut Commands, - element: &DrawElement, - tcmd: &mut TurtleCommands, - turtle_transform: &mut Transform, -) { - match element { - DrawElement::Draw(move_cmd) => { - match move_cmd { - MoveCommand::Forward(length) => { - let start = tcmd.state_mut().position(); - let end = start + (Vec2::from_angle(tcmd.state_mut().heading().to_radians().value()) * length.0); - - tcmd.state_mut().set_position(end); - - // Update turtle position - turtle_transform.translation.x = end.x; - turtle_transform.translation.y = end.y; - - // Draw line - let line = TurtleDrawLine::new(start, end); - commands.spawn(line); - } - MoveCommand::Backward(length) => { - let start = tcmd.state_mut().position(); - let end = start + (Vec2::from_angle(tcmd.state_mut().heading().to_radians().value()) * -length.0); - - tcmd.state_mut().set_position(end); - - // Update turtle position - turtle_transform.translation.x = end.x; - turtle_transform.translation.y = end.y; - - // Draw line - let line = TurtleDrawLine::new(start, end); - commands.spawn(line); - } - MoveCommand::Circle { radius, angle } => { - let start = tcmd.state_mut().position(); - let radii = Vec2::ONE * radius.0.abs(); - let left_right = Angle::degrees(if radius.0 >= 0. { 90. } else { -90. }); - let heading = tcmd.state_mut().heading(); - let center = start + (Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - ((heading + left_right).to_radians()).value(), - ))); - let end_heading = heading + if radius.0 > 0. { *angle } else { -*angle }; - let end = center + Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle( - (heading + *angle - left_right).to_radians().value(), - )); - - tcmd.state_mut().set_position(end); - tcmd.state_mut().set_heading(end_heading); - - // Update turtle position and rotation - turtle_transform.translation.x = end.x; - turtle_transform.translation.y = end.y; - turtle_transform.rotation = Quat::from_rotation_z(end_heading.to_radians().value()); - - // Draw circle arc - let circle = TurtleDrawCircle::new(center, radii, *angle, start, end); - commands.spawn(circle); - } - MoveCommand::Goto(_coord) => { - // TODO: implement goto - } - } - } - DrawElement::Move(move_cmd) => { - match move_cmd { - MoveCommand::Forward(length) => { - let new_pos = tcmd.state_mut().position() + (Vec2::from_angle(tcmd.state_mut().heading().to_radians().value()) * length.0); - tcmd.state_mut().set_position(new_pos); - turtle_transform.translation.x = new_pos.x; - turtle_transform.translation.y = new_pos.y; - } - MoveCommand::Backward(length) => { - let new_pos = tcmd.state_mut().position() + (Vec2::from_angle(tcmd.state_mut().heading().to_radians().value()) * -length.0); - tcmd.state_mut().set_position(new_pos); - turtle_transform.translation.x = new_pos.x; - turtle_transform.translation.y = new_pos.y; - } - MoveCommand::Circle { .. } => { - // TODO: implement move circle - } - MoveCommand::Goto(_coord) => { - // TODO: implement goto - } - } - } - DrawElement::Orient(orient_cmd) => { - match orient_cmd { - OrientationCommand::Left(angle) => { - let new_heading = tcmd.state_mut().heading() - *angle; - tcmd.state_mut().set_heading(new_heading); - turtle_transform.rotation = Quat::from_rotation_z(new_heading.to_radians().value()); - } - OrientationCommand::Right(angle) => { - let new_heading = tcmd.state_mut().heading() + *angle; - tcmd.state_mut().set_heading(new_heading); - turtle_transform.rotation = Quat::from_rotation_z(new_heading.to_radians().value()); - } - OrientationCommand::SetHeading => { - // TODO: implement set_heading - } - OrientationCommand::LookAt(_coord) => { - // TODO: implement look_at - } - } - } - DrawElement::Drip(_breadcrumb) => { - // TODO: implement breadcrumbs - } - } -} diff --git a/turtle-lib/src/drawing/line_segments.rs b/turtle-lib/src/drawing/line_segments.rs deleted file mode 100644 index bfaa417..0000000 --- a/turtle-lib/src/drawing/line_segments.rs +++ /dev/null @@ -1,99 +0,0 @@ -use bevy::{ - prelude::{Bundle, Color, Component, Name, Vec2}, - reflect::Reflect, -}; -use bevy_prototype_lyon::{ - draw::{Fill, Stroke}, - entity::Shape, - geometry::ShapeBuilder, - path::ShapePath, - prelude::ShapeBuilderBase as _, - shapes::Line, -}; - -use crate::general::{angle::Angle, Precision}; - -#[derive(Bundle, Reflect, Default)] -pub struct TurtleDrawLine { - #[reflect(ignore)] - line: Shape, - name: Name, - marker: LineMarker, -} - -impl std::fmt::Debug for TurtleDrawLine { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TurtleDrawLine") - .field("name", &self.name) - .field("marker", &self.marker) - .finish() - } -} - -#[derive(Component, Default, Reflect, Debug, Clone, Copy)] -struct LineMarker; - -impl TurtleDrawLine { - pub(crate) fn new(start: Vec2, end: Vec2) -> Self { - let line = Line(start, end); - Self { - line: ShapeBuilder::with(&line) - .fill(Fill::color(Color::NONE)) - .stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0)) - .build(), - name: Name::new(format!("Line {}-{}", start, end)), - marker: LineMarker, - } - } -} - -#[derive(Bundle, Reflect, Default)] - -pub struct TurtleDrawCircle { - #[reflect(ignore)] - line: Shape, - name: Name, - marker: CircleMarker, -} - -impl std::fmt::Debug for TurtleDrawCircle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TurtleDrawCircle") - .field("name", &self.name) - .field("marker", &self.marker) - .finish() - } -} - -#[derive(Component, Default, Reflect, Debug, Clone)] -struct CircleMarker; - -impl TurtleDrawCircle { - pub(crate) fn new( - center: Vec2, - radii: Vec2, - angle: Angle, - start: Vec2, - _end: Vec2, - ) -> Self { - // The center point of the radius - this is responsible for the orientation of the ellipse, - // then the radii in x and y direction - this can be rotated using the x_rotation parameter, - // then the angle - the part of the circle that will be drawn like (PI/2.0) for a quarter circle, - // then the x_rotation (maybe the rotation of the radii?) - let path = - ShapePath::new() - .move_to(start) - .arc(center, radii, angle.to_radians().value(), 0.); - - println!("Draw Circle: {} {} {:?}", center, radii, angle); - - Self { - line: ShapeBuilder::with(&path) - .fill(Fill::color(Color::NONE)) - .stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0)) - .build(), - name: Name::new(format!("Circle at {}, {}", center.x, center.y)), - marker: CircleMarker, - } - } -} diff --git a/turtle-lib/src/drawing/run_step.rs b/turtle-lib/src/drawing/run_step.rs deleted file mode 100644 index b272b66..0000000 --- a/turtle-lib/src/drawing/run_step.rs +++ /dev/null @@ -1,58 +0,0 @@ -use bevy::prelude::{Commands, Query, Transform, With}; -use bevy_tweening::Animator; - -use crate::{commands::TurtleCommands, shapes::TurtleShape}; - -use super::{animation::TurtleAnimationSegment, TurtleGraphElement}; - -pub fn run_animation_step( - commands: &mut Commands, - tcmd: &mut TurtleCommands, - turtle: &mut Query<&mut Animator, With>, -) { - loop { - match tcmd.next() { - Some(TurtleAnimationSegment { - 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((line, line_animation)); - } - TurtleGraphElement::Noop => (), - TurtleGraphElement::TurtleCircle(circle) => { - commands.spawn((circle, line_animation)); - } - } - return; - } - // In case a rotation is performed the line drawing can be skipped - Some(TurtleAnimationSegment { - turtle_animation: Some(turtle_animation), - line_segment: Some(_), - line_animation: None, - })| - // In case a rotation is performed the line drawing can be skipped - Some(TurtleAnimationSegment { - turtle_animation: Some(turtle_animation), - line_segment: None, - line_animation: None, - }) => { - let mut turtle = turtle.single_mut(); - turtle.set_tweenable(turtle_animation); - return; - } - Some(_e) => { - println!("without animation"); - } - None => { - println!("nothing to draw"); - return; - } - }; - } -} diff --git a/turtle-lib/src/events.rs b/turtle-lib/src/events.rs deleted file mode 100644 index db2850e..0000000 --- a/turtle-lib/src/events.rs +++ /dev/null @@ -1,4 +0,0 @@ -use bevy::prelude::{Entity, Message}; - -#[derive(Message)] -pub struct DrawingStartedEvent(pub Entity); diff --git a/turtle-lib/src/general.rs b/turtle-lib/src/general.rs deleted file mode 100644 index 335289a..0000000 --- a/turtle-lib/src/general.rs +++ /dev/null @@ -1,9 +0,0 @@ -use bevy::prelude::Vec2; - -pub mod angle; -pub mod length; - -pub type Precision = f32; -pub type Coordinate = Vec2; -pub type Visibility = bool; -pub type Speed = u32; diff --git a/turtle-lib/src/general/angle.rs b/turtle-lib/src/general/angle.rs deleted file mode 100644 index 16bf930..0000000 --- a/turtle-lib/src/general/angle.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::{ - f32::consts::PI, - ops::{Add, Div, Mul, Neg, Rem, Sub}, -}; - -use bevy::reflect::Reflect; - -use super::Precision; - -#[derive(Reflect, Copy, Clone, Debug, PartialEq, Eq)] -pub enum AngleUnit { - Degrees(T), - Radians(T), -} - -impl Default for AngleUnit { - fn default() -> Self { - Self::Degrees(Default::default()) - } -} - -#[derive(Reflect, Copy, Default, Clone, Debug, PartialEq, Eq)] -pub struct Angle { - value: AngleUnit, -} - -impl + Default + Send + Sync + Reflect + Copy> From for Angle { - fn from(i: i16) -> Self { - Self { - value: AngleUnit::Degrees(T::from(i)), - } - } -} - -impl> Rem for Angle { - type Output = Self; - - fn rem(self, rhs: T) -> Self::Output { - match self.value { - AngleUnit::Degrees(v) => Self::Output::degrees(v % rhs), - AngleUnit::Radians(v) => Self::Output::radians(v % rhs), - } - } -} - -impl> Mul for Angle { - type Output = Self; - - fn mul(self, rhs: T) -> Self::Output { - match self.value { - AngleUnit::Degrees(v) => Self::Output::degrees(v * rhs), - AngleUnit::Radians(v) => Self::Output::radians(v * rhs), - } - } -} - -impl Angle { - pub fn limit_smaller_than_full_circle(self) -> Self { - match self.value { - AngleUnit::Degrees(v) => Self { - value: AngleUnit::Degrees(v % 360.), - }, - AngleUnit::Radians(v) => Self { - value: AngleUnit::Radians(v % (2. * PI)), - }, - } - } -} -impl> Div for Angle { - type Output = Self; - - fn div(self, rhs: T) -> Self::Output { - match self.value { - AngleUnit::Degrees(v) => Self::Output::degrees(v / rhs), - AngleUnit::Radians(v) => Self::Output::radians(v / rhs), - } - } -} - -impl> Neg - for Angle -{ - type Output = Self; - - fn neg(self) -> Self::Output { - match self.value { - AngleUnit::Degrees(v) => Self::Output::degrees(-v), - AngleUnit::Radians(v) => Self::Output::radians(-v), - } - } -} - -impl> Neg - for &Angle -{ - type Output = Angle; - - fn neg(self) -> Self::Output { - match self.value.clone() { - AngleUnit::Degrees(v) => Self::Output::degrees(-v), - AngleUnit::Radians(v) => Self::Output::radians(-v), - } - } -} - -impl Angle { - pub fn degrees(value: T) -> Angle { - Self { - value: AngleUnit::Degrees(value), - } - } - pub fn radians(value: T) -> Angle { - Self { - value: AngleUnit::Radians(value), - } - } - pub fn value(&self) -> T { - match self.value.clone() { - AngleUnit::Degrees(v) => v, - AngleUnit::Radians(v) => v, - } - } -} - -impl Angle { - pub fn to_radians(self) -> Self { - match self.value { - AngleUnit::Degrees(v) => Self { - value: AngleUnit::Radians(v.to_radians()), - }, - AngleUnit::Radians(_) => self, - } - } - pub fn to_degrees(self) -> Self { - match self.value { - AngleUnit::Degrees(_) => self, - AngleUnit::Radians(v) => Self { - value: AngleUnit::Degrees(v.to_degrees()), - }, - } - } -} - -impl + Send + Sync + Reflect + Copy + Default + num_traits::float::Float> Add - for Angle -{ - type Output = Angle; - - fn add(self, rhs: Self) -> Self::Output { - match (self.value, rhs.value) { - (AngleUnit::Degrees(v), AngleUnit::Degrees(o)) => Self::Output { - value: AngleUnit::Degrees(v + o), - }, - (AngleUnit::Degrees(v), AngleUnit::Radians(o)) => Self::Output { - value: AngleUnit::Radians(v.to_radians() + o), - }, - (AngleUnit::Radians(v), AngleUnit::Degrees(o)) => Self::Output { - value: AngleUnit::Radians(v + o.to_radians()), - }, - (AngleUnit::Radians(v), AngleUnit::Radians(o)) => Self::Output { - value: AngleUnit::Radians(v + o), - }, - } - } -} - -impl + Default + Send + Sync + Reflect + Copy + num_traits::float::Float> Sub - for Angle -{ - type Output = Angle; - - fn sub(self, rhs: Self) -> Self::Output { - match (self.value, rhs.value) { - (AngleUnit::Degrees(v), AngleUnit::Degrees(o)) => Self::Output { - value: AngleUnit::Degrees(v - o), - }, - (AngleUnit::Degrees(v), AngleUnit::Radians(o)) => Self::Output { - value: AngleUnit::Radians(v.to_radians() - o), - }, - (AngleUnit::Radians(v), AngleUnit::Degrees(o)) => Self::Output { - value: AngleUnit::Radians(v - o.to_radians()), - }, - (AngleUnit::Radians(v), AngleUnit::Radians(o)) => Self::Output { - value: AngleUnit::Radians(v - o), - }, - } - } -} - -#[test] -fn convert_to_radians() { - let radi = Angle::radians(30f32.to_radians()); - let degr = Angle::degrees(30f32); - let converted = degr.to_radians(); - assert_eq!(radi, converted) -} -#[test] -fn sum_degrees() { - let fst = Angle::degrees(30f32); - let snd = Angle::degrees(30f32); - let sum = fst + snd; - assert!((sum.value() - 60f32).abs() < 0.0001); - assert!((sum.to_radians().value() - 60f32.to_radians()).abs() < 0.0001); -} -#[test] -fn sum_mixed() { - let fst = Angle::degrees(30f32); - let snd = Angle::radians(30f32.to_radians()); - let sum = fst + snd; - assert!((sum.to_degrees().value() - 60f32).abs() < 0.0001); - assert!((sum.to_radians().value() - 60f32.to_radians()).abs() < 0.0001); -} diff --git a/turtle-lib/src/general/length.rs b/turtle-lib/src/general/length.rs deleted file mode 100644 index 5fc8f1a..0000000 --- a/turtle-lib/src/general/length.rs +++ /dev/null @@ -1,19 +0,0 @@ -use bevy::reflect::Reflect; - -use super::Precision; - -#[derive(Reflect, Default, Copy, Clone, Debug)] -pub struct Length(pub Precision); - -impl From for Length { - fn from(i: i16) -> Self { - Self(Precision::from(i)) - } -} - -impl From for Length { - fn from(i: f32) -> Self { - #[allow(clippy::useless_conversion)] - Self(Precision::from(i)) - } -} diff --git a/turtle-lib/src/lib.rs b/turtle-lib/src/lib.rs deleted file mode 100644 index 8b26f36..0000000 --- a/turtle-lib/src/lib.rs +++ /dev/null @@ -1,145 +0,0 @@ -use bevy::{prelude::*, window::WindowResolution}; -#[cfg(feature = "tweening")] -use bevy_prototype_lyon::entity::Shape; -use bevy_prototype_lyon::prelude::ShapePlugin; -#[cfg(feature = "tweening")] -use bevy_tweening::{ - component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween, - TweenCompleted, -}; -use events::DrawingStartedEvent; -use shapes::{TurtleColors, TurtleShape}; -use turtle_bundle::{AnimatedTurtle, TurtleBundle}; - -pub use commands::TurtleCommands; - -pub mod builders; -mod commands; -mod debug; -mod drawing; -pub mod events; -mod general; -pub mod shapes; -mod state; -pub mod turtle_bundle; - -/** -The turtle plugin is the core of this turtle module. - -In order to facilitate the setup this plugin also inserts the `DefaultPlugins` and many other things. - -Before using any of the functions add this plugin using: -```rust - -app::new().add_plugin(turtle_lib::TurtlePlugin) -``` -*/ -pub struct TurtlePlugin; - -impl Plugin for TurtlePlugin { - fn build(&self, app: &mut App) { - app.add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "Immigration Game".to_string(), - resolution: WindowResolution::new(1200, 800), - ..default() - }), - ..default() - })) - .add_plugins(debug::DebugPlugin) - .add_plugins(ShapePlugin) - .add_message::() - .add_systems(Startup, setup) - .add_systems( - Update, - ( - keypresses, - #[cfg(feature = "tweening")] - component_animator_system::, - #[cfg(feature = "tweening")] - component_animator_system::, - #[cfg(feature = "tweening")] - draw_lines, - #[cfg(not(feature = "tweening"))] - draw_immediate, - ), - ) - .register_type::() - .register_type::(); - } -} - -fn setup(mut commands: Commands) { - commands.spawn((Camera2d,)); -} - -pub fn get_a_turtle() -> AnimatedTurtle { - #[cfg(feature = "tweening")] - let animator = Animator::new(Tween::new( - EaseFunction::QuadraticInOut, - Duration::from_millis(3000), - TransformScaleLens { - start: Vec3::ZERO, - end: Vec3::ONE * 1.3, - }, - )); - #[cfg(not(feature = "tweening"))] - let animator = (); - let turtle_bundle = TurtleBundle::default(); - AnimatedTurtle { - animator, - turtle_bundle, - turtle_shape: TurtleShape, - } -} - -fn keypresses( - mut commands: Commands, - _keys: Res>, - mut tcmd: Query<(Entity, &mut TurtleCommands)>, - #[cfg(feature = "tweening")] mut turtle: Query<&mut Animator, With>, - #[cfg(not(feature = "tweening"))] mut turtle: Query<&mut Transform, With>, - mut _ev_start: MessageWriter, -) { - if _keys.just_pressed(KeyCode::KeyW) { - for (entity, mut tcmd) in tcmd.iter_mut() { - #[cfg(feature = "tweening")] - crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle); - - #[cfg(not(feature = "tweening"))] - crate::drawing::immediate::run_all_commands_immediately(&mut commands, &mut tcmd, &mut turtle); - - _ev_start.write(DrawingStartedEvent(entity)); - } - } -} - -#[cfg(feature = "tweening")] -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.read() { - if let Ok(mut tcmd) = tcmd.get_single_mut() { - crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle) - } else { - println!("Failed to get the turtle") - } - } -} - -#[cfg(not(feature = "tweening"))] -fn draw_immediate( - mut commands: Commands, - mut tcmd: Query<&mut TurtleCommands>, - mut turtle: Query<&mut Transform, With>, -) { - for mut tcmd in tcmd.iter_mut() { - // Only draw if there are commands to execute - if tcmd.animation_state() < tcmd.commands().len() { - crate::drawing::immediate::run_all_commands_immediately(&mut commands, &mut tcmd, &mut turtle); - } - } -} diff --git a/turtle-lib/src/shapes.rs b/turtle-lib/src/shapes.rs deleted file mode 100644 index d08f3f2..0000000 --- a/turtle-lib/src/shapes.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod turtle; -use bevy::{ - prelude::{Color, Component}, - reflect::Reflect, -}; -pub use turtle::turtle; - -#[derive(Clone, Component, Reflect)] -pub struct TurtleShape; - -#[derive(Clone, Component, Reflect, Default, Debug)] -pub struct TurtleColors { - color: Color, - fill_color: Color, -} diff --git a/turtle-lib/src/shapes/turtle.rs b/turtle-lib/src/shapes/turtle.rs deleted file mode 100644 index d82614c..0000000 --- a/turtle-lib/src/shapes/turtle.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::f32::consts::PI; - -use bevy::prelude::Vec2; -use bevy_prototype_lyon::prelude::ShapePath; - -use crate::general::Precision; - -pub fn turtle() -> ShapePath { - let polygon: &[[Precision; 2]; 23] = &[ - [-2.5, 14.0], - [-1.25, 10.0], - [-4.0, 7.0], - [-7.0, 9.0], - [-9.0, 8.0], - [-6.0, 5.0], - [-7.0, 1.0], - [-5.0, -3.0], - [-8.0, -6.0], - [-6.0, -8.0], - [-4.0, -5.0], - [0.0, -7.0], - [4.0, -5.0], - [6.0, -8.0], - [8.0, -6.0], - [5.0, -3.0], - [7.0, 1.0], - [6.0, 5.0], - [9.0, 8.0], - [7.0, 9.0], - [4.0, 7.0], - [1.25, 10.0], - [2.5, 14.0], - ]; - let mut turtle_path = ShapePath::new() - .line_to(Vec2::new(1.0, 1.0)) - .line_to(Vec2::new(-1.0, 1.0)) - .line_to(Vec2::new(-1.0, -1.0)) - .line_to(Vec2::new(1.0, -1.0)) - .close() - .move_to(Vec2::new(0.0, 16.0).rotate(Vec2::from_angle(-PI / 2.))); - - for coord in polygon { - turtle_path = turtle_path.line_to(Vec2::from_array(*coord).rotate(Vec2::from_angle(-PI / 2.))); - } - turtle_path.close() -} diff --git a/turtle-lib/src/state.rs b/turtle-lib/src/state.rs deleted file mode 100644 index 8707e80..0000000 --- a/turtle-lib/src/state.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::{cmp::max, time::Duration}; - -use bevy::{ - prelude::{Component, Transform}, - reflect::Reflect, -}; - -use crate::{ - commands::TurtleSegment, - general::{angle::Angle, Coordinate, Precision, Speed, Visibility}, - shapes::TurtleColors, -}; - -/// Describing the full state of a turtle. -#[derive(Component, Reflect, Default, Debug, Clone)] -pub struct TurtleState { - drawing: Vec, - position: Coordinate, - heading: Angle, - colors: TurtleColors, - visible: Visibility, - shape_transform: Transform, - speed: Speed, - segment_index: u64, -} - -impl TurtleState { - pub fn add_segment(&mut self, seg: TurtleSegment) { - self.drawing.push(seg); - } -} - -impl TurtleState { - pub fn segment_index(&self) -> u64 { - self.segment_index - } - pub fn heading(&self) -> Angle { - self.heading - } - pub fn position(&self) -> Coordinate { - self.position - } - pub fn speed(&self) -> Speed { - self.speed - } - /// The duration of animations calculated from the speed. - pub fn animation_duration(&self) -> Duration { - Duration::from_millis(self.speed() as u64) - } - pub fn shape_transform(&self) -> Transform { - self.shape_transform - } -} -impl TurtleState { - pub fn set_heading(&mut self, angle: Angle) -> &mut Self { - self.heading = angle; - self - } - pub fn set_position(&mut self, position: Coordinate) -> &mut Self { - self.position = position; - self - } - pub fn set_speed(&mut self, speed: Speed) -> &mut Self { - self.speed = max(speed, 1); - self - } - pub fn set_shape_transform(&mut self, transform: Transform) -> &mut Self { - self.shape_transform = transform; - self - } -} diff --git a/turtle-lib/src/turtle_bundle.rs b/turtle-lib/src/turtle_bundle.rs deleted file mode 100644 index 2f9d7ee..0000000 --- a/turtle-lib/src/turtle_bundle.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use bevy::prelude::{Bundle, Color, Name}; -use bevy_prototype_lyon::{ - draw::{Fill, Stroke}, - entity::Shape, - geometry::ShapeBuilder, - prelude::ShapeBuilderBase as _, -}; - -use crate::{ - builders::{ - CurvedMovement, DirectionalMovement, InvisibleLinesPlan, StopLine, Turnable, TurtlePlan, - WithCommands, - }, - commands::{TurtleCommands, TurtleSegment}, - general::Speed, - shapes::{self, TurtleColors}, -}; - -#[derive(Bundle)] -pub struct TurtleBundle { - colors: TurtleColors, - pub commands: TurtleCommands, - name: Name, - shape: Shape, -} - -impl Default for TurtleBundle { - fn default() -> Self { - Self { - colors: TurtleColors::default(), - commands: TurtleCommands::new(vec![]), - name: Name::new("Turtle"), - shape: ShapeBuilder::with(&shapes::turtle()) - .fill(Fill::color(Color::srgb(0.098, 0.098, 0.439))) - .stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0)) - .build(), - } - } -} - -impl TurtleBundle { - pub fn apply_plan(&mut self, plan: TurtlePlan) { - self.commands = TurtleCommands::new(plan.get_commands()); - } - pub fn extend_plan(&mut self, plan: TurtlePlan) { - self.commands.extend(plan.get_commands()) - } - pub fn create_plan(&self) -> TurtlePlan { - TurtlePlan::new() - } -} - -impl TurtleBundle { - pub fn set_speed(&mut self, speed: Speed) { - self.commands.set_speed(speed); - } -} - -#[derive(Bundle)] -pub struct AnimatedTurtle { - #[cfg(feature = "tweening")] - pub animator: bevy_tweening::Animator, - #[cfg(not(feature = "tweening"))] - pub animator: (), - pub turtle_bundle: TurtleBundle, - pub turtle_shape: shapes::TurtleShape, -} - -impl Deref for AnimatedTurtle { - type Target = TurtleBundle; - - fn deref(&self) -> &Self::Target { - &self.turtle_bundle - } -} - -impl DerefMut for AnimatedTurtle { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.turtle_bundle - } -} - -impl WithCommands for TurtleBundle { - fn get_mut_commands(&mut self) -> &mut Vec { - self.commands.get_mut_commands() - } - - fn get_commands(self) -> Vec { - self.commands.get_commands() - } -} -impl StopLine for TurtleBundle { - fn pen_up(self) -> crate::builders::InvisibleLinesPlan { - { - InvisibleLinesPlan::new(self) - } - } -} - -impl DirectionalMovement for TurtleBundle {} -impl Turnable for TurtleBundle {} -impl CurvedMovement for TurtleBundle {}