220 lines
6.2 KiB
Rust
220 lines
6.2 KiB
Rust
pub mod builders;
|
|
pub mod state;
|
|
pub mod turtle;
|
|
use std::time::Duration;
|
|
|
|
use bevy::prelude::*;
|
|
use bevy_prototype_lyon::prelude::*;
|
|
use bevy_tweening::{
|
|
component_animator_system, lens::TransformScaleLens, Animator, EaseFunction, RepeatCount,
|
|
Tween, TweenCompleted, TweeningPlugin,
|
|
};
|
|
|
|
#[allow(unused_imports)]
|
|
use crate::paths;
|
|
use crate::{
|
|
animation_step::run_animation_step,
|
|
datatypes::{angle::Angle, length::Length},
|
|
primitives::bundles::{Turtle, TurtleDrawCircle, TurtleDrawLine},
|
|
turtle_movement::TurtleStep,
|
|
};
|
|
|
|
pub struct TurtlePlugin;
|
|
|
|
impl Plugin for TurtlePlugin {
|
|
fn build(&self, app: &mut bevy::prelude::App) {
|
|
app.add_plugin(TweeningPlugin)
|
|
.add_startup_system(setup)
|
|
.add_system(keypresses)
|
|
.add_system(draw_lines)
|
|
.add_system(component_animator_system::<Path>)
|
|
.register_type::<Colors>()
|
|
.register_type::<TurtleCommands>();
|
|
}
|
|
}
|
|
pub type Precision = f32;
|
|
|
|
#[derive(Component, Reflect)]
|
|
pub struct TurtleCommands {
|
|
commands: Vec<TurtleCommand>,
|
|
lines: Vec<TurtleGraphElement>,
|
|
state: TurtleState,
|
|
}
|
|
#[derive(Reflect)]
|
|
pub struct TurtleState {
|
|
pub start: Vec2,
|
|
pub heading: Angle<f32>,
|
|
pub speed: u64,
|
|
pub index: u64,
|
|
pub drawing: bool,
|
|
}
|
|
|
|
impl TurtleCommands {
|
|
pub fn new(commands: Vec<TurtleCommand>) -> Self {
|
|
Self {
|
|
commands,
|
|
lines: vec![],
|
|
state: TurtleState {
|
|
start: Vec2::ZERO,
|
|
heading: Angle::degrees(0.),
|
|
speed: 2000,
|
|
index: 0,
|
|
drawing: true,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TurtleCommands {
|
|
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,
|
|
fill: None,
|
|
stroke: None,
|
|
}
|
|
}
|
|
TurtleCommand::PenDown => {
|
|
self.state.drawing = true;
|
|
|
|
TurtleStep {
|
|
turtle_animation: None,
|
|
line_segment: None,
|
|
line_animation: None,
|
|
fill: None,
|
|
stroke: None,
|
|
}
|
|
}
|
|
TurtleCommand::Circle { radius, angle } => {
|
|
crate::turtle_movement::turtle_circle(&mut self.state, radius.0 as f32, *angle)
|
|
}
|
|
TurtleCommand::Pause => todo!(),
|
|
TurtleCommand::BeginFill => todo!(),
|
|
TurtleCommand::EndFill => todo!(),
|
|
};
|
|
self.state.index = next_index;
|
|
Some(res)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Reflect, Default)]
|
|
pub enum TurtleGraphElement {
|
|
TurtleLine(TurtleDrawLine),
|
|
TurtleCircle(TurtleDrawCircle),
|
|
#[default]
|
|
Noop,
|
|
}
|
|
|
|
#[derive(Clone, Component, Reflect)]
|
|
pub struct TurtleShape;
|
|
|
|
#[derive(Clone, Component, Reflect, Default)]
|
|
pub struct Colors {
|
|
color: Color,
|
|
fill_color: Color,
|
|
}
|
|
|
|
#[derive(Component, Reflect, Default)]
|
|
pub enum TurtleCommand {
|
|
Forward(Length),
|
|
Backward(Length),
|
|
Left(Angle<f32>),
|
|
Right(Angle<f32>),
|
|
PenUp,
|
|
PenDown,
|
|
BeginFill,
|
|
EndFill,
|
|
#[default]
|
|
Pause,
|
|
Circle {
|
|
radius: Length,
|
|
angle: Angle<f32>,
|
|
},
|
|
}
|
|
|
|
fn setup(mut commands: Commands) {
|
|
let animator = Animator::new(
|
|
Tween::new(
|
|
EaseFunction::QuadraticInOut,
|
|
Duration::from_millis(500),
|
|
TransformScaleLens {
|
|
start: Vec3::new(1., 1., 0.),
|
|
end: Vec3::new(1.3, 1.3, 0.),
|
|
},
|
|
)
|
|
.with_repeat_strategy(bevy_tweening::RepeatStrategy::MirroredRepeat)
|
|
.with_repeat_count(RepeatCount::Infinite),
|
|
);
|
|
commands.spawn(Camera2dBundle::default());
|
|
let mut turtle_bundle = Turtle::default();
|
|
let mut tcommands = vec![];
|
|
//for _ in 0..100 {
|
|
tcommands.append(&mut paths::geometry_task::geometry_task());
|
|
//tcommands.append(&mut paths::circle_star::circle_star());
|
|
//}
|
|
turtle_bundle.set_commands(tcommands);
|
|
commands.spawn((
|
|
turtle_bundle,
|
|
animator,
|
|
TurtleShape,
|
|
Fill::color(Color::MIDNIGHT_BLUE),
|
|
Stroke::color(Color::BLACK),
|
|
));
|
|
}
|
|
|
|
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() {
|
|
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) {
|
|
let mut tcmd = tcmd.single_mut();
|
|
tcmd.state = TurtleState {
|
|
start: Vec2::ZERO,
|
|
heading: Angle::degrees(0.),
|
|
speed: 1,
|
|
index: 0,
|
|
drawing: true,
|
|
};
|
|
|
|
run_animation_step(&mut commands, &mut tcmd, &mut turtle);
|
|
}
|
|
}
|