Skip to content

[Proposal] Variable rate tick() #255

Description

@lucasrafael98

Is your feature request related to a problem? Please describe.
This helps with performance. The hacked subclass below makes a simple scene with 200 agents (whose nodes basically set animations and change nav targets, and whose meshes are disabled for the purposes of testing) go from around 10 FPS running ticks every single frame on each agent, to:

  • ~150FPS running every 2 frames
  • ~230FPS running every 5
  • ~290FPS running every 10 and above (increasing the number doesn't seem to yield significant results)

This is not a very scientific test, I know, and the bump from 1 to 2 frames is IMO suspicious, but it's something to think about.

Describe the solution you'd like
It would be interesting, in my view, to not have to process a behaviour tree every frame. If we treat this tree as a check of whether the agent needs to update what it's doing, it might be an unnecessary use of CPU to run this every frame. We could have an optional mode on the behaviour tree that only updates every x frames. It's important to set a random seed for the frame on each iteration (some agents run on every fifth frame, some on every first, see the code below) so that we're not hogging the CPU every few frames updating everything and leading to microstutters.
This should be optional as to not break code that e.g. moves the agent on ticks (which will break when ticks don't happen like clockwork).

Describe alternatives you've considered
I have a semi-hacked subclass of BehaviourTree on my project:

class_name BeehaveTreeFast
extends BeehaveTree

var n := 0 
@export var run_every := 15

func _ready(): 
	n = randi_range(0, run_every - 1)
	super()

func _physics_process(delta): 
	if n < run_every:
		n += 1
		return

	if n >= run_every:
		n = 0
	super(delta)

This works for me, I'm just suggesting we add it to the lib.

I did just notice that I didn't override _process(), which is weird since I did definitely notice that tick() doesn't run every frame (I had improperly designed some nodes to move agents when ticked instead of setting a motion that the agents should follow until the next tick, and I notice they only move every few frames). This isn't 100% relevant to this issue but it doesn't make sense to me to run on every _process() and every _physics_process(), we're updating the agent's state twice on some frames if not all. I did only skim the code so I might be wrong about this.

Feel free to close this if you disagree, just wanted to see your thoughts on the matter! If you find this to be a good addition to the addon I can whip up a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions