Player health to Label text
Asked Answered
M

3

0

I consider myself a beginner in Godot, and it's been a week that I've been trying to fix this, which is updating the health in the player script to the label script.
I've seen and searched for many tutorials and other people's questions to fix this, but I still didn't find a way.

In Player script

extends CharacterBody2D
@export var health = 200

Game script (where all the nodes are)

extends Node
@onready var text = $ui/Health_panel/text_hp2
@onready var health = global.health
func _ready():
	text.text = "Player Health: " + str(health)

global script - for the global variables

extends Node
@export var health = 200

label script - the text itself

extends Label
func update_health():
	var health = global.health

After many tests, these were the only things left. What is better? Try to emit a signal from the player script directly to the label script, or connect variables with the global, or game scripts?
It's my first time asking about coding in a forum, so I still have no experience in this. So I'm gonna be extremelly grateful if someone could help me with this :')

Mosasaur answered 23/6, 2023 at 23:30 Comment(0)
D
0

Mosasaur What is better? Try to emit a signal from the player script directly to the label script, or connect variables with the global, or game scripts?

As stated by Hartwell , you are not updating the Label constantly and it won't change text. Your question is how you do it, right?

I generally try to avoid globals, when there is another solution. And use them when only neccessary, or when their use makes sense.

Generally the rule is signal up (signal to parents and siblings) call down (functions of children)

Setter function is a very neat way to do this, they are called whenever their variables change, and you can do anything inside them

In the player script you can do this:

# Beware that, with export vars, the set function is also called first thing, 
# even on the default value, so try not to access other nodes, 
# as they will not be ready/instantiated yet.
# A workaround can be to have @export var default_health,
# and another var health with setter function 
# Then inside _ready() you do health = default_health
# That was only a solution to problem you might face someday, in a different context
@export var health = 200:
  set(value):
    # Whenever you try to change the health value, 
    # this gets called and the below code is executed
    health = value
    # A signal can carry information too, such as health
    emit_signal("health_changed", health)

signal health_changed(health)

In Game script:

@onready var text = $ui/Health_panel/text_hp2
@onready var player = $Player # or wherever you Player node is in the Game node tree

# The neat thing about _ready() is that it is called AFTER every child node is ready
# Put that in mind and you can traverse the mine field called scene tree :')
func _ ready():
  # connect signals, you can do it in the editor too via signals tab
  # connect the health_changed signal, from the player, to the update_health(new_health) function in the health label
  player.health_changed.connect(text.update_health)
  # Beware that since the children nodes were ready first,
  # if the player emitted a signal( which it did in the set function of the export var),
  # nothing happens because the signal was not connected yet
  text.update_health(player.health) # Neat way to update it first thing and show the health at the start
  # A scum elitist would do player.health = player.health 
  # knowing the set function will be called and emit the already connected signal xD

Now change the update_health function in the label script to something like this

func update_health(new_health):
  text = " Player Health: " + String.num(new_health) # Both sides need to be String type

Tada, you have a label that updates whenever the player's health change

  • Note: The neat thing about signals, is that it separates code logically. So you can cannect the signal to the gui that holds a label and health bar for example, and update both. Or you can connect the signal to another function in the game scene which check the health, and accordingly alert some types of enemies like blood seekers for example. You can go wild with signals!

  • Also notice that you are only updating the label when the health changes, and not ever frame. Much optimization.

I hope that was helpful with the explanations πŸ˜‰

Edit: Correct here and there, add the last notice.

Demivolt answered 24/6, 2023 at 6:30 Comment(0)
H
0

In the function _physics_process(delta) there should be the life bar because if you put it in ready, only the data that was there when the script was executed will appear

Hartwell answered 24/6, 2023 at 2:24 Comment(0)
D
0

Mosasaur What is better? Try to emit a signal from the player script directly to the label script, or connect variables with the global, or game scripts?

As stated by Hartwell , you are not updating the Label constantly and it won't change text. Your question is how you do it, right?

I generally try to avoid globals, when there is another solution. And use them when only neccessary, or when their use makes sense.

Generally the rule is signal up (signal to parents and siblings) call down (functions of children)

Setter function is a very neat way to do this, they are called whenever their variables change, and you can do anything inside them

In the player script you can do this:

# Beware that, with export vars, the set function is also called first thing, 
# even on the default value, so try not to access other nodes, 
# as they will not be ready/instantiated yet.
# A workaround can be to have @export var default_health,
# and another var health with setter function 
# Then inside _ready() you do health = default_health
# That was only a solution to problem you might face someday, in a different context
@export var health = 200:
  set(value):
    # Whenever you try to change the health value, 
    # this gets called and the below code is executed
    health = value
    # A signal can carry information too, such as health
    emit_signal("health_changed", health)

signal health_changed(health)

In Game script:

@onready var text = $ui/Health_panel/text_hp2
@onready var player = $Player # or wherever you Player node is in the Game node tree

# The neat thing about _ready() is that it is called AFTER every child node is ready
# Put that in mind and you can traverse the mine field called scene tree :')
func _ ready():
  # connect signals, you can do it in the editor too via signals tab
  # connect the health_changed signal, from the player, to the update_health(new_health) function in the health label
  player.health_changed.connect(text.update_health)
  # Beware that since the children nodes were ready first,
  # if the player emitted a signal( which it did in the set function of the export var),
  # nothing happens because the signal was not connected yet
  text.update_health(player.health) # Neat way to update it first thing and show the health at the start
  # A scum elitist would do player.health = player.health 
  # knowing the set function will be called and emit the already connected signal xD

Now change the update_health function in the label script to something like this

func update_health(new_health):
  text = " Player Health: " + String.num(new_health) # Both sides need to be String type

Tada, you have a label that updates whenever the player's health change

  • Note: The neat thing about signals, is that it separates code logically. So you can cannect the signal to the gui that holds a label and health bar for example, and update both. Or you can connect the signal to another function in the game scene which check the health, and accordingly alert some types of enemies like blood seekers for example. You can go wild with signals!

  • Also notice that you are only updating the label when the health changes, and not ever frame. Much optimization.

I hope that was helpful with the explanations πŸ˜‰

Edit: Correct here and there, add the last notice.

Demivolt answered 24/6, 2023 at 6:30 Comment(0)
M
0

Demivolt Ohhh, that worked right as I tested it, thank you so much!
And thanks you two for reminding me of updating the Label constantly, I think that was the main reason it was not working.
But thank you again πŸ™‚

Mosasaur answered 24/6, 2023 at 17:7 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.