My (probably wrong) understanding of RNG is as follows:
The RandomNumberGenerator class is effectively already instantiated globally, however with an initial Seed (used to generate the random number) value that is static. By this I mean if you start a blank scene and run :
func _ready():
print("RNG1: " + str(rand_range(-10.0, 10.0)))
Then rerun the exact same scene without modification, you will get the same output each time.
Now, I assume the RandomNumberGenerator class also by default increases the Seed value every time the function is called, such that if you start a blank scene and run:
var physcount = 0
func _physics_process(delta):
if physcount % 60==0:
print("RNG1: " + str(rand_range(-10.0, 10.0)))
physcount+=1
You will get a new random number every second by design. Again though if you rerun the project, you will get the same output each time as the initial Seed is the same. Situationally, you may want this behavior but usually, it is not intentional (not really sure why it's the default behaviour tbh). For example, the original Pokemon could be manipulated as there was no persistent system clock in the original GBA, so a fresh power on/game run effectively had predictable RNG as long as you knew exactly how many Seed iterations had occurred.
Where does randomize() come in:
By calling randomize() in the _ready() function, your effectively taking your current system time in microseconds and using this to generate a new random starting Seed. As your system time is essentially never the same twice, this means you should never see the same string of numbers twice when running the above.
So why do I need to instantiate a new RandomNumberGenerator?
Most of the time you don't, but it does no harm to get into the habit.
Calling randomize() once in ANY node's ready function will generate a new global seed which will result in all rand_range() calls to generate a new set of numbers. Where you may want to be careful or spin up your own is during things like repeatable randomly generated level design or restoring from save states, where you may want repeatable generation for a given subset of nodes based on a seed value. If you were to do this without re-randomizing after generation or using multiple generators, you're back to Pokemon RNG. See 'XCOM Save Scumming' for how this is often overlooked even in modern games.
For the above reason, randomize() usually only needs to be called once when a given script initiates. Regenerating the random number generator for every frame is unnecessary as assuming a unique starting seed, it will already generate a new number for every frame. Given I think all this does is check the system clock to set a float value, the performance of rerunning randomize() should be negliable?
The bigger performance hit in your code comes from calling 'get_simple_path' every frame, as this is computationally expensive and unless the target is moving every frame? unnecessary.
Even if the target IS moving every frame (such as an enemy pathing towards the player), in many cases you can cheat and perform these checks every ~5th frame without the user noticing, and batch queries for groups (i.e. 5 enemies check their paths on frames 1,6,11,16... next 5 on frames 2,7,12,17... etc.). AND nav pathing can be turned off when the player is within uninterrupted LOS in favor of just charging at them (this is a bit of a brain dump at this point so I'll stop now ).