M crates/bevy_dice/src/die.rs => crates/bevy_dice/src/die.rs +17 -10
@@ 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<DieStopped>,
+ 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 });
}
}
M crates/bevy_dice/src/face.rs => crates/bevy_dice/src/face.rs +6 -2
@@ 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<Entity, With<crate::Die>>,
q_children: Query<&Children>,
q_faces: Query<&Face>,
M crates/bevy_dice/src/lib.rs => crates/bevy_dice/src/lib.rs +14 -2
@@ 24,6 24,7 @@ impl Plugin for DicePlugin {
.register_type::<DieVariant>()
.register_type::<Die>()
.register_type::<Face>()
+ .add_event::<DieResult>()
.add_plugins(EntropyPlugin::<WyRand>::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<Quat>,
}
+/// 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<ThrowDie>,
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());
M crates/bevy_dice_demo/src/main.rs => crates/bevy_dice_demo/src/main.rs +10 -2
@@ 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<DieResult>) {
+ info!("{}: {}", trigger.id, trigger.result);
+}
+
fn rotate_light(mut q_lights: Query<&mut Transform, With<PointLight>>, r_time: Res<Time>) {
q_lights.iter_mut().for_each(|mut transform| {
transform.rotate_around(