120 lines
3.8 KiB
Rust
120 lines
3.8 KiB
Rust
use std::{f32::consts::PI, time::Duration};
|
|
|
|
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
|
|
use bevy_tweening::{
|
|
lens::{TransformPositionLens, TransformRotateAxisLens, TransformRotateZLens},
|
|
EaseFunction, Tween, TweeningType,
|
|
};
|
|
|
|
use crate::{
|
|
datatypes::angle::Angle,
|
|
primitives::{CircleAnimationLens, CircleMovementLens},
|
|
turtle::{TurtleGraphElement, TurtleState},
|
|
};
|
|
|
|
pub fn turtle_turn(
|
|
state: &mut TurtleState,
|
|
angle_to_turn: Angle<f32>,
|
|
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
|
let start = state.heading;
|
|
let end = state.heading + angle_to_turn;
|
|
let animation = Tween::new(
|
|
// Use a quadratic easing on both endpoints
|
|
EaseFunction::QuadraticInOut,
|
|
TweeningType::Once,
|
|
// Animation time
|
|
Duration::from_millis(state.speed),
|
|
// Rotate the turtle
|
|
TransformRotateZLens {
|
|
start: start.to_radians().value(),
|
|
end: end.to_radians().value(),
|
|
},
|
|
)
|
|
.with_completed_event(state.index as u64);
|
|
// Dont move and draw
|
|
let line = TurtleGraphElement::Noop;
|
|
// Update the state
|
|
state.heading = end.limit_smaller_than_full_circle();
|
|
(Some(animation), Some(line))
|
|
}
|
|
|
|
pub fn turtle_move(
|
|
state: &mut TurtleState,
|
|
length: f32,
|
|
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
|
let start = state.start;
|
|
let end = state.start + (Vec2::from_angle(state.heading.to_radians().value()) * length);
|
|
let turtle_movement_animation = Tween::new(
|
|
// accelerate and decelerate
|
|
EaseFunction::QuadraticInOut,
|
|
TweeningType::Once,
|
|
// later to be controlled by speed
|
|
Duration::from_millis(state.speed),
|
|
// set the start and end of the animation
|
|
TransformPositionLens {
|
|
start: start.extend(0.),
|
|
end: end.extend(0.),
|
|
},
|
|
)
|
|
.with_completed_event(state.index as u64);
|
|
// The line for animating and drawing
|
|
let line = if state.drawing {
|
|
TurtleGraphElement::TurtleLine { start, end }
|
|
} else {
|
|
TurtleGraphElement::Noop
|
|
};
|
|
state.start = end;
|
|
(Some(turtle_movement_animation), Some(line))
|
|
}
|
|
|
|
pub fn turtle_circle(
|
|
state: &mut TurtleState,
|
|
radius: f32,
|
|
angle: Angle<f32>,
|
|
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
|
let radius_tuple = 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(
|
|
// accelerate and decelerate
|
|
EaseFunction::QuadraticInOut,
|
|
TweeningType::Once,
|
|
// later to be controlled by speed
|
|
Duration::from_millis(state.speed),
|
|
// set the start and end of the animation
|
|
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);
|
|
// The line for animating and drawing
|
|
let line = if state.drawing {
|
|
TurtleGraphElement::TurtleCircle {
|
|
center,
|
|
radii: radius_tuple,
|
|
angle,
|
|
start: state.start,
|
|
end: state.start,
|
|
}
|
|
} else {
|
|
TurtleGraphElement::Noop
|
|
};
|
|
let end_pos = center
|
|
+ Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
|
|
(state.heading + angle - left_right).to_radians().value(),
|
|
));
|
|
state.start = end_pos;
|
|
state.heading = state.heading + angle;
|
|
(Some(turtle_movement_animation), Some(line))
|
|
}
|