Compare commits

..
11 Commits
Author SHA1 Message Date
dietrich 5f4e47f540 refactor and cleanup 2022-08-24 08:17:53 +02:00
dietrich f9a4c1d81a Add more detail to geometry_tasks 2022-08-23 14:46:32 +02:00
dietrich ee2c869a03 reorganizing the code 2022-08-23 10:52:20 +02:00
dietrich d8a5c67fd5 Finalize the circle command 2022-08-22 14:17:26 +02:00
dietrich d16607ff4d Angle as proper type 2022-08-20 15:33:47 +02:00
dietrich a5a1be2392 circles partially working 2022-08-19 22:30:28 +02:00
dietrich 7a543685d3 first circle try 2022-08-19 19:08:02 +02:00
dietrich 62ca3eb79d adjusting gitignore 2022-08-13 16:02:39 +02:00
dietrich 4d49dd44ba working animation 2022-08-11 17:14:42 +02:00
dietrich 1d1787b8c0 refine queries 2022-08-09 22:37:26 +02:00
dietrich 92458b55e5 forward backward left right working 2022-08-08 14:31:58 +02:00
21 changed files with 971 additions and 264 deletions
+1
View File
@@ -1 +1,2 @@
/target /target
/.vscode
Generated
+52 -60
View File
@@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "ab_glyph" name = "ab_glyph"
version = "0.2.15" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" checksum = "846ffacb9d0c8b879ef9e565b59e18fb76d6a61013e5bd24ecc659864e6b1a1f"
dependencies = [ dependencies = [
"ab_glyph_rasterizer", "ab_glyph_rasterizer",
"owned_ttf_parser", "owned_ttf_parser",
@@ -110,9 +110,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.60" version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
[[package]] [[package]]
name = "approx" name = "approx"
@@ -165,9 +165,9 @@ dependencies = [
[[package]] [[package]]
name = "async-channel" name = "async-channel"
version = "1.6.1" version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
dependencies = [ dependencies = [
"concurrent-queue", "concurrent-queue",
"event-listener", "event-listener",
@@ -422,9 +422,9 @@ dependencies = [
[[package]] [[package]]
name = "bevy_egui" name = "bevy_egui"
version = "0.15.0" version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ab46f07c3f360507fae9bc3b9c000c583e0d67661f0dd6dd5a24a709775b1e" checksum = "acbf44ff770566dca66b805a6829df783f64700bd01d35aec1034dff31b531a4"
dependencies = [ dependencies = [
"arboard", "arboard",
"bevy", "bevy",
@@ -594,9 +594,9 @@ dependencies = [
[[package]] [[package]]
name = "bevy_pbr" name = "bevy_pbr"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9a81bbd02f5e0a57899a41aec37d9cb14965e1e4d510547f3f680323d05c0f" checksum = "176073021a4caeb8b448f24ce790fb57fde74b114f345064a8b102d2f7bed905"
dependencies = [ dependencies = [
"bevy_app", "bevy_app",
"bevy_asset", "bevy_asset",
@@ -741,9 +741,9 @@ dependencies = [
[[package]] [[package]]
name = "bevy_sprite" name = "bevy_sprite"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f83dfe8897d6c0d9d5ce3818d49a13e58ae2b9b9ecf4f4bb85aa31bb0678f68" checksum = "69c419f3db09d7ac1f4d45e0874d349d5d6f47f48bc10d55cd0da36413e2331e"
dependencies = [ dependencies = [
"bevy_app", "bevy_app",
"bevy_asset", "bevy_asset",
@@ -841,9 +841,9 @@ dependencies = [
[[package]] [[package]]
name = "bevy_ui" name = "bevy_ui"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac181a7b637da61fad72981ff9d2e5b899283ca7d54b2b7ea49c431121331c53" checksum = "062ce086de1a4a470e5df48cb5c16a1dc97ab610e635cafabdef26c4a1ef5756"
dependencies = [ dependencies = [
"bevy_app", "bevy_app",
"bevy_asset", "bevy_asset",
@@ -875,7 +875,7 @@ checksum = "8bda6dada53e546845887ae7357eec57b8d547ef71627b716b33839b4a98b687"
dependencies = [ dependencies = [
"ahash", "ahash",
"getrandom", "getrandom",
"hashbrown 0.12.3", "hashbrown",
"instant", "instant",
"tracing", "tracing",
"uuid", "uuid",
@@ -883,9 +883,9 @@ dependencies = [
[[package]] [[package]]
name = "bevy_window" name = "bevy_window"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3bdc3a220a9bb2fad9bd30d5f44c6645725398fe1bc588fc87abf09f092696e" checksum = "707dbbebfac72b1e63e874e7a11a345feab8c440355c0bd71e6dff26709fba9a"
dependencies = [ dependencies = [
"bevy_app", "bevy_app",
"bevy_ecs", "bevy_ecs",
@@ -964,24 +964,24 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.10.0" version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.11.0" version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da"
dependencies = [ dependencies = [
"bytemuck_derive", "bytemuck_derive",
] ]
[[package]] [[package]]
name = "bytemuck_derive" name = "bytemuck_derive"
version = "1.1.1" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfd2f4180c5721da6335cc9e9061cce522b87a35e51cc57636d28d22a9863c80" checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1119,9 +1119,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.4" version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
dependencies = [ dependencies = [
"bytes", "bytes",
"memchr", "memchr",
@@ -1592,15 +1592,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.21" version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115"
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.21" version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5"
[[package]] [[package]]
name = "futures-lite" name = "futures-lite"
@@ -1778,13 +1778,13 @@ dependencies = [
[[package]] [[package]]
name = "gpu-descriptor" name = "gpu-descriptor"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"gpu-descriptor-types", "gpu-descriptor-types",
"hashbrown 0.11.2", "hashbrown",
] ]
[[package]] [[package]]
@@ -1826,15 +1826,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@@ -1931,7 +1922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown 0.12.3", "hashbrown",
] ]
[[package]] [[package]]
@@ -1996,9 +1987,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]] [[package]]
name = "jni" name = "jni"
@@ -2100,9 +2091,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]] [[package]]
name = "libloading" name = "libloading"
@@ -2632,9 +2623,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]] [[package]]
name = "owned_ttf_parser" name = "owned_ttf_parser"
@@ -2774,9 +2765,9 @@ checksum = "a8815d101cfb4cb491154896bdab292a395a7ac9ab185a9941a2f5be0135900d"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "1.2.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d50bfb8c23f23915855a00d98b5a35ef2e0b871bb52937bacadb798fbb66c8" checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"thiserror", "thiserror",
@@ -2942,18 +2933,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.141" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7af873f2c95b99fcb0bd0fe622a43e29514658873c8ceba88c4cb88833a22500" checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.141" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75743a150d003dd863b51dc809bcad0d73f2102c53632f1e954e738192a3413f" checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2962,9 +2953,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.82" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -3247,6 +3238,7 @@ dependencies = [
"bevy-inspector-egui", "bevy-inspector-egui",
"bevy_prototype_lyon", "bevy_prototype_lyon",
"bevy_tweening", "bevy_tweening",
"num-traits",
] ]
[[package]] [[package]]
@@ -3263,9 +3255,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
@@ -3662,9 +3654,9 @@ dependencies = [
[[package]] [[package]]
name = "x11-dl" name = "x11-dl"
version = "2.19.1" version = "2.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
+3 -2
View File
@@ -8,9 +8,10 @@ default-run = "turtlers"
[dependencies] [dependencies]
bevy = { version = "0.8", features = ["dynamic"] } bevy = { version = "0.8", features = ["dynamic"] }
bevy-inspector-egui = "0.12.1" bevy-inspector-egui = "0.12"
bevy_prototype_lyon = "0.6" bevy_prototype_lyon = "0.6"
bevy_tweening = "0.5.0" bevy_tweening = "0.5"
num-traits = "0.2"
# Enable a small amount of optimization in debug mode # Enable a small amount of optimization in debug mode
[profile.dev] [profile.dev]
+1
View File
@@ -0,0 +1 @@
*[x] make the
+53
View File
@@ -0,0 +1,53 @@
use bevy::prelude::{Commands, Query, Transform, With};
use bevy_tweening::Animator;
use crate::{
turtle::{TurtleCommands, TurtleGraphElement, TurtleShape},
turtle_movement::TurtleStep,
};
pub(crate) fn run_animation_step(
commands: &mut Commands,
tcmd: &mut TurtleCommands,
turtle: &mut Query<&mut Animator<Transform>, With<TurtleShape>>,
) {
loop {
match tcmd.get_next() {
Some(TurtleStep {
turtle_animation: Some(turtle_animation),
line_segment: Some(graph_element_to_draw),
line_animation: Some(line_animation),
}) => {
let mut turtle = turtle.single_mut();
turtle.set_tweenable(turtle_animation);
match graph_element_to_draw {
TurtleGraphElement::TurtleLine(line) => {
commands.spawn_bundle(line).insert(line_animation);
}
TurtleGraphElement::Noop => (),
TurtleGraphElement::TurtleCircle(circle) => {
commands.spawn_bundle(circle).insert(line_animation);
}
}
return;
}
// In case a rotation is performed the line drawing can be skipped
Some(TurtleStep {
turtle_animation: Some(turtle_animation),
line_segment: Some(_),
line_animation: None,
}) => {
let mut turtle = turtle.single_mut();
turtle.set_tweenable(turtle_animation);
return;
}
Some(_) => {
println!("without animation");
}
None => {
println!("nothing to draw");
return;
}
};
}
}
+30
View File
@@ -0,0 +1,30 @@
use bevy::prelude::*;
use bevy_prototype_lyon::prelude::*;
fn main() {
App::new()
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_plugin(ShapePlugin)
.add_startup_system(setup_system)
.run();
}
fn setup_system(mut commands: Commands) {
let mut path_builder = PathBuilder::new();
path_builder.move_to(Vec2::new(100., 0.));
path_builder.arc(
100.0 * Vec2::ZERO,
100.0 * Vec2::ONE,
90f32.to_radians(),
0.,
);
let line = path_builder.build();
commands.spawn_bundle(Camera2dBundle::default());
commands.spawn_bundle(GeometryBuilder::build_as(
&line,
DrawMode::Stroke(StrokeMode::new(Color::BLACK, 10.0)),
Transform::default(),
));
}
+2
View File
@@ -0,0 +1,2 @@
pub mod angle;
pub mod length;
+179
View File
@@ -0,0 +1,179 @@
use bevy_inspector_egui::Inspectable;
use std::{
f32::consts::PI,
ops::{Add, Div, Mul, Neg, Rem, Sub},
};
use crate::turtle::Precision;
#[derive(Inspectable, Copy, Clone, Debug, PartialEq, Eq)]
pub enum AngleUnit<T: Default> {
Degrees(T),
Radians(T),
}
impl<T: Default> Default for AngleUnit<T> {
fn default() -> Self {
Self::Degrees(Default::default())
}
}
#[derive(Inspectable, Copy, Default, Clone, Debug, PartialEq, Eq)]
pub struct Angle<T: Default> {
value: AngleUnit<T>,
}
impl<T: Default + Clone + Rem<T, Output = T>> Rem<T> for Angle<T> {
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<T: Default + Clone + Mul<T, Output = T>> Mul<T> for Angle<T> {
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<Precision> {
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<T: Default + Clone + Div<T, Output = T>> Div<T> for Angle<T> {
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<T: Default + Clone + std::ops::Neg<Output = T>> Neg for Angle<T> {
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<T: Default + Clone + std::ops::Neg<Output = T>> Neg for &Angle<T> {
type Output = Angle<T>;
fn neg(self) -> Self::Output {
match self.value.clone() {
AngleUnit::Degrees(v) => Self::Output::degrees(-v),
AngleUnit::Radians(v) => Self::Output::radians(-v),
}
}
}
impl<T: Default + Clone> Angle<T> {
pub fn degrees(value: T) -> Angle<T> {
Self {
value: AngleUnit::Degrees(value),
}
}
pub fn radians(value: T) -> Angle<T> {
Self {
value: AngleUnit::Radians(value),
}
}
pub fn value(&self) -> T {
match self.value.clone() {
AngleUnit::Degrees(v) => v,
AngleUnit::Radians(v) => v,
}
}
}
impl<T: Default + num_traits::float::Float> Angle<T> {
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<T: Add<Output = T> + Default + num_traits::float::Float> Add for Angle<T> {
type Output = Angle<T>;
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<T: Sub<Output = T> + Default + num_traits::float::Float> Sub for Angle<T> {
type Output = Angle<T>;
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)
}
+6
View File
@@ -0,0 +1,6 @@
use bevy_inspector_egui::Inspectable;
use crate::turtle::Precision;
#[derive(Inspectable, Default, Copy, Clone, Debug)]
pub struct Length(pub Precision);
+7 -3
View File
@@ -1,6 +1,10 @@
mod animation_step;
mod datatypes;
mod debug; mod debug;
mod paths;
mod primitives;
mod turtle; mod turtle;
mod turtle_shapes; mod turtle_movement;
use bevy::{prelude::*, window::close_on_esc}; use bevy::{prelude::*, window::close_on_esc};
use bevy_prototype_lyon::prelude::*; use bevy_prototype_lyon::prelude::*;
@@ -11,8 +15,8 @@ fn main() {
.insert_resource(Msaa { samples: 4 }) .insert_resource(Msaa { samples: 4 })
.insert_resource(ClearColor(Color::BEIGE)) .insert_resource(ClearColor(Color::BEIGE))
.insert_resource(WindowDescriptor { .insert_resource(WindowDescriptor {
width: 400.0, width: 500.0,
height: 400.0, height: 500.0,
title: "Turtle Window".to_string(), title: "Turtle Window".to_string(),
present_mode: bevy::window::PresentMode::AutoVsync, present_mode: bevy::window::PresentMode::AutoVsync,
..default() ..default()
+46
View File
@@ -0,0 +1,46 @@
use crate::{
datatypes::{angle::Angle, length::Length},
turtle::TurtleCommand,
};
#[allow(dead_code)]
pub fn circle_star() -> Vec<TurtleCommand> {
vec![
TurtleCommand::Right(Angle::degrees(36.)),
TurtleCommand::Forward(Length(200.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Circle {
radius: Length(20.),
angle: Angle::degrees(324.),
},
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(200.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Circle {
radius: Length(20.),
angle: Angle::degrees(324.),
},
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(200.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Circle {
radius: Length(20.),
angle: Angle::degrees(324.),
},
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(200.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Circle {
radius: Length(20.),
angle: Angle::degrees(324.),
},
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(200.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Circle {
radius: Length(20.),
angle: Angle::degrees(324.),
},
TurtleCommand::Right(Angle::degrees(90.)),
]
}
+43
View File
@@ -0,0 +1,43 @@
use crate::{
datatypes::{angle::Angle, length::Length},
turtle::TurtleCommand,
};
#[allow(dead_code)]
pub fn geometry_task() -> Vec<TurtleCommand> {
let mut before = vec![
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Backward(Length(100.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(45.)),
];
for _ in 0..10 {
let mut dash = vec![
TurtleCommand::PenUp,
TurtleCommand::Forward(Length(5.)),
TurtleCommand::PenDown,
TurtleCommand::Forward(Length(5.)),
];
before.append(&mut dash);
}
let mut after = vec![
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(50.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(90.)),
TurtleCommand::Forward(Length(50.)),
TurtleCommand::Right(Angle::degrees(45.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle::degrees(120.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle::degrees(120.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Right(Angle::degrees(150.)),
TurtleCommand::Forward(Length(100.)),
];
before.append(&mut after);
before
}
+2
View File
@@ -0,0 +1,2 @@
pub mod circle_star;
pub mod geometry_task;
+5
View File
@@ -0,0 +1,5 @@
pub mod animation;
pub mod bundles;
pub mod components;
pub mod turtle_primitives;
pub mod turtle_shapes;
+72
View File
@@ -0,0 +1,72 @@
use bevy::prelude::{Quat, Transform, Vec2};
use bevy_prototype_lyon::{
prelude::{Path, PathBuilder, ShapePath},
shapes,
};
use bevy_tweening::Lens;
use crate::{datatypes::angle::Angle, turtle::Precision};
pub(crate) struct LineAnimationLens {
start: Vec2,
end: Vec2,
}
impl LineAnimationLens {
pub(crate) fn new(start: Vec2, end: Vec2) -> Self {
Self { start, end }
}
}
impl Lens<Path> for LineAnimationLens {
fn lerp(&mut self, target: &mut Path, ratio: f32) {
let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio));
*target = ShapePath::build_as(&line);
}
}
pub(crate) struct CircleAnimationLens {
pub start_pos: Vec2,
pub center: Vec2,
pub radii: Vec2,
pub start: Angle<Precision>,
pub end: Angle<Precision>,
}
impl Lens<Path> for CircleAnimationLens {
fn lerp(&mut self, target: &mut Path, ratio: f32) {
let mut path_builder = PathBuilder::new();
path_builder.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_builder.arc(
self.center,
self.radii,
(self.start + ((self.end - self.start) * ratio))
.to_radians()
.value(),
0.,
);
let line = path_builder.build();
*target = ShapePath::build_as(&line);
}
}
pub(crate) struct CircleMovementLens {
pub center: Vec2,
pub start: Transform,
pub end: Angle<Precision>,
}
impl Lens<Transform> 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;
}
}
+138
View File
@@ -0,0 +1,138 @@
use bevy::prelude::{Bundle, Color, Component, Name, Transform, Vec2};
use bevy_inspector_egui::Inspectable;
use bevy_prototype_lyon::{
entity::ShapeBundle,
prelude::{DrawMode, FillMode, GeometryBuilder, PathBuilder, StrokeMode},
shapes::Line,
};
use crate::{
datatypes::angle::Angle,
turtle::{Colors, Precision, TurtleCommand, TurtleCommands},
};
use super::turtle_shapes;
#[derive(Bundle, Inspectable, Default)]
pub struct TurtleDrawLine {
#[bundle]
#[inspectable(ignore)]
line: ShapeBundle,
name: Name,
marker: LineMarker,
}
#[derive(Component, Default, Inspectable)]
struct LineMarker;
impl TurtleDrawLine {
pub(crate) fn new(start: Vec2, _end: Vec2, index: u64) -> Self {
Self {
line: GeometryBuilder::build_as(
&Line(start, start),
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
),
name: Name::new(format!("Line {}", index)),
marker: LineMarker,
}
}
}
#[derive(Bundle, Inspectable, Default)]
pub struct TurtleDrawCircle {
#[bundle]
#[inspectable(ignore)]
line: ShapeBundle,
name: Name,
marker: CircleMarker,
}
#[derive(Component, Default, Inspectable)]
struct CircleMarker;
impl TurtleDrawCircle {
pub(crate) fn new(
center: Vec2,
radii: Vec2,
angle: Angle<Precision>,
index: u64,
start: Vec2,
end: Vec2,
) -> 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,
// 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?)
path_builder.arc(center, radii, angle.to_radians().value(), 0.);
let line = path_builder.build();
println!("Draw Circle: {} {} {:?}", center, radii, angle);
Self {
line: GeometryBuilder::build_as(
&line,
DrawMode::Outlined {
fill_mode: FillMode::color(Color::rgba(0., 0., 0., 0.)),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
),
name: Name::new(format!("Circle {}", index)),
marker: CircleMarker,
}
}
}
#[derive(Bundle)]
pub struct Turtle {
colors: Colors,
commands: TurtleCommands,
name: Name,
#[bundle]
shape: ShapeBundle,
}
impl Default for Turtle {
fn default() -> Self {
Self {
colors: Colors::default(),
commands: TurtleCommands::new(vec![]),
name: Name::new("Turtle"),
shape: GeometryBuilder::build_as(
&turtle_shapes::turtle(),
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
),
}
}
}
impl Turtle {
/* pub fn set_color(&mut self, color: Color) {
self.colors.color = color;
}
pub fn set_fill_color(&mut self, color: Color) {
self.colors.fill_color = color;
}
pub fn get_colors(&self) -> &Colors {
&self.colors
}
pub fn forward(&mut self) -> &mut Self {
self.commands
.commands
.push(TurtleCommand::Forward(Length(100.0)));
self
} */
pub fn set_commands(&mut self, commands: Vec<TurtleCommand>) {
self.commands = TurtleCommands::new(commands);
}
}
View File
+23
View File
@@ -0,0 +1,23 @@
use bevy::prelude::Vec2;
use crate::{datatypes::angle::Angle, turtle::Precision};
pub struct TurtleAction {
heading: Angle<Precision>,
position: Vec2,
primitive: TurtleActionType,
}
pub enum TurtleActionType {
Straight {
target: Vec2,
},
Rotate {
angle: Angle<Precision>,
},
Circle {
center: Vec2,
radii: Vec2,
extent: Angle<Precision>,
},
}
@@ -3,31 +3,33 @@ use std::f32::consts::PI;
use bevy::prelude::Vec2; use bevy::prelude::Vec2;
use bevy_prototype_lyon::prelude::{Path, PathBuilder}; use bevy_prototype_lyon::prelude::{Path, PathBuilder};
use crate::turtle::Precision;
pub fn turtle() -> Path { pub fn turtle() -> Path {
let polygon = &[ let polygon: &[[Precision; 2]; 23] = &[
[-2.5f32, 14.0f32], [-2.5, 14.0],
[-1.25f32, 10.0f32], [-1.25, 10.0],
[-4.0f32, 7.0f32], [-4.0, 7.0],
[-7.0f32, 9.0f32], [-7.0, 9.0],
[-9.0f32, 8.0f32], [-9.0, 8.0],
[-6.0f32, 5.0f32], [-6.0, 5.0],
[-7.0f32, 1.0f32], [-7.0, 1.0],
[-5.0f32, -3.0f32], [-5.0, -3.0],
[-8.0f32, -6.0f32], [-8.0, -6.0],
[-6.0f32, -8.0f32], [-6.0, -8.0],
[-4.0f32, -5.0f32], [-4.0, -5.0],
[0.0f32, -7.0f32], [0.0, -7.0],
[4.0f32, -5.0f32], [4.0, -5.0],
[6.0f32, -8.0f32], [6.0, -8.0],
[8.0f32, -6.0f32], [8.0, -6.0],
[5.0f32, -3.0f32], [5.0, -3.0],
[7.0f32, 1.0f32], [7.0, 1.0],
[6.0f32, 5.0f32], [6.0, 5.0],
[9.0f32, 8.0f32], [9.0, 8.0],
[7.0f32, 9.0f32], [7.0, 9.0],
[4.0f32, 7.0f32], [4.0, 7.0],
[1.25f32, 10.0f32], [1.25, 10.0],
[2.5f32, 14.0f32], [2.5, 14.0],
]; ];
let mut turtle_path = PathBuilder::new(); let mut turtle_path = PathBuilder::new();
turtle_path.line_to(Vec2::new(1.0, 1.0)); turtle_path.line_to(Vec2::new(1.0, 1.0));
+135 -171
View File
@@ -1,14 +1,21 @@
use std::{f32::consts::PI, time::Duration}; use std::time::Duration;
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::{Inspectable, RegisterInspectable}; use bevy_inspector_egui::{Inspectable, RegisterInspectable};
use bevy_prototype_lyon::prelude::*; use bevy_prototype_lyon::prelude::*;
use bevy_tweening::{ use bevy_tweening::{
lens::{TransformPositionLens, TransformRotateZLens}, component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween,
Animator, EaseFunction, Sequence, Tween, TweeningPlugin, TweeningType, TweenCompleted, TweeningPlugin, TweeningType,
}; };
use crate::turtle_shapes; #[allow(unused_imports)]
use crate::paths::{circle_star::circle_star, geometry_task::geometry_task};
use crate::{
animation_step::run_animation_step,
datatypes::{angle::Angle, length::Length},
primitives::bundles::{Turtle, TurtleDrawCircle, TurtleDrawLine},
turtle_movement::TurtleStep,
};
pub struct TurtlePlugin; pub struct TurtlePlugin;
@@ -17,218 +24,175 @@ impl Plugin for TurtlePlugin {
app.add_plugin(TweeningPlugin) app.add_plugin(TweeningPlugin)
.add_startup_system(setup) .add_startup_system(setup)
.add_system(keypresses) .add_system(keypresses)
.add_system(draw_lines)
.add_system(component_animator_system::<Path>)
.register_inspectable::<Colors>() .register_inspectable::<Colors>()
.register_inspectable::<TurtleCommands>(); .register_inspectable::<TurtleCommands>();
} }
} }
#[derive(Bundle)] pub type Precision = f32;
pub struct Turtle {
colors: Colors,
commands: TurtleCommands,
}
impl Default for Turtle {
fn default() -> Self {
Self {
colors: Colors {
color: Color::DARK_GRAY,
fill_color: Color::BLACK,
},
commands: TurtleCommands(vec![
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle(90.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle(90.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle(90.)),
TurtleCommand::Forward(Length(100.)),
TurtleCommand::Left(Angle(90.)),
]), /*
shape: TurtleShape(GeometryBuilder::build_as(
&turtle_shapes::turtle(),
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Default::default(),
)), */
}
}
}
impl Turtle {
pub fn set_color(&mut self, color: Color) {
self.colors.color = color;
}
pub fn set_fill_color(&mut self, color: Color) {
self.colors.fill_color = color;
}
pub fn get_colors(&self) -> &Colors {
&self.colors
}
pub fn forward(&mut self) -> &mut Self {
self.commands.0.push(TurtleCommand::Forward(Length(100.0)));
self
}
}
#[derive(Component, Inspectable)] #[derive(Component, Inspectable)]
pub struct TurtleCommands(Vec<TurtleCommand>); pub struct TurtleCommands {
commands: Vec<TurtleCommand>,
lines: Vec<TurtleGraphElement>,
state: TurtleState,
}
#[derive(Inspectable)]
pub struct TurtleState {
pub start: Vec2,
pub heading: Angle<f32>,
pub speed: u64,
pub index: u64,
pub drawing: bool,
}
impl TurtleCommands { impl TurtleCommands {
fn generate_tweenable(&self) -> Sequence<Transform> { pub fn new(commands: Vec<TurtleCommand>) -> Self {
let mut seq = Sequence::with_capacity(self.0.len()); Self {
let mut pos = Vec2::ZERO; commands,
let mut ori: f32 = 0.; lines: vec![],
for op in &self.0 { state: TurtleState {
match op { start: Vec2::ZERO,
TurtleCommand::Forward(Length(x)) => { heading: Angle::degrees(0.),
println!("Adding Forward"); speed: 2000,
let start = pos; index: 0,
let end = pos + (Vec2::from_angle(ori) * *x as f32); drawing: true,
seq = seq.then(Tween::new(
// accelerate and decelerate
EaseFunction::QuadraticInOut,
// Loop animation back and forth.
TweeningType::Once,
// later to be controlled by speed
Duration::from_secs(1),
// set the start and end of the animation
TransformPositionLens {
start: start.extend(0.),
end: end.extend(0.),
}, },
));
pos = end;
} }
TurtleCommand::Backward(_) => todo!(),
TurtleCommand::Left(Angle(x)) => {
println!("Adding Left");
let start = ori;
let end = ori + (*x as f32 * PI / 180.);
seq = seq.then(Tween::new(
// Use a quadratic easing on both endpoints.
EaseFunction::QuadraticInOut,
// Loop animation back and forth.
TweeningType::Once,
// Animation time (one way only; for ping-pong it takes 2 seconds
// to come back to start).
Duration::from_secs(1),
// The lens gives access to the Transform component of the Entity,
// for the Animator to animate it. It also contains the start and
// end values respectively associated with the progress ratios 0. and 1.
TransformRotateZLens { start, end },
));
ori = end % (2. * PI);
} }
TurtleCommand::Right(_) => todo!(), }
TurtleCommand::PenUp => todo!(),
TurtleCommand::PenDown => todo!(), impl TurtleCommands {
TurtleCommand::Circle => todo!(), pub(crate) fn get_next(&mut self) -> Option<TurtleStep> {
let index = self.state.index;
let next_index = index + 1;
if let Some(command) = self.commands.get(self.state.index as usize) {
let res = match command {
TurtleCommand::Forward(Length(x)) => {
crate::turtle_movement::turtle_move(&mut self.state, *x as f32)
}
TurtleCommand::Backward(Length(x)) => {
crate::turtle_movement::turtle_move(&mut self.state, -*x as f32)
}
TurtleCommand::Left(angle) => {
crate::turtle_movement::turtle_turn(&mut self.state, *angle)
}
TurtleCommand::Right(angle) => {
crate::turtle_movement::turtle_turn(&mut self.state, -angle)
}
TurtleCommand::PenUp => {
self.state.drawing = false;
TurtleStep {
turtle_animation: None,
line_segment: None,
line_animation: None,
}
}
TurtleCommand::PenDown => {
self.state.drawing = true;
TurtleStep {
turtle_animation: None,
line_segment: None,
line_animation: None,
}
}
TurtleCommand::Circle { radius, angle } => {
crate::turtle_movement::turtle_circle(&mut self.state, radius.0 as f32, *angle)
}
TurtleCommand::Pause => todo!(), TurtleCommand::Pause => todo!(),
};
self.state.index = next_index;
Some(res)
} else {
None
} }
} }
seq }
}
#[derive(Inspectable, Default)]
pub enum TurtleGraphElement {
TurtleLine(TurtleDrawLine),
TurtleCircle(TurtleDrawCircle),
#[default]
Noop,
} }
#[derive(Clone, Component, Inspectable)] #[derive(Clone, Component, Inspectable)]
pub struct TurtleShape; pub struct TurtleShape;
#[derive(Clone, Component, Inspectable)] #[derive(Clone, Component, Inspectable, Default)]
pub struct Colors { pub struct Colors {
color: Color, color: Color,
fill_color: Color, fill_color: Color,
} }
#[derive(Inspectable, Default)]
pub struct Length(f64);
#[derive(Inspectable, Default)]
pub struct Angle(f64);
#[derive(Component, Inspectable, Default)] #[derive(Component, Inspectable, Default)]
enum TurtleCommand { pub enum TurtleCommand {
Forward(Length), Forward(Length),
Backward(Length), Backward(Length),
Left(Angle), Left(Angle<f32>),
Right(Angle), Right(Angle<f32>),
PenUp, PenUp,
PenDown, PenDown,
#[default] #[default]
Pause, Pause,
Circle, Circle {
radius: Length,
angle: Angle<f32>,
},
} }
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
let animator = Animator::new(Tween::new( let animator = Animator::new(Tween::new(
// Use a quadratic easing on both endpoints.
EaseFunction::QuadraticInOut, EaseFunction::QuadraticInOut,
// Loop animation back and forth.
TweeningType::PingPong, TweeningType::PingPong,
// Animation time (one way only; for ping-pong it takes 2 seconds Duration::from_millis(500),
// to come back to start). TransformScaleLens {
Duration::from_secs(1), start: Vec3::new(1., 1., 0.),
// The lens gives access to the Transform component of the Entity, end: Vec3::new(1.3, 1.3, 0.),
// for the Animator to animate it. It also contains the start and
// end values respectively associated with the progress ratios 0. and 1.
TransformPositionLens {
start: Vec3::ZERO,
end: Vec3::new(40., 40., 0.),
}, },
)); ));
commands.spawn_bundle(Camera2dBundle::default()); commands.spawn_bundle(Camera2dBundle::default());
let mut turtle_bundle = Turtle::default();
turtle_bundle.set_commands(circle_star());
commands commands
.spawn_bundle(Turtle::default()) .spawn_bundle(turtle_bundle)
.insert_bundle(GeometryBuilder::build_as( .insert(animator)
&turtle_shapes::turtle(), .insert(TurtleShape);
DrawMode::Outlined {
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::identity(),
))
.insert(animator);
} }
/// The sprite is animated by changing its translation depending on the time that has passed since fn draw_lines(
/// the last frame.
fn keypresses(
//time: Res<Time>,
keys: Res<Input<KeyCode>>,
mut commands: Commands, mut commands: Commands,
mut qry: Query<&mut Animator<Transform>>, mut tcmd: Query<&mut TurtleCommands>,
tcmd: Query<&TurtleCommands>, mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
mut query_event: EventReader<TweenCompleted>, // TODO: howto attach only to the right event?
) { ) {
for ev in query_event.iter() {
let mut tcmd = tcmd.single_mut();
run_animation_step(&mut commands, &mut tcmd, &mut turtle)
}
}
fn keypresses(
mut commands: Commands,
keys: Res<Input<KeyCode>>,
mut tcmd: Query<&mut TurtleCommands>,
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
) {
if keys.just_pressed(KeyCode::W) { if keys.just_pressed(KeyCode::W) {
let tcmd = tcmd.single(); let mut tcmd = tcmd.single_mut();
let c = tcmd.generate_tweenable(); tcmd.state = TurtleState {
let mut shap = qry.single_mut(); start: Vec2::ZERO,
shap.set_tweenable(c); heading: Angle::degrees(0.),
/* commands speed: 500,
.spawn_bundle(Turtle::default()) index: 0,
.insert_bundle(GeometryBuilder::build_as( drawing: true,
&turtle_shapes::turtle(), };
DrawMode::Outlined {
fill_mode: FillMode::color(Color::RED), run_animation_step(&mut commands, &mut tcmd, &mut turtle);
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
},
Transform::from_translation(Vec3::new(-100., 0., 0.)),
))
.insert(Animator::new(Tween::new(
// Use a quadratic easing on both endpoints.
EaseFunction::QuadraticInOut,
// Loop animation back and forth.
TweeningType::PingPong,
// Animation time (one way only; for ping-pong it takes 2 seconds
// to come back to start).
Duration::from_secs(1),
// The lens gives access to the Transform component of the Entity,
// for the Animator to animate it. It also contains the start and
// end values respectively associated with the progress ratios 0. and 1.
TransformPositionLens {
start: Vec3::new(-100., 0., 0.),
end: Vec3::new(-140., 40., 0.),
},
))); */
} }
} }
+143
View File
@@ -0,0 +1,143 @@
use std::time::Duration;
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
use bevy_prototype_lyon::prelude::Path;
use bevy_tweening::{
lens::{TransformPositionLens, TransformRotateZLens},
Animator, EaseFunction, Tween, TweeningType,
};
use crate::{
datatypes::angle::Angle,
primitives::{
animation::{CircleAnimationLens, CircleMovementLens, LineAnimationLens},
bundles::{TurtleDrawCircle, TurtleDrawLine},
},
turtle::{Precision, TurtleGraphElement, TurtleState},
};
pub struct TurtleStep {
pub turtle_animation: Option<Tween<Transform>>,
pub line_segment: Option<TurtleGraphElement>,
pub line_animation: Option<Animator<Path>>,
}
pub fn turtle_turn(state: &mut TurtleState, angle_to_turn: Angle<Precision>) -> TurtleStep {
let start = state.heading;
let end = state.heading + angle_to_turn;
let animation = Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
TransformRotateZLens {
start: start.to_radians().value(),
end: end.to_radians().value(),
},
)
.with_completed_event(state.index as u64);
// Don't draw as the position does not change
let line = TurtleGraphElement::Noop;
// Update the state
state.heading = end.limit_smaller_than_full_circle();
TurtleStep {
turtle_animation: Some(animation),
line_segment: Some(line),
line_animation: None,
}
}
pub fn turtle_move(state: &mut TurtleState, length: Precision) -> TurtleStep {
let start = state.start;
let end = state.start + (Vec2::from_angle(state.heading.to_radians().value()) * length);
let turtle_movement_animation = Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
TransformPositionLens {
start: start.extend(0.),
end: end.extend(0.),
},
)
.with_completed_event(state.index as u64);
let line = if state.drawing {
TurtleGraphElement::TurtleLine(TurtleDrawLine::new(start, end, state.index))
} else {
TurtleGraphElement::Noop
};
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
LineAnimationLens::new(start, end),
));
state.start = end;
TurtleStep {
turtle_animation: Some(turtle_movement_animation),
line_segment: Some(line),
line_animation: Some(line_animator),
}
}
pub fn turtle_circle(
state: &mut TurtleState,
radius: Precision,
angle: Angle<Precision>,
) -> TurtleStep {
let radii = Vec2::ONE * radius.abs();
let left_right = Angle::degrees(if radius >= 0. { 90. } else { -90. });
let center = state.start
+ (Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
((state.heading + left_right).to_radians()).value(),
)));
let turtle_movement_animation = Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
CircleMovementLens {
start: Transform {
translation: state.start.extend(0.),
rotation: Quat::from_rotation_z(state.heading.to_radians().value()),
scale: Vec3::ONE,
},
end: angle,
center,
},
)
.with_completed_event(state.index as u64);
let end_pos = center
+ Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
(state.heading + angle - left_right).to_radians().value(),
));
let line = if state.drawing {
TurtleGraphElement::TurtleCircle(TurtleDrawCircle::new(
center,
radii,
Angle::degrees(0.),
state.index,
state.start,
end_pos,
))
} else {
TurtleGraphElement::Noop
};
let line_animator = Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(state.speed),
CircleAnimationLens {
start_pos: state.start,
center,
radii,
start: Angle::degrees(0.),
end: angle,
},
));
state.start = end_pos;
state.heading = state.heading + angle;
TurtleStep {
turtle_animation: Some(turtle_movement_animation),
line_segment: Some(line),
line_animation: Some(line_animator),
}
}