I have an array of Resources (Supply). The Resources have been created via the editor. local_to_scene is ticked.
The problem is that both Actors on the right are being damaged, despite the damage only being applied to the rightmost one (see the fire). As it isnt applied to the other actor, is it something to do with affecting every instance of the scene, rather than just a specific instance? If so, how would I have the resource be specific to the instance?
Here’s the relevant Actor’s Scene, showing the local_to_scene still ticked.
The Resource is a Supply class. Here’s the (slightly reduced) code:
## info regarding a changeable value, such as health or mana.
@icon("res://assets/node_icons/supply.png")
class_name SupplyComponent
extends Resource
#region SIGNALS
signal value_changed() ## the resource value has changed
signal value_decreased(amount: float) ## the resource value has decreased
signal emptied() ## there is none of the resource left
signal max_value_changed() ## the resource's max value has changed
#endregion
#region EXPORTS
@export_group("Details")
@export var type: Constants.SUPPLY_TYPE ## @REQUIRED.
@export var max_value: int = 999: ## @REQUIRED.
set(value):
max_value = clamp(value, 1, INF)
if max_value < value:
set_value(max_value)
value_changed.emit()
@export var regeneration_per_second: float = 0
#endregion
#region VARS
var value: int:
set(value):
push_warning("SupplyComponent: Can't set value directly. Use funcs.")
get:
return _value
var _value: int = 999:
set(value):
if value > max_value:
_value = max_value
else:
_value = value
value_changed.emit()
# Signal out when health is at 0
if value <= 0:
emptied.emit()
#endregion
I need more info because in the gif that you have uploaded, it seems like both units are being hit with only one projectile which would make me want to place a Breakpoint at the point of the projectile hitting the enemy.
Does it send a signal? maybe every enemy picks up on the value_decreased() signal even though it should only be affecting the one enemy being hit.
No the resources are not shared. The problem seems to be elsewhere, since the visual effects are also applied, except for the fire. They have their own health, but they are hurt when one of them is hurt, which leads to them dying at the same time
I think whats happening here is, that the chain-effect is applied veryfast back and forth between the targets. Thats why they both get damaged and die.
I just checked out the code and I believe the crux of the problem is in your deal_damage_effect.gd line41: supply.decrease(damage)
This will then decrease its value and then emit the signal.
Who is listening to the signal? I believe it is every single Combat Actor that has this component installed. combat_actor.gd line58 and line60
Don’t take my word for it though, I just briefly skimmed through the code
it seems like both units are being hit with only one projectile which would make me want to place a Breakpoint at the point of the projectile hitting the enem
I think that is just how it looks, though I’ll check. The collision stuff was working fine until this move to Resources. I’ll check!
they are [both] hurt when one of them is hurt
You could well be right. I thought it was because they are sharing an instance of Health (the Supply), but absolutely could be something else.
I think whats happening here is, that the chain-effect is applied veryfast back and forth between the targets.
Hmm. I was using Nodes for the Health and that didnt happen, so with the only thing changing being moving to inherit from Resource rather than Node I didnt think it was that. I’ll double check, though.
I just checked out the code and I believe the crux of the problem is in your deal_damage_effect.gd line41: supply.decrease(damage)
This will then decrease its value and then emit the signal.
Who is listening to the signal? I believe it is every single Combat Actor that has this component installed.
That should be easy enough for me to confirm, as in that case the Health would only change for 1 of them.
Despite only 1 being hit, both are effected. Not collision issue.
When applying damage (i.e. reducing health) we use a specific CombatActor, so doesnt seem to be accidentally affecting all of them.
class_name DealDamageEffect
[...]
## reduce health of target
func apply(target: CombatActor) -> void:
var supplies: SupplyContainerComponent = target.get_node_or_null("SupplyContainer")
if supplies is SupplyContainerComponent:
var supply = supplies.get_supply(target_supply)
var damage = _calculate_damage(target)
supply.decrease(damage)
I find the Resource bit really confusing. The object ref in the debugger doesnt match the one in the Remote Scene Tab.
supply variable:
Click to inspect and I get:
If I go through the Remote Scene Tree and hover over what would be Health in the SupplyContainer, we see the same ref as the debugger:
Okay yes they should have different object-ids, so your first assumption appears to be correct. This might be a caching-error, you can try to delete the cache and see if it still happens.
I once had a problem where the local_to_scene was working but sadly i dont remember how i fixed it
I still believe when you emit the signal of value_decreased() signal, that you should also include an id of the combat actor that you want to address or else every combat actor will receive the signal and then say “Okay, this signal is for me. I need to take damage.”
I haven’t implemented Components yet but I have the firm belief that every actor should know which component it uses, and also every component should know who it belongs to.
How about every component have a variable called owner and whenever a combat_actor initializes their components, they also pass themselves along as a parameter so the component saves it as the owner.
Whenever the component receives a signal, it also checks the id if it’s the same as its owner. If not the same, ignore the signal and return
in your combat actor can you print out the health?
if _supply_container is SupplyContainerComponent:
var health = _supply_container.get_supply(Constants.SUPPLY_TYPE.health)
print("My health: ", health)
health.value_decreased.connect(_on_hit_flash.activate.unbind(1)) # activate flash on hit
health.emptied.connect(func(): died.emit()) # inform of death when empty
health.value_decreased.connect(_damage_numbers.display_number)
they should technically all have their own object-id. if they all print the same object-id, they share the same health. That would mean that this is a bug and you should probably open up an issue on github
@Locher very happy to give that a try when back at the computer later, though I’m unsure why that would only be an issue after moving to inheriting from Resource instead of Node (unless some other change I am forgetting caused it! )
For the start, you could print out the name of the parent_node when it goes into the handler of whenever the damage number is displayed. Our goal is that when the projectile hits one enemy, only the affected enemy should receive damage and show the damage number.
If the damage number is displayed more than one time, then we will slowly walk back the code procedure to find out if it’s a resource-sharing problem or a signal-oversight.
This is a bug. Looks like there have been a few patches to fix related problems, but they didn’t solve this specific issue. Don’t forget to give it a thumbs-up vote on GitHub. For now, you would have to work around this by duplicating the resource in your script.
class_name CombatActor
[...]
func _ready() -> void:
if _supply_container is SupplyContainerComponent:
var health = _supply_container.get_supply(Constants.SUPPLY_TYPE.health)
print("CombatActor._ready:", self, " has this health component: ", health)
Which resulted in this:
CombatActor._ready:WolfRider:<RigidBody2D#55448700198> has this health component: <Resource#-9223371979996789257>
CombatActor._ready:HorseyRider:<RigidBody2D#56035902797> has this health component: <Resource#-9223371979996789257>
CombatActor._ready:HorseyRider2:<RigidBody2D#56472110477> has this health component: <Resource#-9223371979996789257>
Also added print to pop up numbers, which returned this from a single instance of damage:
PopUpNumbers.display_number: called on WolfRider:<RigidBody2D#55448700198>
PopUpNumbers.display_number: called on HorseyRider:<RigidBody2D#56035902797>
PopUpNumbers.display_number: called on HorseyRider2:<RigidBody2D#56472110477>
So does that confirm that they’re all sharing the Resource?
@trickster721 ah, I saw the fix listed for 4.3 and assumed it was sorted. Found this workaround suggested. All seems to be working now!
Result:
Code:
class_name SupplyContainerComponent
[...]
@export var _editor_supplies: Array[SupplyComponent] = [] ## this is a wrapper for _supplies, due to godot's issue with arrays always sharing resources.
var _supplies: Array[SupplyComponent] ## all supplies. copied from _editor_supplies on _ready.
func _ready() -> void:
_duplicate_supplies_array()
## duplicate all supplies in _editor_supplies to _supplies
func _duplicate_supplies_array() -> void:
for supply in _editor_supplies:
_supplies.append(supply.duplicate(true))
Thank you to everyone for all of your help!
P.S. can I do something to make this easier to help others with the same issue?
Yes they share the same health-resource as they have the same object-id.
I think the marked solution is automatically linked to the original help-message, which should help people to just click on it and see the solution. So you dont need to do anything