0 votes

I have a bunch of minions on the board that I need to move around and their AI is based on the state and position of the other minions on the board. I came up with 3 ways of doing it, but I'm not sure which is correct or what the pro and cons are of each.

Method 1

In each minion node's script:

func _fixed_process(delta):
     # Get surrounding minions details and calculate new
     # velocity vector for this minion, but don't change the position yet.
     # This is important because I need to
     # calculate new velocities for all minions before anything moves.

func _process(delta):
     # Actually move the minions based on velocities
     # calculated in _fixed_process().
     self.set_pos(self.get_pos() + self.velocity * delta)

Is this correct to use both _fixed_process and _process? Also, can I be guaranteed that _fixed_process() will be called on all my minions before _process() is?

Or can I think of _fixed_process() and _process() like 2 separate threads? One for physics and one for rendering?

Method 2

In the minions' parent node:

func _fixed_process(delta)
 # Basically do the same thing as method 1 except loop
 # through all minions on the board and do it to each minion.

func _process(delta)
 # Same as method 1 except again looping through
 # each minion to update its new position.

for minion in minions:
    minion.set_pos(minion.get_pos() + minion.velocity * delta)

So instead of relying on the Godot engine to loop through minions, I am doing it myself. Would this be too much processing in one function?
Not strictly related, but is there a guaranteed order in which _fixed_process() and _process() are called down the tree? Is it breadth first? Depth first?

Method 3

Create an Area2D circle on each minion.

Use collision triggers to set AI update flags:

_on_Minion_area_enter(area):
    flagNeedsAIUpdate = true

_on_Minion_area_exit(area):
    if length(get_overlapping_areas()) <= 0:
         flagNeedsAIUpdate = false


func _on_fixed_process(delta):
   if flagNeedsAIUpdate:
       # Do same thing as method 1

func _on_process(delta):
   # Do same thing as method 1

I guess this is just on optimization of method 1 (I think?)

I can get my minions to do what I want them to do, I'm just wondering what's the best way to structure this.

in Engine by (56 points)
edited by

Sorry about the formatting, it does not match the preview!!! And I don't know how to escape those things....

enter image description here

select code blocks and press this button.

Thank you! Updated formatting.

1 Answer

0 votes
Best answer

I think there is not an universal best way. You can structure your code as it best matches your game logic/mechanics.

Things to consider:
- _process() is called per rendered frame. So you may be interested in changing visual stuff here, if that's what you mean with 'rendering'. But if changes are not complex and you are fixed-frame-based, that would be overkill.
- _fixed_process() is called uniformly at your target FPS (so it may be called multiple times per visual frame). This is the best place for almost anything if you are using Godot's physics. Also note that collision callbacks, etc. belong to this same "fixed frame realm".

You can have a look at my talk where I dissected the engine loop so you can have a clearer awareness of when things happen exactly: Node Nuggets, from minute 14.

by (182 points)
selected by

That was a great talk, I watched the whole thing! I think the information about the game loop would be useful to add to the docs.

I ended up doing something like this:

func _fixed_process(delta):
    doPhysicsCalcs(all_minions)
    moveMinions(minions)

and I had nothing in _process

I'm happy you liked it! I was never sure about its potential.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.