How to disable physics for a node and its children?

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

Hi, I’m wondering if it’s possible to disable physics at a node and have it take effect for all children of that node as well? Similar to how you can disable visibility for a node and none of the children render either.

I’m trying to do some chunk-culling with my game map. The game map is made of a series of tiles grouped together under chunks. At the moment I’m adding and removing chunks as necessary but there’s a small stutter each time I do this.

I’ve experimented with just leaving the tree hierarchy alone and toggling visibility on the chunks instead. This works without the stutter but I also need to disable physics on all of the children and was hoping to not have to loop over them all each time I enable/disable a chunk.

How are you adding chunks? Have you tried call_deffered("add_child", Node node)?

decepticlown | 2021-12-07 06:51

I was just using add_child. I did play with having a remove and add queue that would spread the chunk adding over a series of frames but the performance was a little worse.

bepis | 2021-12-07 16:01

:bust_in_silhouette: Reply From: timothybrentwood

There’s the propagate_call() function which will call a function on a node and its children, otherwise you can add all of the nodes in a chunk to a group then use call_group(). Note that both of those things are roughly the equivalent of looping over all of them. I’m not aware of anything analogous to disabling visibility on the physics side.

If you’re still experiencing stuttering issues you may want to consider spinning up a thread to do the work so you don’t block the main thread. I think your approach of disabling the processing should clear up your stuttering though.

Interacting directly with the PhysicsServer object is useful for making highly optimized physics related changes at runtime. It’s a little more involved than just interacting with nodes but I’ve read that it’s significantly faster.

Thanks I may try and go the PhysicsServer route. There’s hardly any stutter now that I moved to hiding/showing chunks but on weaker devices there’s consistent lower frame rates. If I can cull the physics objects in a fast way, I hope to gain at least a few fps. The map is 36x580 so 20,880 children tiles :stuck_out_tongue:

bepis | 2021-12-07 15:30

Oh wow, yeah that is a lot of objects. I would recommend interacting with the PhysicsServer in a new thread so you don’t get any stuttering. There’s also an analogous VisualServer so you can show/hide faster as well (you might not get significant performance improvements there).

You could also break up how you you process the chunks over multiple frames too:

var nodes_to_process : Array
export var nodes_per_frame : int = 100

func initiate_process():
	nodes_to_process = get_children()
	process_node_chunk()
		
func process_node_chunk():
	if nodes_to_process:
		var nodes_this_frame : Array
		var end_of_array = nodes_to_process.size() - 1
		
		if nodes_per_frame < end_of_array:
			nodes_this_frame = nodes_to_process.slice(0, nodes_per_frame - 1)
			nodes_to_process = nodes_to_process.slice(nodes_per_frame, end_of_array)
		else:
			nodes_this_frame = nodes_to_process
			nodes_to_process = []
			
		process_nodes(nodes_this_frame)
		call_deferred("process_node_chunk")

func process_nodes(nodes : Array):
	var flag = not nodes[0].visible
	
	for node in nodes:
		node.visible = flag
		node.set_physics_process(flag)

timothybrentwood | 2021-12-07 17:46

Thanks man I’ll give that a go. I’m also reading this post about the PhysicsServer which has some examples: HowTo: Drawing a metric ton of bullets in Godot - Bittersweet Birthday by World Eater Games

bepis | 2021-12-07 19:22

I think I’m just gonna let it be for now and see if the performance needs more optimization after adding other areas of the game since further than visibility culling is not very trivial. Without using PhysicsServer, one thing I think I could do is make each chunk a StaticBody2D and add all the tile collision shapes as children. At the moment each chunk is a Node2D with StaticBody2D tile children.

bepis | 2021-12-07 21:18

I see. I haven’t personally interacted with the PhysicsServer directly but I have read about how it’s very fast from the contributors.

I’d suggest trying my code out. I think the stutter is happening because you’re trying to do too much in one frame. Dividing the work out over multiple frames should remove that stutter. Play around with increasing/decreasing nodes_per_frame until you eliminate the stutter. If you can’t eliminate the stutter while maintaining the desired behavior of your game, you’ll likely need to create a new thread to handle the work.

https://docs.godotengine.org/en/stable/tutorials/threads/using_multiple_threads.html

timothybrentwood | 2021-12-08 01:45

I got rid of the stutter by just switching back to keeping the children instanced and toggling visibility. It results in a little bit worse constant performance but it’s definitely playable. But there’s a lot more to add to the game and those performance losses might add up in the end and I’ll need to look back into this. It’s for the OUYA game console lol so hardware limitations are a big deal.

bepis | 2021-12-08 20:47