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, }; use crate::{ datatypes::angle::Angle, primitives::{ animation::{CircleAnimationLens, CircleMovementLens, LineAnimationLens}, bundles::{TurtleDrawCircle, TurtleDrawLine}, }, turtle::{Precision, TurtleGraphElement, TurtleState}, }; pub struct TurtleStep { pub turtle_animation: Option>, pub line_segment: Option, pub line_animation: Option>, } pub fn turtle_turn(state: &mut TurtleState, angle_to_turn: Angle) -> TurtleStep { let start = state.heading; let end = state.heading + angle_to_turn; let animation = Tween::new( EaseFunction::QuadraticInOut, 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, 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, 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, ) -> 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, 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, 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), } }