Hello.
I designed an animation module where you give it a pointer to some numeric data, your desired final value, and the duration in which you want it to get to that final value, and it will lerp and update the values as long as you keep calling .update() on the Animator.
Pretty happy with the code, here it is in it's full glory:
#[derive(Default)]
pub(crate) struct Animator {
jobs: Vec<AnimationJob>,
cleanup: Vec<usize>,
}
impl Animator {
pub fn animate(&mut self, data: *mut f32, end_value: f32, seconds: f64) {
self.jobs.push(AnimationJob::new(data, end_value, seconds));
}
pub fn update(&mut self) {
// run jobs
for (i, job) in self.jobs.iter_mut().enumerate() {
job.process();
if job.is_complete {
self.cleanup.push(i);
}
}
// remove any complete jobs
while let Some(i) = self.cleanup.pop() {
self.jobs.remove(i);
}
}
}
struct AnimationJob {
data: *mut f32, // pointer to the data I will mutate
value_start: f32,
value_end: f32,
timer: Timer,
is_complete: bool,
}
impl AnimationJob {
fn new(data: *mut f32, value_end: f32, seconds: f64) -> Self {
Self {
data,
value_start: unsafe { *data },
value_end,
timer: Timer::new(seconds),
is_complete: false,
}
}
fn process(&mut self) {
let step = self.timer.step();
// update value based on lerp of time
unsafe {
*self.data = self.lerp(step as f32);
};
// determine status of job
self.is_complete = step >= 1.;
}
fn lerp(&self, step: f32) -> f32 {
self.value_start * (1. - step) + self.value_end * step
}
}
#[derive(Debug)]
struct Timer {
time_start: f64,
time_end: f64,
}
impl Timer {
fn new(seconds: f64) -> Self {
let time_start = date::now();
let time_end = time_start + seconds;
Self {
time_start,
time_end,
}
}
// 0.0 - 1.0 between beginning and end times
fn step(&self) -> f64 {
let step = (date::now() - self.time_start) / (self.time_end - self.time_start);
if step > 1. {
1.
} else {
step
}
}
}
But as you can see, there is one glaring problem. It needs to hold an unsafe pointer.
I could have it ask for a borrow every time it wants to update the value (rather than storing the pointer itself) but then my Animator module would have to know about things outside of the module, and how to request it.
I like that my module is completely agnostic.
So how would I get around this?