@export variable not updating in hitpoints declaration

Hello everyone!
I’m not sure if this is specific to Godot 4.2, but it seems like the declaration of hitpoints does not work as intended. I was a bit confused because I changed the max_hitpoints value in the inspector, but nothing changed when the game started. A few print statements later, I found out that

var hitpoints: int = max_hitpoints:

does not use the updated value of max_hitpoints from the inspector. Do I see that right?
My solution here was to delete the variable reference in the declaration of hitpoints and then set hitpoints to max_hitpoints in the _onready function.

Does anyone else find the problem? Is it Godot 4.2-specific, or do I have something else wrong?

This is a very interesting observation, and one of several reasons I tend to avoid @export variables. After reproducing your result in a sandbox project, I realize now that Bram’s code appears to work in the video only because he never attempts to change max_hitpoints from its default value in any of the lectures.

I can confirm there is nothing wrong with the syntax you posted here becausemy project uses identical syntax, but I get max_hitpoints in a completely different way that isn’t relevant here.

There is definitely confusion out there over how to use @export because it doesn’t actually pull its updated value from the inspector at the time of its declaration. I’m not sure if it does so exactly at _ready() or slightly before, but in either case, it will be there for _ready(). There is similar confusion about _ready() itself.

Your solution works, and is essentially how you would go about fixing the timing mismatch in this case. A slightly more straightforward way to fix the code is to revert your changes and do this (same change, just less code):

@export var max_hitpoints := 100
@onready var hitpoints = max_hitpoints
1 Like

Hello BH67,

Thanks for checking in and reproducing the issue! I changed my code as recommended by you.
Is there another way to access variables from the inspector than using @export, or are you just trying to use it as little as possible in general?

It feels a bit like a bug since, in the course, Bram is using the @export syntac just to make the variables accessible from the inspector, but in this case, the inspector changes are overwritten by the values in code. :sweat_smile:

Ah, see, this is what I first thought as well the first time I encountered similar issues, but it’s actually not what’s happening. When you define a normal variable like this:
var imanumber = 5
the variable is created and its value is assigned on the same line, but more to the point, both of these things are actually happening at this time, exactly as the code suggests it should.

@export variables do not work this way, which is counter-intuitive because the code is in the same format. It does indeed feel like a bug, but only because we expect @export variables to follow the same pattern as normal variables… because why on earth wouldn’t they?

It’s not that the default value is overwriting what the inspector shows; rather, the default value is all that the game has at the moment this line is executed because it hasn’t even checked the inspector yet. The purpose of using @onready in the way we both did is basically to tell the game to wait until the inspector is read (and therefore max_hitpoints receives its true value) before using max_hitpoints to assign a value to hitpoints.

@export variables absolutely have their place (great for quick prototyping for example), but yes, I barely use them in general. There are a few inherent problems with @export variables, but there’s pretty much always a way around using them in the first place, and each problem can still be overcome without doing so:

  • Not scalable, unless you’re specifically using them in a template of some kind that will be inherited or instantiated by something else dynamically… and in that case, is it really necessary to use @export variables instead of normal ones? Maybe, but I can’t see an example.
  • If a field is left empty by mistake and you don’t set a default value in code, it’s almost certain your code will break. Writing your own exception-handling can fix this (checking if empty during _ready() for example).
  • If you do have a default value and you change the value in the inspector, there is nothing in your code that will indicate you are using a non-default value. I ran into that one face-first during Kaan’s Alien Attack. This is harder to solve (console output is one solution during development), but again just comes down to the context in which you’re using the variable.

Hope that all makes sense =)

1 Like

Okay, I’ve no questions left! :smiley:

Thanks a lot four your answers!

1 Like

Privacy & Terms