0 votes

I created a class which stores some values like Health, Level etc.

extends Node
var Level = 1 setget set_Level, get_Level
var Health = 100 setget set_Health, get_Health
var Max_Health = 100 setget set_Max_Health, get_Max_Health
var Experience = 0 setget set_Experience, get_Experience
var Max_Experience = 10 setget set_Max_Experience, get_Max_Experience
var Regeneration = 0.01 setget set_Regeneration, get_Regeneration
var Walk_Speed = 200.0 setget set_Walk_Speed, get_Walk_Speed
var Gravity = 200.0 setget set_Gravity, get_Gravity
var Jump_Height = 200.0 setget set_Jump_Height, get_Jump_Height
var Attackspeed_Multiplier = 1.0 setget set_Attackspeed_Multiplier, get_Attackspeed_Multiplier
var Base_Damage = 5 setget set_Base_Damage, get_Base_Damage
var Damage_Multiplier = 1.0 setget set_Damage_Multiplier, get_Damage_Multiplier
var Damage setget ,get_Damage
var Protection = 0 setget set_Protection, get_Protection
var Hero = 0 setget set_Hero, get_Hero






func _ready():
    pass


func set_Level(var level):
    Level = level
func get_Level():
    return Level

func set_Health(var health):
    Health = health
func get_Health():
    return Health

func set_Max_Health(var max_Health):
    Max_Health = max_Health
func get_Max_Health():
    return Max_Health

func set_Experience(var experience):
    Experience = experience
func get_Experience():
    return Experience

func set_Max_Experience(var max_Experience):
    Max_Experience = max_Experience
func get_Max_Experience():
    return Max_Experience


func set_Regeneration(var regeneration):
    Regeneration = regeneration
func get_Regeneration():
    return Regeneration

func set_Walk_Speed(var walk_Speed):
    Walk_Speed = walk_Speed
func get_Walk_Speed():
    return Walk_Speed

func set_Gravity(var gravity):
    Gravity = gravity
func get_Gravity():
    return Gravity

func set_Jump_Height(var jump_Height):
    Jump_Height = jump_Height
func get_Jump_Height():
    return Jump_Height

func set_Damage_Multiplier(var damage_Multiplier):
    Damage_Multiplier = damage_Multiplier
func get_Damage_Multiplier():
    return Damage_Multiplier

func set_Attackspeed_Multiplier(var attackspeed_Multiplier):
    Attackspeed_Multiplier = attackspeed_Multiplier
func get_Attackspeed_Multiplier():
    return Attackspeed_Multiplier

func set_Base_Damage(var base_Damage):
    Base_Damage = base_Damage
func get_Base_Damage():
    return Base_Damage

func set_Protection(var protection):
    Protection = Protection
func get_Protection():
    return Protection

func get_Damage(var enemy):
    return (get_Base_Damage() * get_Damage_Multiplier())*(1-enemy.get_Protection()/100)

func set_Hero(var hero):
    Hero = hero
func get_Hero():
    return Hero

But I don't know how I should call this class correctly. In my hero.gd I use

var stats = preload('res://scripts/stats.gd').new()

BUT if I use this in another class the values are not the same.
Is there a way I can use to make the full class static?

static func set_Level(var level):
    Level = level
static func get_Level():
    return Level

Won't work because it can't finde Level

in Engine by (64 points)

Be careful about singletons. Because they are not scoped, global things tend to leak and their usage is hard to track down. It's fine for constants, but you have to remember global variables should be up to date. Do all your code actually needs to access all of them at any time?

By the way, constants can be declared with const and you don't need to have a singleton class for them, just do preload("script.gd").THE_CONSTANT.

There can't be constants because for example the Health variable needs to change everytime the enemy hits the hero... And it needs to be accessed anytime because the health display also needs to access this variable.

Yeah, but I mean, do you also need that when on the main menu or settings for example?
If it's just a matter of communication you could tell the GUI to track a specific health node for example. That way you can manage health the same way for everything having a health.

Also, if one day you decide to have two heros, a pet or something (changes happens a lot in game dev!), you would be screwed because your singleton and all code using it will have to be refactored, and refactoring GDScript is not easy :p

Anyways, these are design ideas :) Singletons should be fine for very simple games, but my experience told me they become a problem when a project gets larger. Not telling they should be banished totally, just used with care if you have no other solution.

Okay that makes sense... But how can I get the stats of the hero into an other scene? I can't just load the scene and then the hero, because there will be multiple levels which means there will be multiple instances of stats.gd if I use get_node("hero").stats

I have to admit that I don't know much ways of preserving data when changing the scene.
The first solution is of course auto-load, but if you have a HUD for example (or stats in your case) you don't want it to go be recreated everytime just because you loaded a new level.
Another solution is to have a host scene which loads levels as child at a specific location. I did that for my game, but sadly I still needed a singleton JUST to pass the level number from the main menu, which is only used at one particular moment. Strange fate for a singleton :p

But again, I would say it depends on the project's scale. autoload is convenient but just because it makes a node's lifetime and access to span the WHOLE program execution, I try to limit that scope the best I can to prevent mistakes.

1 Answer

+1 vote
Best answer
by (1,277 points)
selected by

He doesn't ask for a singleton but for a data container. Maybe it can be a singleton here, but there are case where multiple entities use the same structure but for their own instance. For instance, Zelda 4 swords would have 4 different heroes, with each one his own level, health, damage...
His problem in his code is that he creates a new instance of the class instead of using the instance of the hero, like get_node("hero").stats.

Since it's only 1 hero I think the singleton is the best way because I can still use the variable in other scenes for example a shop...
But thank you. get_node("hero").stats works too!

@gokumatic Well I was not judging on what he is doing but from his question he was asking for something he called 'Full static classes' -> and that would be singletons. But yeah it's hard to not agree with you, I would probably prefer to use reference to 'Hero' in this case as well.

@kubecz3k Sorry. I didn't mean to be rude.

@Gokumatic Don't think you were rude, it was all ok for me :) We all are here to help, good thing that you mentioned what is other way to do this stuff :)

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.