Help storing and calculating dice results

Godot Version

4.3

Question

`I’m trying to grab and display dice results, then further store the dice results so they can be calculated and determine if the user has any points in their roll as part of a dice game. I’m using raycasts to get the side of the dice it lands on but I cannot seem to properly store the results in integers and send them to a function to be calculated. Any help is appreciated. Heres my current code:
Dice script:

extends RigidBody3D

@onready var raycasts = $Raycasts.get_children()
@onready var dice_manager: Node3D = $".."  # Path to DiceManager, adjust if necessary

var start_pos
var roll_strength = 30
var is_rolling = false
signal roll_finished(value)

var die_name = ""  # This will be set automatically

func _ready():
	start_pos = global_position
	die_name = name  # Automatically set die_name based on the instance's name

func roll():
	# Reset state
	sleeping = false
	freeze = false
	transform.origin = start_pos
	linear_velocity = Vector3.ZERO
	angular_velocity = Vector3.ZERO

	# Random rotation
	transform.basis = Basis(Vector3.RIGHT, randf_range(0, 2 * PI)) * transform.basis
	transform.basis = Basis(Vector3.UP, randf_range(0, 2 * PI)) * transform.basis
	transform.basis = Basis(Vector3.FORWARD, randf_range(0, 2 * PI)) * transform.basis

	# Random throw impulse
	var throw_vector = Vector3(randf_range(-1, 1), 0, randf_range(-1, 1)).normalized()
	angular_velocity = throw_vector * roll_strength / 2
	apply_central_impulse(throw_vector * roll_strength)

	is_rolling = true
	dice_manager.set_dice_state(die_name, true)
	
func _on_sleeping_state_changed() -> void:
	if sleeping:
		var landed_on_side = false
		for raycast in raycasts:
			if raycast.is_colliding():
				# Capture the result (side of the die the raycast hits)
				var result = int(raycast.opposite_side)  # Explicitly cast to int (side of the die)
				print("Emitting results: ", result)  # Debug print before emitting
				roll_finished.emit(result)  # Emit the result
				is_rolling = false
				landed_on_side = true
				dice_manager.set_dice_state(die_name, false, result)  # Pass result to manager

		if not landed_on_side:
			roll()  # Re-roll if not landed correctly

dice_manager script:

extends Node

@onready var dice_1: RigidBody3D = $Dice1
@onready var dice_2: RigidBody3D = $Dice2
@onready var dice_3: RigidBody3D = $Dice3


var dice_states = {
	"Dice": false,
	"Dice2": false,
	"Dice3": false,
}

var dice_results = []  # Array to store the dice results

func _input(event):
	# Check if all dice are not rolling before allowing a new roll
	if event.is_action_pressed("ui_accept") and not dice_states["Dice"] and not dice_states["Dice2"] and not dice_states["Dice3"]:
		# Reset dice results for a fresh roll
		dice_results.clear()
		print("Rolling dice...")
		dice_1.roll()
		dice_2.roll()
		dice_3.roll()

func set_dice_state(die_name: String, is_rolling: bool, result: Variant = null) -> void:
	dice_states[die_name] = is_rolling
`

Personally, I would use the rotation of each dice to determine its value – not a raycast for each face.

In any case, isn’t your problem simply because you’re not storing the results? You’re not using your dice_results array.

set_dice_state() should contain:

	dice_results[die_name] = is_rolling

…not:

	dice_states[die_name] = is_rolling

To add to this, your die_name string can only be used as a selector in a Dictionary, not an Array which expects an integer value as the selector. Therefore, define your dice_results as a Dictionary. Do var dice_results = {} instead of var dice_results = []


I hope that helps.


Actually, scratch that. I misunderstood your system. Instead I have a question:

  • Why don’t you just define dice_results as a Dictionary, and then store the result for each die in that?

It seems pretty straightforward to me to just do:

func set_dice_state(die_name: String, is_rolling: bool, result: Variant = null) -> void:
	dice_states[die_name] = is_rolling
	if not is_rolling:
		dice_results[die_name] = result

Am I missing something here?

1 Like

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