Proof of concept for textured dice

Now to integrate with the game.
Also need to figure out best way to do multiple dice.
Probably multiple cameras + textures.
But we can probably share one mesh.
main
Elijah C. Voigt 1 year ago
parent 57e8caa1b7
commit ba19b6342e

@ -0,0 +1,190 @@
use std::f32::consts::PI;
use bevy::{
prelude::*,
render::{
camera::RenderTarget,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, add_texture)
.add_systems(Update, rotate_mesh.run_if(|keys: Res<ButtonInput<KeyCode>>| -> bool {
keys.pressed(KeyCode::Space)
}))
.run();
}
fn add_texture(
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut commands: Commands,
) {
let image_handle = {
let size = Extent3d {
width: 256,
height: 256 * 6,
..default()
};
let mut image = Image {
texture_descriptor: TextureDescriptor {
label: None,
size,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8UnormSrgb,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
},
..default()
};
image.resize(size);
images.add(image)
};
let texture_camera = commands
.spawn(Camera2dBundle {
camera: Camera {
order: -1,
target: RenderTarget::Image(image_handle.clone()),
..default()
},
..default()
})
.id();
commands
.spawn((
NodeBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
background_color: BackgroundColor(Color::GOLD),
..default()
},
TargetCamera(texture_camera),
))
.with_children(|parent| {
["Up", "Down", "Left", "Right", "Top", "Bottom"]
.into_iter()
.for_each(|text| {
parent.spawn(NodeBundle {
style: Style {
height: Val::Percent(100.0 / 6.0),
width: Val::Percent(100.0),
justify_content: JustifyContent::Center,
justify_items: JustifyItems::Center,
align_items: AlignItems::Center,
align_content: AlignContent::Center,
..default()
},
..default()
}).with_children(|parent| {
parent.spawn(TextBundle {
text: Text::from_section(
text,
TextStyle {
color: Color::BLACK,
font_size: 64.0,
..default()
},
),
..default()
});
});
});
});
commands.spawn(DirectionalLightBundle { ..default() });
{
commands.spawn(ImageBundle {
style: Style {
top: Val::Px(0.0),
left: Val::Px(0.0),
position_type: PositionType::Absolute,
max_height: Val::Percent(100.0),
..default()
},
image: UiImage {
texture: image_handle.clone(),
..default()
},
..default()
});
}
{
let cube_size = 4.0;
let a = 1.0 / 6.0;
let b = 2.0 * a;
let c = 3.0 * a;
let d = 4.0 * a;
let e = 5.0 * a;
let f = 1.0;
let cuboid = Mesh::from(Cuboid::new(cube_size, cube_size, cube_size))
.with_inserted_attribute(
Mesh::ATTRIBUTE_UV_0,
vec![
// Top side
[1.0, 0.0], [0.0, 0.0], [0.0, a], [1.0, a],
// Bottom side
[1.0, a], [0.0, a], [0.0, b], [1.0, b],
// Right side
[1.0, b], [0.0, b], [0.0, c], [1.0, c],
// Left side
[1.0, c], [0.0, c], [0.0, d], [1.0, d],
// Back side
[1.0, d], [0.0, d], [0.0, e], [1.0, e],
// Front side
[1.0, e], [0.0, e], [0.0, f], [1.0, f],
]);
let mesh = meshes.add(cuboid);
let material = materials.add(StandardMaterial {
base_color_texture: Some(image_handle),
..default()
});
let transform =
Transform::from_xyz(0.0, 0.0, 1.5).with_rotation(Quat::from_rotation_x(-PI / 5.0));
commands.spawn(PbrBundle {
mesh,
material,
transform,
..default()
});
}
{
let transform = Transform::from_xyz(0.0, 0.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(Camera3dBundle {
transform,
..default()
});
}
}
fn rotate_mesh(
mut query: Query<&mut Transform, With<Handle<Mesh>>>,
time: Res<Time>,
) {
query.iter_mut().for_each(|mut t| {
t.rotate_x(time.delta_seconds() * 0.5);
t.rotate_y(time.delta_seconds() * 0.5);
t.rotate_z(time.delta_seconds() * 0.5);
});
}

@ -70,26 +70,37 @@ fn init_dice_ui(mut commands: Commands) {
fn init_dice( fn init_dice(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>, mut materials: ResMut<Assets<ColorMaterial>>,
mut commands: Commands mut commands: Commands,
) { ) {
[ [
["a", "b", "c", "d", "e", "f"], ["a", "b", "c", "d", "e", "f"],
["g", "h", "i", "j", "k", "l"], ["g", "h", "i", "j", "k", "l"],
["m", "n", "o", "p", "q", "r"], ["m", "n", "o", "p", "q", "r"],
].into_iter().enumerate().for_each(|(idx, set)| { ]
commands.spawn(( .into_iter()
GameChoice::Dice, MenuState::Closed, .enumerate()
.for_each(|(idx, set)| {
commands
.spawn((
GameChoice::Dice,
MenuState::Closed,
Die::new(set), Die::new(set),
PickableBundle { ..default() }, PickableBundle { ..default() },
On::<Pointer<Drag>>::target_component_mut::<Transform>(|m, transform| { On::<Pointer<Drag>>::target_component_mut::<Transform>(|m, transform| {
transform.translation.x += m.delta.x; transform.translation.x += m.delta.x;
transform.translation.y -= m.delta.y; transform.translation.y -= m.delta.y;
}),
))
.insert(MaterialMesh2dBundle {
mesh: meshes
.add(Rectangle {
half_size: Vec2::splat(32.0),
}) })
)).insert(MaterialMesh2dBundle { .into(),
mesh: meshes.add(Rectangle { half_size: Vec2::splat(32.0) }).into(),
material: materials.add(Color::PINK), material: materials.add(Color::PINK),
..default() ..default()
}).insert(Text2dBundle { })
.insert(Text2dBundle {
text: Text::from_section( text: Text::from_section(
"", "",
TextStyle { TextStyle {
@ -99,7 +110,8 @@ fn init_dice(
}, },
), ),
..default() ..default()
}).insert(Transform::from_xyz(idx as f32 * 100.0, 100.0, 0.0)); })
.insert(Transform::from_xyz(idx as f32 * 100.0, 100.0, 0.0));
}); });
} }
@ -120,24 +132,40 @@ fn roll_die(mut r: EventReader<DiceAction>, mut q: Query<&mut Die>, time: Res<Ti
}); });
} }
fn move_die(mut e: EventReader<KeyboardInput>, mut q: Query<&mut Transform, With<Die>>, time: Res<Time>) { fn move_die(
e.read().for_each(|KeyboardInput { key_code, state, .. }| { mut e: EventReader<KeyboardInput>,
mut q: Query<&mut Transform, With<Die>>,
time: Res<Time>,
) {
e.read().for_each(
|KeyboardInput {
key_code, state, ..
}| {
match state { match state {
ButtonState::Pressed => { ButtonState::Pressed => {
q.iter_mut().for_each(|mut t| { q.iter_mut().for_each(|mut t| {
match key_code { match key_code {
KeyCode::ArrowLeft => t.translation -= Vec3::X * time.delta_seconds() * 1000.0, KeyCode::ArrowLeft => {
KeyCode::ArrowRight => t.translation += Vec3::X * time.delta_seconds() * 1000.0, t.translation -= Vec3::X * time.delta_seconds() * 1000.0
KeyCode::ArrowDown => t.translation -= Vec3::Y * time.delta_seconds() * 1000.0, }
KeyCode::ArrowUp => t.translation += Vec3::Y * time.delta_seconds() * 1000.0, KeyCode::ArrowRight => {
_ => () t.translation += Vec3::X * time.delta_seconds() * 1000.0
}
KeyCode::ArrowDown => {
t.translation -= Vec3::Y * time.delta_seconds() * 1000.0
}
KeyCode::ArrowUp => {
t.translation += Vec3::Y * time.delta_seconds() * 1000.0
}
_ => (),
} }
info!("Moved die {:?}", t.translation); info!("Moved die {:?}", t.translation);
}); });
},
_ => ()
} }
}) _ => (),
}
},
)
} }
/// Component for each dice /// Component for each dice

@ -1,10 +1,10 @@
pub(crate) use std::fmt::Debug; pub(crate) use std::fmt::Debug;
/// Bevy imports
pub(crate) use bevy::prelude::*;
pub(crate) use bevy::ecs::system::EntityCommand; pub(crate) use bevy::ecs::system::EntityCommand;
pub(crate) use bevy::input::keyboard::KeyboardInput; pub(crate) use bevy::input::keyboard::KeyboardInput;
pub(crate) use bevy::input::ButtonState; pub(crate) use bevy::input::ButtonState;
/// Bevy imports
pub(crate) use bevy::prelude::*;
pub(crate) use bevy::sprite::MaterialMesh2dBundle; pub(crate) use bevy::sprite::MaterialMesh2dBundle;
/// Bevy Plugins /// Bevy Plugins

Loading…
Cancel
Save