use std::f64::consts::{PI, TAU};
use limited_direction::{RigidWalk, WalkAct};
use macroquad::{
input::{is_key_down, KeyCode},
prelude::*,
};
const BG: Color = color_u8!(30, 30, 40, 255);
#[macroquad::main("Rigid Walk Visualizer")]
async fn main() {
enum Algo {
Walk4,
Walk8,
}
impl Algo {
fn cycle(&self) -> Algo {
match self {
Algo::Walk4 => Algo::Walk8,
Algo::Walk8 => Algo::Walk4,
}
}
}
let change_angle_speed = PI / 500.0;
let change_distance_speed = 1.0f64;
let change_offset_speed = 0.5f64;
let mut angle = 0.0f64;
let mut distance = 300.0f64;
let mut offset = 10.0f64;
let mut algorithm = Algo::Walk8;
loop {
clear_background(BG);
angle += change_angle_speed;
angle = angle % TAU;
if is_key_down(KeyCode::W) {
distance += change_distance_speed;
}
if is_key_down(KeyCode::S) {
distance -= change_distance_speed;
}
if is_key_down(KeyCode::A) {
offset -= change_offset_speed;
if offset < 0.5 {
offset = 0.5;
}
}
if is_key_down(KeyCode::D) {
offset += change_offset_speed;
}
if is_key_pressed(KeyCode::N) {
algorithm = algorithm.cycle();
}
let mid_x = screen_width() / 2.0;
let mid_y = screen_height() / 2.0;
draw_stump_line_angle(mid_x, mid_y, angle, distance, 2.0, GRAY);
draw_offset(
mid_x,
mid_y,
angle,
offset,
distance,
color_u8!(75, 75, 75, 255),
);
let walk = match algorithm {
Algo::Walk4 => RigidWalk::walk4(angle, distance, offset),
Algo::Walk8 => RigidWalk::walk8(angle, distance, offset),
};
draw_walk(mid_x, mid_y, &walk);
next_frame().await
}
}
fn draw_walk(x: f32, y: f32, walk: &RigidWalk) {
let mut turtle_x = x as f64;
let mut turtle_y = y as f64;
let color = [RED, GREEN, BLUE];
for (i, WalkAct { angle, distance }) in walk.iter_full(false).enumerate() {
let x1 = turtle_x;
let y1 = turtle_y;
let x2 = x1 + angle.sin() * distance;
let y2 = y1 + angle.cos() * distance;
turtle_x += angle.sin() * distance;
turtle_y += angle.cos() * distance;
draw_stump_line(
x1 as f32,
y1 as f32,
x2 as f32,
y2 as f32,
5.0,
color[i % color.len()],
);
}
}
fn draw_offset(x: f32, y: f32, angle: f64, offset: f64, length: f64, color: Color) {
draw_stump_dotted_line_angle(
x + ((PI - angle).cos() * offset) as f32,
y + ((PI - angle).sin() * offset) as f32,
angle,
length,
2.0,
5.0,
color,
);
draw_stump_dotted_line_angle(
x - ((PI - angle).cos() * offset) as f32,
y - ((PI - angle).sin() * offset) as f32,
angle,
length,
2.0,
5.0,
color,
);
}
fn draw_stump_dotted_line(
x1: f32,
y1: f32,
x2: f32,
y2: f32,
dot_length: f32,
thickness: f32,
color: Color,
) {
let mut switch = true;
let height = y2 - y1;
let base = x2 - x1;
let length = (height * height + base * base).sqrt();
let dot_height = height * dot_length / length;
let dot_base = base * dot_length / length;
let mut x = x1;
let mut y = y1;
for _ in 0..((length / dot_length) as u32) {
let x1 = x;
let y1 = y;
let x2 = x + dot_height;
let y2 = y + dot_base;
if switch {
draw_stump_line(x1, y1, x2, y2, thickness, color);
}
x += dot_height;
y += dot_base;
switch = !switch;
}
}
fn draw_stump_dotted_line_angle(
x: f32,
y: f32,
angle: f64,
length: f64,
thickness: f32,
dot_length: f32,
color: Color,
) {
draw_stump_dotted_line(
x,
y,
x + (angle.cos() * length) as f32,
y + (angle.sin() * length) as f32,
dot_length,
thickness,
color,
)
}
fn draw_stump_line_angle(x: f32, y: f32, angle: f64, length: f64, thickness: f32, color: Color) {
draw_stump_line(
x,
y,
x + (angle.sin() * length) as f32,
y + (angle.cos() * length) as f32,
thickness,
color,
);
}
fn draw_stump_line(x1: f32, y1: f32, x2: f32, y2: f32, thickness: f32, color: Color) {
draw_circle(x1, y1, thickness / 2.0, color);
draw_circle(x2, y2, thickness / 2.0, color);
draw_line(x1, y1, x2, y2, thickness, color);
}