move actions to their own UI element

main
Elijah Voigt 2 years ago
parent e6ceffa8d1
commit 5952ee5608

@ -3,30 +3,19 @@
// Editor for creating Monologue Trees levels // Editor for creating Monologue Trees levels
// //
// BUGS: // BUGS:
// * Not loading scenes with Active refactor
// * Not pause animations with Active refactor
// * Camera order ambiguity // * Camera order ambiguity
// * Load new GLTF -> Despawn all level entities // * Load new GLTF -> Despawn all level entities
// //
// TODO: // TODO:
// * Disable auto start/load // * Disable auto start/load
// * (hard) Harden Active Camera // * (hard) Harden Active Camera
// * (medium) Despawn entire scene when GLTF changed?
// * (medium) Select Font -> "Default Font" Resource // * (medium) Select Font -> "Default Font" Resource
// * (medium) Pre-compute animation target entities // * (medium) Pre-compute animation target entities
// * (medium) Animation buttons only visible when playable
// * (easy) Clear button to wipe spawned scene
// * Better handle hide/close monologue // * Better handle hide/close monologue
// * (brutal) export level // * (brutal) export level
// * (hard) import level // * (hard) import level
//
// Asset types:
// * Audios (done)
// * Loop individual (done)
// * Gltfs (doing)
// * Scenes
// * Animations
// * Play/Pause all
// * Fonts (done)
// * Monologues (done)
use bevy::{ use bevy::{
asset::{Asset, AssetLoader, Assets, ChangeWatcher, LoadContext, LoadedAsset}, asset::{Asset, AssetLoader, Assets, ChangeWatcher, LoadContext, LoadedAsset},
@ -72,8 +61,6 @@ fn main() {
.init_resource::<AssetRegistry>() .init_resource::<AssetRegistry>()
.add_asset::<Monologue>() .add_asset::<Monologue>()
.init_asset_loader::<MonologueLoader>() .init_asset_loader::<MonologueLoader>()
.add_event::<CustomAssetEvent<Scene>>()
.add_event::<CustomAssetEvent<AnimationClip>>()
.add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message)) .add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message))
.add_systems( .add_systems(
Update, Update,
@ -89,16 +76,8 @@ fn main() {
Update, Update,
(remove_scenes_ui, add_scenes_ui, control_active_scenes), (remove_scenes_ui, add_scenes_ui, control_active_scenes),
) )
.add_systems( .add_systems(Update, (cameras_ui, manage_active_camera, fallback_camera))
Update, .add_systems(Update, (audio_ui, play_audio, pause_audio))
(
cameras_ui,
manage_active_camera,
control_active_camera,
fallback_camera,
),
)
.add_systems(Update, (audio_ui, play_audio))
.add_systems( .add_systems(
Update, Update,
( (
@ -106,7 +85,7 @@ fn main() {
gltf_ui, gltf_ui,
fonts_ui, fonts_ui,
texts_ui, texts_ui,
manage_active_gltf, control_active_gltf,
show_preview_text, show_preview_text,
sync_monologue_font, sync_monologue_font,
), ),
@ -126,13 +105,6 @@ fn main() {
#[derive(Resource, Default)] #[derive(Resource, Default)]
pub struct AssetRegistry(Vec<HandleUntyped>); pub struct AssetRegistry(Vec<HandleUntyped>);
#[derive(Event)]
pub enum CustomAssetEvent<T: Asset> {
Add { handle: Handle<T>, name: String },
Remove { handle: Handle<T> },
Clear,
}
#[derive(Debug, Component)] #[derive(Debug, Component)]
pub struct TabRoot; pub struct TabRoot;
@ -162,6 +134,15 @@ fn initialize_ui(mut commands: Commands) {
..default() ..default()
}; };
let simple_button = ButtonBundle {
style: Style {
..base_style.clone()
},
background_color: Color::WHITE.into(),
border_color: Color::BLACK.into(),
..default()
};
commands commands
.spawn(NodeBundle { .spawn(NodeBundle {
style: Style { style: Style {
@ -198,15 +179,6 @@ fn initialize_ui(mut commands: Commands) {
// HACK: This is super janky but I think we need it like this for UI layout rules // HACK: This is super janky but I think we need it like this for UI layout rules
let mut content_containers: Vec<(String, Entity)> = Vec::new(); let mut content_containers: Vec<(String, Entity)> = Vec::new();
let simple_button = ButtonBundle {
style: Style {
..base_style.clone()
},
background_color: Color::WHITE.into(),
border_color: Color::BLACK.into(),
..default()
};
// Containers with asset content // Containers with asset content
parent parent
.spawn(( .spawn((
@ -297,25 +269,6 @@ fn initialize_ui(mut commands: Commands) {
)); ));
}, },
); );
parent.spawn((
simple_button.clone(),
ClearAssets,
ui::Sorting(90),
ui::Title {
text: "Clear Assets".into(),
..default()
},
));
parent.spawn((
simple_button.clone(),
ClearLevel,
ui::Sorting(95),
ui::Title {
text: "Reset Level".into(),
..default()
},
));
}); });
}) })
.id(); .id();
@ -329,6 +282,73 @@ fn initialize_ui(mut commands: Commands) {
ui::Sorting(0), ui::Sorting(0),
)); ));
}); });
commands
.spawn(NodeBundle {
style: Style {
bottom: Val::Px(0.0),
left: Val::Px(0.0),
position_type: PositionType::Absolute,
border: UiRect::all(Val::Px(1.0)),
margin: UiRect::all(Val::Px(1.0)),
padding: UiRect::all(Val::Px(1.0)),
flex_direction: FlexDirection::Column,
overflow: Overflow::clip(),
..default()
},
background_color: Color::WHITE.into(),
border_color: Color::BLACK.into(),
..default()
})
.with_children(|parent| {
let container = parent
.spawn((
NodeBundle {
style: Style {
border: UiRect::all(Val::Px(1.0)),
margin: UiRect::all(Val::Px(1.0)),
padding: UiRect::all(Val::Px(1.0)),
flex_direction: FlexDirection::Column,
overflow: Overflow::clip(),
..default()
},
background_color: Color::WHITE.into(),
border_color: Color::BLACK.into(),
..default()
},
ui::Sorting(99),
ui::Select::Action,
))
.with_children(|parent| {
parent.spawn((
simple_button.clone(),
ClearAssets,
ui::Sorting(1),
ui::Title {
text: "Clear Assets".into(),
..default()
},
));
parent.spawn((
simple_button.clone(),
ClearLevel,
ui::Sorting(2),
ui::Title {
text: "Reset Level".into(),
..default()
},
));
})
.id();
parent.spawn((
ui::TitleBarBase::new(Color::WHITE).bundle(),
ui::Title {
text: "Actions".into(),
..default()
},
ui::Minimize { target: container },
ui::Sorting(0),
));
});
} }
fn welcome_message(mut writer: EventWriter<ui::Alert>) { fn welcome_message(mut writer: EventWriter<ui::Alert>) {
@ -466,27 +486,22 @@ mod audio {
}); });
} }
pub fn play_audio( pub fn play_audio(events: Query<&AudioSink, (With<Button>, Added<ui::Active>)>) {
events: Query<(Entity, &Interaction, &AudioSink), (With<Button>, Changed<Interaction>)>, events.iter().for_each(|sink| {
mut commands: Commands, sink.play();
) { });
}
pub fn pause_audio(mut events: RemovedComponents<ui::Active>, sinks: Query<&AudioSink>) {
events events
.iter() .iter()
.filter(|(_, &interaction, _)| interaction == Interaction::Pressed) .filter_map(|entity| sinks.get(entity).ok())
.for_each(|(entity, _, sink)| { .for_each(|sink| sink.stop());
sink.toggle();
if sink.is_paused() {
commands.entity(entity).remove::<ui::Active>();
} else {
commands.entity(entity).insert(ui::Active);
}
});
} }
} }
use assets::*; use assets::*;
mod assets { mod assets {
use super::*; use super::*;
pub fn get_asset_name<T: Asset>(server: &AssetServer, handle: Handle<T>) -> String { pub fn get_asset_name<T: Asset>(server: &AssetServer, handle: Handle<T>) -> String {
@ -602,7 +617,6 @@ mod gltf {
#[derive(Debug, Component, Default)] #[derive(Debug, Component, Default)]
pub struct GltfWidget; pub struct GltfWidget;
// TODO: Mark selected gltf as active ~single exclusive~
pub fn gltf_ui( pub fn gltf_ui(
mut events: EventReader<AssetEvent<Gltf>>, mut events: EventReader<AssetEvent<Gltf>>,
mut commands: Commands, mut commands: Commands,
@ -655,24 +669,14 @@ mod gltf {
}); });
} }
pub fn manage_active_gltf( pub fn control_active_gltf(
events: Query< events: Query<Entity, (With<ui::TargetAsset<Gltf>>, Added<ui::Active>)>,
(Entity, &Interaction, Option<&ui::Active>), root: Query<Entity, With<LevelRoot>>,
(With<Button>, Changed<Interaction>),
>,
mut commands: Commands, mut commands: Commands,
) { ) {
events events.iter().for_each(|_| {
.iter() commands.entity(root.single()).despawn_descendants();
.filter(|(_, &interaction, _)| interaction == Interaction::Pressed) });
.for_each(|(entity, _, active_ish)| match active_ish {
Some(_) => {
commands.entity(entity).remove::<ui::Active>();
}
None => {
commands.entity(entity).insert(ui::Active);
}
});
} }
} }
@ -1194,8 +1198,9 @@ mod cameras {
pub struct CameraWidget; pub struct CameraWidget;
pub fn cameras_ui( pub fn cameras_ui(
mut added: Query<(Entity, &mut Camera, &Name), (Added<Camera>, Without<EditorCamera>)>, mut added: Query<(Entity, &mut Camera, &Name), Added<Camera>>,
mut removed: RemovedComponents<Camera>, mut removed: RemovedComponents<Camera>,
editor_camera: Query<Entity, With<EditorCamera>>,
widget: Query<Entity, With<CameraWidget>>, widget: Query<Entity, With<CameraWidget>>,
current: Query<(Entity, &ui::TargetEntity)>, current: Query<(Entity, &ui::TargetEntity)>,
mut commands: Commands, mut commands: Commands,
@ -1212,47 +1217,25 @@ mod cameras {
ui::TargetEntity { entity }, ui::TargetEntity { entity },
name.as_str().into(), name.as_str().into(),
); );
camera.is_active = false; camera.is_active = entity == editor_camera.single();
}); });
} }
/// Set the camera active component based on button clicks /// Set the camera active component based on button clicks
pub fn manage_active_camera( pub fn manage_active_camera(
events: Query<(&Interaction, &ui::TargetEntity), Changed<Interaction>>, events: Query<&ui::TargetEntity, Added<ui::Active>>,
cameras: Query<Entity, With<Camera>>, mut cameras: Query<(Entity, &mut Camera)>,
mut commands: Commands,
) { ) {
events events.iter().for_each(|ui::TargetEntity { entity }| {
.iter() cameras.iter_mut().for_each(|(this_entity, mut camera)| {
.filter(|(&interaction, _)| interaction == Interaction::Pressed) if this_entity == *entity {
.for_each(|(_, ui::TargetEntity { entity })| { info!("Marking {:?} as active camera", entity);
cameras.iter().for_each(|this_entity| { camera.is_active = true;
if this_entity == *entity { } else {
info!("Marking {:?} as active camera", entity); info!("Marking {:?} as inactive camera", entity);
commands.entity(this_entity).insert(ui::Active); camera.is_active = false;
} else { }
info!("Marking {:?} as inactive camera", entity);
commands.entity(this_entity).remove::<ui::Active>();
}
});
}); });
}
/// Set the active camera based on the Active marker component
pub fn control_active_camera(
added: Query<Entity, (Added<ui::Active>, With<Camera>)>,
mut removed: RemovedComponents<ui::Active>,
mut cameras: Query<&mut Camera>,
) {
removed.iter().for_each(|entity| {
if let Ok(mut camera) = cameras.get_mut(entity) {
camera.is_active = false;
}
});
added.iter().for_each(|entity| {
if let Ok(mut camera) = cameras.get_mut(entity) {
camera.is_active = true;
}
}); });
} }
@ -1360,12 +1343,13 @@ mod reset {
mut commands: Commands, mut commands: Commands,
) { ) {
events.iter().for_each(|entity| { events.iter().for_each(|entity| {
// Clear buttons holding asset references
asset_holders asset_holders
.iter() .iter()
.for_each(|entity| commands.entity(entity).despawn_recursive()); .for_each(|entity| commands.entity(entity).despawn_recursive());
// Empty asset registry
registry.0.clear(); registry.0.clear();
// TODO: .clear() assets?
commands.entity(entity).remove::<ui::Active>();
}) })
} }
} }

@ -423,28 +423,48 @@ mod buttons {
pub enum Select { pub enum Select {
Multi, Multi,
Single, Single,
Action,
} }
pub fn manage_select_active( pub fn manage_select_active(
events: Query<(Entity, &Parent), Added<Active>>, events: Query<
children: Query<(&Select, &Children)>, (Entity, &Parent, Option<&Active>, &Interaction),
(With<Button>, Changed<Interaction>),
>,
selects: Query<(&Select, &Children)>,
mut commands: Commands, mut commands: Commands,
) { ) {
events.iter().for_each(|(entity, parent)| { events
if let Ok((select, childs)) = children.get(parent.get()) { .iter()
match select { .filter(|(_, _, _, &interaction)| interaction == Interaction::Pressed)
Select::Single => { .for_each(|(entity, parent, active, _)| {
childs selects
.iter() .get(parent.get())
.filter(|&child| *child != entity) .iter()
.for_each(|&child| { .for_each(|(select, children)| {
commands.entity(child).remove::<Active>(); match active {
}) Some(_) => {
} commands.entity(entity).remove::<Active>();
Select::Multi => (), }
} None => {
} commands.entity(entity).insert(Active);
}); }
}
match select {
Select::Action => {
commands.entity(entity).remove::<Active>();
}
Select::Multi => (),
Select::Single => {
children.iter().filter(|&child| *child != entity).for_each(
|&child| {
commands.entity(child).remove::<Active>();
},
);
}
}
});
});
} }
} }

Loading…
Cancel
Save