(GDScript) Simple time-conditional animations

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By newgame

For example, 2D animations all stop when velocity is 0 via the usual code

get_node(...).stop()

Animations often stop at some middle-of-the-animation frame because velocity is 0. How to add a history of velocity check to it? Animation stops if current velocity is 0 and past velocity for some time was 0.

Even better in general, finer granularity, using nested history of velocity checks, in pseudo-code:

if velocity is > X pixels/s & velocity was > Y pixels/s sometime in the last 10 seconds & average velocity was > Z pixels/s for last 20 seconds 
        get_node("...").animation = "..."

(and a long list of these)

What is the correct GDScript syntax needed for that? What is the best GDScript manner to write that?

  1. “&” should be achieved via nested “if … else …” but is there a more direct way to write it? Presumably more efficient?

  2. Are there already functions in GDScript for averaging or reading the maximum of some variable reached during some time period? What about the minimum reached during some time period?

Your second question asks, “Are there already functions in GDScript for averaging or reading the maximum of some variable reached during some time period?” If you need to keep a variable in some range, you can clamp the variable. For example:

 some_value = clamp(current_value, 0, 10)

Hope that helps.

Ertain | 2022-09-30 17:33

:bust_in_silhouette: Reply From: godot_dev_

I am not sure if Godot directly offers functions to help you directly achieve this, but for the average, you could use a moving average. You could define a list l of time-velocity pairs (these pairs could be 2-element arrays). The time would indicated a timestamp of when the velocity was applied. Every frame, you take note of the time elapsed, the current time, and the velocity, and store the timestamp and velocity into your list (e.g., l.append([_timestamp,_velocity])).

To achieve the moving average (average within last X seconds), continuously check the timestamp of the last element of the list. If it exceeds X seconds, remove that time-velocity pair (you might want to check many elements in case lag or something makes it so more than one pair becomes stale after one frame). Then, to get the average velocity, do as follows:

const TIMESTAMP_IX=0
const VELOCITY_IX=1
func computeMovingAverage(l):
   var avg=0
   #iterate over every recent pair of timestamp-velocity entries
   for pair in l:
      var velocity = pair[VELOCITY_IX]
      avg = avg + velocity

  return avg/l.size() #careful for divisions by 0, which shouldn't be the case though. You may also need to cast l.size() to a float, since language like Java and C++ risk doing an integer division if avg ends up being a integer (I think it's fine though if the timestamps are floats)