I’m trying to randomize what frames are shown on screen as the dice ‘rolls’. In the _on_roll_dice_pressed() method, I had the code that gets a random frame for each animatedsprite2D stored in an array, but that line of code doesn’t work for some reason.
extends Node2D
var num_of_columns: int = 2
var num_of_rows: int = 2
var dice_grid_size: int
var ghost_dice_bag
var placed_animated_sprites = []
var roll_balance: int
var total_balance: int
@onready var balance_amt_label: Label = $"../Main_CanvasLayer/VBoxContainer/HBoxContainer/Balance"
@onready var animated_sprite_2d: AnimatedSprite2D = $"../AnimatedSprite2D"
@onready var timer: Timer = $"../Timer"
# Called when the node enters the scene tree for the first time.
func _ready():
places_dice()
func places_dice():
ghost_dice_bag = Globals.dice_bag.duplicate()
dice_grid()
#Resets the array, so a new set of dice can be placed on the grid
placed_animated_sprites.clear()
for i in range(0, num_of_columns):
for j in range(0, num_of_rows):
#if statement runs only if the dice bag is not empty
if ghost_dice_bag.is_empty() == false:
var die_key = ghost_dice_bag.pick_random()
var die_node = animated_sprite_2d.duplicate()
die_node.animation = die_key
die_node.visible = true
placed_animated_sprites.append(die_node)
add_child(die_node)
#Places the dice in a grid formation
die_node.position.y = 80 + ((i+1)*16)
die_node.position.x = 600 + ((j+1)*16)
#Ensures the same die doesn't get choosen twice
ghost_dice_bag.erase(die_key)
#Places the die on a random frame
var frame_count = die_node.sprite_frames.get_frame_count(die_key)
die_node.frame = randi_range(0, frame_count)
func dice_grid():
if (num_of_columns * num_of_rows) > Globals.dice_bag.size():
dice_grid_size = Globals.dice_bag.size()
else:
dice_grid_size = num_of_columns * num_of_rows
func _on_roll_dice_pressed():
#Clears the dice from the screen. Without this, the dice sprite would be placed over each other
for child in get_children():
child.queue_free()
#Places new dice
places_dice()
#Starts rolling animation of each dice placed
timer.start()
for key in placed_animated_sprites:
#Places the die on a random frame
var frame_count = key.sprite_frames.get_frame_count(key) #<---doesn't work
key.frame = randi_range(0, frame_count)
func _on_timer_timeout():
for key in placed_animated_sprites:
key.stop()
#Calculates 'income' from dice roll
roll_balance += (key.frame + 1)
#Adds 'income' to total balance
total_balance += roll_balance
#Resets dice roll 'income'
roll_balance = 0
#Updates balance shown on screen
balance_amt_label.text = str(total_balance)
Below is the code I have for Globals:
extends Node
#Stores dice that are available for rolling, name of die must be the same name as its animation
var dice_bag = [
"D2-plastic",
"D6-gold",
]
You’re passing key, which is an AnimatedSprite2D, as an argument of get_frame_count() method, which expects a StringName of an animation.
You probably have a type mismatch error in the console telling you that.
I suggest you to start adding some type hints into your scripts, it will make it much easier to debug.
So I implemented your solution did make the game work, but another issue came up. When I ‘roll dice’ button gets pressed, I just see the final frame of the AnimatedSprite2D onscreen. I did add a “print(key)” and I do see in the output the AnimatedSprite2D comments (ex. @AnimatedSprite2D@3:<AnimatedSprite2D#30819747335>). So the ‘while’ statement does seem to work but I’m seeing only the last frame on screen, instead of each randomized frame being replaced with the previous one (and hence, creating the illusion that the dice is rolling). Not sure how to fix this.
extends Node2D
var num_of_columns: int = 2
var num_of_rows: int = 2
var dice_grid_size: int
var ghost_dice_bag
var placed_animated_sprites = []
var roll_balance: int
var total_balance: int
var duration: float
@onready var balance_amt_label: Label = $"../Main_CanvasLayer/VBoxContainer/HBoxContainer/Balance"
@onready var animated_sprite_2d: AnimatedSprite2D = $"../AnimatedSprite2D"
# Called when the node enters the scene tree for the first time.
func _ready():
places_dice()
func places_dice():
ghost_dice_bag = Globals.dice_bag.duplicate()
dice_grid()
#Resets the array, so a new set of dice can be placed on the grid
placed_animated_sprites.clear()
for i in range(0, num_of_columns):
for j in range(0, num_of_rows):
#if statement runs only if the dice bag is not empty
if ghost_dice_bag.is_empty() == false:
var die_key = ghost_dice_bag.pick_random()
var die_node = animated_sprite_2d.duplicate()
die_node.animation = die_key
die_node.visible = true
placed_animated_sprites.append(die_node)
add_child(die_node)
#Places the dice in a grid formation
die_node.position.y = 80 + ((i+1)*16)
die_node.position.x = 600 + ((j+1)*16)
#Ensures the same die doesn't get choosen twice
ghost_dice_bag.erase(die_key)
#Places the die on a random frame
var frame_count = die_node.sprite_frames.get_frame_count(die_key)
die_node.frame = randi_range(0, frame_count)
func dice_grid():
if (num_of_columns * num_of_rows) > Globals.dice_bag.size():
dice_grid_size = Globals.dice_bag.size()
else:
dice_grid_size = num_of_columns * num_of_rows
func _on_roll_dice_pressed():
#Clears the dice from the screen. Without this, the dice sprite would be placed over each other
for child in get_children():
child.queue_free()
#Places new dice
places_dice()
rolling_dice()
calculate_income()
func rolling_dice():
while duration < 1.0:
for key in placed_animated_sprites:
for die in Globals.dice_bag:
#Places the die on a random frame
var frame_count = key.sprite_frames.get_frame_count(die)
print(key)
key.frame = randi_range(0, frame_count)
duration += 0.1
func calculate_income():
for key in placed_animated_sprites:
#Calculates 'income' from dice roll
roll_balance += (key.frame + 1)
#Adds 'income' to total balance
total_balance += roll_balance
#Resets dice roll 'income'
roll_balance = 0
#Updates balance shown on screen
balance_amt_label.text = str(total_balance)
Your whole while is being executed within the same frame. You can add await get_tree().create_timer(0.1).timeout within your while loop to make it actually wait.
However, I would consider moving this to the _process() or creating a dedicated Timer instead of while and await.