first port to modern bevy
This commit is contained in:
+32
-16
@@ -1,25 +1,22 @@
|
||||
use bevy::{
|
||||
prelude::Component,
|
||||
reflect::{FromReflect, Reflect},
|
||||
};
|
||||
use bevy::{prelude::Component, reflect::Reflect};
|
||||
|
||||
use crate::{
|
||||
builders::WithCommands,
|
||||
drawing::{
|
||||
animation::{
|
||||
draw_circle_segment, draw_straight_segment, move_straight_segment, turtle_turn,
|
||||
ToAnimationSegment, TurtleAnimationSegment,
|
||||
},
|
||||
TurtleGraphElement,
|
||||
},
|
||||
drawing::TurtleGraphElement,
|
||||
general::{angle::Angle, length::Length, Coordinate, Precision, Speed},
|
||||
state::TurtleState,
|
||||
};
|
||||
|
||||
#[cfg(feature = "tweening")]
|
||||
use crate::drawing::animation::{
|
||||
draw_circle_segment, draw_straight_segment, move_straight_segment, turtle_turn,
|
||||
ToAnimationSegment, TurtleAnimationSegment,
|
||||
};
|
||||
/**
|
||||
* All the possibilities to draw something with turtle. All the commands can get the position, heading,
|
||||
* color and fill_color from the turtles state.
|
||||
*/
|
||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
||||
#[derive(Component, Reflect, Debug, Clone)]
|
||||
pub enum MoveCommand {
|
||||
Forward(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.
|
||||
|
||||
#[derive(Component, Reflect, FromReflect, Default, Debug, Clone)]
|
||||
#[derive(Component, Reflect, Default, Debug, Clone)]
|
||||
pub enum Breadcrumb {
|
||||
Dot,
|
||||
#[default]
|
||||
@@ -45,7 +42,7 @@ pub enum Breadcrumb {
|
||||
}
|
||||
|
||||
/// Different ways that change the orientation of the turtle.
|
||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
||||
#[derive(Component, Reflect, Debug, Clone)]
|
||||
pub enum OrientationCommand {
|
||||
Left(Angle<Precision>),
|
||||
Right(Angle<Precision>),
|
||||
@@ -60,7 +57,7 @@ impl Default for OrientationCommand {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Draw(MoveCommand),
|
||||
Move(MoveCommand),
|
||||
@@ -73,6 +70,8 @@ impl Default for DrawElement {
|
||||
Self::Draw(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tweening")]
|
||||
impl ToAnimationSegment for DrawElement {
|
||||
fn to_draw_segment(
|
||||
&self,
|
||||
@@ -104,7 +103,7 @@ impl ToAnimationSegment for DrawElement {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Reflect, FromReflect, Debug, Clone)]
|
||||
#[derive(Component, Reflect, Debug, Clone)]
|
||||
pub enum TurtleSegment {
|
||||
Single(DrawElement),
|
||||
Outline(Vec<DrawElement>),
|
||||
@@ -116,6 +115,8 @@ impl Default for TurtleSegment {
|
||||
Self::Single(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tweening")]
|
||||
impl ToAnimationSegment for TurtleSegment {
|
||||
fn to_draw_segment(
|
||||
&self,
|
||||
@@ -156,8 +157,23 @@ impl TurtleCommands {
|
||||
pub fn set_speed(&mut self, speed: Speed) {
|
||||
self.state.set_speed(speed);
|
||||
}
|
||||
|
||||
// Public accessors for immediate drawing
|
||||
pub(crate) fn animation_state(&self) -> usize {
|
||||
self.animation_state
|
||||
}
|
||||
pub(crate) fn animation_state_mut(&mut self) -> &mut usize {
|
||||
&mut self.animation_state
|
||||
}
|
||||
pub(crate) fn commands(&self) -> &[TurtleSegment] {
|
||||
&self.commands
|
||||
}
|
||||
pub(crate) fn state_mut(&mut self) -> &mut TurtleState {
|
||||
&mut self.state
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tweening")]
|
||||
impl Iterator for TurtleCommands {
|
||||
type Item = TurtleAnimationSegment;
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use bevy::prelude::Plugin;
|
||||
#[cfg(feature = "inspector")]
|
||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||
|
||||
pub struct DebugPlugin;
|
||||
|
||||
impl Plugin for DebugPlugin {
|
||||
fn build(&self, app: &mut bevy::prelude::App) {
|
||||
fn build(&self, _app: &mut bevy::prelude::App) {
|
||||
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};
|
||||
|
||||
#[cfg(feature = "tweening")]
|
||||
pub mod animation;
|
||||
#[cfg(not(feature = "tweening"))]
|
||||
pub(crate) mod immediate;
|
||||
mod line_segments;
|
||||
#[cfg(feature = "tweening")]
|
||||
pub(crate) mod run_step;
|
||||
|
||||
#[derive(Reflect, FromReflect, Default, Debug)]
|
||||
#[derive(Reflect, Default, Debug)]
|
||||
pub enum TurtleGraphElement {
|
||||
TurtleLine(TurtleDrawLine),
|
||||
TurtleCircle(TurtleDrawCircle),
|
||||
|
||||
@@ -2,7 +2,7 @@ mod circle_lens;
|
||||
mod line_lens;
|
||||
|
||||
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
|
||||
use bevy_prototype_lyon::prelude::Path;
|
||||
use bevy_prototype_lyon::prelude::Shape;
|
||||
use bevy_tweening::{
|
||||
lens::{TransformPositionLens, TransformRotateZLens},
|
||||
Animator, EaseFunction, Tween,
|
||||
@@ -23,7 +23,7 @@ use super::{TurtleDrawCircle, TurtleDrawLine, TurtleGraphElement};
|
||||
pub struct TurtleAnimationSegment {
|
||||
pub turtle_animation: Option<Tween<Transform>>,
|
||||
pub line_segment: Option<TurtleGraphElement>,
|
||||
pub line_animation: Option<Animator<Path>>,
|
||||
pub line_animation: Option<Animator<Shape>>,
|
||||
}
|
||||
|
||||
pub trait ToAnimationSegment {
|
||||
@@ -102,7 +102,7 @@ struct MoveStraightLineAnimation {
|
||||
_start: Coordinate,
|
||||
_end: Coordinate,
|
||||
line: TurtleDrawLine,
|
||||
animation: Tween<Path>,
|
||||
animation: Tween<Shape>,
|
||||
}
|
||||
|
||||
impl MoveStraightLineAnimation {
|
||||
@@ -159,7 +159,7 @@ struct MoveCircleLineAnimation {
|
||||
_start: Coordinate,
|
||||
_end: Coordinate,
|
||||
line: TurtleDrawCircle,
|
||||
animation: Tween<Path>,
|
||||
animation: Tween<Shape>,
|
||||
}
|
||||
|
||||
impl MoveCircleLineAnimation {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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 crate::general::{angle::Angle, Precision};
|
||||
@@ -12,12 +13,12 @@ pub(crate) struct CircleAnimationLens {
|
||||
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);
|
||||
impl Lens<Shape> for CircleAnimationLens {
|
||||
fn lerp(&mut self, target: &mut Shape, ratio: f32) {
|
||||
let mut path = ShapePath::new();
|
||||
path = path.move_to(self.start_pos);
|
||||
// The center point of the radius, then the radii in x and y direction, then the angle that will be drawn, then the x_rotation ?
|
||||
path_builder.arc(
|
||||
path = path.arc(
|
||||
self.center,
|
||||
self.radii,
|
||||
(self.start + ((self.end - self.start) * ratio))
|
||||
@@ -25,8 +26,7 @@ impl Lens<Path> for CircleAnimationLens {
|
||||
.value(),
|
||||
0.,
|
||||
);
|
||||
let line = path_builder.build();
|
||||
*target = ShapePath::build_as(&line);
|
||||
*target = Shape::from(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use bevy::prelude::Vec2;
|
||||
use bevy_prototype_lyon::{
|
||||
prelude::{Path, ShapePath},
|
||||
shapes,
|
||||
};
|
||||
use bevy_prototype_lyon::{prelude::{Shape, ShapePath}, shapes};
|
||||
use bevy_tweening::Lens;
|
||||
|
||||
pub(crate) struct LineAnimationLens {
|
||||
@@ -16,9 +13,9 @@ impl LineAnimationLens {
|
||||
}
|
||||
}
|
||||
|
||||
impl Lens<Path> for LineAnimationLens {
|
||||
fn lerp(&mut self, target: &mut Path, ratio: f32) {
|
||||
impl Lens<Shape> for LineAnimationLens {
|
||||
fn lerp(&mut self, target: &mut Shape, ratio: f32) {
|
||||
let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio));
|
||||
*target = ShapePath::build_as(&line);
|
||||
*target = Shape::from(ShapePath::build_as(&line));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::{
|
||||
prelude::{Bundle, Color, Component, Name, Transform, Vec2},
|
||||
reflect::{FromReflect, Reflect},
|
||||
prelude::{Bundle, Color, Component, Name, Vec2},
|
||||
reflect::Reflect,
|
||||
};
|
||||
use bevy_prototype_lyon::{
|
||||
entity::ShapeBundle,
|
||||
prelude::{DrawMode, FillMode, GeometryBuilder, PathBuilder, StrokeMode},
|
||||
draw::{Fill, Stroke},
|
||||
entity::Shape,
|
||||
geometry::ShapeBuilder,
|
||||
path::ShapePath,
|
||||
prelude::ShapeBuilderBase as _,
|
||||
shapes::Line,
|
||||
};
|
||||
|
||||
use crate::general::{angle::Angle, Precision};
|
||||
|
||||
#[derive(Bundle, Reflect, FromReflect, Default)]
|
||||
#[derive(Bundle, Reflect, Default)]
|
||||
pub struct TurtleDrawLine {
|
||||
#[reflect(ignore)]
|
||||
line: ShapeBundle,
|
||||
line: Shape,
|
||||
name: Name,
|
||||
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;
|
||||
|
||||
impl TurtleDrawLine {
|
||||
pub(crate) fn new(start: Vec2, end: Vec2) -> Self {
|
||||
let line = Line(start, end);
|
||||
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,
|
||||
),
|
||||
line: ShapeBuilder::with(&line)
|
||||
.fill(Fill::color(Color::NONE))
|
||||
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||
.build(),
|
||||
name: Name::new(format!("Line {}-{}", start, end)),
|
||||
marker: LineMarker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Bundle, Reflect, FromReflect, Default)]
|
||||
#[derive(Bundle, Reflect, Default)]
|
||||
|
||||
pub struct TurtleDrawCircle {
|
||||
#[reflect(ignore)]
|
||||
line: ShapeBundle,
|
||||
line: Shape,
|
||||
name: Name,
|
||||
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;
|
||||
|
||||
impl TurtleDrawCircle {
|
||||
@@ -76,25 +76,22 @@ impl TurtleDrawCircle {
|
||||
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();
|
||||
let path =
|
||||
ShapePath::new()
|
||||
.move_to(start)
|
||||
.arc(center, radii, angle.to_radians().value(), 0.);
|
||||
|
||||
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,
|
||||
),
|
||||
line: ShapeBuilder::with(&path)
|
||||
.fill(Fill::color(Color::NONE))
|
||||
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||
.build(),
|
||||
name: Name::new(format!("Circle at {}, {}", center.x, center.y)),
|
||||
marker: CircleMarker,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use bevy::prelude::Entity;
|
||||
use bevy::prelude::{Entity, Message};
|
||||
|
||||
#[derive(Message)]
|
||||
pub struct DrawingStartedEvent(pub Entity);
|
||||
|
||||
@@ -3,28 +3,28 @@ use std::{
|
||||
ops::{Add, Div, Mul, Neg, Rem, Sub},
|
||||
};
|
||||
|
||||
use bevy::reflect::{FromReflect, Reflect};
|
||||
use bevy::reflect::Reflect;
|
||||
|
||||
use super::Precision;
|
||||
|
||||
#[derive(Reflect, FromReflect, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AngleUnit<T: Default + Send + Sync + Reflect + Copy + FromReflect> {
|
||||
#[derive(Reflect, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AngleUnit<T: Default + Send + Sync + Reflect + Copy> {
|
||||
Degrees(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 {
|
||||
Self::Degrees(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Reflect, FromReflect, Copy, Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Angle<T: Default + Send + Sync + Reflect + Copy + FromReflect> {
|
||||
#[derive(Reflect, Copy, Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Angle<T: Default + Send + Sync + Reflect + Copy> {
|
||||
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 {
|
||||
Self {
|
||||
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>
|
||||
for Angle<T>
|
||||
{
|
||||
impl<T: Default + Send + Sync + Reflect + Clone + Copy + Rem<T, Output = T>> Rem<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
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>
|
||||
for Angle<T>
|
||||
{
|
||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + Mul<T, Output = T>> Mul<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
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>
|
||||
for Angle<T>
|
||||
{
|
||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + Div<T, Output = T>> Div<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
@@ -83,9 +77,8 @@ impl<T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + Div<T, Ou
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + std::ops::Neg<Output = T>,
|
||||
> Neg for Angle<T>
|
||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + std::ops::Neg<Output = T>> Neg
|
||||
for Angle<T>
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
@@ -97,9 +90,8 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: Default + Clone + Send + Sync + Reflect + Copy + FromReflect + std::ops::Neg<Output = T>,
|
||||
> Neg for &Angle<T>
|
||||
impl<T: Default + Clone + Send + Sync + Reflect + Copy + std::ops::Neg<Output = T>> Neg
|
||||
for &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> {
|
||||
Self {
|
||||
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 {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self {
|
||||
@@ -149,16 +141,8 @@ impl<T: Default + Send + Sync + Reflect + Copy + FromReflect + num_traits::float
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: Add<Output = T>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Reflect
|
||||
+ Copy
|
||||
+ FromReflect
|
||||
+ Default
|
||||
+ num_traits::float::Float,
|
||||
> Add for Angle<T>
|
||||
impl<T: Add<Output = T> + Send + Sync + Reflect + Copy + Default + num_traits::float::Float> Add
|
||||
for Angle<T>
|
||||
{
|
||||
type Output = Angle<T>;
|
||||
|
||||
@@ -180,16 +164,8 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: Sub<Output = T>
|
||||
+ Default
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Reflect
|
||||
+ Copy
|
||||
+ FromReflect
|
||||
+ num_traits::float::Float,
|
||||
> Sub for Angle<T>
|
||||
impl<T: Sub<Output = T> + Default + Send + Sync + Reflect + Copy + num_traits::float::Float> Sub
|
||||
for Angle<T>
|
||||
{
|
||||
type Output = Angle<T>;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use bevy::reflect::{FromReflect, Reflect};
|
||||
use bevy::reflect::Reflect;
|
||||
|
||||
use super::Precision;
|
||||
|
||||
#[derive(Reflect, FromReflect, Default, Copy, Clone, Debug)]
|
||||
#[derive(Reflect, Default, Copy, Clone, Debug)]
|
||||
pub struct Length(pub Precision);
|
||||
|
||||
impl From<i16> for Length {
|
||||
|
||||
+59
-32
@@ -1,10 +1,11 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::close_on_esc};
|
||||
use bevy_prototype_lyon::prelude::{Path, ShapePlugin};
|
||||
use bevy::{prelude::*, window::WindowResolution};
|
||||
#[cfg(feature = "tweening")]
|
||||
use bevy_prototype_lyon::entity::Shape;
|
||||
use bevy_prototype_lyon::prelude::ShapePlugin;
|
||||
#[cfg(feature = "tweening")]
|
||||
use bevy_tweening::{
|
||||
component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, Tween,
|
||||
TweenCompleted, TweeningPlugin,
|
||||
TweenCompleted,
|
||||
};
|
||||
use events::DrawingStartedEvent;
|
||||
use shapes::{TurtleColors, TurtleShape};
|
||||
@@ -38,39 +39,42 @@ pub struct TurtlePlugin;
|
||||
impl Plugin for TurtlePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||
window: WindowDescriptor {
|
||||
primary_window: Some(Window {
|
||||
title: "Immigration Game".to_string(),
|
||||
width: 1200.,
|
||||
height: 800.,
|
||||
present_mode: bevy::window::PresentMode::Fifo, // vsync
|
||||
..Default::default()
|
||||
},
|
||||
resolution: WindowResolution::new(1200, 800),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}))
|
||||
.add_plugin(debug::DebugPlugin)
|
||||
.add_plugin(ShapePlugin)
|
||||
.add_plugin(TweeningPlugin)
|
||||
.add_event::<DrawingStartedEvent>()
|
||||
.add_startup_system(setup)
|
||||
.add_system(keypresses)
|
||||
.add_system(component_animator_system::<Path>)
|
||||
.add_system(close_on_esc)
|
||||
.add_system(draw_lines)
|
||||
.add_plugins(debug::DebugPlugin)
|
||||
.add_plugins(ShapePlugin)
|
||||
.add_message::<DrawingStartedEvent>()
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
keypresses,
|
||||
#[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::<TurtleCommands>();
|
||||
}
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands) {
|
||||
commands.spawn(Camera2dBundle {
|
||||
camera_2d: Camera2d {
|
||||
clear_color: ClearColorConfig::Custom(Color::BEIGE),
|
||||
},
|
||||
..default()
|
||||
});
|
||||
commands.spawn((Camera2d,));
|
||||
}
|
||||
|
||||
pub fn get_a_turtle() -> AnimatedTurtle {
|
||||
#[cfg(feature = "tweening")]
|
||||
let animator = Animator::new(Tween::new(
|
||||
EaseFunction::QuadraticInOut,
|
||||
Duration::from_millis(3000),
|
||||
@@ -79,6 +83,8 @@ pub fn get_a_turtle() -> AnimatedTurtle {
|
||||
end: Vec3::ONE * 1.3,
|
||||
},
|
||||
));
|
||||
#[cfg(not(feature = "tweening"))]
|
||||
let animator = ();
|
||||
let turtle_bundle = TurtleBundle::default();
|
||||
AnimatedTurtle {
|
||||
animator,
|
||||
@@ -89,26 +95,33 @@ pub fn get_a_turtle() -> AnimatedTurtle {
|
||||
|
||||
fn keypresses(
|
||||
mut commands: Commands,
|
||||
keys: Res<Input<KeyCode>>,
|
||||
_keys: Res<ButtonInput<KeyCode>>,
|
||||
mut tcmd: Query<(Entity, &mut TurtleCommands)>,
|
||||
mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
||||
mut ev_start: EventWriter<DrawingStartedEvent>,
|
||||
#[cfg(feature = "tweening")] mut turtle: Query<&mut Animator<Transform>, With<TurtleShape>>,
|
||||
#[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() {
|
||||
#[cfg(feature = "tweening")]
|
||||
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(
|
||||
mut commands: Commands,
|
||||
mut tcmd: Query<&mut 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() {
|
||||
for _ev in query_event.read() {
|
||||
if let Ok(mut tcmd) = tcmd.get_single_mut() {
|
||||
crate::drawing::run_step::run_animation_step(&mut commands, &mut tcmd, &mut turtle)
|
||||
} else {
|
||||
@@ -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 bevy::prelude::Vec2;
|
||||
use bevy_prototype_lyon::prelude::{Path, PathBuilder};
|
||||
use bevy_prototype_lyon::prelude::ShapePath;
|
||||
|
||||
use crate::general::Precision;
|
||||
|
||||
pub fn turtle() -> Path {
|
||||
pub fn turtle() -> ShapePath {
|
||||
let polygon: &[[Precision; 2]; 23] = &[
|
||||
[-2.5, 14.0],
|
||||
[-1.25, 10.0],
|
||||
@@ -31,16 +31,16 @@ pub fn turtle() -> Path {
|
||||
[1.25, 10.0],
|
||||
[2.5, 14.0],
|
||||
];
|
||||
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));
|
||||
turtle_path.line_to(Vec2::new(-1.0, -1.0));
|
||||
turtle_path.line_to(Vec2::new(1.0, -1.0));
|
||||
turtle_path.close();
|
||||
turtle_path.move_to(Vec2::new(0.0, 16.0).rotate(Vec2::from_angle(-PI / 2.)));
|
||||
let mut turtle_path = ShapePath::new()
|
||||
.line_to(Vec2::new(1.0, 1.0))
|
||||
.line_to(Vec2::new(-1.0, 1.0))
|
||||
.line_to(Vec2::new(-1.0, -1.0))
|
||||
.line_to(Vec2::new(1.0, -1.0))
|
||||
.close()
|
||||
.move_to(Vec2::new(0.0, 16.0).rotate(Vec2::from_angle(-PI / 2.)));
|
||||
|
||||
for coord in polygon {
|
||||
turtle_path.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.build()
|
||||
turtle_path.close()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use bevy::prelude::{Bundle, Color, Name, Transform};
|
||||
use bevy::prelude::{Bundle, Color, Name};
|
||||
use bevy_prototype_lyon::{
|
||||
entity::ShapeBundle,
|
||||
prelude::{DrawMode, FillMode, GeometryBuilder, StrokeMode},
|
||||
draw::{Fill, Stroke},
|
||||
entity::Shape,
|
||||
geometry::ShapeBuilder,
|
||||
prelude::ShapeBuilderBase as _,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -21,7 +23,7 @@ pub struct TurtleBundle {
|
||||
colors: TurtleColors,
|
||||
pub commands: TurtleCommands,
|
||||
name: Name,
|
||||
shape: ShapeBundle,
|
||||
shape: Shape,
|
||||
}
|
||||
|
||||
impl Default for TurtleBundle {
|
||||
@@ -30,14 +32,10 @@ impl Default for TurtleBundle {
|
||||
colors: TurtleColors::default(),
|
||||
commands: TurtleCommands::new(vec![]),
|
||||
name: Name::new("Turtle"),
|
||||
shape: GeometryBuilder::build_as(
|
||||
&shapes::turtle(),
|
||||
DrawMode::Outlined {
|
||||
fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
|
||||
outline_mode: StrokeMode::new(Color::BLACK, 1.0),
|
||||
},
|
||||
Transform::IDENTITY,
|
||||
),
|
||||
shape: ShapeBuilder::with(&shapes::turtle())
|
||||
.fill(Fill::color(Color::srgb(0.098, 0.098, 0.439)))
|
||||
.stroke(Stroke::new(Color::srgb(0.0, 0.0, 0.0), 1.0))
|
||||
.build(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +60,10 @@ impl TurtleBundle {
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct AnimatedTurtle {
|
||||
#[cfg(feature = "tweening")]
|
||||
pub animator: bevy_tweening::Animator<bevy::prelude::Transform>,
|
||||
#[cfg(not(feature = "tweening"))]
|
||||
pub animator: (),
|
||||
pub turtle_bundle: TurtleBundle,
|
||||
pub turtle_shape: shapes::TurtleShape,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user