generated from 2ndbeam/bevy-template
Compare commits
No commits in common. "929ad455716fad47ef7a93fd57e4175f9b047d39" and "3cddecf592e8311ed82d7bac1a6a88a4ee540a4e" have entirely different histories.
929ad45571
...
3cddecf592
13 changed files with 38 additions and 134 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
|
@ -1035,16 +1035,6 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_light_2d"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d40446e54d26895cdf32a5c6c0f5dd3104bbdeff53fc392ec85fb2d164fa51a"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_log"
|
||||
version = "0.18.0"
|
||||
|
|
@ -2533,7 +2523,6 @@ dependencies = [
|
|||
"bevy",
|
||||
"bevy_common_assets",
|
||||
"bevy_input",
|
||||
"bevy_light_2d",
|
||||
"bevy_rapier2d",
|
||||
"clap",
|
||||
"leafwing-input-manager",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ edition = "2024"
|
|||
bevy = { version = "0.18.0", features = ["bevy_remote", "debug", "experimental_bevy_ui_widgets"] }
|
||||
bevy_common_assets = { version = "0.15.0", features = ["toml"] }
|
||||
bevy_input = { version = "0.18.0", features = ["serde", "serialize"] }
|
||||
bevy_light_2d = "0.9.0"
|
||||
bevy_rapier2d = { version = "0.33.0", features = ["rapier-debug-render"] }
|
||||
clap = { version = "4.6.0", features = ["derive"] }
|
||||
leafwing-input-manager = "0.20.0"
|
||||
|
|
|
|||
|
|
@ -111,13 +111,3 @@ h = 2
|
|||
[[interactive.containers.items]]
|
||||
id = "lockpick"
|
||||
rotated = true
|
||||
|
||||
[[interactive.lamps]]
|
||||
x = 8
|
||||
y = 3
|
||||
|
||||
[[interactive.lamps]]
|
||||
x = 8
|
||||
y = 7
|
||||
intensity = 3
|
||||
radius = 6
|
||||
|
|
|
|||
|
|
@ -52,8 +52,3 @@ containers = [
|
|||
],
|
||||
},
|
||||
]
|
||||
lamps = [
|
||||
{ x = 8, y = 3 },
|
||||
{ x = 8, y = 7, intensity = 3, radius = 16 },
|
||||
{ x = 8, y = 11, intensity = 2, radius = 16 },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,9 +3,20 @@ use std::collections::HashMap;
|
|||
use bevy::prelude::*;
|
||||
|
||||
use crate::{
|
||||
LoadingState, item::lockpick::lockpick_bundle, layout::{
|
||||
Level, LevelAssetHandle, asset::structs::*, container::container_bundle, door::door_bundle, light::lamp_bundle, lock::padlock_bundle, stairs::stairs_bundle, tilemap::tilemap_bundle
|
||||
}, meters, player::player_bundle
|
||||
LoadingState,
|
||||
meters,
|
||||
item::lockpick::lockpick_bundle,
|
||||
layout::{
|
||||
Level,
|
||||
LevelAssetHandle,
|
||||
asset::structs::*,
|
||||
container::container_bundle,
|
||||
door::door_bundle,
|
||||
lock::padlock_bundle,
|
||||
stairs::stairs_bundle,
|
||||
tilemap::tilemap_bundle
|
||||
},
|
||||
player::player_bundle,
|
||||
};
|
||||
|
||||
pub mod structs;
|
||||
|
|
@ -96,10 +107,5 @@ pub fn load_level (
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for LampData { pos, intensity, radius } in level.interactive.lamps.iter() {
|
||||
let pos = vec2(meters(pos.x), meters(pos.y - 0.5));
|
||||
parent.spawn(lamp_bundle(&asset_server, pos, *intensity, meters(*radius)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,31 +176,6 @@ impl From<ContainerDataInner> for ContainerData {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn default_intensity() -> f32 { 2. }
|
||||
|
||||
pub(super) fn default_radius() -> f32 { 4. }
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Clone, Reflect)]
|
||||
#[reflect(Debug, Default, Deserialize, Serialize, PartialEq, Clone)]
|
||||
pub(super) struct LampDataInner {
|
||||
#[serde(flatten)]
|
||||
pub pos: Pos,
|
||||
#[serde(default = "default_intensity")]
|
||||
pub intensity: f32,
|
||||
#[serde(default = "default_radius")]
|
||||
pub radius: f32,
|
||||
}
|
||||
|
||||
impl From<LampDataInner> for LampData {
|
||||
fn from(LampDataInner { pos, intensity, radius }: LampDataInner) -> Self {
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
intensity,
|
||||
radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Clone, Reflect)]
|
||||
#[reflect(Debug, Default, Deserialize, Serialize, PartialEq, Clone)]
|
||||
pub(super) struct InteractiveInner {
|
||||
|
|
@ -211,18 +186,15 @@ pub(super) struct InteractiveInner {
|
|||
pub stairs: Option<Vec<StairsData>>,
|
||||
#[serde(default)]
|
||||
pub containers: Option<Vec<ContainerData>>,
|
||||
#[serde(default)]
|
||||
pub lamps: Option<Vec<LampData>>,
|
||||
}
|
||||
|
||||
impl From<InteractiveInner> for Interactive {
|
||||
fn from(InteractiveInner { player, doors, stairs, containers, lamps }: InteractiveInner) -> Self {
|
||||
fn from(InteractiveInner { player, doors, stairs, containers }: InteractiveInner) -> Self {
|
||||
Self {
|
||||
player: player.into(),
|
||||
doors: doors.unwrap_or_default(),
|
||||
stairs: stairs.unwrap_or_default(),
|
||||
containers: containers.unwrap_or_default(),
|
||||
lamps: lamps.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,15 +67,6 @@ pub struct ContainerData {
|
|||
pub items: Vec<ItemData>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Clone, Reflect)]
|
||||
#[reflect(Debug, Default, Deserialize, Serialize, PartialEq, Clone)]
|
||||
#[serde(from = "inner::LampDataInner")]
|
||||
pub struct LampData {
|
||||
pub pos: Vec2,
|
||||
pub intensity: f32,
|
||||
pub radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Clone, Reflect)]
|
||||
#[reflect(Debug, Default, Deserialize, Serialize, PartialEq, Clone)]
|
||||
#[serde(from = "inner::InteractiveInner")]
|
||||
|
|
@ -87,8 +78,6 @@ pub struct Interactive {
|
|||
pub stairs: Vec<StairsData>,
|
||||
#[serde(default)]
|
||||
pub containers: Vec<ContainerData>,
|
||||
#[serde(default)]
|
||||
pub lamps: Vec<LampData>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone, Deref, DerefMut, Reflect)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_light_2d::prelude::*;
|
||||
use bevy_rapier2d::prelude::*;
|
||||
|
||||
use crate::meters;
|
||||
|
|
@ -14,11 +13,6 @@ const DOOR_CLOSED_ASSET: &'static str = "sprites/interactive/door_closed.png";
|
|||
#[require(Sprite, InteractiveObject)]
|
||||
pub struct Door(pub i8);
|
||||
|
||||
#[derive(Component, Clone, Copy, Reflect, Default, PartialEq, Eq, Debug)]
|
||||
#[reflect(Component, Clone, Default, PartialEq, Debug)]
|
||||
#[require(Collider, LightOccluder2d)]
|
||||
pub struct DoorCollider;
|
||||
|
||||
impl Default for Door {
|
||||
fn default() -> Self {
|
||||
Self(1)
|
||||
|
|
@ -29,22 +23,26 @@ pub fn on_door_interact(
|
|||
event: On<InteractionEvent>,
|
||||
mut commands: Commands,
|
||||
locked_query: Query<(), With<Locked>>,
|
||||
collider_query: Query<(), (With<Door>, With<Collider>)>,
|
||||
no_collider_query: Query<(), (With<Door>, Without<Collider>)>,
|
||||
door_query: Query<(&Door, &Children)>,
|
||||
door_collider_query: Query<Entity, With<DoorCollider>>,
|
||||
mut sprite_query: Query<(&mut Sprite, &mut Transform)>,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
if locked_query.get(event.entity).is_ok() {
|
||||
return;
|
||||
}
|
||||
let was_opened = if collider_query.get(event.entity).is_ok() { false }
|
||||
else if no_collider_query.get(event.entity).is_ok() { true }
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Ok((door, children)) = door_query.get(event.entity) else {
|
||||
return;
|
||||
};
|
||||
let maybe_door_collider = children.iter()
|
||||
.find_map(|id| if let Ok(id) = door_collider_query.get(id) { Some(id) } else { None } );
|
||||
for child in children {
|
||||
if let Ok((mut sprite, mut transform)) = sprite_query.get_mut(*child) {
|
||||
let (image, translation) = if maybe_door_collider.is_none() { (DOOR_CLOSED_ASSET, 0.) }
|
||||
let (image, translation) = if was_opened { (DOOR_CLOSED_ASSET, 0.) }
|
||||
else { (DOOR_OPENED_ASSET, door.0 as f32 * meters(0.5)) };
|
||||
sprite.image = asset_server.load(image);
|
||||
transform.translation.x = translation;
|
||||
|
|
@ -52,20 +50,15 @@ pub fn on_door_interact(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(id) = maybe_door_collider {
|
||||
commands.entity(id).despawn();
|
||||
if was_opened {
|
||||
commands.entity(event.entity).insert(door_collider());
|
||||
} else {
|
||||
commands.entity(event.entity).with_child(door_collider_bundle());
|
||||
commands.entity(event.entity).remove::<Collider>();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn door_collider_bundle() -> impl Bundle {
|
||||
let size = vec2(meters(0.06125), meters(1.));
|
||||
(
|
||||
DoorCollider,
|
||||
Collider::cuboid(size.x, size.y),
|
||||
LightOccluder2d { shape: LightOccluder2dShape::Rectangle { half_size: size } },
|
||||
)
|
||||
fn door_collider() -> Collider {
|
||||
Collider::cuboid(meters(0.06125), meters(1.))
|
||||
}
|
||||
|
||||
pub fn door_bundle(asset_server: &Res<AssetServer>, position: Vec2, facing_left: bool) -> impl Bundle {
|
||||
|
|
@ -75,8 +68,8 @@ pub fn door_bundle(asset_server: &Res<AssetServer>, position: Vec2, facing_left:
|
|||
Door(direction),
|
||||
Transform::from_xyz(position.x, position.y, 0.),
|
||||
Name::new(format!("Door ({}, {})", position.x, position.y)),
|
||||
door_collider(),
|
||||
children![
|
||||
door_collider_bundle(),
|
||||
(
|
||||
Collider::cuboid(meters(0.5), meters(1.)),
|
||||
Sensor,
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_light_2d::prelude::*;
|
||||
|
||||
use crate::meters;
|
||||
|
||||
const LAMP_IMAGE_PATH: &'static str = "sprites/interactive/lamp.png";
|
||||
|
||||
#[derive(Component, Clone, Copy, Default, Reflect, Debug, PartialEq, Eq)]
|
||||
#[reflect(Component, Clone, Default, Debug, PartialEq)]
|
||||
#[require(Transform)]
|
||||
pub struct Lamp;
|
||||
|
||||
pub fn lamp_bundle(asset_server: &Res<AssetServer>, pos: Vec2, intensity: f32, radius: f32) -> impl Bundle {
|
||||
let image = asset_server.load(LAMP_IMAGE_PATH);
|
||||
(
|
||||
SpotLight2d {
|
||||
intensity,
|
||||
radius,
|
||||
source_width: meters(0.5),
|
||||
cast_shadows: true,
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(pos.x, pos.y, 0.),
|
||||
Sprite::from_image(image),
|
||||
)
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ use bevy::prelude::*;
|
|||
pub mod asset;
|
||||
pub mod container;
|
||||
pub mod door;
|
||||
pub mod light;
|
||||
pub mod lock;
|
||||
pub mod stairs;
|
||||
pub mod systems;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use bevy::{
|
|||
TilemapChunkTileData,
|
||||
},
|
||||
};
|
||||
use bevy_light_2d::prelude::*;
|
||||
use bevy_rapier2d::prelude::*;
|
||||
|
||||
use crate::meters;
|
||||
|
|
@ -59,13 +58,10 @@ pub fn tilemap_bundle(
|
|||
let mut rect = rect.as_rect();
|
||||
rect.max = vec2(rect.max.x + 1., rect.max.y + 1.);
|
||||
|
||||
let (width, height) = (meters(rect.width() * 0.5), meters(rect.height() * 0.5));
|
||||
let (width, height) = (rect.width(), rect.height());
|
||||
let offset = rect.center();
|
||||
(
|
||||
Collider::cuboid(width, height),
|
||||
LightOccluder2d {
|
||||
shape: LightOccluder2dShape::Rectangle { half_size: vec2(width, height) },
|
||||
},
|
||||
Collider::cuboid(meters(width * 0.5), meters(height * 0.5)),
|
||||
Transform::from_xyz(
|
||||
meters(offset.x - size.x as f32 * 0.5),
|
||||
meters(offset.y - size.y as f32 * 0.5),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use bevy_rapier2d::{
|
|||
prelude::*,
|
||||
rapier::prelude::IntegrationParameters,
|
||||
};
|
||||
use bevy_light_2d::prelude::*;
|
||||
use clap::Parser;
|
||||
|
||||
pub mod input;
|
||||
|
|
@ -61,9 +60,6 @@ pub fn camera_bundle() -> impl Bundle {
|
|||
scale: 1.,
|
||||
..OrthographicProjection::default_2d()
|
||||
}),
|
||||
Light2d {
|
||||
ambient_light: AmbientLight2d { brightness: 0.25, ..default() }
|
||||
},
|
||||
Name::new("Camera2d"),
|
||||
)
|
||||
}
|
||||
|
|
@ -105,7 +101,6 @@ impl Plugin for ExpeditionPlugin {
|
|||
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>()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,13 @@ fn deserialize_from_str() {
|
|||
let level_alt_str = include_str!("../../assets/levels/level_alt.toml");
|
||||
let level = toml::de::from_str::<LevelAsset>(level_str).unwrap();
|
||||
let level_alt = toml::de::from_str::<LevelAsset>(level_alt_str).unwrap();
|
||||
|
||||
assert_eq!(level.meta, level_alt.meta);
|
||||
assert_eq!(level.interactive, level_alt.interactive);
|
||||
for (tiles_id, tiles) in level.tiles.tiles {
|
||||
let (_, other_tiles) = level_alt.tiles.iter().find(|(k, _)| k == &&tiles_id).unwrap();
|
||||
assert_eq!(&tiles, other_tiles);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue