Using button player presses to emit signal works as intended when coded in for AI it doesn't work correctly

Godot Version

4.3beta3

Question

I have a “battler” that has a readiness value and it ticks up every physics process. Once it hits 100 the game pauses and waits for an action to be chosen and then resumes.

This works for the player when they pick an action through the menu. But for the AI (or if I try to not use the menu for the player) they don’t reset like they should. Even though I use the exact same signal that gets emitted when an action button is pressed.

Things I’ve Done:

  • I first thought that the readiness variable wasn’t getting reset, but it was.
  • Then I thought maybe it wasn’t unpausing correctly but it is.
  • The opponent is selecting a move and it is firing the signal and using the move
  • If I take away the menu from the player and try to have it pick randomly it also just sits there without resetting
  • If I add the menu to the opponent it works as it should
  • There is no code in the menu that touches anything outside of itself other than when it sends the signal from the BattleManager autoload script

I do have my code on GitHub I’m not sure I’m explaining it well enough… I’ve been stuck on this single problem for three days now. My rubber duck is tired of listening to me repeat myself.

This is the code of the action button

extends TextureButton

@onready var icon: TextureRect = $HBoxContainer/Icon
@onready var label: Label = $HBoxContainer/Label

var action_resource : Action

func _ready() -> void:
	icon.texture = action_resource.action_icon #Set icon based on resource
	label.text = action_resource.action_name #Set name based on resource

 func _on_pressed() -> void:
 	#action_resource._on_press()
 	BattleManager.action_chosen.emit(action_resource)

This is the code of the turn manager system where the difference between a player and the AI is:

 func _play_turn(battler: Battler):
 	#TODO: Add fatigue system
 	_pause(true) #Pause all of the battlers
 	if battler.battler_resource.is_player: #If battler is player
 		is_player_turn = true
 		ui_menu.setup(battler.battler_resource) #Setup menu for the player
 		ui_menu.show()#Show the player's menu
 	else: #Opponent AI Turn
 		is_player_turn = false
 		#Just pick action randomly
 		var random_move = battler.battler_resource.action_list.pick_random()
 		BattleManager.action_chosen.emit(random_move)

Can you post the code for the signal’s receiver? (I know you have the github link but this way I don’t have to find it).

Have you tried putting breakpoints into the _play_turn method and signal receivers and stepping through with F11? You can see the scoped variables and their values while doing this, it might help you find the problem.

1 Like

Here is the function that gets called by the signal…

func _action_chosen(action):
	var formulas = Formulas.new() #Create instance of the formulas for use
	var dmg = 0 #Create variable to hold damage amount
	if is_player_turn:
		ui_menu.hide() #Hide the menu
		dmg = formulas.calculate_base_damage(battle.player_chaomon, battle.opponent_chaomon, action)
		battle.opponent_chaomon._take_damage(dmg)
		_reset(_player) #Reset readiness for player
	else:
		dmg = formulas.calculate_base_damage(battle.opponent_chaomon, battle.player_chaomon, action)
		battle.player_chaomon._take_damage(dmg)
		_reset(_opponent) #Reset readiness for opponent
	
	_pause(false) #Unpause all of the battlers

This is the reset function… Even with the enemy when it does its actions it does reset the readiness. So I know its going through the functions.

func _reset(battler):
	battler._readiness = 0.0 #Set readiness back to 0.0
	print(battler.battler_resource.chaomon_name)
	print(battler._readiness)
	battler.pause(false) #Make sure they aren't paused

Just so it is here, this is the battler code where the _readiness runs

func _physics_process(delta: float) -> void:
	if battler_resource and !_paused: #If the resource is correct and not paused
		_set_readiness(_readiness + battler_resource.base_speed * delta * _timescale) #Set the readiness

#Sets the readiness of the Chaomon
func _set_readiness(value: float) -> void: #Set the readiness of the Battler
	_readiness = value #Set readiness
	readiness_changed.emit(_readiness) #Emit the new readiness
	if !battler_resource.is_player:
		print(battler_resource.chaomon_name)
		print(_readiness)
	if _readiness >= 100.0: #If battler is ready to act
		ready_to_act.emit() #Signal that battler is ready to act
		pause(true)
	else:
		pause(false)

Have you tried putting breakpoints into the _play_turn method and signal receivers and stepping through with F11? You can see the scoped variables and their values while doing this, it might help you find the problem.

I haven’t done breakpoints, I didn’t know you could do them, but I’ve put print statements and looked at the tree to see what the variables are doing and they were fine but I’ll try doing it step by step to see if there is something else going on.

Breakpoints helped… It was a problem with where I had a pause function. I don’t know why when using a button it somehow skipped over that pause function call but it works now.

Thank you so much! The breakpoints is a Godsend. I should have remembered from my old C++ days.

1 Like

Glad I could (sort of) help. Given how quickly you can iterate in Godot, breakpoints have very quickly become my first step in a lot of debugging situations. There are actually two ways to use them in GDScript as well - you can click the margin (or hit F9) in the Script editor as you would in any other IDE or you can use the breakpoint keyword in your script. I’ve not found much use for the second option yet but it’s good to know about.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.