first port to modern bevy
This commit is contained in:
parent
da7b9493ec
commit
8a56176ceb
4084
Cargo.lock
generated
4084
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
32
Cargo.toml
Normal file
32
Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
|
members = ["turtle-lib", "turtle-example"]
|
||||||
|
|
||||||
|
[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
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
|
||||||
|
[profile.dev.package."*"]
|
||||||
|
opt-level = 3
|
||||||
@ -7,9 +7,15 @@ license = "MIT OR Apache-2.0"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[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 }
|
||||||
|
|
||||||
bevy = { version = "0.9" }
|
[features]
|
||||||
bevy_prototype_lyon = {version="0.7"}
|
default = []
|
||||||
bevy-inspector-egui = "0.16"
|
# Enable debug inspector UI (bevy-inspector-egui)
|
||||||
num-traits = "0.2"
|
inspector = ["dep:bevy-inspector-egui"]
|
||||||
bevy_tweening = {version="0.6"}
|
# Enable animations (bevy_tweening)
|
||||||
|
tweening = ["dep:bevy_tweening"]
|
||||||
|
|||||||
240
turtle-lib/NotesWhileUpgradingBevy.md
Normal file
240
turtle-lib/NotesWhileUpgradingBevy.md
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
# 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::<Path>)` → `.add_systems(Update, component_animator_system::<Path>)`
|
||||||
|
- `.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::<DrawingStartedEvent>()` 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<Input<KeyCode>>` 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::<T>()`. 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::<DrawingStartedEvent>()` 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<KeyCode>`, `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<T>`), derive `Reflect` for `T` and call `app.register_type::<T>()`.
|
||||||
|
|
||||||
|
- 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<T>::lerp(&mut self, target: &mut T, ratio: f32)` → `Lens<T>::lerp(&mut self, target: &mut dyn Targetable<T>, ratio: f32)`.
|
||||||
|
- Code using `target` can remain unchanged because `dyn Targetable<T>` 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::<Path>` in `Update` to animate `Animator<Path>` (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<TweenCompleted>::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<Path>` → `Animator<Shape>`
|
||||||
|
- `component_animator_system::<Path>` → `component_animator_system::<Shape>`
|
||||||
|
- Lenses (`drawing/animation/line_lens.rs`, `circle_lens.rs`):
|
||||||
|
- `impl Lens<Path> for ...` → `impl Lens<Shape> 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.
|
||||||
@ -1,25 +1,22 @@
|
|||||||
use bevy::{
|
use bevy::{prelude::Component, reflect::Reflect};
|
||||||
prelude::Component,
|
|
||||||
reflect::{FromReflect, Reflect},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builders::WithCommands,
|
builders::WithCommands,
|
||||||
drawing::{
|
drawing::TurtleGraphElement,
|
||||||
animation::{
|
|
||||||
draw_circle_segment, draw_straight_segment, move_straight_segment, turtle_turn,
|
|
||||||
ToAnimationSegment, TurtleAnimationSegment,
|
|
||||||
},
|
|
||||||
TurtleGraphElement,
|
|
||||||
},
|
|
||||||
general::{angle::Angle, length::Length, Coordinate, Precision, Speed},
|
general::{angle::Angle, length::Length, Coordinate, Precision, Speed},
|
||||||
state::TurtleState,
|
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,
|
* All the possibilities to draw something with turtle. All the commands can get the position, heading,
|
||||||
* color and fill_color from the turtles state.
|
* color and fill_color from the turtles state.
|
||||||
*/
|
*/
|
||||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
#[derive(Component, Reflect, Debug, Clone)]
|
||||||
pub enum MoveCommand {
|
pub enum MoveCommand {
|
||||||
Forward(Length),
|
Forward(Length),
|
||||||
Backward(Length),
|
Backward(Length),
|
||||||
@ -37,7 +34,7 @@ impl Default for MoveCommand {
|
|||||||
}
|
}
|
||||||
/// Different ways to drop breadcrumbs on the way like a dot or a stamp of the turtles shape.
|
/// Different ways to drop breadcrumbs on the way like a dot or a stamp of the turtles shape.
|
||||||
|
|
||||||
#[derive(Component, Reflect, FromReflect, Default, Debug, Clone)]
|
#[derive(Component, Reflect, Default, Debug, Clone)]
|
||||||
pub enum Breadcrumb {
|
pub enum Breadcrumb {
|
||||||
Dot,
|
Dot,
|
||||||
#[default]
|
#[default]
|
||||||
@ -45,7 +42,7 @@ pub enum Breadcrumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Different ways that change the orientation of the turtle.
|
/// Different ways that change the orientation of the turtle.
|
||||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
#[derive(Component, Reflect, Debug, Clone)]
|
||||||
pub enum OrientationCommand {
|
pub enum OrientationCommand {
|
||||||
Left(Angle<Precision>),
|
Left(Angle<Precision>),
|
||||||
Right(Angle<Precision>),
|
Right(Angle<Precision>),
|
||||||
@ -60,7 +57,7 @@ impl Default for OrientationCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A combination of all commands that can be used while drawing.
|
/// A combination of all commands that can be used while drawing.
|
||||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
#[derive(Component, Reflect, Debug, Clone)]
|
||||||
pub enum DrawElement {
|
pub enum DrawElement {
|
||||||
Draw(MoveCommand),
|
Draw(MoveCommand),
|
||||||
Move(MoveCommand),
|
Move(MoveCommand),
|
||||||
@ -73,6 +70,8 @@ impl Default for DrawElement {
|
|||||||
Self::Draw(Default::default())
|
Self::Draw(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
impl ToAnimationSegment for DrawElement {
|
impl ToAnimationSegment for DrawElement {
|
||||||
fn to_draw_segment(
|
fn to_draw_segment(
|
||||||
&self,
|
&self,
|
||||||
@ -104,7 +103,7 @@ impl ToAnimationSegment for DrawElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
#[derive(Component, Reflect, Debug, Clone)]
|
||||||
pub enum TurtleSegment {
|
pub enum TurtleSegment {
|
||||||
Single(DrawElement),
|
Single(DrawElement),
|
||||||
Outline(Vec<DrawElement>),
|
Outline(Vec<DrawElement>),
|
||||||
@ -116,6 +115,8 @@ impl Default for TurtleSegment {
|
|||||||
Self::Single(Default::default())
|
Self::Single(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
impl ToAnimationSegment for TurtleSegment {
|
impl ToAnimationSegment for TurtleSegment {
|
||||||
fn to_draw_segment(
|
fn to_draw_segment(
|
||||||
&self,
|
&self,
|
||||||
@ -156,8 +157,23 @@ impl TurtleCommands {
|
|||||||
pub fn set_speed(&mut self, speed: Speed) {
|
pub fn set_speed(&mut self, speed: Speed) {
|
||||||
self.state.set_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 {
|
impl Iterator for TurtleCommands {
|
||||||
type Item = TurtleAnimationSegment;
|
type Item = TurtleAnimationSegment;
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
use bevy::prelude::Plugin;
|
use bevy::prelude::Plugin;
|
||||||
|
#[cfg(feature = "inspector")]
|
||||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
|
||||||
pub struct DebugPlugin;
|
pub struct DebugPlugin;
|
||||||
|
|
||||||
impl Plugin for DebugPlugin {
|
impl Plugin for DebugPlugin {
|
||||||
fn build(&self, app: &mut bevy::prelude::App) {
|
fn build(&self, _app: &mut bevy::prelude::App) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
app.add_plugin(WorldInspectorPlugin);
|
#[cfg(feature = "inspector")]
|
||||||
|
app.add_plugins(WorldInspectorPlugin::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
use bevy::reflect::{FromReflect, Reflect};
|
use bevy::reflect::Reflect;
|
||||||
|
|
||||||
pub use self::line_segments::{TurtleDrawCircle, TurtleDrawLine};
|
pub use self::line_segments::{TurtleDrawCircle, TurtleDrawLine};
|
||||||
|
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
pub mod animation;
|
pub mod animation;
|
||||||
|
#[cfg(not(feature = "tweening"))]
|
||||||
|
pub(crate) mod immediate;
|
||||||
mod line_segments;
|
mod line_segments;
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
pub(crate) mod run_step;
|
pub(crate) mod run_step;
|
||||||
|
|
||||||
#[derive(Reflect, FromReflect, Default, Debug)]
|
#[derive(Reflect, Default, Debug)]
|
||||||
pub enum TurtleGraphElement {
|
pub enum TurtleGraphElement {
|
||||||
TurtleLine(TurtleDrawLine),
|
TurtleLine(TurtleDrawLine),
|
||||||
TurtleCircle(TurtleDrawCircle),
|
TurtleCircle(TurtleDrawCircle),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ mod circle_lens;
|
|||||||
mod line_lens;
|
mod line_lens;
|
||||||
|
|
||||||
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
|
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
|
||||||
use bevy_prototype_lyon::prelude::Path;
|
use bevy_prototype_lyon::prelude::Shape;
|
||||||
use bevy_tweening::{
|
use bevy_tweening::{
|
||||||
lens::{TransformPositionLens, TransformRotateZLens},
|
lens::{TransformPositionLens, TransformRotateZLens},
|
||||||
Animator, EaseFunction, Tween,
|
Animator, EaseFunction, Tween,
|
||||||
@ -23,7 +23,7 @@ use super::{TurtleDrawCircle, TurtleDrawLine, TurtleGraphElement};
|
|||||||
pub struct TurtleAnimationSegment {
|
pub struct TurtleAnimationSegment {
|
||||||
pub turtle_animation: Option<Tween<Transform>>,
|
pub turtle_animation: Option<Tween<Transform>>,
|
||||||
pub line_segment: Option<TurtleGraphElement>,
|
pub line_segment: Option<TurtleGraphElement>,
|
||||||
pub line_animation: Option<Animator<Path>>,
|
pub line_animation: Option<Animator<Shape>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToAnimationSegment {
|
pub trait ToAnimationSegment {
|
||||||
@ -102,7 +102,7 @@ struct MoveStraightLineAnimation {
|
|||||||
_start: Coordinate,
|
_start: Coordinate,
|
||||||
_end: Coordinate,
|
_end: Coordinate,
|
||||||
line: TurtleDrawLine,
|
line: TurtleDrawLine,
|
||||||
animation: Tween<Path>,
|
animation: Tween<Shape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveStraightLineAnimation {
|
impl MoveStraightLineAnimation {
|
||||||
@ -159,7 +159,7 @@ struct MoveCircleLineAnimation {
|
|||||||
_start: Coordinate,
|
_start: Coordinate,
|
||||||
_end: Coordinate,
|
_end: Coordinate,
|
||||||
line: TurtleDrawCircle,
|
line: TurtleDrawCircle,
|
||||||
animation: Tween<Path>,
|
animation: Tween<Shape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveCircleLineAnimation {
|
impl MoveCircleLineAnimation {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use bevy::prelude::{Quat, Transform, Vec2};
|
use bevy::prelude::{Quat, Transform, Vec2};
|
||||||
use bevy_prototype_lyon::prelude::{Path, PathBuilder, ShapePath};
|
use bevy_prototype_lyon::{path::ShapePath, prelude::*, self as lyon_crate};
|
||||||
|
use lyon_crate::entity::Shape;
|
||||||
use bevy_tweening::Lens;
|
use bevy_tweening::Lens;
|
||||||
|
|
||||||
use crate::general::{angle::Angle, Precision};
|
use crate::general::{angle::Angle, Precision};
|
||||||
@ -12,12 +13,12 @@ pub(crate) struct CircleAnimationLens {
|
|||||||
pub end: Angle<Precision>,
|
pub end: Angle<Precision>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lens<Path> for CircleAnimationLens {
|
impl Lens<Shape> for CircleAnimationLens {
|
||||||
fn lerp(&mut self, target: &mut Path, ratio: f32) {
|
fn lerp(&mut self, target: &mut Shape, ratio: f32) {
|
||||||
let mut path_builder = PathBuilder::new();
|
let mut path = ShapePath::new();
|
||||||
path_builder.move_to(self.start_pos);
|
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 ?
|
// 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(
|
path = path.arc(
|
||||||
self.center,
|
self.center,
|
||||||
self.radii,
|
self.radii,
|
||||||
(self.start + ((self.end - self.start) * ratio))
|
(self.start + ((self.end - self.start) * ratio))
|
||||||
@ -25,8 +26,7 @@ impl Lens<Path> for CircleAnimationLens {
|
|||||||
.value(),
|
.value(),
|
||||||
0.,
|
0.,
|
||||||
);
|
);
|
||||||
let line = path_builder.build();
|
*target = Shape::from(path);
|
||||||
*target = ShapePath::build_as(&line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use bevy::prelude::Vec2;
|
use bevy::prelude::Vec2;
|
||||||
use bevy_prototype_lyon::{
|
use bevy_prototype_lyon::{prelude::{Shape, ShapePath}, shapes};
|
||||||
prelude::{Path, ShapePath},
|
|
||||||
shapes,
|
|
||||||
};
|
|
||||||
use bevy_tweening::Lens;
|
use bevy_tweening::Lens;
|
||||||
|
|
||||||
pub(crate) struct LineAnimationLens {
|
pub(crate) struct LineAnimationLens {
|
||||||
@ -16,9 +13,9 @@ impl LineAnimationLens {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lens<Path> for LineAnimationLens {
|
impl Lens<Shape> for LineAnimationLens {
|
||||||
fn lerp(&mut self, target: &mut Path, ratio: f32) {
|
fn lerp(&mut self, target: &mut Shape, ratio: f32) {
|
||||||
let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio));
|
let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio));
|
||||||
*target = ShapePath::build_as(&line);
|
*target = Shape::from(ShapePath::build_as(&line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
159
turtle-lib/src/drawing/immediate.rs
Normal file
159
turtle-lib/src/drawing/immediate.rs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
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<TurtleShape>>,
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +1,22 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::{Bundle, Color, Component, Name, Transform, Vec2},
|
prelude::{Bundle, Color, Component, Name, Vec2},
|
||||||
reflect::{FromReflect, Reflect},
|
reflect::Reflect,
|
||||||
};
|
};
|
||||||
use bevy_prototype_lyon::{
|
use bevy_prototype_lyon::{
|
||||||
entity::ShapeBundle,
|
draw::{Fill, Stroke},
|
||||||
prelude::{DrawMode, FillMode, GeometryBuilder, PathBuilder, StrokeMode},
|
entity::Shape,
|
||||||
|
geometry::ShapeBuilder,
|
||||||
|
path::ShapePath,
|
||||||
|
prelude::ShapeBuilderBase as _,
|
||||||
shapes::Line,
|
shapes::Line,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::general::{angle::Angle, Precision};
|
use crate::general::{angle::Angle, Precision};
|
||||||
|
|
||||||
#[derive(Bundle, Reflect, FromReflect, Default)]
|
#[derive(Bundle, Reflect, Default)]
|
||||||
pub struct TurtleDrawLine {
|
pub struct TurtleDrawLine {
|
||||||
#[reflect(ignore)]
|
#[reflect(ignore)]
|
||||||
line: ShapeBundle,
|
line: Shape,
|
||||||
name: Name,
|
name: Name,
|
||||||
marker: LineMarker,
|
marker: LineMarker,
|
||||||
}
|
}
|
||||||
@ -27,31 +30,28 @@ impl std::fmt::Debug for TurtleDrawLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default, Reflect, FromReflect, Debug, Clone, Copy)]
|
#[derive(Component, Default, Reflect, Debug, Clone, Copy)]
|
||||||
struct LineMarker;
|
struct LineMarker;
|
||||||
|
|
||||||
impl TurtleDrawLine {
|
impl TurtleDrawLine {
|
||||||
pub(crate) fn new(start: Vec2, end: Vec2) -> Self {
|
pub(crate) fn new(start: Vec2, end: Vec2) -> Self {
|
||||||
|
let line = Line(start, end);
|
||||||
Self {
|
Self {
|
||||||
line: GeometryBuilder::build_as(
|
line: ShapeBuilder::with(&line)
|
||||||
&Line(start, start),
|
.fill(Fill::color(Color::NONE))
|
||||||
DrawMode::Outlined {
|
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||||
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
|
.build(),
|
||||||
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
|
|
||||||
},
|
|
||||||
Transform::IDENTITY,
|
|
||||||
),
|
|
||||||
name: Name::new(format!("Line {}-{}", start, end)),
|
name: Name::new(format!("Line {}-{}", start, end)),
|
||||||
marker: LineMarker,
|
marker: LineMarker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Bundle, Reflect, FromReflect, Default)]
|
#[derive(Bundle, Reflect, Default)]
|
||||||
|
|
||||||
pub struct TurtleDrawCircle {
|
pub struct TurtleDrawCircle {
|
||||||
#[reflect(ignore)]
|
#[reflect(ignore)]
|
||||||
line: ShapeBundle,
|
line: Shape,
|
||||||
name: Name,
|
name: Name,
|
||||||
marker: CircleMarker,
|
marker: CircleMarker,
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ impl std::fmt::Debug for TurtleDrawCircle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default, Reflect, FromReflect, Debug, Clone)]
|
#[derive(Component, Default, Reflect, Debug, Clone)]
|
||||||
struct CircleMarker;
|
struct CircleMarker;
|
||||||
|
|
||||||
impl TurtleDrawCircle {
|
impl TurtleDrawCircle {
|
||||||
@ -76,25 +76,22 @@ impl TurtleDrawCircle {
|
|||||||
start: Vec2,
|
start: Vec2,
|
||||||
_end: Vec2,
|
_end: Vec2,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut path_builder = PathBuilder::new();
|
|
||||||
path_builder.move_to(start);
|
|
||||||
// The center point of the radius - this is responsible for the orientation of the ellipse,
|
// 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 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 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?)
|
// then the x_rotation (maybe the rotation of the radii?)
|
||||||
path_builder.arc(center, radii, angle.to_radians().value(), 0.);
|
let path =
|
||||||
let line = path_builder.build();
|
ShapePath::new()
|
||||||
|
.move_to(start)
|
||||||
|
.arc(center, radii, angle.to_radians().value(), 0.);
|
||||||
|
|
||||||
println!("Draw Circle: {} {} {:?}", center, radii, angle);
|
println!("Draw Circle: {} {} {:?}", center, radii, angle);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
line: GeometryBuilder::build_as(
|
line: ShapeBuilder::with(&path)
|
||||||
&line,
|
.fill(Fill::color(Color::NONE))
|
||||||
DrawMode::Outlined {
|
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||||
fill_mode: FillMode::color(Color::rgba(0., 0., 0., 0.)),
|
.build(),
|
||||||
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
|
|
||||||
},
|
|
||||||
Transform::IDENTITY,
|
|
||||||
),
|
|
||||||
name: Name::new(format!("Circle at {}, {}", center.x, center.y)),
|
name: Name::new(format!("Circle at {}, {}", center.x, center.y)),
|
||||||
marker: CircleMarker,
|
marker: CircleMarker,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
use bevy::prelude::Entity;
|
use bevy::prelude::{Entity, Message};
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
pub struct DrawingStartedEvent(pub Entity);
|
pub struct DrawingStartedEvent(pub Entity);
|
||||||
|
|||||||
@ -3,28 +3,28 @@ use std::{
|
|||||||
ops::{Add, Div, Mul, Neg, Rem, Sub},
|
ops::{Add, Div, Mul, Neg, Rem, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::reflect::{FromReflect, Reflect};
|
use bevy::reflect::Reflect;
|
||||||
|
|
||||||
use super::Precision;
|
use super::Precision;
|
||||||
|
|
||||||
#[derive(Reflect, FromReflect, Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Reflect, Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum AngleUnit<T: Default + Send + Sync + Reflect + Copy + FromReflect> {
|
pub enum AngleUnit<T: Default + Send + Sync + Reflect + Copy> {
|
||||||
Degrees(T),
|
Degrees(T),
|
||||||
Radians(T),
|
Radians(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Send + Sync + Reflect + Copy + FromReflect> Default for AngleUnit<T> {
|
impl<T: Default + Send + Sync + Reflect + Copy> Default for AngleUnit<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Degrees(Default::default())
|
Self::Degrees(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Reflect, FromReflect, Copy, Default, Clone, Debug, PartialEq, Eq)]
|
#[derive(Reflect, Copy, Default, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Angle<T: Default + Send + Sync + Reflect + Copy + FromReflect> {
|
pub struct Angle<T: Default + Send + Sync + Reflect + Copy> {
|
||||||
value: AngleUnit<T>,
|
value: AngleUnit<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: From<i16> + Default + Send + Sync + Reflect + Copy + FromReflect> From<i16> for Angle<T> {
|
impl<T: From<i16> + Default + Send + Sync + Reflect + Copy> From<i16> for Angle<T> {
|
||||||
fn from(i: i16) -> Self {
|
fn from(i: i16) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: AngleUnit::Degrees(T::from(i)),
|
value: AngleUnit::Degrees(T::from(i)),
|
||||||
@ -32,9 +32,7 @@ impl<T: From<i16> + Default + Send + Sync + Reflect + Copy + FromReflect> From<i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Send + Sync + Reflect + Clone + Copy + FromReflect + Rem<T, Output = T>> Rem<T>
|
impl<T: Default + Send + Sync + Reflect + Clone + Copy + Rem<T, Output = T>> Rem<T> for Angle<T> {
|
||||||
for Angle<T>
|
|
||||||
{
|
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn rem(self, rhs: T) -> Self::Output {
|
fn rem(self, rhs: T) -> Self::Output {
|
||||||
@ -45,9 +43,7 @@ impl<T: Default + Send + Sync + Reflect + Clone + Copy + FromReflect + Rem<T, Ou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + Mul<T, Output = T>> Mul<T>
|
impl<T: Default + Clone + Send + Sync + Reflect + Copy + Mul<T, Output = T>> Mul<T> for Angle<T> {
|
||||||
for Angle<T>
|
|
||||||
{
|
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn mul(self, rhs: T) -> Self::Output {
|
fn mul(self, rhs: T) -> Self::Output {
|
||||||
@ -70,9 +66,7 @@ impl Angle<Precision> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + Div<T, Output = T>> Div<T>
|
impl<T: Default + Clone + Send + Sync + Reflect + Copy + Div<T, Output = T>> Div<T> for Angle<T> {
|
||||||
for Angle<T>
|
|
||||||
{
|
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn div(self, rhs: T) -> Self::Output {
|
fn div(self, rhs: T) -> Self::Output {
|
||||||
@ -83,9 +77,8 @@ impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + Div<T, Ou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<T: Default + Clone + Send + Sync + Reflect + Copy + std::ops::Neg<Output = T>> Neg
|
||||||
T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + std::ops::Neg<Output = T>,
|
for Angle<T>
|
||||||
> Neg for Angle<T>
|
|
||||||
{
|
{
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -97,9 +90,8 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<T: Default + Clone + Send + Sync + Reflect + Copy + std::ops::Neg<Output = T>> Neg
|
||||||
T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + std::ops::Neg<Output = T>,
|
for &Angle<T>
|
||||||
> Neg for &Angle<T>
|
|
||||||
{
|
{
|
||||||
type Output = Angle<T>;
|
type Output = Angle<T>;
|
||||||
|
|
||||||
@ -111,7 +103,7 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect> Angle<T> {
|
impl<T: Default + Clone + Send + Sync + Reflect + Copy> Angle<T> {
|
||||||
pub fn degrees(value: T) -> Angle<T> {
|
pub fn degrees(value: T) -> Angle<T> {
|
||||||
Self {
|
Self {
|
||||||
value: AngleUnit::Degrees(value),
|
value: AngleUnit::Degrees(value),
|
||||||
@ -130,7 +122,7 @@ impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect> Angle<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Send + Sync + Reflect + Copy + FromReflect + num_traits::float::Float> Angle<T> {
|
impl<T: Default + Send + Sync + Reflect + Copy + num_traits::float::Float> Angle<T> {
|
||||||
pub fn to_radians(self) -> Self {
|
pub fn to_radians(self) -> Self {
|
||||||
match self.value {
|
match self.value {
|
||||||
AngleUnit::Degrees(v) => Self {
|
AngleUnit::Degrees(v) => Self {
|
||||||
@ -149,16 +141,8 @@ impl<T: Default + Send + Sync + Reflect + Copy + FromReflect + num_traits::float
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<T: Add<Output = T> + Send + Sync + Reflect + Copy + Default + num_traits::float::Float> Add
|
||||||
T: Add<Output = T>
|
for Angle<T>
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ Reflect
|
|
||||||
+ Copy
|
|
||||||
+ FromReflect
|
|
||||||
+ Default
|
|
||||||
+ num_traits::float::Float,
|
|
||||||
> Add for Angle<T>
|
|
||||||
{
|
{
|
||||||
type Output = Angle<T>;
|
type Output = Angle<T>;
|
||||||
|
|
||||||
@ -180,16 +164,8 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<T: Sub<Output = T> + Default + Send + Sync + Reflect + Copy + num_traits::float::Float> Sub
|
||||||
T: Sub<Output = T>
|
for Angle<T>
|
||||||
+ Default
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ Reflect
|
|
||||||
+ Copy
|
|
||||||
+ FromReflect
|
|
||||||
+ num_traits::float::Float,
|
|
||||||
> Sub for Angle<T>
|
|
||||||
{
|
{
|
||||||
type Output = Angle<T>;
|
type Output = Angle<T>;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use bevy::reflect::{FromReflect, Reflect};
|
use bevy::reflect::Reflect;
|
||||||
|
|
||||||
use super::Precision;
|
use super::Precision;
|
||||||
|
|
||||||
#[derive(Reflect, FromReflect, Default, Copy, Clone, Debug)]
|
#[derive(Reflect, Default, Copy, Clone, Debug)]
|
||||||
pub struct Length(pub Precision);
|
pub struct Length(pub Precision);
|
||||||
|
|
||||||
impl From<i16> for Length {
|
impl From<i16> for Length {
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use std::time::Duration;
|
use bevy::{prelude::*, window::WindowResolution};
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::close_on_esc};
|
use bevy_prototype_lyon::entity::Shape;
|
||||||
use bevy_prototype_lyon::prelude::{Path, ShapePlugin};
|
use bevy_prototype_lyon::prelude::ShapePlugin;
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
use bevy_tweening::{
|
use bevy_tweening::{
|
||||||
component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween,
|
component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween,
|
||||||
TweenCompleted, TweeningPlugin,
|
TweenCompleted,
|
||||||
};
|
};
|
||||||
use events::DrawingStartedEvent;
|
use events::DrawingStartedEvent;
|
||||||
use shapes::{TurtleColors, TurtleShape};
|
use shapes::{TurtleColors, TurtleShape};
|
||||||
@ -38,39 +39,42 @@ pub struct TurtlePlugin;
|
|||||||
impl Plugin for TurtlePlugin {
|
impl Plugin for TurtlePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||||
window: WindowDescriptor {
|
primary_window: Some(Window {
|
||||||
title: "Immigration Game".to_string(),
|
title: "Immigration Game".to_string(),
|
||||||
width: 1200.,
|
resolution: WindowResolution::new(1200, 800),
|
||||||
height: 800.,
|
..default()
|
||||||
present_mode: bevy::window::PresentMode::Fifo, // vsync
|
}),
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..default()
|
..default()
|
||||||
}))
|
}))
|
||||||
.add_plugin(debug::DebugPlugin)
|
.add_plugins(debug::DebugPlugin)
|
||||||
.add_plugin(ShapePlugin)
|
.add_plugins(ShapePlugin)
|
||||||
.add_plugin(TweeningPlugin)
|
.add_message::<DrawingStartedEvent>()
|
||||||
.add_event::<DrawingStartedEvent>()
|
.add_systems(Startup, setup)
|
||||||
.add_startup_system(setup)
|
.add_systems(
|
||||||
.add_system(keypresses)
|
Update,
|
||||||
.add_system(component_animator_system::<Path>)
|
(
|
||||||
.add_system(close_on_esc)
|
keypresses,
|
||||||
.add_system(draw_lines)
|
#[cfg(feature = "tweening")]
|
||||||
|
component_animator_system::<Transform>,
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
|
component_animator_system::<Shape>,
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
|
draw_lines,
|
||||||
|
#[cfg(not(feature = "tweening"))]
|
||||||
|
draw_immediate,
|
||||||
|
),
|
||||||
|
)
|
||||||
.register_type::<TurtleColors>()
|
.register_type::<TurtleColors>()
|
||||||
.register_type::<TurtleCommands>();
|
.register_type::<TurtleCommands>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(mut commands: Commands) {
|
fn setup(mut commands: Commands) {
|
||||||
commands.spawn(Camera2dBundle {
|
commands.spawn((Camera2d,));
|
||||||
camera_2d: Camera2d {
|
|
||||||
clear_color: ClearColorConfig::Custom(Color::BEIGE),
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_a_turtle() -> AnimatedTurtle {
|
pub fn get_a_turtle() -> AnimatedTurtle {
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
let animator = Animator::new(Tween::new(
|
let animator = Animator::new(Tween::new(
|
||||||
EaseFunction::QuadraticInOut,
|
EaseFunction::QuadraticInOut,
|
||||||
Duration::from_millis(3000),
|
Duration::from_millis(3000),
|
||||||
@ -79,6 +83,8 @@ pub fn get_a_turtle() -> AnimatedTurtle {
|
|||||||
end: Vec3::ONE * 1.3,
|
end: Vec3::ONE * 1.3,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
#[cfg(not(feature = "tweening"))]
|
||||||
|
let animator = ();
|
||||||
let turtle_bundle = TurtleBundle::default();
|
let turtle_bundle = TurtleBundle::default();
|
||||||
AnimatedTurtle {
|
AnimatedTurtle {
|
||||||
animator,
|
animator,
|
||||||
@ -89,26 +95,33 @@ pub fn get_a_turtle() -> AnimatedTurtle {
|
|||||||
|
|
||||||
fn keypresses(
|
fn keypresses(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
keys: Res<Input<KeyCode>>,
|
_keys: Res<ButtonInput<KeyCode>>,
|
||||||
mut tcmd: Query<(Entity, &mut TurtleCommands)>,
|
mut tcmd: Query<(Entity, &mut TurtleCommands)>,
|
||||||
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
#[cfg(feature = "tweening")] mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
||||||
mut ev_start: EventWriter<DrawingStartedEvent>,
|
#[cfg(not(feature = "tweening"))] mut turtle: Query<&mut Transform, With<TurtleShape>>,
|
||||||
|
mut _ev_start: MessageWriter<DrawingStartedEvent>,
|
||||||
) {
|
) {
|
||||||
if keys.just_pressed(KeyCode::W) {
|
if _keys.just_pressed(KeyCode::KeyW) {
|
||||||
for (entity, mut tcmd) in tcmd.iter_mut() {
|
for (entity, mut tcmd) in tcmd.iter_mut() {
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle);
|
crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle);
|
||||||
ev_start.send(DrawingStartedEvent(entity))
|
|
||||||
|
#[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(
|
fn draw_lines(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut tcmd: Query<&mut TurtleCommands>,
|
mut tcmd: Query<&mut TurtleCommands>,
|
||||||
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
||||||
mut query_event: EventReader<TweenCompleted>, // TODO: howto attach only to the right event?
|
mut query_event: EventReader<TweenCompleted>, // TODO: howto attach only to the right event?
|
||||||
) {
|
) {
|
||||||
for _ev in query_event.iter() {
|
for _ev in query_event.read() {
|
||||||
if let Ok(mut tcmd) = tcmd.get_single_mut() {
|
if let Ok(mut tcmd) = tcmd.get_single_mut() {
|
||||||
crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle)
|
crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle)
|
||||||
} else {
|
} else {
|
||||||
@ -116,3 +129,17 @@ fn draw_lines(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "tweening"))]
|
||||||
|
fn draw_immediate(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut tcmd: Query<&mut TurtleCommands>,
|
||||||
|
mut turtle: Query<&mut Transform, With<TurtleShape>>,
|
||||||
|
) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
use std::f32::consts::PI;
|
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::ShapePath;
|
||||||
|
|
||||||
use crate::general::Precision;
|
use crate::general::Precision;
|
||||||
|
|
||||||
pub fn turtle() -> Path {
|
pub fn turtle() -> ShapePath {
|
||||||
let polygon: &[[Precision; 2]; 23] = &[
|
let polygon: &[[Precision; 2]; 23] = &[
|
||||||
[-2.5, 14.0],
|
[-2.5, 14.0],
|
||||||
[-1.25, 10.0],
|
[-1.25, 10.0],
|
||||||
@ -31,16 +31,16 @@ pub fn turtle() -> Path {
|
|||||||
[1.25, 10.0],
|
[1.25, 10.0],
|
||||||
[2.5, 14.0],
|
[2.5, 14.0],
|
||||||
];
|
];
|
||||||
let mut turtle_path = PathBuilder::new();
|
let mut turtle_path = ShapePath::new()
|
||||||
turtle_path.line_to(Vec2::new(1.0, 1.0));
|
.line_to(Vec2::new(1.0, 1.0))
|
||||||
turtle_path.line_to(Vec2::new(-1.0, 1.0));
|
.line_to(Vec2::new(-1.0, 1.0))
|
||||||
turtle_path.line_to(Vec2::new(-1.0, -1.0));
|
.line_to(Vec2::new(-1.0, -1.0))
|
||||||
turtle_path.line_to(Vec2::new(1.0, -1.0));
|
.line_to(Vec2::new(1.0, -1.0))
|
||||||
turtle_path.close();
|
.close()
|
||||||
turtle_path.move_to(Vec2::new(0.0, 16.0).rotate(Vec2::from_angle(-PI / 2.)));
|
.move_to(Vec2::new(0.0, 16.0).rotate(Vec2::from_angle(-PI / 2.)));
|
||||||
|
|
||||||
for coord in polygon {
|
for coord in polygon {
|
||||||
turtle_path.line_to(Vec2::from_array(*coord).rotate(Vec2::from_angle(-PI / 2.)));
|
turtle_path = turtle_path.line_to(Vec2::from_array(*coord).rotate(Vec2::from_angle(-PI / 2.)));
|
||||||
}
|
}
|
||||||
turtle_path.close();
|
turtle_path.close()
|
||||||
turtle_path.build()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use bevy::prelude::{Bundle, Color, Name, Transform};
|
use bevy::prelude::{Bundle, Color, Name};
|
||||||
use bevy_prototype_lyon::{
|
use bevy_prototype_lyon::{
|
||||||
entity::ShapeBundle,
|
draw::{Fill, Stroke},
|
||||||
prelude::{DrawMode, FillMode, GeometryBuilder, StrokeMode},
|
entity::Shape,
|
||||||
|
geometry::ShapeBuilder,
|
||||||
|
prelude::ShapeBuilderBase as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -21,7 +23,7 @@ pub struct TurtleBundle {
|
|||||||
colors: TurtleColors,
|
colors: TurtleColors,
|
||||||
pub commands: TurtleCommands,
|
pub commands: TurtleCommands,
|
||||||
name: Name,
|
name: Name,
|
||||||
shape: ShapeBundle,
|
shape: Shape,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TurtleBundle {
|
impl Default for TurtleBundle {
|
||||||
@ -30,14 +32,10 @@ impl Default for TurtleBundle {
|
|||||||
colors: TurtleColors::default(),
|
colors: TurtleColors::default(),
|
||||||
commands: TurtleCommands::new(vec![]),
|
commands: TurtleCommands::new(vec![]),
|
||||||
name: Name::new("Turtle"),
|
name: Name::new("Turtle"),
|
||||||
shape: GeometryBuilder::build_as(
|
shape: ShapeBuilder::with(&shapes::turtle())
|
||||||
&shapes::turtle(),
|
.fill(Fill::color(Color::srgb(0.098, 0.098, 0.439)))
|
||||||
DrawMode::Outlined {
|
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||||
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
|
.build(),
|
||||||
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
|
|
||||||
},
|
|
||||||
Transform::IDENTITY,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,7 +60,10 @@ impl TurtleBundle {
|
|||||||
|
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub struct AnimatedTurtle {
|
pub struct AnimatedTurtle {
|
||||||
|
#[cfg(feature = "tweening")]
|
||||||
pub animator: bevy_tweening::Animator<bevy::prelude::Transform>,
|
pub animator: bevy_tweening::Animator<bevy::prelude::Transform>,
|
||||||
|
#[cfg(not(feature = "tweening"))]
|
||||||
|
pub animator: (),
|
||||||
pub turtle_bundle: TurtleBundle,
|
pub turtle_bundle: TurtleBundle,
|
||||||
pub turtle_shape: shapes::TurtleShape,
|
pub turtle_shape: shapes::TurtleShape,
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user