Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toggle debug visible collision shapes at runtime #2072

Open
chucklepie opened this issue Jan 4, 2021 · 8 comments
Open

Toggle debug visible collision shapes at runtime #2072

chucklepie opened this issue Jan 4, 2021 · 8 comments

Comments

@chucklepie
Copy link

chucklepie commented Jan 4, 2021

Describe the project you are working on

rhino simulator

Describe the problem or limitation you are having in your project

Debugging collision problems is difficult and you don't always know when they occur or how to easily get back to that point or recreate it upon enabling collision shapes and restarting the code. Lesser, but similarly, when you have collisions on it makes the screen very cluttered and there are many times when you want to turn collision shapes off as you want to test something else while still running the code.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

I presume there is a reason for this omissions, but you cannot enable/disable collision shapes from the Debug menu when the code is running.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

When the menu item is clicked in debug it informs the remote window to turn on collisions

Is there a reason why this should be core and not an add-on in the asset library?

It's basic debugging aid.

@Rubonnek
Copy link
Member

Here's the GDScript equivalent that seems to be what's needed for toggling this in the meantime:

	get_tree().set_debug_collisions_hint(p_toggled_setting)
	var root_node : Node = get_tree().get_root()
	var queue_stack : Array = []
	queue_stack.push_back(root_node)
	# Traverse tree to call update methods where available.
	while not queue_stack.empty():
		var node : Node = queue_stack.pop_back()
		if is_instance_valid(node):
			if node.has_method("update"):
				#warning-ignore:unsafe_method_access
				node.update()
			var children_count : int = node.get_child_count()
			for child_index in range(0, children_count):
				queue_stack.push_back(node.get_child(child_index))

@andrejp88
Copy link

Here's the GDScript equivalent that seems to be what's needed for toggling this in the meantime:

Thank you for this, I long ago reluctantly accepted that this was impossible. My workaround has been to have the option always enabled, then add every single CollisionShape/Polygon to a group called "Debug" and toggle the visibility of all nodes in that group on a certain key press. It worked but was really prone to human forgetfulness :P

Your implementation is made for Godot 3 I assume, since it didn't work for me in 4.0.2. Here is a Godot 4 compatible version that toggles whatever the current state is:

func toggle_collision_shape_visibility() -> void:
	var tree := get_tree()
	tree.debug_collisions_hint = not tree.debug_collisions_hint

	# Traverse tree to call queue_redraw on instances of
	# CollisionShape2D and CollisionPolygon2D.
	var node_stack: Array[Node] = [tree.get_root()]
	while not node_stack.is_empty():
		var node: Node = node_stack.pop_back()
		if is_instance_valid(node):
			if node is CollisionShape2D or node is CollisionPolygon2D:
				node.queue_redraw()
			node_stack.append_array(node.get_children())

update was renamed to queue_redraw and I removed the nested loop (though it probably doesn't make much of a difference unless you have a node with a crazy number of children). Instead of checking for the existence of the method, I check the type of the node, since the only nodes that should require a redraw are CollisionShape/Polygon2D whereas queue_redraw is present in all CanvasItems.

Not sure how it works in 3D, but I assume you would just also check for the corresponding 3D types.

@Iaknihs
Copy link

Iaknihs commented Jul 21, 2023

This is probably not the cleanest possible, but since the above solution wasn't working for TileMap in Godot 4 and using queue_redraw on a TileMap didn't work either, I modified it slightly to add

if node is TileMap:
    node.collision_visibility_mode = TileMap.VISIBILITY_MODE_FORCE_HIDE
    node.collision_visibility_mode = TileMap.VISIBILITY_MODE_DEFAULT

basically setting VISIBILITY_MODE_FORCE_HIDE to make it update, then setting VISIBILITY_MODE_DEFAULT mode again to make it depend on whatever was set before.

There's probably a way to do this in one step, but I haven't looked into TileMaps all that much. So here's what seems to work fine for me right now in total:

func toggle_collision_shape_visibility() -> void:
	var tree := get_tree()
	tree.debug_collisions_hint = not tree.debug_collisions_hint

	# Traverse tree to call queue_redraw on instances of
	# CollisionShape2D and CollisionPolygon2D.
	var node_stack: Array[Node] = [tree.get_root()]
	while not node_stack.is_empty():
		var node: Node = node_stack.pop_back()
		if is_instance_valid(node):
			if node is CollisionShape2D or node is CollisionPolygon2D:
				node.queue_redraw()
			if node is TileMap:
				node.collision_visibility_mode = TileMap.VISIBILITY_MODE_FORCE_HIDE
				node.collision_visibility_mode = TileMap.VISIBILITY_MODE_DEFAULT
			node_stack.append_array(node.get_children())

@Bimbam360
Copy link

The debug options (visible collision shapes, paths, nav, avoidance) should just be options available on SubViewport nodes under the 'Debug Draw' drop down.
Never understood why these weren't exposed there, and now we have detachable windows, super useful for having actual/debug scenes side by side.

@Calinou
Copy link
Member

Calinou commented Nov 14, 2023

The debug options (visible collision shapes, paths, nav, avoidance) should just be options available on SubViewport nodes under the 'Debug Draw' drop down. Never understood why these weren't exposed there, and now we have detachable windows, super useful for having actual/debug scenes side by side.

Making debug drawing visible on specific viewports only via SubViewport properties is a lot of work, as the engine would need to keep track of visibility layers for the debug meshes.

@raldone01
Copy link

raldone01 commented Jan 12, 2024

My current workaround kinda works for 3D:

var show_debug_collisions_hint: bool:
	set(visible):
		print("Set show_debug_collisions_hint: ", visible)
		var tree: SceneTree = get_tree()
		# https://github.com/godotengine/godot-proposals/issues/2072
		tree.debug_collisions_hint = visible

		# Traverse tree to call toggle collision visibility
		var node_stack: Array[Node] = [tree.get_root()]
		while not node_stack.is_empty():
			var node: Node = node_stack.pop_back()
			if is_instance_valid(node):
				if   node is CollisionShape2D \
					or node is CollisionPolygon2D \
					or node is CollisionObject2D:
					# queue_redraw on instances of
					node.queue_redraw()
				elif node is TileMap:
					# use visibility mode to force redraw
					node.collision_visibility_mode = TileMap.VISIBILITY_MODE_FORCE_HIDE
					node.collision_visibility_mode = TileMap.VISIBILITY_MODE_DEFAULT
				elif node is RayCast3D \
					or node is CollisionShape3D \
					or node is CollisionPolygon3D \
					or node is CollisionObject3D \
					or node is GPUParticlesCollision3D \
					or node is GPUParticlesCollisionBox3D \
					or node is GPUParticlesCollisionHeightField3D \
					or node is GPUParticlesCollisionSDF3D \
					or node is GPUParticlesCollisionSphere3D:
					# remove and re-add the node to the tree to force a redraw
					# https://github.com/godotengine/godot/blob/26b1fd0d842fa3c2f090ead47e8ea7cd2d6515e1/scene/3d/collision_object_3d.cpp#L39
					var parent: Node = node.get_parent()
					if parent:
						parent.remove_child(node)
						parent.add_child(node)
				node_stack.append_array(node.get_children())
	get:
		return get_tree().debug_collisions_hint

I would love to be able to set it on specific nodes only and at runtime.

@CsloudX
Copy link

CsloudX commented Jul 8, 2024

For 3D.
should be?

var parent: Node = node.get_parent()
if parent:
    parent.set_block_signal(true)
    parent.remove_child(node)
    parent.add_child(node)
    parent.set_block_signal(false)

@Ignawesome
Copy link

Ignawesome commented Sep 12, 2024

Currently, there is an addon that includes this option: GodotRuntimeDebugTools

I found it to be extremely useful and this is one of the features I would like to see built into the engine.
The addon also supports in-game flying navigation mode and clicking on elements at runtime to show their properties in the inspector.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants