DEVELOPMENT ENVIRONMENT

~liljamo/bevy_dice

fe240c89d764ea344e194e6e5fe6d54f1633cfd3 — Jonni Liljamo 3 days ago 0758753
feat: die id, print res in demo, visibility fixes
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(