I don't believe I understand how empty / null variables work

Godot 4.5

So what the below script is meant to do, in theory, is that first, the toggle_dice function at the bottom lets you choose which two dice you want to roll. You can only ever have two chosen, and when you choose a third, it replaces one of the currently chosen ones, and this all seems to work fine. The stuff with the indexes is just because the toggles are children of a different node than the dice, so I have to match the child index of the toggle to the die, but thats all good.

The roll_dice function is called via a signal from elsewhere, and in theory, should call a function inside the dice only if dice are selected. I know it’s not sending a second one, because i can call the function with only one die instance in existence. Once the die has made its roll, it returns its self and roll info via a signal. It needs to be done like this, because the actual dice are modular, where you can change what each face does, so this needs to work the same regardless of what the dice actually are.

Since I don’t know how long each roll will take to complete, my solution is to have the dice assign their roll info to a variable, roll_one or roll_two depending on which die was rolled, and then send_results. And theoretically, send_results checks if you have data for both rolls, and only then sends them onward, which means that theoretically the first send_results called should not trigger as both rolls are not in yet, only the second one. And then both roll arrays are cleared for the next one.

However, even when I roll with only one die selected, meaning die_two = null, the roll is sent off anyways, evidenced by the fact that a textbox updates which only does it when the results signal is emitted.

What I need is some way to send the results only when both have returned, and clearly this doesnt do that.

var die_one: Node = null
var die_two: Node = null
var roll_one: Array
var roll_two: Array
signal results()

func roll_dice():
	if die_one: die_one.die_grid.rollem()
	if die_two: die_two.die_grid.rollem()

func return_roll(which_die: Node, result: Array):
	if which_die == die_one:
		roll_one = result
		send_results()
	else:
		roll_two = result
		send_results()

func send_results():
	if roll_one != null && roll_two != null:
		results.emit(roll_one, roll_two)
		roll_one.clear()
		roll_two.clear()

func toggle_dice(toggle: Node):
	var index = toggle.get_index()
	var curr_die = dice_vbox.get_child(index)
	if die_one == curr_die:
		die_one = null
	elif die_two == curr_die:
		die_two = null
	else:
		if die_one && die_two:
			var i = die_two.get_index()
			var tog = dice_toggles.get_child(i)
			tog.button_pressed = false
		die_two = die_one
		die_one = curr_die

The Variant page in the docs has an important note about this:

All types within Variant except Nil and Object cannot be null and must always store a valid value. These types within Variant are therefore called non-nullable types.

One of the Variant types is Nil which can only store the value null. Therefore, it is possible for a Variant to contain the value null, even though all Variant types excluding Nil and Object are non-nullable.

A variable type hinted as : Array contains an empty array. And an array, even if it’s empty, cannot be null. If you want to check if an array is empty or not, use Array.is_empty() or just if array:

	if roll_one and roll_two:
1 Like

So you are only ever sending the results of one dice at a time , which means this will never evaluate: (or it always will , depending on the results of the previous roll)

roll_one and roll_two are variables that exist outside of that function.
so when roll_one is set to result, it will store that until it’s changed. but I think i got my solution, thanks for the reply

gotcha, thats what I was missing. thank you!

1 Like