Skip to content

Commit aba3315

Browse files
committed
chore: migrate to Bevy 0.19
- Bump deps to 0.19-compatible versions: bevy 0.19, avian3d 0.7, bevy-inspector-egui 0.37, bevy_brp_extras 0.20, bevy_enhanced_input 0.26, bevy_kana 0.1, bevy_lagrange 0.0.4, bevy_liminal 0.0.2 (crates.io), bevy_window_manager 0.21 - Scenes now load as bevy_world_serialization::WorldAsset (GLTF #Scene0); Handle<Scene>->Handle<WorldAsset>, SceneRoot->WorldAssetRoot - Rework nateroid death materials: the old GLTF scene-World introspection is gone in 0.19, so precompute fades the donut/icing materials the meshes actually use and classifies each mesh by name at swap time - Camera input: OrbitCam button/trackpad fields moved to a separate OrbitCamInputMode::Preset(OrbitCamPreset::BlenderLike) component - Outline: MeshOutline->Outline::jump_flood(..).build(), MeshOutlinePlugin-> LiminalPlugin - Adapt remaining API changes: FontSize enum, DirectionalLight shadow_maps_enabled, Hdr moved to bevy::camera, TextLayout::justify - Fix deprecations: SystemCondition::or_else, egui_wants_pointer_input Claude-Session: https://claude.ai/code/session_01ALGByx7bTLmFfbL8vpdi9s
1 parent f05afd0 commit aba3315

17 files changed

Lines changed: 1384 additions & 1171 deletions

Cargo.lock

Lines changed: 1249 additions & 1046 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ wildcard_imports = "allow" # Bevy prelude convention
3636
missing_docs = "deny"
3737

3838
[dependencies]
39-
avian3d = { version = "0.6.1", features = ["debug-plugin", "parallel", "simd"] }
40-
bevy = { version = "0.18.1", features = ["bevy_dev_tools", "bevy_remote"] }
41-
bevy-inspector-egui = "0.36.0"
42-
bevy_brp_extras = "0.19.0"
43-
bevy_enhanced_input = "0.25.0"
44-
bevy_kana = { version = "0.0.6", features = ["input"] }
45-
bevy_lagrange = { version = "0.0.3", features = ["fit_overlay"] }
46-
bevy_liminal = { git = "https://github.com/natepiano/bevy_liminal", rev = "572cd0fc44879cf62223cfc91a5a08ee57bf7d32" }
47-
bevy_window_manager = "0.20.2"
39+
avian3d = { version = "0.7.0", features = ["debug-plugin", "parallel", "simd"] }
40+
bevy = { version = "0.19.0", features = ["bevy_dev_tools", "bevy_remote"] }
41+
bevy-inspector-egui = "0.37.0"
42+
bevy_brp_extras = "0.20.1"
43+
bevy_enhanced_input = "0.26.0"
44+
bevy_kana = { version = "0.1.0", features = ["input"] }
45+
bevy_lagrange = { version = "0.0.4", features = ["fit_overlay"] }
46+
bevy_liminal = "0.0.2"
47+
bevy_window_manager = "0.21.0"
4848
rand = "0.10.1"
4949

5050
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:

src/actor/nateroid/death_materials.rs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,46 @@ use super::constants::ICING_MESH_NAME;
1010
use crate::actor::constants::NATEROID_DEATH_ALPHA_STEP;
1111
use crate::asset_loader::SceneAssets;
1212

13-
/// Precomputed materials for `Nateroid` death animation at different transparency levels
13+
/// Precomputed `Nateroid` death-animation materials: one faded donut+icing set
14+
/// per transparency level. Fades the donut/icing materials the meshes actually
15+
/// use (applied by `apply_nateroid_materials_to_children`), matched per mesh.
1416
#[derive(Resource)]
1517
pub(crate) struct NateroidDeathMaterials {
16-
pub(crate) materials: Vec<Vec<Handle<StandardMaterial>>>,
18+
levels: Vec<NateroidDeathLevel>,
19+
}
20+
21+
/// Faded donut and icing materials for a single transparency level.
22+
struct NateroidDeathLevel {
23+
donut: Handle<StandardMaterial>,
24+
icing: Handle<StandardMaterial>,
25+
}
26+
27+
impl NateroidDeathLevel {
28+
const fn handle(&self, mesh: NateroidMesh) -> &Handle<StandardMaterial> {
29+
match mesh {
30+
NateroidMesh::Donut => &self.donut,
31+
NateroidMesh::Icing => &self.icing,
32+
}
33+
}
34+
}
35+
36+
impl NateroidDeathMaterials {
37+
/// Number of precomputed transparency levels.
38+
pub const fn level_count(&self) -> usize { self.levels.len() }
39+
40+
/// Faded material for the given alpha `level`, matched to `mesh_name`
41+
/// (donut/icing). Unknown mesh names fall back to the donut material.
42+
pub fn material_for(
43+
&self,
44+
level: usize,
45+
mesh_name: Option<&str>,
46+
) -> Option<Handle<StandardMaterial>> {
47+
let level = self.levels.get(level)?;
48+
let mesh = mesh_name
49+
.and_then(NateroidMesh::classify)
50+
.unwrap_or(NateroidMesh::Donut);
51+
Some(level.handle(mesh).clone())
52+
}
1753
}
1854

1955
#[derive(Clone, Copy)]
@@ -154,17 +190,28 @@ pub(super) fn debug_mesh_components(
154190
}
155191
}
156192

157-
/// System that precomputes death materials when assets are loaded
193+
/// Precomputes faded donut/icing materials for the death animation once assets
194+
/// are loaded. Fades the custom materials the meshes use rather than the GLTF
195+
/// originals (the GLTF scene's embedded `World` is no longer queryable in 0.19).
158196
pub(super) fn precompute_death_materials(
159197
mut commands: Commands,
160198
scene_assets: Res<SceneAssets>,
161-
scenes: Res<Assets<Scene>>,
162199
mut materials: ResMut<Assets<StandardMaterial>>,
163200
nateroid_settings: Res<NateroidSettings>,
164201
) {
165-
// Get the nateroid scene
166-
let Some(nateroid_scene) = scenes.get(&scene_assets.nateroid) else {
167-
warn!("Nateroid scene not loaded yet");
202+
let Some(donut_handle) = scene_assets.nateroid_donut_material.clone() else {
203+
warn!("Nateroid donut material not created yet");
204+
return;
205+
};
206+
let Some(icing_handle) = scene_assets.nateroid_icing_material.clone() else {
207+
warn!("Nateroid icing material not created yet");
208+
return;
209+
};
210+
let (Some(donut_base), Some(icing_base)) = (
211+
materials.get(&donut_handle).cloned(),
212+
materials.get(&icing_handle).cloned(),
213+
) else {
214+
warn!("Nateroid base materials not loaded yet");
168215
return;
169216
};
170217

@@ -174,57 +221,27 @@ pub(super) fn precompute_death_materials(
174221
let level_count =
175222
((initial_alpha - target_alpha) * (1.0 / NATEROID_DEATH_ALPHA_STEP)).to_usize() + 1;
176223

177-
// Collect material handles from the scene's world using try_query
178-
let mut material_handles = Vec::new();
179-
if let Some(mut query_state) = nateroid_scene
180-
.world
181-
.try_query::<&MeshMaterial3d<StandardMaterial>>()
182-
{
183-
for mesh_material in query_state.iter(&nateroid_scene.world) {
184-
material_handles.push(mesh_material.0.clone());
185-
}
186-
}
187-
188-
if material_handles.is_empty() {
189-
warn!("No materials found in nateroid scene");
190-
return;
191-
}
192-
193-
debug!(
194-
"Collected {} material handles from nateroid scene",
195-
material_handles.len()
196-
);
197-
198-
// Precompute materials for each alpha level
199-
let mut precomputed_materials = Vec::with_capacity(level_count);
224+
let mut levels = Vec::with_capacity(level_count);
200225
for level in 0..level_count {
201226
// FMA optimization (faster + more precise): initial_alpha - (level as f32 * step)
202227
let alpha = level
203228
.to_f32()
204229
.mul_add(-NATEROID_DEATH_ALPHA_STEP, initial_alpha);
205-
let mut level_materials = Vec::with_capacity(material_handles.len());
206-
207-
for material_handle in &material_handles {
208-
if let Some(original_material) = materials.get(material_handle) {
209-
let mut cloned_material = original_material.clone();
210-
cloned_material.base_color.set_alpha(alpha);
211-
cloned_material.alpha_mode = AlphaMode::Blend;
212-
level_materials.push(materials.add(cloned_material));
213-
}
214-
}
215-
216-
precomputed_materials.push(level_materials);
230+
levels.push(NateroidDeathLevel {
231+
donut: materials.add(faded_material(&donut_base, alpha)),
232+
icing: materials.add(faded_material(&icing_base, alpha)),
233+
});
217234
}
218235

219-
let material_set_count = precomputed_materials.len();
220-
let materials_per_set_count = material_handles.len();
221-
222-
// Insert the resource
223-
commands.insert_resource(NateroidDeathMaterials {
224-
materials: precomputed_materials,
225-
});
236+
let level_count = levels.len();
237+
commands.insert_resource(NateroidDeathMaterials { levels });
238+
debug!("Precomputed {level_count} nateroid death-material levels (donut + icing)");
239+
}
226240

227-
debug!(
228-
"Precomputed {material_set_count} material sets with {materials_per_set_count} materials each"
229-
);
241+
/// Clones `base` into a translucent material at the given `alpha`.
242+
fn faded_material(base: &StandardMaterial, alpha: f32) -> StandardMaterial {
243+
let mut material = base.clone();
244+
material.base_color.set_alpha(alpha);
245+
material.alpha_mode = AlphaMode::Blend;
246+
material
230247
}

src/actor/settings.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use avian3d::prelude::*;
22
use bevy::camera::visibility::RenderLayers;
33
use bevy::prelude::*;
4+
use bevy::world_serialization::WorldAsset;
5+
use bevy::world_serialization::WorldAssetRoot;
46
use bevy_inspector_egui::inspector_options::std_options::NumberDisplay;
57
use bevy_inspector_egui::prelude::*;
68
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
@@ -140,7 +142,7 @@ pub(crate) struct ActorSettings {
140142
pub(crate) restitution_combine_rule: CoefficientCombine,
141143
pub(crate) rigid_body: RigidBody,
142144
#[reflect(ignore)]
143-
pub(crate) scene: Handle<Scene>,
145+
pub(crate) scene: Handle<WorldAsset>,
144146
pub(crate) spawn_timer_seconds: Option<f32>,
145147
pub(crate) transform: Transform,
146148
#[reflect(ignore)]
@@ -206,7 +208,10 @@ fn create_spawn_timer(spawn_timer_seconds: Option<f32>) -> Option<Timer> {
206208
spawn_timer_seconds.map(|seconds| Timer::from_seconds(seconds, TimerMode::Repeating))
207209
}
208210

209-
fn initialize_actor_settings(actor_settings: &mut ActorSettings, scene_handle: &Handle<Scene>) {
211+
fn initialize_actor_settings(
212+
actor_settings: &mut ActorSettings,
213+
scene_handle: &Handle<WorldAsset>,
214+
) {
210215
actor_settings.spawn_timer = create_spawn_timer(actor_settings.spawn_timer_seconds);
211216
actor_settings.scene = scene_handle.clone();
212217
}
@@ -237,7 +242,7 @@ pub(super) fn insert_configured_components(
237242
MaxAngularSpeed(settings.max_angular_velocity),
238243
MaxLinearSpeed(settings.max_linear_velocity),
239244
settings.render_layer.layers(),
240-
SceneRoot(settings.scene.clone()),
245+
WorldAssetRoot(settings.scene.clone()),
241246
));
242247

243248
// Apply damping if configured

src/asset_loader.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use bevy::asset::LoadState;
22
use bevy::prelude::*;
3+
use bevy::world_serialization::WorldAsset;
34

45
use crate::constants::ENVIRONMENT_DIFFUSE_MAP_ASSET_PATH;
56
use crate::constants::ENVIRONMENT_SPECULAR_MAP_ASSET_PATH;
@@ -42,15 +43,15 @@ pub(crate) enum AssetsState {
4243
Loaded,
4344
}
4445

45-
// `SceneAssets` stores GLTF `Handle<Scene>` values whose scene graphs can spawn
46-
// multiple child meshes from a single actor asset.
46+
// `SceneAssets` stores GLTF `Handle<WorldAsset>` values whose scene graphs can
47+
// spawn multiple child meshes from a single actor asset.
4748
#[derive(Resource, Clone, Debug, Default)]
4849
pub(crate) struct SceneAssets {
49-
pub(crate) missile: Handle<Scene>,
50-
pub(crate) nateroid: Handle<Scene>,
50+
pub(crate) missile: Handle<WorldAsset>,
51+
pub(crate) nateroid: Handle<WorldAsset>,
5152
pub(crate) nateroid_donut_material: Option<Handle<StandardMaterial>>,
5253
pub(crate) nateroid_icing_material: Option<Handle<StandardMaterial>>,
53-
pub(crate) spaceship: Handle<Scene>,
54+
pub(crate) spaceship: Handle<WorldAsset>,
5455
pub(crate) environment_diffuse_map: Handle<Image>,
5556
pub(crate) environment_specular_map: Handle<Image>,
5657
}

src/camera/constants.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ pub(super) const CAMERA_SPLASH_START_PITCH: f32 = FRAC_PI_2;
3939
pub(super) const CAMERA_SPLASH_START_RADIUS: f32 = 3000.0;
4040
pub(super) const CAMERA_SPLASH_START_YAW: f32 = -PI;
4141

42-
// camera trackpad
43-
pub(super) const CAMERA_TRACKPAD_SENSITIVITY: f32 = 0.8;
44-
4542
// camera zoom
4643
/// Minimum zoom distance (allows zoom-to-fit to get very close)
4744
pub(super) const CAMERA_ZOOM_LOWER_LIMIT: f32 = 0.001;

src/camera/focus_gizmo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ fn draw_camera_focus_gizmo(
162162
commands.spawn((
163163
Text::new(text),
164164
TextFont {
165-
font_size: EDGE_MARKER_FONT_SIZE,
165+
font_size: FontSize::Px(EDGE_MARKER_FONT_SIZE),
166166
..default()
167167
},
168168
TextColor(focus_settings.color),

src/camera/game.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use bevy_inspector_egui::inspector_options::std_options::NumberDisplay;
44
use bevy_inspector_egui::prelude::*;
55
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
66
use bevy_kana::Position;
7-
use bevy_lagrange::InputControl;
87
use bevy_lagrange::OrbitCam;
9-
use bevy_lagrange::TrackpadInput;
8+
use bevy_lagrange::OrbitCamInputMode;
9+
use bevy_lagrange::OrbitCamPreset;
1010
use bevy_liminal::OutlineCamera;
1111

1212
use super::RenderLayer;
@@ -27,7 +27,6 @@ use super::constants::CAMERA_SPLASH_START_FOCUS;
2727
use super::constants::CAMERA_SPLASH_START_PITCH;
2828
use super::constants::CAMERA_SPLASH_START_RADIUS;
2929
use super::constants::CAMERA_SPLASH_START_YAW;
30-
use super::constants::CAMERA_TRACKPAD_SENSITIVITY;
3130
use super::constants::CAMERA_ZOOM_LOWER_LIMIT;
3231
use super::constants::CAMERA_ZOOM_SENSITIVITY;
3332
use super::constants::CAMERA_ZOOM_SMOOTHNESS;
@@ -180,20 +179,12 @@ pub(super) fn spawn_game_camera(
180179
OrbitCam {
181180
focus: Vec3::ZERO,
182181
target_radius: camera_settings.splash_start.radius,
183-
button_orbit: MouseButton::Middle,
184-
button_pan: MouseButton::Middle,
185-
modifier_pan: Some(KeyCode::ShiftLeft),
186182
zoom_sensitivity: CAMERA_ZOOM_SENSITIVITY,
187183
zoom_lower_limit: CAMERA_ZOOM_LOWER_LIMIT,
188-
input_control: Some(InputControl {
189-
trackpad: Some(TrackpadInput {
190-
sensitivity: CAMERA_TRACKPAD_SENSITIVITY,
191-
..TrackpadInput::blender_default()
192-
}),
193-
..default()
194-
}),
195184
..default()
196185
},
186+
// Middle-drag orbit, Shift+middle-drag pan, Blender-style trackpad.
187+
OrbitCamInputMode::Preset(OrbitCamPreset::BlenderLike),
197188
Camera {
198189
order: CameraOrder::Game.order(),
199190
// can't obscure the star camera with this on

src/camera/lights.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ fn spawn_directional_light(
220220
.spawn(DirectionalLight {
221221
color: directional_light_settings.color,
222222
illuminance: directional_light_settings.illuminance,
223-
shadows_enabled: matches!(directional_light_settings.shadow_switch, ShadowSwitch::On),
223+
shadow_maps_enabled: matches!(
224+
directional_light_settings.shadow_switch,
225+
ShadowSwitch::On
226+
),
224227
shadow_depth_bias: SHADOW_DEPTH_BIAS,
225228
shadow_normal_bias: SHADOW_NORMAL_BIAS,
226229
..default()
@@ -282,7 +285,7 @@ fn manage_lighting(
282285
// Update the existing `DirectionalLight`.
283286
light.color = directional_light_settings.color;
284287
light.illuminance = directional_light_settings.illuminance;
285-
light.shadows_enabled =
288+
light.shadow_maps_enabled =
286289
matches!(directional_light_settings.shadow_switch, ShadowSwitch::On);
287290
},
288291
(Some((entity, _, _)), LightSwitch::Off) => {

src/camera/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod zoom;
1414
use bevy::picking::mesh_picking::MeshPickingPlugin;
1515
use bevy::prelude::*;
1616
use bevy_lagrange::LagrangePlugin;
17-
use bevy_liminal::MeshOutlinePlugin;
17+
use bevy_liminal::LiminalPlugin;
1818
pub(crate) use constants::ZOOM_MARGIN;
1919
use focus_gizmo::FocusGizmoPlugin;
2020
pub(crate) use game::CameraSettings;
@@ -34,7 +34,7 @@ impl Plugin for CameraPlugin {
3434
fn build(&self, app: &mut App) {
3535
app.add_plugins(MeshPickingPlugin)
3636
.add_plugins(LagrangePlugin)
37-
.add_plugins(MeshOutlinePlugin)
37+
.add_plugins(LiminalPlugin)
3838
.add_plugins(GameCameraPlugin)
3939
.add_plugins(ZoomPlugin)
4040
.add_plugins(FocusGizmoPlugin)

0 commit comments

Comments
 (0)