From fe240c89d764ea344e194e6e5fe6d54f1633cfd3 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Sun, 1 Jun 2025 17:59:59 +0300 Subject: [PATCH] feat: die id, print res in demo, visibility fixes --- crates/bevy_dice/src/die.rs | 27 +++++++++++++++++---------- crates/bevy_dice/src/face.rs | 8 ++++++-- crates/bevy_dice/src/lib.rs | 16 ++++++++++++++-- crates/bevy_dice_demo/src/main.rs | 12 ++++++++++-- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/crates/bevy_dice/src/die.rs b/crates/bevy_dice/src/die.rs index e794339..3f8d2bf 100644 --- a/crates/bevy_dice/src/die.rs +++ b/crates/bevy_dice/src/die.rs @@ -7,21 +7,27 @@ use avian3d::prelude::*; use bevy::prelude::*; +use crate::DieResult; + #[derive(Component, Reflect)] pub struct Die { - pub rolling: bool, + id: u32, + rolling: bool, } -impl Default for Die { - fn default() -> Self { - Self { rolling: true } +impl Die { + pub fn new(id: u32) -> Self { + Self { id, rolling: true } } } #[derive(Event)] -pub struct DieStopped(Entity); +pub(super) struct DieStopped(Entity); -pub fn die_wait_for_stop(mut commands: Commands, q_dice: Query<(Entity, &Die, &AngularVelocity)>) { +pub(super) fn die_wait_for_stop( + mut commands: Commands, + q_dice: Query<(Entity, &Die, &AngularVelocity)>, +) { for (die_entity, die, angular_velocity) in q_dice { if die.rolling { let angular_velocity_abs = angular_velocity.abs(); @@ -35,8 +41,9 @@ pub fn die_wait_for_stop(mut commands: Commands, q_dice: Query<(Entity, &Die, &A } } -pub fn die_stopped( +pub(super) fn die_stopped( trigger: Trigger, + mut commands: Commands, mut q_dice: Query<&mut Die>, q_children: Query<&Children>, q_faces: Query<&crate::Face>, @@ -46,7 +53,7 @@ pub fn die_stopped( die.rolling = false; let mut highest = f32::NEG_INFINITY; - let mut value = 0; + let mut result = 0; for face_entity in q_children.iter_descendants(trigger.0) { if let Ok(face) = q_faces.get(face_entity) { @@ -54,12 +61,12 @@ pub fn die_stopped( let y = global_transform.translation().y; if y > highest { highest = y; - value = face.value; + result = face.value(); } } } } - info!("Rolled {}", value); + commands.trigger(DieResult { id: die.id, result }); } } diff --git a/crates/bevy_dice/src/face.rs b/crates/bevy_dice/src/face.rs index c7d93ca..ce621b9 100644 --- a/crates/bevy_dice/src/face.rs +++ b/crates/bevy_dice/src/face.rs @@ -38,17 +38,21 @@ const DEBUG_GIZMO_COLOURS: [Srgba; 20] = [ #[derive(Component, Reflect, Clone)] pub struct Face { /// The value of the face. - pub value: u8, + value: u8, } impl Face { pub fn new(value: u8) -> Self { Self { value } } + + pub(crate) fn value(&self) -> u8 { + self.value + } } #[cfg(feature = "debug")] -pub fn draw_face_gizmos( +pub(super) fn draw_face_gizmos( q_dice: Query>, q_children: Query<&Children>, q_faces: Query<&Face>, diff --git a/crates/bevy_dice/src/lib.rs b/crates/bevy_dice/src/lib.rs index 7a5ef2d..c10ff61 100644 --- a/crates/bevy_dice/src/lib.rs +++ b/crates/bevy_dice/src/lib.rs @@ -24,6 +24,7 @@ impl Plugin for DicePlugin { .register_type::() .register_type::() .register_type::() + .add_event::() .add_plugins(EntropyPlugin::::new()) .add_observer(throw_die) .add_observer(die::die_stopped) @@ -91,6 +92,8 @@ impl DieVariant { #[derive(Event)] pub struct ThrowDie { + /// Die ID, required to identify DieResult events. + pub id: u32, /// Die variant. pub variant: DieVariant, /// Initial angular velocity, random if not set. @@ -99,6 +102,15 @@ pub struct ThrowDie { pub rotation: Option, } +/// Result of a die roll. +#[derive(Event)] +pub struct DieResult { + /// The ID of the die rolled. + pub id: u32, + /// The result. + pub result: u8, +} + fn throw_die( trigger: Trigger, mut commands: Commands, @@ -152,14 +164,14 @@ fn throw_die( RigidBody::Dynamic, Collider::convex_hull_from_mesh(mesh).unwrap(), angular_velocity, - Die::default(), + Die::new(trigger.id), )); die.with_children(|parent| { if let Some(overrides) = r_config.override_face_positions.get(&trigger.variant) { let defaults = trigger.variant.faces(); for default in defaults { - if let Some(new_value) = overrides.get(&default.0.value) { + if let Some(new_value) = overrides.get(&default.0.value()) { parent.spawn((Face::new(*new_value), default.1)); } else { parent.spawn(default.clone()); diff --git a/crates/bevy_dice_demo/src/main.rs b/crates/bevy_dice_demo/src/main.rs index a252cba..5321bf2 100644 --- a/crates/bevy_dice_demo/src/main.rs +++ b/crates/bevy_dice_demo/src/main.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use avian3d::prelude::*; use bevy::{asset::LoadState, prelude::*}; -use bevy_dice::{DicePlugin, DicePluginConfig, Die, DieVariant, ThrowDie}; +use bevy_dice::{DicePlugin, DicePluginConfig, Die, DieResult, DieVariant, ThrowDie}; use bevy_egui::{EguiContextPass, EguiContexts, EguiPlugin, egui}; use bevy_embedded_assets::EmbeddedAssetPlugin; #[cfg(feature = "debug")] @@ -61,7 +61,7 @@ fn main() { app.add_systems(Update, rotate_light); - app.add_observer(despawn_dice); + app.add_observer(despawn_dice).add_observer(show_die_result); app.run(); } @@ -153,12 +153,14 @@ struct ExampleAssets { #[derive(Resource)] struct UIState { selected_variant: DieVariant, + die_id: u32, } impl Default for UIState { fn default() -> Self { Self { selected_variant: DieVariant::D6, + die_id: 0, } } } @@ -179,10 +181,12 @@ fn ui(mut commands: Commands, mut contexts: EguiContexts, mut r_ui_state: ResMut if ui.button("Throw").clicked() { commands.trigger(ThrowDie { + id: r_ui_state.die_id, variant: r_ui_state.selected_variant, angular_velocity: None, rotation: None, }); + r_ui_state.die_id += 1; } if ui.button("Despawn Dice").clicked() { @@ -204,6 +208,10 @@ fn despawn_dice( } } +fn show_die_result(trigger: Trigger) { + info!("{}: {}", trigger.id, trigger.result); +} + fn rotate_light(mut q_lights: Query<&mut Transform, With>, r_time: Res