Random Walk - Part 2
In this second part we want to add a fade effect so that the trail from the walker fades to the background colour.
This will be implemented in a brute force way. Yes I know I could make a list of locations the walk had been and then only update those buffer locations, but we will just do a simple iteration through the buffer checking each pixel to see if it is white (0xFFFFFF) if it is not white then do a +=0x010101.
The other part of this code is to add a delay in so that you can decide if you want to slow the fade down. To do this we set a constant FADE_SPEED to a value, then only update the fade very "FADE_SPEED" iterations.
The updated Rust code
// 8 way random walk with minifb and a 5px dot. // Now with added fade! // written for maths.earth 20250101 use minifb::{Key, Window, WindowOptions}; use rand::Rng; // Define the size of the window. const WIDTH: usize = 800; const HEIGHT: usize = 600; // Define the size of the dot as an odd number so the "centre" aligns with the walker's (x, y). const DOT_SIZE: usize = 5; // Define fade speed. const FADE_SPEED: u16 = 15; // Define struct to store the walker's position. struct Walker { x: usize, y: usize, } // Define methods for the Walker. impl Walker { fn new() -> Self { Walker { x: WIDTH / 2, y: HEIGHT / 2, } } fn step(&mut self) { // 8 directions: 0..8 let mut rng = rand::thread_rng(); match rng.gen_range(0..8) { 0 => { // Right if self.x < WIDTH - 1 { self.x += 1; } } 1 => { // Left if self.x > 0 { self.x -= 1; } } 2 => { // Down if self.y < HEIGHT - 1 { self.y += 1; } } 3 => { // Up if self.y > 0 { self.y -= 1; } } 4 => { // Diagonal down-right if self.x < WIDTH - 1 { self.x += 1; } if self.y < HEIGHT - 1 { self.y += 1; } } 5 => { // Diagonal up-right if self.x < WIDTH - 1 { self.x += 1; } if self.y > 0 { self.y -= 1; } } 6 => { // Diagonal down-left if self.x > 0 { self.x -= 1; } if self.y < HEIGHT - 1 { self.y += 1; } } 7 => { // Diagonal up-left if self.x > 0 { self.x -= 1; } if self.y > 0 { self.y -= 1; } } _ => {} } } fn show(&self, buffer: &mut [u32]) { // Plot a small DOT_SIZE x DOT_SIZE block around (x, y). // Make sure we stay within bounds. let half = (DOT_SIZE / 2) as isize; for dy in -half..=half { for dx in -half..=half { let px = self.x as isize + dx; let py = self.y as isize + dy; if px >= 0 && px < WIDTH as isize && py >= 0 && py < HEIGHT as isize { buffer[py as usize * WIDTH + px as usize] = 0x000000; // black } } } } } fn main() { // Create a window with default options. let mut window = Window::new( "Random Walk (8-way movement)", WIDTH, HEIGHT, WindowOptions::default(), ) .unwrap_or_else(|e| { panic!("Failed to create window: {}", e); }); let mut temp_pixel: u32; let mut fade_speed: u16 = FADE_SPEED; // Create a buffer for the entire screen, initialised to white. let mut buffer = vec![0xFFFFFF; WIDTH * HEIGHT]; // Create our Walker. let mut walker = Walker::new(); // Main event loop. while window.is_open() && !window.is_key_down(Key::Escape) { if fade_speed == 0 { // Fade the buffer to white. for pixel in buffer.iter_mut() { // if pixel is not white incremete by 1 for each channel. if *pixel != 0xFFFFFF { temp_pixel = *pixel; temp_pixel += 0x010101; if temp_pixel > 0xFFFFFF { *pixel = 0xFFFFFF; } else { *pixel = temp_pixel; } } } fade_speed = FADE_SPEED; } else { fade_speed -= 1; } // Update the walker's position. walker.step(); // Draw the new position with a larger dot. walker.show(&mut buffer); // Render the updated buffer. window .update_with_buffer(&buffer, WIDTH, HEIGHT) .unwrap(); } }
Cargo.toml
[package] name = "randomwalk" version = "0.1.0" edition = "2021" [dependencies] minifb = "0.27.0" rand = "0.8"
The image produced:
Mission Accomplished
And there we have it, our walk train fades to white at a preset variable fade rate.