Starting on ui example

main
Elijah Voigt 3 months ago
parent 9643ff94f4
commit c349ce08d0

@ -20,3 +20,6 @@ features = ["wayland", "dynamic_linking"]
[build-dependencies]
chrono = "*"
walkdir = "*"
# [hints]
# mostly-unused = true

@ -50,10 +50,16 @@ fn write_monologues_file() {
walkdir::WalkDir::new("assets/trees")
.into_iter()
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry.path().extension() == Some(std::ffi::OsStr::new("mono"))
})
.filter(|entry| entry.path().extension() == Some(std::ffi::OsStr::new("mono")))
.for_each(|entry| {
let _ = writeln!(file, "{}", entry.path().to_string_lossy().strip_prefix("assets/").unwrap());
let _ = writeln!(
file,
"{}",
entry
.path()
.to_string_lossy()
.strip_prefix("assets/")
.unwrap()
);
});
}

@ -0,0 +1,53 @@
//! This example illustrates scrolling in Bevy UI.
use games::*;
fn main() {
let mut app = App::new();
app.add_plugins(BaseGamePlugin::default())
.add_systems(Startup, setup);
app.run();
}
const LINE_HEIGHT: f32 = 21.;
fn setup(mut commands: Commands) {
// Scrolling list
commands
.spawn((
Node {
flex_direction: FlexDirection::Column,
// If height is not set, we need both align_self: Stetch and overflow: scroll()
height: Val::Percent(50.0),
// align_self: AlignSelf::Stretch,
overflow: Overflow::scroll(),
..default()
},
BackgroundColor(Color::srgb(0.10, 0.10, 0.10)),
))
.with_children(|parent| {
// List items
(0..250).for_each(|i| {
parent.spawn(Text(format!("Item {i}")));
});
})
.observe(scroll);
}
/// Updates the scroll position of scrollable nodes in response to mouse input
pub fn scroll(
trigger: Trigger<Pointer<Scroll>>,
mut scrollers: Query<&mut ScrollPosition>,
) {
let Pointer { event: Scroll { unit, x, y, .. }, .. } = trigger.event();
let (dx, dy) = match unit {
MouseScrollUnit::Line => (x * LINE_HEIGHT, y * LINE_HEIGHT),
MouseScrollUnit::Pixel => (x * 1., y * 1.),
};
if let Ok(mut pos) = scrollers.get_mut(trigger.target()) {
pos.offset_x -= dx;
pos.offset_y -= dy;
}
}

@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1750506804,
"narHash": "sha256-VLFNc4egNjovYVxDGyBYTrvVCgDYgENp5bVi9fPTDYc=",
"lastModified": 1752480373,
"narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4206c4cb56751df534751b058295ea61357bbbaa",
"rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08",
"type": "github"
},
"original": {

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2025-06-16"
channel = "nightly-2025-07-16"
components = [ "rustfmt", "rustc-dev", "cargo", "clippy", "rust-analyzer", "rustc-codegen-cranelift" ]
targets = [ "x86_64-unknown-linux-gnu", "wasm32-unknown-unknown" ]

@ -27,6 +27,7 @@ impl Plugin for BaseGamePlugin {
.add_plugins(MeshPickingPlugin)
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
.add_plugins(LoadingPlugin)
.add_plugins(BaseUiPlugin)
.add_systems(Startup, setup_camera);
}
}

@ -528,13 +528,11 @@ fn delete_tree(trigger: Trigger<Pointer<Click>>, mut commands: Commands) {
}
/// Load all monologues so they are in the asset store and trigger on-load events
fn load_monologues(
server: ResMut<AssetServer>,
mut loaded_assets: Local<Vec<Handle<Monologue>>>,
) {
*loaded_assets = include_str!("../../../assets/trees/MONOLOGUES").split("\n").map(|path| {
server.load(path)
}).collect();
fn load_monologues(server: ResMut<AssetServer>, mut loaded_assets: Local<Vec<Handle<Monologue>>>) {
*loaded_assets = include_str!("../../../assets/trees/MONOLOGUES")
.split("\n")
.map(|path| server.load(path))
.collect();
}
fn spawn_debug_buttons(
@ -700,6 +698,7 @@ fn hide_monologue_preview(
mut commands: Commands,
) {
if !query.contains(trigger.target()) {
info!("Processing over: {:?}", trigger.target());
commands.entity(*preview).despawn_related::<Children>();
}
}
@ -709,17 +708,18 @@ fn drag_tree(
state: Res<State<DebuggingState>>,
mut query: Query<&mut Transform, With<Tree>>,
camera: Single<(&Camera, &GlobalTransform), With<Camera>>,
window: Single<&Window>
window: Single<&Window>,
) {
if *state.get() == DebuggingState::On {
if let Ok(mut t) = query.get_mut(trigger.target()) {
let world_position = window
.cursor_position()
.and_then(|cursor| {
camera.0.viewport_to_world(camera.1, cursor).ok()
}).map(|ray| {
.and_then(|cursor| camera.0.viewport_to_world(camera.1, cursor).ok())
.map(|ray| {
// Compute ray's distance to entity
let distance = ray.intersect_plane(t.translation, InfinitePlane3d::new(t.up())).unwrap();
let distance = ray
.intersect_plane(t.translation, InfinitePlane3d::new(t.up()))
.unwrap();
ray.get_point(distance)
});
t.translation = world_position.unwrap();

@ -42,9 +42,7 @@ impl Display for MonologueLine {
impl From<String> for MonologueLine {
fn from(value: String) -> Self {
MonologueLine {
value
}
MonologueLine { value }
}
}
@ -57,7 +55,7 @@ impl Into<String> for MonologueLine {
impl From<&str> for MonologueLine {
fn from(value: &str) -> Self {
MonologueLine {
value: value.into()
value: value.into(),
}
}
}

@ -1,5 +1,13 @@
use super::*;
pub(crate) struct BaseUiPlugin;
impl Plugin for BaseUiPlugin {
fn build(&self, app: &mut App) {
// Nope!
}
}
/// Marker component for handling Resource -> Ui Sync
#[derive(Component, Default, Debug)]
pub struct SyncResource<R: Resource + Default + Display>(R);

Loading…
Cancel
Save