I made health property as component, so any object with that property can be damaged.

extends Node

class_name Health, 'res://assets/icons/health_ico.png'

var entity
var stats_name
var init_health = 4
var health = init_health

func _init():

    self.stats_name = 'health'

func _ready():
    entity = get_parent()
    self.entity.stats[self.stats_name] = self
    print('target:' + str(entity))
    print('me:' + str(self))

func apply_damage(damage = 0):
    self.health -= damage
    if health <= 0:

But the problem is that no matter what I attack, all the damage dealt is applied to a single entity.

I'm sure it's a problem with a reference to a component, but can't find/fix it.

The log says that they are all different nodes:


The bullet code that hits entities:

extends Area2D

var damage = 1
var speed: int
var lifetime: float
func _init(speed: int = 500, lifetime: float = 1.0):
    self.speed = speed
    self.lifetime = lifetime

func _physics_process(delta: float):
    position += transform.x * speed * delta
    lifetime -= delta
    if lifetime < 0:

func _on_bullet_body_entered(body):
    print('attack target' + str(body))
    if body.is_in_group('projectile_bound'):
    print('attack health' + str(body.stats['health']))

The entity code:

extends Node

@onready var label = get_node("Label")
@onready var health = get_node("Health")
const stats = {} #This is actually the real problem

func on_0_health():
func _process(delta):
    label.text = 'damage: ' + str(-health.health)

1 Answer 1


I am using Godot 4.0 alpha 15.

The "fun thing" is that Dictionary defined with const keyword is shared between all instances. So when bullet call health component from stats: Dictionary property on any attackable entity, it call the same dictionary.

Here's another work-around for static variable in GDScript, which hasn't been mentioned yet.

Define a const Dictionary variable on your class. Store and access your static variables as properties on that Dictionary. This works because the const Dictionary instance is shared between instances of the class. Even though the Dictionary is const and can't be re-assigned, it is still "mutable", so you can change its properties as much as you want.

class_name Main
extends Node

func _ready() -> void:
    var a := MyClass.new()
    var b := MyClass.new()

    a.STATIC_VARIABLES.is_my_flag_enabled = true


class MyClass extends Reference:

    const STATIC_VARIABLES := {
        is_my_flag_enabled = false,


  • \$\begingroup\$ The problem was that Dictionary defined with const on target entity, instead of preventing variable from reassignment, shares it's instance between all entities. Like static properties in other languages. So problem wasn't in health component at all. \$\endgroup\$ Sep 15 at 15:08
  • \$\begingroup\$ You should edit the answer to highlight just this, as right now, the answer does mention a dictionary, but it is not linked at all to the question. \$\endgroup\$
    – Vaillancourt
    Sep 15 at 15:12
  • 2
    \$\begingroup\$ The original question doesn't even mention a dictionary. If you want to share your knowledge by self-answer, then you should ensure that the question is phrased in a way that it actually contains all information someone else would need to arrive at your answer. \$\endgroup\$
    – Philipp
    Sep 15 at 15:22
  • \$\begingroup\$ @Philipp This is strange behaviour of engine. I found the answer by accident when I tried all possible options, and started randomly changing pieces of code. So of course it is not related to original answer. \$\endgroup\$ Sep 15 at 15:28
  • \$\begingroup\$ @KirillMoskalew well then it's better to either delete the question or update it. Currently it's not useful for anyone \$\endgroup\$
    – Arian_ki
    Sep 15 at 18:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .