I am working on an rpg battle system, and so far the animations/sequencing is working but for some odd reason, the targeted health/variable is not updated after a function (attacking). What am I doing wrong? I just upgraded to Godot 4.

NOTE: I included most of the code for this scene for consistency, but I am pretty sure the _attackCommand() is where the error lies. B

Basically, when the enemy is damaged, their health bar should be moving, but it's not, because the value isn't. I don't get it - everything else in the function is working. My debug shows its the health that is not changing.

extends Node2D


var _player1health = 100
var _player1maxHP = _player1health
var _player1str = 5
var _player1con = 3
var _player1dex = 5
var _player1int = 3
var _player1wis = 5
var _player1lck = 3


var _enemy1health = 100
var _enemy1maxHP = _enemy1health
var _enemy1str = 3
var _enemy1con = 2
var _enemy1dex = 2
var _enemy1int = 2
var _enemy1wis = 2
var _enemy1lck = 2

@export var _canRetreat : bool = true
@export var _enemy1name : String = "Monster"

var _battleStep : int = 0
var _commandReady : bool = false
var _playerState : int = 0
enum _PLAYER_STATES {IDLE,ATTACK,TECH,BLOCK,RUN,WEAK,DEAD}


func _ready() -> void:
	$EnemyHUD/EnemyHealth.max_value = _enemy1health
	$PlayerInfoHUD/PlayerHealth.max_value = _player1health
	$SystemAlert/SystemLabel.text = str(_enemy1name+" appeared!")
	$Command_UI/CommandAnimator.play("RESET")
	$TextRolling.play("RESET")
	$PlayerSprite.play("idle")
	$Enemy1Sprite.play("idle")
	$TextRolling.play("open_alert")
	$SystemTimer.start(1)
	_battleStep+=1


func _process(_delta: float) -> void:
	$EnemyHUD/EnemyHealth.value = _enemy1health
	$PlayerInfoHUD/PlayerHealth.value = _player1health


func _on_attack_button_pressed() -> void:
	if _commandReady:
		_playerState = 1
		$Command_UI/CommandAnimator.play_backwards("open")
		$ActivityAlert/ActivityInfo.text = "YOU ATTACKED!"
		$TextRolling.play("action_alert")
		_attackCommand(_player1str,_enemy1health,$EnemyDamage,$PlayerSprite/PlayerAnimator)


func _on_system_timer_timeout() -> void:
	match _battleStep:
		1:
			$TextRolling.play_backwards("open_alert")
			_battleStep+=1
			$SystemTimer.start(0.5)
		2:
			$TextRolling.play("hp_bar_open")
			_battleStep+=1
			$SystemTimer.start(0.5)
		3:
			$Command_UI/CommandAnimator.play("open")
			_commandReady = true



func _on_player_sprite_animation_finished() -> void:
	if $PlayerSprite.animation == "attack":
		$EnemyDamage/EnemyDamageAnimator.play("report")
	if $PlayerSprite.animation != "idle":
		$PlayerSprite.play("idle")


### pretty sure the problem is here, but what?
func _attackCommand(_stat:int,_health:int,_label:Label,_animator:AnimationPlayer):
	$TextRolling.play_backwards("action_alert")
	_animator.play("attack")
	randomize()
	var _d6 = randi_range(0,_stat+1)
	var _damage
	if _d6 == _stat+1:
		_damage = _stat*3
	else:
		_damage = _d6 + _stat
	
	_label.text = str(_damage)
	_health-=_damage ### this is not working?
  • xyz replied to this.
  • SnapCracklins Only objects are passed by reference. Basic types like ints and floats are passed by value.

    SnapCracklins changed the title to Why is this value not updating? .

    Is _attackCommand getting called?

    randomize() should only be called once, for example in _ready(), but that's not likely to be the problem here.

    @"DaveTheCoder"#p145846 it is (and you're right I should just call randomize at ready(), good catch) and everything in it is running. I even put a print command in there to check and it worked with the damage total. It's the health that's not passing.

    xyz Only objects are passed by reference. Basic types like ints and floats are passed by value.

    How would I apply that here? The stat variable here seems to be passing the attack value fine for the damage. I'm just generally confused why only one line isn't working. How would I fix this or pass these by value?

    xyz ok I think I got it. I made a separate variable for passing damage outside the function. It works now but now the progress bar is not updating.

    • xyz replied to this.

      SnapCracklins Here's an example to test and try to explain:

      var foo = 1
      
      func _ready():
      	print(foo)
      	f(foo)
      	print(foo)
      	
      func f(foo):
      	foo = 2

      Will it print

      1
      2

      ?

        xyz that's some good literature, thank you. I'll pore over it when I have time.

        Though to wit - my bar was not updated because I forgot to drop in StyleBoxes. 🤣

        For the fix though, I passed the value as you said, since I am sure someone will need it:

        var _damagePool : int = 0

        then I passed the value to the damage pool before using it. That worked a treat, thanks.

        • xyz replied to this.

          xyz i would say 1 because it's referencing the original declaration?

          • xyz replied to this.

            SnapCracklins Declaring a class-wide property is not passing. Passing refers only to giving stuff to functions via its arguments.

            SnapCracklins i would say 1 because it's referencing the original declaration?

            There are two prints and the function is updating foo. Will it print 1,1 or 1,2 ? If the answer is not immediately obvious, you have some reading up to do.

              5 days later

              xyz the answer is 1,1.

              and I did read that, because I am always anxious to learn.

              The reason it did so is because the original foo was declared outside the scope of the function, whereas the foo in the f(foo) the function has a scope limited to that function.

              I'll have my cookie now.

              • xyz replied to this.

                SnapCracklins I'll have my cookie now.

                Wait. There's a level 2 to the question 😉:

                var foo = [0]
                
                func _ready():
                	foo[0] = 1
                	print(foo[0])
                	f(foo)
                	print(foo[0])
                	
                func f(foo):
                	foo[0] = 2

                  xyz this is a good lesson. Now I'm understanding what I did wrong. Appreciate that.

                  While foo is declared as an array with one value of zero, the array is updated at ready, changing foo to 1. Then foo is updated by a function during the same ready() function, so the value of that single in the array is now 2.

                  That's two cookies you owe me. I prefer peanut butter. 🤣

                  • xyz replied to this.

                    SnapCracklins But wait. There's level 3 😃

                    var foo = [0]
                    
                    func _ready():
                    	foo[0] = 1
                    	print(foo[0])
                    	f(foo)
                    	print(foo[0])
                    	
                    func f(bar):
                    	bar[0] += 1
                    	foo[0] += 1

                      xyz

                      1 then 3.

                      foo is declared as a single value array with a value of 0.
                      in ready, that variable foo is set to zero, then passed to the f(foo) function where it is passed to bar then increased by one and then that original variable is modified as well.

                      Three cookies, sir.

                      • xyz replied to this.