godot 4 setter with connect()

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Naowut

Im following along with a tutorial and succeeding in converting it to godot 4 so far. However, I’m not quite sure how to use the new setters with a connect. Below is my code.

 var hearts = 100: 
	set(val): 
		hearts = setHearts(val);
	get:
		return hearts;

func _ready():
	self.hearts = PlayerStats.health;
	PlayerStats.connect("health_updated", setHearts);

func setHearts(val):
	print(val);
	print(hearts);
	return clamp(val, 0, max_hearts);

print val = correct
print hearts = not correct
This is most likely because the setHearts function just returns a value which I dont assign to hearts. I’m not sure what the best way is to call the setter from connect. Setting hearts inside the function like I would expect throws an infinite recursion error.

Fixed it by adding a new function updateHearts but I think its a bandaid and would like to set it directly from the connect() function…

var hearts = 100: 
	set(val): 
		hearts = setHearts(val);
	get:
		return hearts;

func _ready():
	self.hearts = PlayerStats.health;
	PlayerStats.connect("health_updated", updateHearts);

func updateHearts(val):
	hearts = val;

func setHearts(val):
	return clamp(val, 0, max_hearts);

Naowut | 2023-01-09 19:27

Hello, thank you for the solution, I modified it a bit to not have 2 functions, clamp(val, 0, max_hearts) can be moved directly in the health’s setter (instead of another function) like in the initial tutorial (which I am also following) and then made updateHearts into set_hearts to look more like the tutorial’s code, this is the result and it works in Godot 4.0.2:

extends Control

@onready var label = $Label

var hearts = 4:
	get:
		return hearts
	set(value):
		hearts = clamp(value, 0, max_hearts)

func set_hearts(value):
	hearts = value;
	
var max_hearts = 4:
	get:
		return max_hearts
	set(value):
		max_hearts = max(value, 1)

func _ready():
	self.max_hearts = PlayerStats.max_health 
	self.hearts = PlayerStats.health
	PlayerStats.health_changed.connect(set_hearts)
 

FIREHIVE | 2023-04-22 09:11

:bust_in_silhouette: Reply From: stormreaver

You’re close. You’re printing hearts before you assign it.

Assign hearts in your setHearts() function, and don’t bother with a return value.

func setHearts(val):
    print(val);
    hearts = clamp(val, 0, max_hearts);
    print(hearts);

or do it in your set method:

 var hearts = 100: 
    set(val): 
        hearts = clamp(val, 0, max_hearts);

I haven’t tested the code, but I think it will work.

Thanks for your anwser but the print isnt the problem. It never gets assigned.
When running the code in a loop, the val goes down but the hearts stay the same.

The problem is here:

PlayerStats.connect("health_updated", setHearts);

Your first solution gives the ininite recursion error I talked about.
Your second solution doesnt work for me because I need a callable inside the connect function. And thats exactly my problem.

PlayerStats.connect("health_updated", <HOW MAKE THIS WORK>);

Naowut | 2023-01-09 18:54

Godot 4’s connection system has changed from prior versions.

Godot 3 would use (assuming PlayerStats is an object, and not something else like a class):

PlayerStats.connect("health_updated",self, healthUpdatedHandler)

While Godot 4 uses:

PlayerStats.health_updated.connect(healthUpdatedHandler)

Without having your complete code, I have to make some assumptions.

In either case, the handler would be:

func healthUpdatedHandler(value):
    pass

That assumes that the health_updated signal passes a single parameter.

stormreaver | 2023-01-10 00:26

You must create and assign the set or get functions within your variable to make them callable in Godot 4.

 var hearts = 100: 
    set = setHearts

func _ready():
    self.hearts = PlayerStats.health
    PlayerStats.health_updated.connect(setHearts)

func setHearts(val):
    hearts = clamp(val, 0, max_hearts)

Apewall | 2023-03-14 20:18