• 2D
  • How to make KinematicBody2d not collide with RigidBody2d in runtime?

Hello, There's a part of my game where I want the Player (KinematicBody2d) to not be able to catch a RigidBody2d object. I want the RigidBody2d to just fall through the Player and be deleted when it hits through the ground . I tried setting the collision mask bits to false on both the Player node and object node so they won't detect each other like so:

	set_collision_mask_bit(0, false) # changes the layer mask in the object node
	body.set_collision_mask_bit(1, false)  # changes the layer mask for the Player node

But doing this causes an odd behavior where the object node does collide with the Player node momentarily, but then it sinks slowly past the Player. Is there something else I need to do to have the object node normally pass through the Player?

Thank you in advance!

What are the complete values for the object's and Player's collision layer and mask?

If object A has collision layer LayerA and collision mask MaskA, and object B has layer LayerB and mask MaskB, then A and B can collide if LayerA & MaskB != 0 or LayerB & MaskA != 0.

@DaveTheCoder The Player has collision layer Layer1 and has collision mask Layer2. The object has collision layer Layer2 and has collision mask Layer1. So with these settings, they are colliding with each other. But if I turn off the Player’s and object’s collision masks, I see that they collide but the object slowly sinks past the Player. If I were to turn off the collision masks manually in the editor, it works as expected where the object passes seamlessly through the Player.

"has collision layer Layer1" "turn off the Player’s and object’s collision masks"

That's not clear.

It would be helpful if you print the values of the properties collision_layer and collision_mask for both Player and the object, for both of the cases you described.

@DaveTheCoder

Here is the Player's and object's collision_layer and collision_mask properties at the start of the game:

Now when the Player tries to catch the object when the capacity is met, I tried modified the Player's and object's collision_mask properties like so: Player's collision_mask properties: 0 False 1 False 2 True 3 False 4 False 5 False 6 False 7 False 8 False 9 False 10 False 11 False 12 False 13 False 14 False 15 False 16 False 17 False 18 False 19 False

Pet's collision_mask properties: 0 False 1 False 2 False 3 False 4 False 5 False 6 False 7 False 8 False 9 False 10 False 11 False 12 False 13 False 14 False 15 False 16 False 17 False 18 False 19 False

If the following correct?

You can verify by printing out the properties collision_layer and collision_mask. For example: print_debug("Player/initially, collision_layer=", collision_layer) print_debug(""Player/initially, collision_mask=", collision_mask)


Initially: Player's collision_layer = 1 Player's collision_mask = 6 Object's collision_layer = 2 Object's collision_mask = 1

After you change them: Player's collision_layer = 1 Player's collision_mask = 4 Object's collision_layer = 2 Object's collision_mask = 0

If these numbers are correct, then with the initial values Player and Object will collide, and with the changed values they won't collide. The "sinking" issue you described must be due to something else. Is the Object's Gravity Scale non-zero?

Yes, that looks correct. Here is what I see in my output: Player/initially, collision_layer=1 Player/initially, collision_mask=6 Object/initially, collision_layer=2 Object/initially, collision_mask=1

Player/changed, collision_layer=1 Player/changed, collision_mask=4 Object/changed, collision_layer=2 Object/changed, collision_mask=0

The Object's gravity scale is set to 1 and is not changed. I'm wondering if it has to do with the method I am changing the collision layer/mask. Here is the full method that I have, which is triggered when the Object collides with the Player:

func _on_Object_body_entered(body):
	var possible_hud_nodes = get_tree().get_nodes_in_group("HUD")
	var hud_node = possible_hud_nodes[0]
	
	if not hud_node._is_capacity_full():
		print("Object has reached Player")
		hud_node._on_pet_collected() # updates the HUD
		queue_free() # deletes Object
	else:
		#print("Turn off layer masking to prevent collision from player")
		print_debug("Player/initially, collision_layer=", body.collision_layer)
		print_debug("Player/initially, collision_mask=", body.collision_mask)
		
		print_debug("Object/initially, collision_layer=", collision_layer)
		print_debug("Object/initially, collision_mask=", collision_mask)
		
		
		set_collision_mask_bit(0, false) # changes the Object's collision mask

		body.set_collision_mask_bit(1, false) # changes the Player's collision mask
		
		print_debug("Player/changed, collision_layer=", body.collision_layer)
		print_debug("Player/changed, collision_mask=", body.collision_mask)
		
		print_debug("Object/changed, collision_layer=", collision_layer)
		print_debug("Object/changed, collision_mask=", collision_mask)

I tried comment out the if statement and the code under it, but the sinking issue still persists.

The Object's gravity scale is set to 1

That would explain the sinking. Set the gravity scale to 0 to "turn off" gravity. Or do you want the Objects to be affected by gravity?

@DaveTheCoder I set the gravity scale to 0 but the sinking effect still happens. I think I want the Objects to still be affected by gravity since I want them to descend at a constant speed, not accelerate. Is there a way to do that with the gravity scale set to 0?

If there's no collision and gravity is off, I don't know why the sinking would occur.

RigidBody2D has a number of physics properties. I don't know how you're handling the movement.

These are my settings for the Object node:

I didn't modify the other physics settings, so the rest of the physics properties are set to their default values.

I noticed that if I were to modify the Object's and Player's properties so they would not collide to one another in the editor and start my game, the sinking effect does not occur. How I usually do it is spawn one instance of an Object at a time in the scene based on a Timer I set. The Object instance would then descend down from the top of the screen at a random speed:

# Main.gd
func _on_Object_Timer_timeout():
	# will create random Object instance
	# and pick a random starting location
	#along Path2D
	
	# Choose a random location on Path2D.
	$ObjectPath/ObjectSpawnLocation.offset = randi()
	# Create a Object instance and add it to the scene.
	var obj = Object.instance()
	add_child(obj)
	# Set the object's direction perpendicular to the path direction.
	var direction = $ObjectPath/ObjectSpawnLocation.rotation + PI / 2
	# Set the object's position to a random location.
	obj.position = $ObjectPath/ObjectSpawnLocation.position
	# Set the velocity (speed & direction).
	obj.linear_velocity = Vector2(0, rand_range(obj.min_speed, obj.max_speed))

Is it possible the issue is caused by working with instances of the Object when I modify the collision mask in my Object script?

I think I fixed it! I think it was an issue with working with instances of my Object node. So what I did was have my main script check when to have the Object not collide with the Player, rather than my Object script. If so, it would change the collision mask for both the Player and the Object instance being created when it was time to spawn the new Object instance.