2026-8-26
It totally hasn’t been 19 days since the last devlog…
I’m planning to add more powerups. One of them includes a roller powerup, which erases all tiles of the same color touching the powerup’s collision point.
I’ve already added a paintball powerup that turns nearby tiles into the same color as the one the powerup is touching:

And also, powerups are now stored globally; you get exactly 5 powerups per game. The code was already designed like this, I just made the UI reflect that too.
But for the roller, I must create a smooth animation of the tiles slowly being deleted. This involves recursively calling a neighbor search with a certain delay between each call, essentially doing BFS with a task scheduler.
Only thing is… I never wrote a task scheduler, and was trying to avoid it as it would add complexity to the project. And it makes sense, as I usually use the hardcoded 24fps frame rate as a scheduler by waiting for the next frame, and have my own basic delay checker for gravity. But for any complicated animations, a scheduler is very necessary and will make my life much easier in the future.
pub struct Task {
time: Instant,
run: Box<dyn FnOnce(&mut State)>,
}
impl PartialEq for Task {
fn eq(&self, other: &Self) -> bool {
self.time == other.time
}
}
// more comparison trait implementations
pub fn update_tasks(state: &mut State) {
let task_is_due = state
.task_queue
.peek()
.is_some_and(|Reverse(task)| task.time <= Instant::now());
if task_is_due {
let Reverse(task) = state.task_queue.pop().unwrap();
(task.run)(state);
update_tasks(state); // probably pretty easy to use a while loop, but recursion is even easier
}
}
pub fn add_task(time: Duration, callback: impl FnOnce(&mut State) + 'static, state: &mut State) {
state.task_queue.push(Reverse(Task {
time: Instant::now() + time,
run: Box::new(callback),
}));
}
Nice, that wasn’t too bad. I finally had an opportunity to use Rust’s closure types, and learned a bit about FnOnce, FnMut, and some borrowing rules.
And it works great! I moved gravity over to the task scheduler (in the form of a recursive task that spawns another task in its callback), and everything is working normally.
Total time: 1 hr