bevy-expedition-demo/src/lib.rs
2ndbeam 79fe190b6b feat: Level loading from TOML asset
- Fixed detect_interactions system
- Added test for deserializing asset with plugin
2026-03-28 01:46:27 +03:00

123 lines
4 KiB
Rust

use bevy::{
prelude::*,
ui_widgets::ScrollbarPlugin,
};
use bevy_common_assets::toml::TomlAssetPlugin;
use bevy_rapier2d::{
prelude::*,
rapier::prelude::IntegrationParameters,
};
pub mod input;
pub mod inventory;
pub mod item;
pub mod layout;
pub mod player;
#[cfg(test)]
mod tests;
pub mod ui;
pub const PIXELS_PER_METER: f32 = 16.0;
pub struct ExpeditionPlugin;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Reflect)]
#[reflect(Clone, PartialEq, Debug, Default, Hash, State)]
pub enum GameState {
#[default]
Running,
Inventory,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Reflect)]
#[reflect(Clone, PartialEq, Debug, Default, Hash, State)]
pub enum LoadingState {
#[default]
Loading,
Ready,
}
fn camera_bundle() -> impl Bundle {
(
Camera2d,
Camera {
clear_color: ClearColorConfig::Custom(Color::hsl(0.02, 0.67, 0.65)),
..default()
},
Projection::Orthographic(OrthographicProjection {
scaling_mode: bevy::camera::ScalingMode::FixedVertical {
viewport_height: 384.,
},
scale: 1.,
..OrthographicProjection::default_2d()
}),
Name::new("Camera2d"),
)
}
fn insert_entity_name(names: Query<(Entity, &mut Name), Added<Name>>) {
for (entity, mut name) in names {
name.mutate(|name| name.insert_str(0, format!("{entity}: ").as_str()));
}
}
#[inline(always)]
pub const fn meters(value: f32) -> f32 {
PIXELS_PER_METER * value
}
fn setup_global(mut commands: Commands) {
commands.spawn(camera_bundle());
commands.spawn(ui::UiRoot::new());
}
impl Plugin for ExpeditionPlugin {
fn build(&self, app: &mut App) {
let rapier_init = RapierContextInitialization::InitializeDefaultRapierContext {
integration_parameters: IntegrationParameters {
length_unit: PIXELS_PER_METER,
..default()
},
rapier_configuration: RapierConfiguration {
gravity: Vec2::ZERO,
physics_pipeline_active: true,
scaled_shape_subdivision: 10,
force_update_from_transform_changes: false,
},
};
app.add_plugins((
RapierDebugRenderPlugin::default(),
RapierPhysicsPlugin::<()>::default()
.with_custom_initialization(rapier_init),
ScrollbarPlugin,
TomlAssetPlugin::<layout::asset::structs::LevelAsset>::new(&["toml"]),
input::plugin::InputAssetPlugin::<input::InputAction>::default(),
input::plugin::InputAssetPlugin::<input::UiAction>::default(),
))
.init_state::<LoadingState>()
.init_state::<GameState>()
.insert_resource(ui::WindowSize::default())
.add_systems(Startup, (
setup_global,
layout::systems::setup_world,
))
.add_systems(Update, (
insert_entity_name,
layout::asset::check_loading
.run_if(|state: Res<State<LoadingState>>| *state == LoadingState::Loading),
layout::systems::detect_interact_collisions,
layout::systems::lock_door,
player::systems::handle_input,
ui::update_window_size,
ui::handle_input,
))
.add_systems(OnEnter(LoadingState::Ready), layout::asset::load_level)
.add_systems(OnEnter(GameState::Inventory), ui::inventory::systems::setup_ui_inventory)
.add_systems(OnExit(GameState::Inventory), ui::inventory::systems::clear_ui_inventory)
.add_observer(ui::inventory::observers::on_ui_rotate)
.add_observer(layout::container::on_container_interact)
.add_observer(layout::door::on_door_interact)
.add_observer(layout::lock::on_padlock_interaction)
.add_observer(layout::stairs::on_stairs_interact);
}
}