Simple rhythm game - issues with "note" collision

Godot Version

3.5.3

Question

Rookie here - I am working on a simple rhythm game and I can’t get the collisions for my “notes” to work. When they collide with the player, they physically get stuck, even though I think collision layers/masks are setup correctly?

Each “note” is controlled by a script called “Hazard_Controller” which is posted below. The note moves upwards and listens for collisions with the “Player” layer. (both the player and hazard have a Kinematic Body2D + CollisionShape 2D, and are set to their respective “Player” and “Hazards” collision layers).

If a note collides with the player body, the player has .5 seconds to press a button to “parry” the note. If the player successfully presses the button within .5 seconds of collision, the node is destroyed instantly and the track continues uninterrupted (see lines 19 & 20). However, if the player does not press a button in .5 seconds, the player’s input is temporarily disabled for 3 seconds before then destroying the note node (see lines 17 & 18).

Sadly, I can’t get the collision to work. When I print the bool “hazardCollision”, (which indicates if there’s a collision), it always says “false” even when the note collides with the player.

Thanks to anybody who can help. Can’t upload a video since I’m new.

extends KinematicBody2D

var hazardCollision = false
var collisionTimer = 0
var inputDisabled = false

var speed: float = 200.0
var y_position: float
var acceleration: float = 0.0
var acceleration_rate: float = 1.2  # Adjust this to control acceleration rate
var deceleration_rate: float = 2.0  # Adjust this to control deceleration rate

func _process(delta):
	print(hazardCollision)
	if hazardCollision:
		collisionTimer += delta
		if collisionTimer >= 0.5 and not inputDisabled:
			disableInputAndDestroyHazard()
		elif Input.is_action_pressed("destroy_hazard"):
			destroyHazard()
	# Check if Global.is_moving is true
	if Global.is_moving:
		# Increase acceleration, clamped at 1
		acceleration = min(acceleration + acceleration_rate * delta, 1.0)
	else:
		# Decrease acceleration to 0 with a faster rate
		acceleration = max(acceleration - deceleration_rate * delta, 0.0)
	# Move the hazard upwards along the y-axis with adjusted speed based on acceleration
	move_hazard_up(delta)

func _on_Hazard_body_entered(body):
	if body.is_in_group("Player"):
		hazardCollision = true

func _on_Hazard_body_exited(body):
	if body.is_in_group("Player"):
		hazardCollision = false
		collisionTimer = 0

func disableInputAndDestroyHazard():
	inputDisabled = true
	$Mouse_Detector.input_pickable = false
	$Button_Detector.input_pickable = false
	yield(get_tree().create_timer(3), "timeout")
	inputDisabled = false
	$Mouse_Detector.input_pickable = true
	$Button_Detector.input_pickable = true
	destroyHazard()

func destroyHazard():
	queue_free()

func move_hazard_up(delta):
	# Move the KinematicBody2D upwards along the y-axis
	move_and_slide(Vector2(0, -speed * acceleration), Vector2.ZERO)

That sounds like a collision layer and mask issue.

Notes should be in a layer but have no mask for player layer. Player should be in its own layer and a mask for notes.

I’m wondering if you may need a collision delegate like an area body that does not physically collide but can detect collisions.

Hm. I’m still a bit confused by masks and layers…

Originally, I put the Player in Layer 1 and had no masks. And, I put the Note in Layer 2 and had a mask for the Player. I did this because the page you linked says that masks are the layers that the body will scan for - so, since the note is the body that’s scanning for the Player, wouldn’t I want a mask for the Player? Am I misunderstanding that?

Regarding the collision delegate - are you saying I should try adding an Area2D to the Note and check for collisions with “on_area_entered”, instead of “on_body_entered”?

I’m wondering if collidable bodies can’t actually just sense for collisions without colliding.

So I would add an area2d as a child to the player or note. Which makes sense to you. That will do the collision checking, but still allow the note and player to pass through each other. So yes the area entered signal instead of body entered. The note and player will be on separate layers and mask while the area node will be on the other mask and/or layer.