bevy-expedition-demo/src/lib.rs
2ndbeam b2efc73602 feat!: Half-implemented sprite container
- Updated all assets
- Refactored door again
- Half of the sprites are visually broken for now
2026-04-01 09:40:00 +03:00

138 lines
4.6 KiB
Rust

use bevy::{
prelude::*,
ui_widgets::ScrollbarPlugin,
};
use bevy_common_assets::toml::TomlAssetPlugin;
use bevy_rapier2d::{
prelude::*,
rapier::prelude::IntegrationParameters,
};
use bevy_light_2d::prelude::*;
use clap::Parser;
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,
}
#[derive(Parser, Resource, Clone, PartialEq, Eq, Hash, Debug, Reflect, Default)]
#[reflect(Resource, Clone, PartialEq, Hash, Debug, Default)]
pub struct StartupArgs {
#[arg(long, short, default_value = "levels/level.toml")]
/// Level to load (relative to assets folder)
level: String,
}
pub 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()
}),
Light2d {
ambient_light: AmbientLight2d { brightness: 0.25, ..default() }
},
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(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(),
Light2dPlugin,
))
.init_state::<LoadingState>()
.init_state::<GameState>()
.insert_resource(ui::WindowSize::default())
.insert_resource(layout::LayoutTextures::default())
.add_systems(Startup, (
setup_global,
layout::systems::setup_world,
layout::systems::load_layout_textures,
))
.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);
}
}