How to update Progress Bar value?

Godot Version 4.2.1

Question

Hi! I’m trying to create the logic for the main mechanic of my game. Basically what it needs to happen is that if an enemy Area2D enters the Area2D of the player (I’m using this node for now but let me know if there are better nodes to do this), the enemy progress bar starts to fill up. Do you have any suggestions on how to do so? Also this system needs to be modular(idk if it’s the right term for this) meaning that there are different enemies and they’re going to have bigger/smaller max values for the progress bars, and the player can increase the rate at which they fill up through upgrades.

1 Like

Hi Daggherino,

In the script assigned to the Area2D you can use the “get_overlapping_bodies” function to get all the object inside the area. Then loop through all the bodies and check if they have the charge function on them and if they do, call it.
Alternatively you could register and deregister the objects with the body_entered and body_exited. That’s probably what I would do.

Untested Pseudo Code

extends Area2D

var objects_in_area = []
var charge_per_second = 5.0


func _ready():
	body_entered.connect(on_body_entered)
	body_exited.connect(on_body_exited)


func _process(delta) -> void:
	for obj in objects_in_area:
		obj.charge_power(charge_per_second * delta)


func on_body_entered(body):
	# only objects that have the right function get added to the list by using has_method to qualify them
	if body.has_method("charge_power"):
		objects_in_area.append(body)


func on_body_exited(body):
	objects_in_area.erase(body)
1 Like

Doing this per frame could be costly if its a lot of objects. Its the easiest solution from a code point of view, but not from a performance point of view.

Its far better do it from the enemy point of view, if the enemy enters the player area it does the work instead. That way only the enemies in the area are running that code.

The player shoudlnt need to worry about what the enemies are doing in good OOD design.

1 Like

So I’m liking @Arnklit’s logic and I want to test it out. I was writing some code on my own and I’m kind of stuck. Basically I want that the single enemy does the calculation like @OriginalBadBoy said but I can’t figure out how to make the collision shape of the enemy communicate with the Area2D of the player. Should I had an Area2D to the enemy also?

These are my scenes for the player and the entity if it can be of any help
ET
PT

So I would not worry about performance early on, just try stuff out and play around. So if you would rather do it from the enemies point of view. You can do something like this.

extends Area2D

@onready var halo_area = get_tree().get_first_node_in_group("halo")


func _process(delta) -> void:
	if overlaps_area(halo_area):
		# Perform logic for charging

Note you’d have to set the halo areas group as “halo” as that is how I get the reference in this example.

1 Like

Am I doing something wrong?

Looks like conversionsArea is null. did you set the nodes Group to be “Enemies”?

I didn’t! Now no errors, but no print.

Hmm not sure. looks right to me from what I can see.

Yes so you would have a script on the enemy that detects the hit with the player area.

And then the work you want to do on the enemy is done there instead.

The player doesnt even need to worry out it then.

1 Like

For today I can’t work on it anymore. I’m going to give you an update tomorrow

@OriginalBadBoy @Arnklit I found a solution for now.

extends Area2D

@onready var entityBar = $"../EntityBar"

@export var maxValue:float = 100

var isConverting:bool = false

func _ready():
	entityBar.value = 0
	entityBar.max_value = maxValue
	
#Handles the convRate added to the entityBar.value
func _process(_delta):
	if isConverting == true:
		entityBar.value = entityBar.value + PlayerVariables.convRate
	else:
		return

func on_entity_area_entered(area):
	if area.name == "HaloArea":
			isConverting = true

func _on_entity_area_exited(area):
	if area.name == "HaloArea":
		isConverting = false```

this is the code inside the Entity's Area2D
2 Likes

This is a demo on how the mechanic works

I’d rather use get_overlapping_areas + timer.
To summarize: you get a list of overlapping areas, then iterate through it, checking objects for a group, name or tag. If you catch what you need, call the method from the side of the caught one.
As for performance, it is not necessary to call the method every frame… it is enough to connect a timer with a period of, for example, 0.2 seconds.

Implementation option in C#:
image

Where I have GD.Print(area), you will call the method of the same name from the side of the mobs, where a parameter will be specified in the mob itself that affects the speed of filling the progress bar.

Sure that will work , but its not very OOD, and whilst it may not be a performance issue, its not good practice. IMO of course.

If you were to scale that up to say a bullet hell game for example it would be a problem.

The object overlapping should do that itself, it creates cleaner code which is easier to understand and is scaleable.