Issue with canvas layer and scoring scoring system

Hello, i have been working on a top down shooter and I have been trying to implement a scoring system, but when I put the canvas layer node on for the ui, in the main game, the player can no longer shoot, here is the code:

Here is the code for the hud which is attached to a control node which is a child to a canvas layer node:

extends Control

@onready var score = $score:
	set(value):
		score.text = "Score: " + str(value)

Here is the code for the main game:

extends Node2D

@onready var bullet_manager = $bulletmanager
@onready var player = $player
@onready var enemy = $enemy
@onready var hud = $UIlayer/hud

var score: int = 0:
	set(value):
		score = value
		hud.score = score

func _ready() -> void:
	score = 0
	randomize()
	GlobalSignals.bullet_fired.connect(bullet_manager.handle_bullet_spawned)

			
	enemy.killed.connect(_on_enemy_killed)
	
	
func _on_enemy_killed(points):
	score += points
	print(score)
	

 

here is the code for the player:

extends CharacterBody2D
class_name Player



@export var speed: float = 100
@export var accel: float = 10



@onready var weapon = $weapon
@onready var health_stat = $Health

@onready var anim_sprite: AnimatedSprite2D = $AnimatedSprite2D as AnimatedSprite2D




func _physics_process(_delta: float) -> void:
	var direction: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	
	velocity.x = move_toward(velocity.x, speed * direction.x, accel)
	velocity.y = move_toward(velocity.y, speed * direction.y, accel)
	
	look_at(get_global_mouse_position())
	move_and_slide()


func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("shoot"):
		weapon.shoot()
		
		
		
		
		
		
		
		
		
func handle_hit():
	health_stat.health -= 20
	print('ouch!', health_stat.health)

here is the code for the weapon that is used by the player and enemy:

extends Node2D
class_name Weapon


@export var Bullet :PackedScene 


@onready var end_of_gun = $endofgun
@onready var gun_direction = $gundirection
@onready var attack_cooldown = $attackcooldown
@onready var animation_player = $AnimationPlayer

# Called when the node enters the scene tree for the first time.
func shoot():
	if attack_cooldown.is_stopped() and Bullet != null:
		var bullet_instance = Bullet.instantiate()
		var direction = (gun_direction.global_position - end_of_gun.global_position).normalized()
		GlobalSignals.emit_signal("bullet_fired", bullet_instance, end_of_gun.global_position, direction)
		attack_cooldown.start()
		animation_player.play("muzzleflash")




here is the code for the enemy

extends CharacterBody2D

signal killed(points)

@onready var health_stat = $Health
@onready var ai = $AI
@onready var weapon = $weapon

@export var speed: int = 100
@export var points: int = 100

func _ready() -> void:
	ai.initialize(self, weapon)

func rotate_toward(location: Vector2):
	rotation = lerp(rotation, global_position.direction_to(location).angle(), 0.1)

func velocity_toward(location: Vector2) -> Vector2:
	return global_position.direction_to(location) * speed

func handle_hit():
	health_stat.health -= 20
	if health_stat.health <= 0:
		killed.emit(points)
		queue_free()


here is the code for the bullet:

extends CharacterBody2D

signal killed(points)

@onready var health_stat = $Health
@onready var ai = $AI
@onready var weapon = $weapon

@export var speed: int = 100
@export var points: int = 100

func _ready() -> void:
	ai.initialize(self, weapon)

func rotate_toward(location: Vector2):
	rotation = lerp(rotation, global_position.direction_to(location).angle(), 0.1)

func velocity_toward(location: Vector2) -> Vector2:
	return global_position.direction_to(location) * speed

func handle_hit():
	health_stat.health -= 20
	if health_stat.health <= 0:
		killed.emit(points)
		queue_free()


here is the code for the bullet manager:

extends Node2D

func handle_bullet_spawned(bullet: Bullet, position: Vector2, direction: Vector2):
	add_child(bullet)
	bullet.global_position = position
	bullet.set_direction(direction)

here is the code for the enemy ai:

extends Node2D

signal state_changed(new_state)

enum State {
	PATROL,
	ENGAGE
}

@onready var player_detection_zone = $playerdetectionzone
@onready var patrol_timer = $patroltimer

var current_state: int = -1 : set = set_state
var actor: CharacterBody2D = null
var player: Player = null
var weapon: Weapon = null

var origin: Vector2 = Vector2.ZERO 
var patrol_location: Vector2 = Vector2.ZERO
var patrol_location_reached := false
var actor_velocity: Vector2 = Vector2.ZERO


func _ready() -> void:
	set_state(State.PATROL)



func _process(delta: float) -> void:
	match current_state:
		State.PATROL:
			if not patrol_location_reached:
				actor.rotation = lerp(actor.rotation, actor.global_position.direction_to(patrol_location).angle(), 0.1)
				actor.velocity = actor_velocity
				actor.move_and_slide()
				actor.rotate_toward(patrol_location)
				if actor.global_position.distance_to(patrol_location) < 5:
					patrol_location_reached = true
					actor_velocity = Vector2.ZERO
					patrol_timer.start()
		State.ENGAGE:
			if player != null and weapon != null:
				var angle_to_player = actor.global_position.direction_to(player.global_position).angle()
				actor.rotate_toward(player.global_position)
				if abs(actor.rotation - angle_to_player) < 0.1:
					weapon.shoot()
			else:
				print('In the engage state but no weapon or player')
		_:
			print("ERROR: FOUND A STATE FOR OUR ENEMY THAT SHOULD NOT EXIST")

func initialize(actor, weapon: Weapon):
	self.actor = actor
	self.weapon = weapon

func set_state(new_state: int):
	if new_state == current_state:
		return
	
	if new_state == State.PATROL:
		origin = global_position
		patrol_timer.start()
		patrol_location_reached = true
	
	current_state = new_state
	emit_signal("state_changed", current_state)

func _on_playerdetectionzone_body_entered(body: Node) -> void:
	if body.is_in_group("player"):
		set_state(State.ENGAGE)
		player = body

func _on_playerdetectionzone_body_exited(body) -> void:
	if player and body == player:
		set_state(State.PATROL)
		player = null

func _on_patroltimer_timeout() -> void:
	var patrol_range = 50
	var random_x = randf_range(-patrol_range, patrol_range)
	var random_y = randf_range(-patrol_range, patrol_range)
	patrol_location = Vector2(random_x, random_y) + origin
	patrol_location_reached = false
	actor_velocity = actor.velocity_toward(patrol_location)
	

here is the code for the health that can be used for the player and the enemy:



@export var health: int = 100 : set = _set_state, get = _get_state

	

func _set_state(new_health):
	health = clamp(new_health, 0, 100)



func _get_state():
	return health

here is the code for the global signals:

extends Node


signal bullet_fired(bullet, position, direction)


I am using godot 4.2.2

here is the tutorial I have been following: https://www.youtube.com/watch?v=6JGKvJbkTWA

Help would be much appreciated, thank you!

what is your node tree look like?

here is a screenshot

sorry for the late response.
Assuming everything works before you Implement the Ui layer, an easy step to try is putting the UI layer behind the whole game so it doesn’t hold your input hostage
here are some ways:

  1. Just drag the level 1 child until the UIlayer is at the top (drag the first child first to keep the orientation player>enemy>bulletmanager>tilemap)
  2. If that doesn’t work you can try to set UIlayer’s Mouse Filter to Ignore
1 Like

Try changing _unhandled_input to _input as this will recognise all inputs. Control nodes can capture inputs and prevent propagation.

I think it works like this:
_input(event): Receives all input events
_unhandled_input(event): Receives input events not handled by GUI elements
_gui_input(event): For Control nodes, receives GUI-specific input

However, this catches me out all the time too (I am a beginner).

I might be completely wrong here but I am also sure control nodes have a setting to stop inputs or pass them, although I can’t remember where that is. In the inspector somewhere I am sure.

Good luck,

Paul

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.