How do i reference a variable from another resource script in my calculation?

Godot Version

Godot 4.3

Question

Hi, so i’m very new to GDsscript and programming in general, and this is my first programming language, and i was trying to practice creating a resource for my modular skill system that can reference my ClassStat resource

this is the ClassStat script

extends Resource
class_name ClassStat

# Core Stat
@export var health : int
@export var mana : int
@export var base_movement_range : int
@export var dodge : int

# Attribute Stat
@export var strength : int
@export var dexterity : int
@export var agility : int
@export var intelligence : int

@export var willpower : int = 7
var max_health : int
var max_mana : int
var movement_range : int

# Leveling variables
var level : int = 1
var experience : int = 0
var experience_threshold : int = 100

func calculate_base_stat():
	max_health = health + (strength * 3)
	max_mana = mana + (intelligence * 2)
	movement_range = round(agility / 3)
	dodge = round(agility / 4)

func update_stat():
	calculate_base_stat()

func level_up():
	level +=1
	experience_threshold = int (experience_threshold * 1.5) 

func gain_experience(amount : int):
	experience += amount

func leveling_up():
	if experience >= experience_threshold:
		level_up()

and this is the SkillStat script

extends Resource
class_name SkillStat

@export var name : String
@export var base_damage : int
@export var applied_effect : String
var total_damage : int

func calculate_damage():
	total_damage = base_damage + attributes

what i’m confused is how do i reference the attributes in the ClassStat script for the calculation in the SkillStat script, sorry if the answer was obvious to some of you, i’m a newbie through and through in the programming world

You need a reference to an instance of the ClassStat resource in order to reference what is inside it. Depending on how you have your system set up, you can/should either obtain a reference of a ClassStat instance through the use of an @export variable, or via a parameter in calculate_damage():

# Instance reference via exported variable
@export var class_stats: ClassStat

# -----------------------------------------------------

# Instance reference via function parameter
func calculate_damage(class_stats: ClassStat):
	# Your code

Let me know if you have any questions about anything else.

1 Like

oh, i didn’t know you had to reference the ClassStat script, also i don’t know how to reference the attributes in the ClassStat, so i have 3 attributes for damage calculation : Strength, Dexterity, and Intelligence

and what i’m confused about is, how do i reference those 3 in the ClassStat, do i need to write 3 function for each of them, or how do i create a variable that can call each of them when i put the right attributes on the skill resource?

func calculate_damage(base_damage : int, class_stat: ClassStat):
	total damage = base_damage + ClassStat.strength
	return total_damage

what i meant is, i want to export the attributes needed to the inspector panel, and let the code pick the right attributes to calculate itself with if that makes sense? sorry i’m not good with technical words either
thanks for answering me beforehand

Question #1:

How do I reference the stat variables from the ClassStat class?

As mentioned, you need an instance of ClassStat in order to utilize the variables within that class. It seems like you don’t quite grasp the concept of an instance. I will try to provide an adequate description of what it means.

Instances in programming

Let’s start by focusing on ClassStat. Your ClassStat is a class: a concrete description of a unique object. Within a class, you define variables and functions. Variables are used to store and evolve data over time, and functions contain code that performs a set of operations. In short, a class defines the data and behaviour that constitutes an instance of that class. Think of classes as blueprints. You use a blueprint to build a house you can live in but that doesn’t mean you live in the blueprint.

A tried and true example of classes in programming is the Person class.

Person Class Example

Consider the class:

class_name Person

var name: String
var age: int

# This is the constructor for the class.
# A way to initialize the object with specific data.
func _init(name: String, age: int):
	self.name = name
	self.age = age

A person has a name and an age so these will be part of the class. However, we have yet to create any people; we must create Person instances. Therefore, we invoke the following code:

var p1 = new Person("Jake", 32)
var p2 = new Person("Jill", 27)
var p3 = new Person("Joan", 67)

As such, we have now created three distinct people; three instances of the Person class each with their own data.

So, let’s assume you have a ClassStat instance. You can now reference variables and functions inside the instance through dot notation.

I noticed that you are incorrectly referencing the class_stat parameter in your own example. Remember that GDScript’s syntax has the variable name first, then the type. Perhaps you were just tired?

func calculate_damage(class_stat: ClassStat):
	# Since this function is part of SkillStat, you don't need to
	# pass the base_damage in as a parameter. It is already available.
	total_damage = base_damage + class_stat.strength
	return total_damage

…and calculate_damage() would be called with:

var skill_stat: SkillStat # A variable containing a SkillStat instance

var skill_dmg = skill_stat.calculate_damage(self)
# The "self" keyword is a reference to the instance running the code.
# In this case, the ClassStat instance.

Question #2:

I’m afraid I need a better description of what you want to achieve with your skill system.

To export a variable you just need to use the @export attribute. I don’t understand the other part of this question though: “picking the right attributes to calculate itself”. Perhaps you can elaborate this point?

2 Likes

@Sweatix That’s some excellent work. :smile:

With regards to the "right attribute’ I’m going to guess as this is an RPG, the character/s will have/use different attack options. Maybe a sword, spell,etc. So the choice will either be chosen by the player, or the system will determine by the players “class” or similar. We’re missing a lot of information.

willpower is the only variable having a set value. I’m guessing it’s suppose to be null

I was going to suggest the lazy option and just place all of the variables inside the Player script. But if this the game is going to have a lot of players, a modular approach would be a much better choice.

2 Likes

sorry if what i’m saying sound gibberish to you, it’s been a long day for me trying to learn instancing and class resource, and how they connect, so i got everything messed up

so the game that i’m trying to make is, a tactical turn based RPG, where each entity will have a weapon they can equip that have their own skill tree, so the skill aren’t tied to the entity class, but rather the weapon itself will have the skill, as for the entity class, it will only have restriction to what kind of weapon it can use

each entity class then will have 3 main attributes that the skill will use to calculate it’s damage, and they are : Strength, Dexterity and Intelligence

each skill class then have a base damage, which will pick the correct attributes from the ClassStat to be used as calculation, so for example, let’s say a skill need to use the characters Strength attributes to be used as calculation, how do i reference the strength variable from the ClassStat? and then what if the skill use dexterity for the damage calculation, how do i reference that, do i need to create 3 different func for each attributes or how do i tell the code to use the right attributes for damage calculation

so do i put the damage calculation inside the skill itself? since my weapon will just have the sprite and skill it contain, it will do nothing else right?

so this is my understanding about how this code maybe should work

Character here -> equip weapon permissible by their class -> weapon have skills -> character uses the skill inside the weapon to attack

and then for the damage calculation

take skill base damage -> take entity attributes (strength, dexterity, or intelligence) -> do the calculation -> get total damage -> return the damage value to the entity class -> deal damage to character

so the only interactions here as far as i know, are only between the skills and the entity itself, since weapon will just contain their sprite, and their skill set or skill tree

and then do i call this damage func, inside the ClassStat to reduce the health amount? if so would it look like this

var skill_stat = SkillStat

func take_damage(skill_stat : SkillStat):
	health -= skill_stat.total_damage

is that correct, or is my overall perception of doing this is wrong? sorry again for my current knowledge of programming is very basic

Okay. I think I understand your goal now.

Achieving your goal

You want the damage of a skill to be influenced by one or more of the three attributes: strength, dexterity, and intelligence. You want to be able to configure which attributes are taken into account.

One way of doing this is to create an enum that is based on the available attributes (see docs for description).

enum Attributes {
	STR,
	DEX,
	AGI,
	INT
} # The naming is shortened to make it faster to write but it's up to you.

Then you can expose a list in Godot’s inspector that allows you to pick which stat(s) influences the damage output.

class_name SkillStat

@export var stat_influences : Array[Attributes]

Now that you have a list of influential stats, you can iterate over the list of attributes, get the stat for each attribute from the class, and compute the correct damage.

func calculate_damage(class_stat: ClassStat):
	var total_stats = 0

	# Iterate over all the influences
	for i in stat_influences.size(): 
		if stat_influences[i] == Attributes.STR:
			totat_stats += class_stat.strength
		if stat_influences[i] == Attributes.DEX:
			total_stats += class_stat.dexterity
		if stat_influences[i] == Attributes.AGI:
			total_stats += class_stat.agility
		if stat_influences[i] == Attributes.INT:
			total_stats += class_stat.intelligence

	# Compute the damage
	var damage = base_damage * total_stats
	return damage

Additional comments

Yes, that is correct. You seem to already have an understanding of the reductionistic principles of programming; that each object is often comprised of smaller, more specialized objects. If you’re interested, I would recommend that you study inheritance and composition in programming. These concepts are vital to understand if you want to create big systems.


Also correct. Actually, exchanging your arrows for dot notation gets you pretty close to the actual code you would write.

var weapon: Weapon
var damage = weapon.skill.calculate_damage(self)

Well, this is the same as your previous arrow-based example just at a different scope, and a damage-dealing operation at the end.


You could indeed implement health in your ClassStat. However, if you plan to build a game that is more than small in size, you should not rely on such an approach. More often than not, health as a concept is used for a wide set of objects in games. To avoid writing repetitive code (the same code in multiple scripts), you would write a Health class. This class/node would then be added to objects via composition. Other nodes can then subscribe to Health’s signals (damage, heal, or death signal) to retrieve information from the Health instance.

You can find an example of a networked health node I created at the bottom of this post. The post in its entirety is concerned with composition and inheritance.


One last thing. You have to remove your habit of saying sorry for not being good enough. There’s nothing wrong with being a beginner. Be excited that you have any programming knowledge at all!

Reserve saying sorry for times when you realize that you haven’t given something or someone the correct amount of energy or attention.

I hope this answered most of your questions. Let me know if you have any more questions.

1 Like

oh, i think i understand it now, thanks for the explanation buddy, i do read the godot docs for inheritance, class and composition, but i just don’t understand how to applied it in such a big scope

also a quick question, can i still use this inside the ClassStat script?

@export var strength : int
@export var dexterity : int
@export var agility : int
@export var intelligence : int

just for ease of assigning value to the entity later on

also this produces some error

export var attributes : Array[Attributes]
# i change the stat_influence to attributes with lower case a

it says could not find Attributes in the currect scope, did the

var class_stat : ClassStat

not reference the enum perhaps? or did i write something wrong, but the enum in ClassStat the enum are named Attributes with upper case A, just like what you write

enum Attributes {strength, dexterity, intelligence}

i’ll try looking into the docs for now and find some answer

I’m not your buddy, friend! (YouTube)

Sure. You can use the “Message” button on my forum profile. I try to check the forums once a day so expect a reply in that same time frame.

Yes. These variables are there to contain the actual statistic for the attribute. The Attributes enum merely acts as a selector to these variables.


You’re missing a @ in front of export.
The Attributes enum should be part of SkillStat since that is where it is relevant. Like so:

class_name SkillStat

enum Attributes { STR, DEX, AGI, INT }
@export var attributes: Array[Attributes]

Here is the section for enums in the Godot Docs.

EDIT: I don’t know if you can also define Attributes in ClassStat and then do: ClassStat.Attributes.STR. If you can, it probably makes more sense to store it in ClassStat since that is where the stats are also stored.

1 Like

oh yea, i forgot to write the @ at export, sorry about that little mistake

as for the Attributes enum, i write inside the SkillStat? i thought i need to write in the ClassStat, but i did just moved it into the SkillStat and now it’s fixed, thanks so much my friend

i will definitely remember you when i finished my game :smiley:

1 Like