moving code around
Next I might make each part of the editor a plugin I know code moving is toil, but I'm kinda braindead and this is on my todo list...main
parent
0a56361168
commit
3b75fed684
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,155 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct AnimationWidget;
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct AnimationPlayAll;
|
||||||
|
|
||||||
|
pub fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut commands: Commands) {
|
||||||
|
events.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
AnimationPlayAll,
|
||||||
|
ButtonBundle {
|
||||||
|
style: Style {
|
||||||
|
border: UiRect::all(Val::Px(1.0)),
|
||||||
|
margin: UiRect::all(Val::Px(1.0)),
|
||||||
|
padding: UiRect::all(Val::Px(1.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
border_color: Color::BLACK.into(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
ui::Title {
|
||||||
|
text: "Play All".into(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When a new scene is loaded, add any newly compatible animations
|
||||||
|
/// TODO: Add target entity(s) too
|
||||||
|
pub fn add_animations_ui(
|
||||||
|
player_spawned: Query<&Name, Added<AnimationPlayer>>,
|
||||||
|
widget: Query<Entity, With<AnimationWidget>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
gltfs: Res<Assets<Gltf>>,
|
||||||
|
clips: Res<Assets<AnimationClip>>,
|
||||||
|
) {
|
||||||
|
player_spawned.iter().for_each(|player_name| {
|
||||||
|
gltfs
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(_, gltf)| gltf.named_animations.iter())
|
||||||
|
.filter_map(|(clip_name, handle)| {
|
||||||
|
clips.get(&handle).map(|clip| (clip_name, handle, clip))
|
||||||
|
})
|
||||||
|
.filter(|(_, _, clip)| clip.compatible_with(player_name))
|
||||||
|
.for_each(|(clip_name, handle, _)| {
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
clip_name.clone(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a scene is de-selected, remove any outdated animation options
|
||||||
|
pub fn remove_animations_ui(
|
||||||
|
mut removed_players: RemovedComponents<Handle<Scene>>,
|
||||||
|
current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>,
|
||||||
|
clips: Res<Assets<AnimationClip>>,
|
||||||
|
targets: Query<(&AnimationPlayer, &Name)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// For each removed scene
|
||||||
|
removed_players.iter().for_each(|_| {
|
||||||
|
// Iterate over the current animation buttons
|
||||||
|
current
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, ui::TargetAsset { handle })| {
|
||||||
|
// Check if this clip is compatible with any remaining entities
|
||||||
|
// NOTE: We are checking this is *not* compatible with any entities
|
||||||
|
clips
|
||||||
|
.get(handle)
|
||||||
|
.map(|clip| !(targets.iter().any(|(_, name)| clip.compatible_with(name))))
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
|
.for_each(|(_, ui::TargetAsset { handle })| {
|
||||||
|
// Destroy the buton if it is so
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_all_animations(
|
||||||
|
start: Query<Entity, (With<Button>, Added<ui::Active>)>,
|
||||||
|
mut stop: RemovedComponents<ui::Active>,
|
||||||
|
play_all_btn: Query<Entity, With<AnimationPlayAll>>,
|
||||||
|
clip_btns: Query<Entity, With<ui::TargetAsset<AnimationClip>>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
stop.iter()
|
||||||
|
.filter(|&entity| play_all_btn.contains(entity))
|
||||||
|
.for_each(|_| {
|
||||||
|
clip_btns.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).remove::<ui::Active>();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
start
|
||||||
|
.iter()
|
||||||
|
.filter(|&entity| play_all_btn.contains(entity))
|
||||||
|
.for_each(|_| {
|
||||||
|
clip_btns.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).insert(ui::Active);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_animation(
|
||||||
|
start: Query<Entity, (With<Button>, Added<ui::Active>)>,
|
||||||
|
mut stop: RemovedComponents<ui::Active>,
|
||||||
|
clip_refs: Query<&ui::TargetAsset<AnimationClip>>,
|
||||||
|
mut targets: Query<(&mut AnimationPlayer, &Name), With<Transform>>,
|
||||||
|
clips: Res<Assets<AnimationClip>>,
|
||||||
|
) {
|
||||||
|
stop.iter().for_each(|entity| {
|
||||||
|
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
|
||||||
|
let clip = clips.get(&handle).expect("Load animation clip");
|
||||||
|
targets
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|(_, name)| clip.compatible_with(name))
|
||||||
|
.for_each(|(mut player, _)| {
|
||||||
|
player.pause();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
start.iter().for_each(|entity| {
|
||||||
|
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
|
||||||
|
let clip = clips.get(&handle).expect("Load animation clip");
|
||||||
|
targets
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|(_, name)| clip.compatible_with(name))
|
||||||
|
.for_each(|(mut player, _)| {
|
||||||
|
if player.is_paused() {
|
||||||
|
player.resume();
|
||||||
|
} else {
|
||||||
|
player.play(handle.clone()).repeat();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
// This sets buttons to active when their associated handle is spawned
|
||||||
|
pub fn sync_asset_buttons<T: Asset>(
|
||||||
|
events: Query<&Handle<T>, Added<Handle<T>>>,
|
||||||
|
buttons: Query<(Entity, &ui::TargetAsset<T>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|this_handle| {
|
||||||
|
info!("Syncing {:?}", this_handle);
|
||||||
|
buttons
|
||||||
|
.iter()
|
||||||
|
.find_map(|(entity, ui::TargetAsset { handle })| {
|
||||||
|
if handle == this_handle {
|
||||||
|
Some(entity)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.iter()
|
||||||
|
.for_each(|&entity| {
|
||||||
|
commands.entity(entity).insert(ui::Active);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove active when handle is despawned?
|
||||||
|
// ONLY IF there are no instances of that handle [!any(*)]
|
||||||
|
pub fn sync_remove_asset_buttons<T: Asset>(
|
||||||
|
mut events: RemovedComponents<Handle<T>>,
|
||||||
|
asset_entities: Query<&Handle<T>>,
|
||||||
|
buttons: Query<(Entity, &ui::TargetAsset<T>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events
|
||||||
|
.iter()
|
||||||
|
.find_map(|this_asset_entity| asset_entities.get(this_asset_entity).ok())
|
||||||
|
.iter()
|
||||||
|
.for_each(|this_handle| {
|
||||||
|
info!("Syncing removal of {:?}", this_handle);
|
||||||
|
buttons
|
||||||
|
.iter()
|
||||||
|
.find_map(|(entity, ui::TargetAsset { handle })| {
|
||||||
|
if handle == *this_handle {
|
||||||
|
Some(entity)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.iter()
|
||||||
|
.for_each(|&entity| {
|
||||||
|
commands.entity(entity).remove::<ui::Active>();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct EditorCamera;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct CameraWidget;
|
||||||
|
|
||||||
|
pub fn cameras_ui(
|
||||||
|
mut added: Query<(Entity, &mut Camera, &Name), Added<Camera>>,
|
||||||
|
mut removed: RemovedComponents<Camera>,
|
||||||
|
editor_camera: Query<Entity, With<EditorCamera>>,
|
||||||
|
widget: Query<Entity, With<CameraWidget>>,
|
||||||
|
current: Query<(Entity, &ui::TargetEntity)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
removed.iter().for_each(|entity| {
|
||||||
|
info!("Destroy button for {:?}", entity);
|
||||||
|
destroy_entity_button(¤t, &mut commands, &ui::TargetEntity { entity });
|
||||||
|
});
|
||||||
|
added.iter_mut().for_each(|(entity, mut camera, name)| {
|
||||||
|
info!("Camera added {:?} {:?}", entity, name);
|
||||||
|
create_entity_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetEntity { entity },
|
||||||
|
name.as_str().into(),
|
||||||
|
);
|
||||||
|
camera.is_active = entity == editor_camera.single();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the camera active component based on button clicks
|
||||||
|
pub fn manage_active_camera(
|
||||||
|
events: Query<&ui::TargetEntity, Added<ui::Active>>,
|
||||||
|
mut cameras: Query<(Entity, &mut Camera)>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|ui::TargetEntity { entity }| {
|
||||||
|
cameras.iter_mut().for_each(|(this_entity, mut camera)| {
|
||||||
|
if this_entity == *entity {
|
||||||
|
info!("Marking {:?} as active camera", entity);
|
||||||
|
camera.is_active = true;
|
||||||
|
} else {
|
||||||
|
info!("Marking {:?} as inactive camera", entity);
|
||||||
|
camera.is_active = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the event that an active camera is despawned, fall back to the editor camera
|
||||||
|
pub fn fallback_camera(
|
||||||
|
modified: Query<Entity, (Changed<Camera>, Without<EditorCamera>)>,
|
||||||
|
mut removed: RemovedComponents<Camera>,
|
||||||
|
other_cameras: Query<&Camera, Without<EditorCamera>>,
|
||||||
|
mut editor_camera: Query<&mut Camera, With<EditorCamera>>,
|
||||||
|
) {
|
||||||
|
// Any time a camera is modified
|
||||||
|
modified.iter().chain(removed.iter()).for_each(|_| {
|
||||||
|
// If no other cameras are active
|
||||||
|
if !other_cameras.iter().any(|camera| camera.is_active) {
|
||||||
|
// Make the editor camera active
|
||||||
|
editor_camera.single_mut().is_active = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct GltfWidget;
|
||||||
|
|
||||||
|
pub fn gltf_ui(
|
||||||
|
mut events: EventReader<AssetEvent<Gltf>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
widget: Query<Entity, With<GltfWidget>>,
|
||||||
|
current: Query<(Entity, &ui::TargetAsset<Gltf>)>,
|
||||||
|
server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|event| match event {
|
||||||
|
AssetEvent::Created { handle } => {
|
||||||
|
info!("Asset created! {:?}", event);
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
get_asset_name(&server, handle.clone()),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AssetEvent::Removed { handle } => {
|
||||||
|
info!("Asset removed! {:?}", event);
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AssetEvent::Modified { handle } => {
|
||||||
|
info!("Asset modified! {:?}", event);
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
get_asset_name(&server, handle.clone()),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn control_active_gltf(
|
||||||
|
events: Query<Entity, (With<ui::TargetAsset<Gltf>>, Added<ui::Active>)>,
|
||||||
|
root: Query<Entity, With<LevelRoot>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|_| {
|
||||||
|
root.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).despawn_descendants();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,167 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
use bevy::tasks::IoTaskPool;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Reflect, Default)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct LevelRoot;
|
||||||
|
|
||||||
|
pub type Level = DynamicScene;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct LevelWidget;
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct ExportLevel;
|
||||||
|
|
||||||
|
pub fn level_ui(
|
||||||
|
mut events: EventReader<AssetEvent<Level>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
widget: Query<Entity, With<LevelWidget>>,
|
||||||
|
current: Query<(Entity, &ui::TargetAsset<Level>)>,
|
||||||
|
server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|event| match event {
|
||||||
|
AssetEvent::Created { handle } => {
|
||||||
|
info!("Asset created! {:?}", event);
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
get_asset_name(&server, handle.clone()),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AssetEvent::Removed { handle } => {
|
||||||
|
info!("Asset removed! {:?}", event);
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AssetEvent::Modified { handle } => {
|
||||||
|
info!("Asset modified! {:?}", event);
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
get_asset_name(&server, handle.clone()),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_level(
|
||||||
|
events: Query<
|
||||||
|
&ui::TargetAsset<DynamicScene>,
|
||||||
|
(Added<ui::Active>, With<ui::TargetAsset<DynamicScene>>),
|
||||||
|
>,
|
||||||
|
root: Query<Entity, With<LevelRoot>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
root.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).despawn_recursive();
|
||||||
|
});
|
||||||
|
commands.spawn(DynamicSceneBundle {
|
||||||
|
scene: handle.clone(),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_level(
|
||||||
|
level_root: Query<Entity, With<LevelRoot>>,
|
||||||
|
audio_root: Query<Entity, With<AudioRoot>>,
|
||||||
|
children: Query<&Children>,
|
||||||
|
world: &World,
|
||||||
|
) {
|
||||||
|
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
|
||||||
|
let mut builder = DynamicSceneBuilder::from_world(world.clone());
|
||||||
|
|
||||||
|
builder.deny_all_resources();
|
||||||
|
|
||||||
|
// Exclude computed visibility
|
||||||
|
builder.deny_all();
|
||||||
|
|
||||||
|
// Level administrivia
|
||||||
|
builder.allow::<LevelRoot>();
|
||||||
|
builder.allow::<AudioRoot>();
|
||||||
|
|
||||||
|
// TODO: Serialize Timeline
|
||||||
|
|
||||||
|
// Scene components
|
||||||
|
builder.allow::<Handle<Scene>>();
|
||||||
|
|
||||||
|
// Spatial components
|
||||||
|
builder.allow::<Transform>();
|
||||||
|
builder.allow::<GlobalTransform>();
|
||||||
|
builder.allow::<Visibility>();
|
||||||
|
|
||||||
|
// Audio components
|
||||||
|
builder.allow::<Handle<AudioSource>>();
|
||||||
|
builder.allow::<PlaybackSettings>();
|
||||||
|
|
||||||
|
// Text components
|
||||||
|
builder.allow::<Handle<Font>>();
|
||||||
|
builder.allow::<Handle<Monologue>>();
|
||||||
|
|
||||||
|
level_root.iter().for_each(|level| {
|
||||||
|
// Extract the level root
|
||||||
|
builder.extract_entity(level);
|
||||||
|
|
||||||
|
if let Ok(kids) = children.get(level) {
|
||||||
|
builder.extract_entities(kids.into_iter().map(|&e| e));
|
||||||
|
} else {
|
||||||
|
warn!("Level is empty!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
audio_root.iter().for_each(|audio| {
|
||||||
|
// Extract the level root
|
||||||
|
builder.extract_entity(audio);
|
||||||
|
|
||||||
|
if let Ok(kids) = children.get(audio) {
|
||||||
|
builder.extract_entities(kids.into_iter().map(|&e| e));
|
||||||
|
} else {
|
||||||
|
warn!("Audio is empty!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let scene = builder.build();
|
||||||
|
|
||||||
|
let serialized = scene
|
||||||
|
.serialize_ron(&app_type_registry)
|
||||||
|
.expect("Serialize scene");
|
||||||
|
|
||||||
|
IoTaskPool::get()
|
||||||
|
.spawn(async move {
|
||||||
|
// Write the scene RON data to file
|
||||||
|
std::fs::write(format!("assets/output.scn.ron"), serialized.as_bytes())
|
||||||
|
.expect("Error while writing scene to file");
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rehydrate_level<W: Component, WO: Component + Default>(
|
||||||
|
events: Query<Entity, (Added<W>, Without<WO>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).insert(WO::default());
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
pub fn spot_light_force_shadows(mut spot_lights: Query<&mut SpotLight, Added<SpotLight>>) {
|
||||||
|
spot_lights.iter_mut().for_each(|mut light| {
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn directional_light_force_shadows(
|
||||||
|
mut directional_lights: Query<&mut DirectionalLight, Added<DirectionalLight>>,
|
||||||
|
) {
|
||||||
|
directional_lights.iter_mut().for_each(|mut light| {
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn point_light_force_shadows(mut point_lights: Query<&mut PointLight, Added<PointLight>>) {
|
||||||
|
point_lights.iter_mut().for_each(|mut light| {
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
pub use crate::{
|
||||||
|
editor::{
|
||||||
|
animation::*, asset_sync::*, assets::*, audio::*, camera::*, font::*, gltf::*, level::*,
|
||||||
|
lighting::*, monologue::*, quit::*, reset::*, scene::*, timeline::*, *,
|
||||||
|
},
|
||||||
|
ui,
|
||||||
|
};
|
||||||
|
pub use bevy::{gltf::Gltf, prelude::*};
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
use bevy::app::AppExit;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct QuitAction;
|
||||||
|
|
||||||
|
pub fn quit(mut exit: EventWriter<AppExit>) {
|
||||||
|
exit.send(AppExit);
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct ClearLevel;
|
||||||
|
|
||||||
|
pub fn clear_level(
|
||||||
|
events: Query<Entity, (With<ClearLevel>, Added<ui::Active>)>,
|
||||||
|
actives: Query<
|
||||||
|
Entity,
|
||||||
|
(
|
||||||
|
With<ui::Active>,
|
||||||
|
Or<(
|
||||||
|
With<ui::TargetEntity>,
|
||||||
|
With<ui::TargetAsset<Gltf>>,
|
||||||
|
With<ui::TargetAsset<Scene>>,
|
||||||
|
With<ui::TargetAsset<AnimationClip>>,
|
||||||
|
With<ui::TargetAsset<AudioSource>>,
|
||||||
|
With<ui::TargetAsset<Monologue>>,
|
||||||
|
With<ui::TargetAsset<Font>>,
|
||||||
|
)>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
root: Query<Entity, With<LevelRoot>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|_| {
|
||||||
|
actives.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).remove::<ui::Active>();
|
||||||
|
});
|
||||||
|
root.iter().for_each(|entity| {
|
||||||
|
commands.entity(entity).despawn_descendants();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct ClearAssets;
|
||||||
|
|
||||||
|
pub fn clear_assets(
|
||||||
|
asset_holders: Query<
|
||||||
|
Entity,
|
||||||
|
Or<(
|
||||||
|
With<ui::TargetAsset<Gltf>>,
|
||||||
|
With<Handle<Gltf>>,
|
||||||
|
With<ui::TargetAsset<Scene>>,
|
||||||
|
With<Handle<Scene>>,
|
||||||
|
With<ui::TargetAsset<AnimationClip>>,
|
||||||
|
With<Handle<AnimationClip>>,
|
||||||
|
With<ui::TargetAsset<AudioSource>>,
|
||||||
|
With<Handle<AudioSource>>,
|
||||||
|
With<ui::TargetAsset<Monologue>>,
|
||||||
|
With<Handle<Monologue>>,
|
||||||
|
With<ui::TargetAsset<Font>>,
|
||||||
|
With<Handle<Font>>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
|
mut registry: ResMut<AssetRegistry>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
info!("Clearing assets");
|
||||||
|
|
||||||
|
// Clear buttons holding asset references
|
||||||
|
asset_holders
|
||||||
|
.iter()
|
||||||
|
.for_each(|entity| commands.entity(entity).despawn_recursive());
|
||||||
|
|
||||||
|
// Empty asset registry
|
||||||
|
registry.0.clear();
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Default)]
|
||||||
|
pub struct SceneWidget;
|
||||||
|
|
||||||
|
pub fn add_scenes_ui(
|
||||||
|
gltf_selected: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
gltfs: Res<Assets<Gltf>>,
|
||||||
|
widget: Query<Entity, With<SceneWidget>>,
|
||||||
|
) {
|
||||||
|
gltf_selected.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
if let Some(gltf) = gltfs.get(&handle.clone()) {
|
||||||
|
gltf.named_scenes.iter().for_each(|(name, handle)| {
|
||||||
|
create_asset_button(
|
||||||
|
&widget,
|
||||||
|
&mut commands,
|
||||||
|
ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
name.clone(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_scenes_ui(
|
||||||
|
mut gltf_unselected: RemovedComponents<ui::Active>,
|
||||||
|
target_assets: Query<&ui::TargetAsset<Gltf>>,
|
||||||
|
current: Query<(Entity, &ui::TargetAsset<Scene>)>,
|
||||||
|
gltfs: Res<Assets<Gltf>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
gltf_unselected
|
||||||
|
.iter()
|
||||||
|
.filter_map(|entity| target_assets.get(entity).ok())
|
||||||
|
.filter_map(|ui::TargetAsset { handle }| gltfs.get(handle))
|
||||||
|
.for_each(|gltf| {
|
||||||
|
gltf.scenes.iter().for_each(|handle| {
|
||||||
|
destroy_asset_button(
|
||||||
|
¤t,
|
||||||
|
&mut commands,
|
||||||
|
&ui::TargetAsset {
|
||||||
|
handle: handle.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn control_active_scenes(
|
||||||
|
added: Query<Entity, (With<Button>, Added<ui::Active>)>,
|
||||||
|
mut removed: RemovedComponents<ui::Active>,
|
||||||
|
scene_refs: Query<&ui::TargetAsset<Scene>>,
|
||||||
|
scenes: Query<(Entity, &Handle<Scene>)>,
|
||||||
|
level_root: Query<Entity, With<LevelRoot>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// A scene button was marked inactive
|
||||||
|
removed.iter().for_each(|entity| {
|
||||||
|
// Get the handle associated with that button
|
||||||
|
scene_refs
|
||||||
|
.get(entity)
|
||||||
|
.iter()
|
||||||
|
.for_each(|ui::TargetAsset { handle }| {
|
||||||
|
scenes
|
||||||
|
.iter()
|
||||||
|
.find_map(|(entity, this_handle)| (this_handle == handle).then_some(entity))
|
||||||
|
.iter()
|
||||||
|
.for_each(|&entity| {
|
||||||
|
commands.entity(entity).despawn_recursive();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
added.iter().for_each(|entity| {
|
||||||
|
scene_refs
|
||||||
|
.get(entity)
|
||||||
|
.iter()
|
||||||
|
.for_each(|ui::TargetAsset { handle }| {
|
||||||
|
info!("Spawning Scene {:?}", handle);
|
||||||
|
commands
|
||||||
|
.entity(level_root.single())
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn(SceneBundle {
|
||||||
|
scene: handle.clone(),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,325 @@
|
|||||||
|
use crate::editor::prelude::*;
|
||||||
|
|
||||||
|
/// Timeline widget marker
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct TimelineWidget;
|
||||||
|
|
||||||
|
/// Add Epoch component, used on a button to trigger a new epoch addition
|
||||||
|
#[derive(Debug, Component)]
|
||||||
|
pub struct AddEpoch;
|
||||||
|
|
||||||
|
/// Epoch ID Component
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochId {
|
||||||
|
id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch GLTF Component
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochGltf {
|
||||||
|
gltf: Handle<Gltf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch Scene Component
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochScene {
|
||||||
|
scene: Handle<Scene>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch Camera Component, marking the current camera
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochCamera {
|
||||||
|
camera: Entity,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch music component, marking the opening track for this epoch
|
||||||
|
#[derive(Debug, Reflect, Default, Component, Clone)]
|
||||||
|
pub struct EpochMusic {
|
||||||
|
music: Handle<AudioSource>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch monologue, marking the dialog spoken this epoch
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochMonologue {
|
||||||
|
monologue: Handle<Monologue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch font, marking the font used for this epoch's monologue
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochFont {
|
||||||
|
font: Handle<Font>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vector of audios looping this epoch as background tracks
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochSfx {
|
||||||
|
sfx: Vec<Handle<AudioSource>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch animations, looping this epoch
|
||||||
|
#[derive(Debug, Reflect, Component, Clone)]
|
||||||
|
pub struct EpochAnimations {
|
||||||
|
animations: Vec<Handle<AnimationClip>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// System for adding an epoch to the level's timeline
|
||||||
|
/// Triggered when a button with the AddEpoch marker is Active
|
||||||
|
pub fn add_timeline_epoch(
|
||||||
|
root: Query<(Entity, &Children), With<TimelineWidget>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
info!("Adding timeline epoch");
|
||||||
|
|
||||||
|
root.iter().for_each(|(entity, children)| {
|
||||||
|
let id = children.iter().len();
|
||||||
|
let name = format!("{}", id);
|
||||||
|
commands.entity(entity).with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
ButtonBundle {
|
||||||
|
style: Style {
|
||||||
|
border: UiRect::all(Val::Px(1.0)),
|
||||||
|
margin: UiRect::all(Val::Px(1.0)),
|
||||||
|
padding: UiRect::all(Val::Px(1.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
border_color: Color::BLACK.into(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
ui::Title {
|
||||||
|
text: name,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
EpochId { id },
|
||||||
|
));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the GLTF for the current epoch
|
||||||
|
pub fn set_epoch_gltf(
|
||||||
|
events: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a GLTF is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter().for_each(|entity| {
|
||||||
|
// Set the GLTF (overwrite existing GLTF selections)
|
||||||
|
commands.entity(entity).insert(EpochGltf {
|
||||||
|
gltf: handle.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Unset Scene, Camera, Animations
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_gltf(events: Query<Option<&EpochGltf>, (Added<ui::Active>, With<EpochId>)>) {
|
||||||
|
events.iter().for_each(|epoch_gltf| {
|
||||||
|
warn!("TODO: Load epoch GLTF!");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_scene(
|
||||||
|
events: Query<&ui::TargetAsset<Scene>, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter().for_each(|entity| {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands.entity(entity).insert(EpochScene {
|
||||||
|
scene: handle.clone(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_scene(events: Query<Option<&EpochScene>, (Added<ui::Active>, With<EpochId>)>) {
|
||||||
|
events.iter().for_each(|epoch_scene| {
|
||||||
|
warn!("TODO: Load epoch Scene!");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_camera(
|
||||||
|
events: Query<&ui::TargetEntity, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetEntity { entity }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter().for_each(|this_entity| {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands
|
||||||
|
.entity(this_entity)
|
||||||
|
.insert(EpochCamera { camera: *entity });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_camera(events: Query<Option<&EpochCamera>, (Added<ui::Active>, With<EpochId>)>) {
|
||||||
|
events.iter().for_each(|epoch_camera| {
|
||||||
|
warn!("TODO: Load epoch Camera");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_music(
|
||||||
|
events: Query<&ui::TargetAsset<AudioSource>, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
info!("TODO: Select scene music");
|
||||||
|
|
||||||
|
// // Iterate over all (0 or 1) active epochs
|
||||||
|
// active_epoch.iter().for_each(|entity| {
|
||||||
|
// // Set the Scene (overwrite existing Scene selections)
|
||||||
|
// commands.entity(entity).insert(EpochMusic { music: handle.clone() });
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_music(events: Query<Option<&EpochMusic>, (Added<ui::Active>, With<EpochId>)>) {
|
||||||
|
events.iter().for_each(|epoch_music| {
|
||||||
|
warn!("TODO: Load epoch music!");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_monologue(
|
||||||
|
events: Query<&ui::TargetAsset<Monologue>, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter().for_each(|entity| {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands.entity(entity).insert(EpochMonologue {
|
||||||
|
monologue: handle.clone(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_monologue(
|
||||||
|
events: Query<Option<&EpochMonologue>, (Added<ui::Active>, With<EpochId>)>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|epoch_monologue| {
|
||||||
|
warn!("TODO: unset epoch Monologue!");
|
||||||
|
epoch_monologue
|
||||||
|
.iter()
|
||||||
|
.for_each(|EpochMonologue { monologue }| {
|
||||||
|
warn!("TODO: Set level epoch");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_font(
|
||||||
|
events: Query<&ui::TargetAsset<Font>, Added<ui::Active>>,
|
||||||
|
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter().for_each(|entity| {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands.entity(entity).insert(EpochFont {
|
||||||
|
font: handle.clone(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_font(
|
||||||
|
events: Query<Option<&EpochFont>, (Added<ui::Active>, With<EpochId>)>,
|
||||||
|
mut font_info: ResMut<FontInfo>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|epoch_font| {
|
||||||
|
font_info.default = epoch_font.map(|EpochFont { font }| font.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_sfx(
|
||||||
|
events: Query<&ui::TargetAsset<AudioSource>, Added<ui::Active>>,
|
||||||
|
mut active_epoch: Query<(Entity, Option<&mut EpochSfx>), (With<ui::Active>, With<EpochId>)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch.iter_mut().for_each(|(entity, maybe_sfx)| {
|
||||||
|
info!("Adding sfx {:?} to epoch {:?}", maybe_sfx, entity);
|
||||||
|
if let Some(mut epoch_sfx) = maybe_sfx {
|
||||||
|
epoch_sfx.sfx.push(handle.clone());
|
||||||
|
} else {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands.entity(entity).insert(EpochSfx {
|
||||||
|
sfx: vec![handle.clone()],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_sfx(
|
||||||
|
added: Query<Entity, (Added<ui::Active>, With<EpochId>)>,
|
||||||
|
mut removed: RemovedComponents<ui::Active>,
|
||||||
|
epoch_sfx: Query<&EpochSfx>,
|
||||||
|
mut writer: EventWriter<ControlAudio>,
|
||||||
|
) {
|
||||||
|
removed.iter().for_each(|entity| {
|
||||||
|
epoch_sfx.get(entity).iter().for_each(|EpochSfx { sfx }| {
|
||||||
|
sfx.iter().for_each(|handle| {
|
||||||
|
writer.send(ControlAudio::Stop(handle.clone()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
added.iter().for_each(|entity| {
|
||||||
|
epoch_sfx.get(entity).iter().for_each(|EpochSfx { sfx }| {
|
||||||
|
sfx.iter().for_each(|handle| {
|
||||||
|
writer.send(ControlAudio::Loop(handle.clone()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_epoch_animations(
|
||||||
|
events: Query<&ui::TargetAsset<AnimationClip>, Added<ui::Active>>,
|
||||||
|
mut active_epoch: Query<
|
||||||
|
(Entity, Option<&mut EpochAnimations>),
|
||||||
|
(With<ui::Active>, With<EpochId>),
|
||||||
|
>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
// Each time a Scene is selected in the editor
|
||||||
|
events.iter().for_each(|ui::TargetAsset { handle }| {
|
||||||
|
// Iterate over all (0 or 1) active epochs
|
||||||
|
active_epoch
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|(entity, maybe_animations)| {
|
||||||
|
if let Some(mut epoch_animations) = maybe_animations {
|
||||||
|
epoch_animations.animations.push(handle.clone());
|
||||||
|
} else {
|
||||||
|
// Set the Scene (overwrite existing Scene selections)
|
||||||
|
commands.entity(entity).insert(EpochAnimations {
|
||||||
|
animations: vec![handle.clone()],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_epoch_animations(
|
||||||
|
events: Query<Option<&EpochAnimations>, (Added<ui::Active>, With<EpochId>)>,
|
||||||
|
) {
|
||||||
|
events.iter().for_each(|epoch_animations| {
|
||||||
|
warn!("TODO: Load epoch Animations!");
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue