Godot 3D Course - Utilities

,

Hey everyone just wanted to share a little tip to reduce code repetition in the Godot 3D (RPG) course.

First off, sorry if this post is a bit on the longer side, I just want to explain how this works for those newer to game dev / programming (Extension methods can be found near the end) :grin: I am also doing this in C# rather than GDscript but would be happy to create a GDscript version if people are having trouble with translating it.

I’m not very far in yet but there have been a few instances where we need to use InterpolateWith and pass in the exponential function with decay. Rather than writing out the full exponential function every time we could make use of extension methods.

For those that are new to programming, an extension method allows you to add functionality to an already existing component / node, for example when you reference a transform you’ll see a dropdown with suggestions of what you can use (InterpolateWith being the example here). An extension method will show up just like that.

Here are the extension methods I’ve created to handle the exponential decay interpolate methods. These live in their own separate Utilities script

public static partial class Utilities
{
    public static Transform3D Interpolate(this Node3D transform, Transform3D transformTarget, double delta, float decay)
    {
        return transform.GlobalTransform = transform.GlobalTransform.InterpolateWith(transformTarget, 1 - (float)Mathf.Exp(-delta * decay));
    }
    
    public static Transform3D Interpolate(this Transform3D transform, Transform3D transformTarget, double delta, float decay)
    {
        return transform = transform.InterpolateWith(transformTarget, 1 - (float)Mathf.Exp(-delta * decay));
    }
}

As you might have noticed these are static methods and the first parameter uses the “this” keyword, it needs to be public static so it can be accessed anywhere and the “this” keyword tells the method to apply it to the thing we are referencing so you don’t actually have to pass that in.

Using this made my lines go from this

_RigPivot.GlobalTransform = _RigPivot.GlobalTransform.InterpolateWith(targetTransform, 1 - (float)Mathf.Exp(-delta * _AnimationDecay));

to

_RigPivot.GlobalTransform = _RigPivot.Interpolate(targetTransform, delta, _AnimationDecay);

Sure, that’s not a bad idea. The more it’s used, the more sense it makes to do something like this!

For those interested in trying something similar in GDScript, there isn’t a true equivalent to this right now, but there likely will be in the future. The Engine Contributors have acknowledged it would be a useful thing to implement, but they’ve tabled the idea in favour of higher priority stuff. Here are some alternatives in the meantime:

  • Create a full (as in not partial like the above) Utilities class and autoload it. Not ideal because your other classes now depend on this and will have to access the function from there, but it does get the job done. Kaan has a simple demonstration of this with his MyUtilities class in the Mobile course.
  • Create a normal, local, non-static Interpolate() function. Because the definition of this function is directly in the script where it will be used instead of in a separate script, it might make control flow a little harder to follow, depending on how you organize things.
  • Extend the class itself with a custom script (MyMeshInstance3D for example), then make your instances of that type instead of the base class. This is clean, but it really only works if you can do it without creating a branch in the inheritance chain, since multi-inheritance is not supported. The best you could do otherwise is add the same link to each affected branch, leading to a lot of code duplication… which is what we’re trying to avoid =)
  • For argument’s sake, if you really, really want to, you could also just modify the engine’s source files and recompile it. When you solve your problems with a chainsaw, you’ll never have the same problem twice!

There’s also every possibility that I’m missing something altogether better (I sure as heck don’t know everything), so further discussion is always welcome!

1 Like