Page 1 of 1

[SOLVED] Arithmetic needed to animate a numeric counter

Posted: Sun Feb 20, 2022 5:47 pm
by CharlieFuu69
Hello boys. I have tried to implement an animated count similar to AnimatedValue(), but to animate numbers.

This is the code I have created:

Code: Select all

class AnimatedCounter:

    def __init__(self, hit, delay):
        self.hit = hit ## The value to be reached
        self.delay = delay ## The time it takes to get from 0 to self.hit
            
        self.update_rate = None ## Used to calculate the update interval
        self.update_count = 0 ## The current count

    def count(self, st, at):
        if self.update_rate is None:
            self.update_rate = self.delay / self.hit

        if self.update_count < self.hit:
            self.update_count += 1

        return Text("%s" % self.update_count), self.update_rate
I make it work like this:

Code: Select all

screen anim_num(delay, hit):
    default counter = AnimatedCounter(hit = hit, delay = delay)
    add DynamicDisplayable(counter.count) align(0.5, 0.5)
The code runs the count in an animated way and it works fine, except for one thing. The time it should take to count from 0 to self.hit is given by self.delay , which is used to calculate the refresh interval in self.update_rate.
This should work fine, but the time it takes to get from 0 to self.hit isn't appropriate, and I'm very aware that it's a bug in the arithmetic I'm using to calculate the update interval.

The calculation runs on:

Code: Select all

if self.update_rate is None:
    self.update_rate = self.delay / self.hit
What I need at this point is some advice or help to find the correct calculation for this operation, since the code itself works correctly, except for the count delay.

I appreciate the help guys!

Re: Arithmetic needed to animate a numeric counter

Posted: Sun Feb 20, 2022 6:26 pm
by Ocelot
Your problem isn't with arithmetics. The value you return from your function is not binding. It merely means that function will be called again before that much time passes. It is completely possible that function will be called again before time specified. You need to keep track of time passed yourself. This is what st and at are for.

If you wish to keep your code structure like you already have, you can change your class as following:

Code: Select all

    class AnimatedCounter:
        def __init__(self, hit, delay=1.0, start=0):
            self.value = start # Current value
            self.hit = hit # The value to be reached
            self.delay = delay ## The time it takes to get from 0 to self.hit

            self.update_rate = float(self.delay) / abs(self.hit - self.value)
            self.last_hit = None # last time updated
            self.update_displayable()

        def update_displayable(self):
            self.displayable = Text("%s" % self.value)

        def count(self, st, at):
            if self.value == self.hit:
                return self.displayable, None

            if self.last_hit is None:
                self.last_hit = st

            if (self.last_hit + self.update_rate) < st:
                self.last_hit = st
                self.value += (1 if (self.value < self.hit) else -1)
                self.update_displayable()

            return self.displayable, self.last_hit + self.update_rate - st
There are some improvements: you can specify starting value as well as target, it supports both increasing and decreasing counters, caches displayable for perfomance reasons and stops updating when it reaches the goal.

Re: [SOLVED] Arithmetic needed to animate a numeric counter

Posted: Sun Feb 20, 2022 7:43 pm
by CharlieFuu69
Wooah, I see I messed up over something too small. It never crossed my mind to apply the code that way.
Thanks for the help!!!