use std::error::Error;
use std::time::Duration;
use macroquad::prelude::*;
fn window_conf() -> Conf {
Conf {
window_title: "Ferris Follows the Cursor".to_owned(),
window_width: 900,
window_height: 700,
window_resizable: true,
..Default::default()
}
}
use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::FindWindowW};
use windows::core::w;
fn get_hwnd() -> Option<HWND> {
unsafe { FindWindowW(None, w!("Ferris Follows the Cursor")).ok() }
}
fn draw_ferris(pos: Vec2, look_dir: Vec2, time: f32, moving: bool) {
let bob = if moving {
(time * 12.0).sin() * 3.0
} else {
0.0
};
let body_y = pos.y + bob;
let body_center = Vec2::new(pos.x, body_y);
let body_color = Color::from_rgba(196, 85, 8, 255); let dark_orange = Color::from_rgba(150, 60, 5, 255);
let claw_color = Color::from_rgba(220, 100, 20, 255);
let eye_white = Color::from_rgba(255, 255, 255, 255);
let pupil_color = Color::from_rgba(20, 20, 20, 255);
draw_ellipse(
body_center.x,
pos.y + 30.0,
50.0,
12.0,
0.0,
Color::from_rgba(0, 0, 0, 80),
);
let leg_color = dark_orange;
for i in 0..3 {
let x_offset = 25.0 + i as f32 * 8.0;
let y_offset = 15.0 + i as f32 * 6.0;
draw_line(
body_center.x - 30.0,
body_center.y + 10.0,
body_center.x - x_offset - 5.0,
body_center.y + y_offset,
3.0,
leg_color,
);
draw_line(
body_center.x + 30.0,
body_center.y + 10.0,
body_center.x + x_offset + 5.0,
body_center.y + y_offset,
3.0,
leg_color,
);
}
draw_circle(body_center.x - 55.0, body_center.y - 10.0, 18.0, claw_color);
draw_circle(body_center.x + 55.0, body_center.y - 10.0, 18.0, claw_color);
draw_line(
body_center.x - 55.0,
body_center.y - 10.0,
body_center.x - 70.0,
body_center.y - 20.0,
4.0,
claw_color,
);
draw_line(
body_center.x - 55.0,
body_center.y - 10.0,
body_center.x - 70.0,
body_center.y,
4.0,
claw_color,
);
draw_line(
body_center.x + 55.0,
body_center.y - 10.0,
body_center.x + 70.0,
body_center.y - 20.0,
4.0,
claw_color,
);
draw_line(
body_center.x + 55.0,
body_center.y - 10.0,
body_center.x + 70.0,
body_center.y,
4.0,
claw_color,
);
draw_ellipse(body_center.x, body_center.y, 80.0, 50.0, 0.0, body_color);
draw_ellipse(
body_center.x - 10.0,
body_center.y - 8.0,
30.0,
18.0,
0.0,
Color::from_rgba(240, 130, 40, 120),
);
draw_line(
body_center.x - 18.0,
body_center.y - 22.0,
body_center.x - 18.0,
body_center.y - 42.0,
4.0,
dark_orange,
);
draw_line(
body_center.x + 18.0,
body_center.y - 22.0,
body_center.x + 18.0,
body_center.y - 42.0,
4.0,
dark_orange,
);
let eye_offset = look_dir.normalize_or_zero() * 2.5;
let eye_y = body_center.y - 45.0;
draw_circle(body_center.x - 18.0, eye_y, 7.0, eye_white);
draw_circle(body_center.x + 18.0, eye_y, 7.0, eye_white);
draw_circle(
body_center.x - 18.0 + eye_offset.x,
eye_y + eye_offset.y,
3.5,
pupil_color,
);
draw_circle(
body_center.x + 18.0 + eye_offset.x,
eye_y + eye_offset.y,
3.5,
pupil_color,
);
draw_line(
body_center.x - 5.0,
body_center.y + 10.0,
body_center.x + 5.0,
body_center.y + 10.0,
2.0,
dark_orange,
);
}
#[macroquad::main(window_conf)]
async fn main() -> Result<(), Box<dyn Error>> {
let mut crab_pos = Vec2::new(screen_width() / 2.0, screen_height() / 2.0);
let mut target = crab_pos;
let mut flash = 0.0;
let mut flash_pos = Vec2::new(0.0, 0.0);
let hwnd = get_hwnd().unwrap();
let click_forwarder = wallopino::EventForwarder::new(hwnd.0 as _, None, true, false)?;
click_forwarder.forward_events()?;
let mut attacher = wallopino::AttachWindow::auto_attach(hwnd.0 as _, true)?;
attacher.start_watcher(Duration::from_millis(100))?;
loop {
let dt = get_frame_time();
let time = get_time();
let (mx, my) = mouse_position();
let mouse_pos = Vec2::new(mx, my);
let look_dir = mouse_pos - crab_pos;
let moving = is_mouse_button_down(MouseButton::Left);
if moving {
target = mouse_pos;
}
if moving {
let t = 1.0 - (-8.0 * dt).exp();
crab_pos += (target - crab_pos) * t;
}
if is_mouse_button_pressed(MouseButton::Left) {
flash = 1.0;
flash_pos = mouse_pos;
}
if flash > 0.0 {
flash = (flash - dt * 2.0).max(0.0);
}
clear_background(Color::from_rgba(18, 18, 30, 255));
let grid_color = Color::from_rgba(45, 45, 65, 120);
let step = 40.0;
let mut x = 0.0;
while x < screen_width() {
draw_line(x, 0.0, x, screen_height(), 1.0, grid_color);
x += step;
}
let mut y = 0.0;
while y < screen_height() {
draw_line(0.0, y, screen_width(), y, 1.0, grid_color);
y += step;
}
let text_color = if flash > 0.0 {
let glow = (flash * 255.0) as u8;
Color::from_rgba(255, 150, 40, glow)
} else {
Color::from_rgba(180, 70, 20, 120)
};
draw_text("RUST", 25.0, 55.0, 70.0, text_color);
if flash > 0.0 {
let alpha = (flash * 0.35 * 255.0) as u8;
let radius = 60.0 + (1.0 - flash) * 250.0;
draw_circle(
flash_pos.x,
flash_pos.y,
radius,
Color::from_rgba(255, 150, 50, alpha),
);
let overlay_alpha = (flash * 0.05 * 255.0) as u8;
draw_rectangle(
0.0,
0.0,
screen_width(),
screen_height(),
Color::from_rgba(255, 120, 30, overlay_alpha),
);
}
draw_ferris(crab_pos, look_dir, time as _, moving);
draw_text(
"Hold left mouse button to make Ferris walk",
10.0,
screen_height() - 10.0,
20.0,
Color::from_rgba(200, 200, 200, 180),
);
next_frame().await
}
}