feat: Level loading from TOML asset

- Fixed detect_interactions system
- Added test for deserializing asset with plugin
This commit is contained in:
Alexey 2026-03-28 01:46:27 +03:00
commit 79fe190b6b
9 changed files with 124 additions and 97 deletions

View file

@ -6,12 +6,7 @@ use bevy::{
use bevy_rapier2d::prelude::*;
use crate::{
meters,
item::lockpick::lockpick_bundle,
player::{
Player,
player_bundle,
},
player::Player,
};
use super::*;
@ -33,6 +28,22 @@ fn get_interactive_id<F: QueryFilter>(
}
}
fn interact_collisions_inner<F: QueryFilter>(
first: Entity,
second: Entity,
interactive_query: Query<(), F>,
player_query: Query<(), With<Player>>,
parent_query: Query<&ChildOf, With<Collider>>,
) -> Option<Entity> {
let Some(interactive_id) = get_interactive_id(first, interactive_query, parent_query) else {
return None;
};
if player_query.get(second).is_err() {
return None;
}
Some(interactive_id)
}
pub fn detect_interact_collisions(
mut commands: Commands,
mut collision_events: MessageReader<CollisionEvent>,
@ -44,22 +55,20 @@ pub fn detect_interact_collisions(
for collision_event in collision_events.read() {
match collision_event {
CollisionEvent::Started(first, second, _) => {
let Some(interactive_id) = get_interactive_id(*first, interactive_query1, parent_query) else {
continue;
};
if player_query.get(*second).is_err() {
continue;
if let Some(interactive_id) = interact_collisions_inner(*first, *second, interactive_query1, player_query, parent_query) {
commands.entity(interactive_id).insert(MayInteract);
}
if let Some(interactive_id) = interact_collisions_inner(*second, *first, interactive_query1, player_query, parent_query) {
commands.entity(interactive_id).insert(MayInteract);
}
commands.entity(interactive_id).insert(MayInteract);
},
CollisionEvent::Stopped(first, second, _) => {
let Some(interactive_id) = get_interactive_id(*first, interactive_query2, parent_query) else {
continue;
};
if player_query.get(*second).is_err() {
continue;
if let Some(interactive_id) = interact_collisions_inner(*first, *second, interactive_query2, player_query, parent_query) {
commands.entity(interactive_id).remove::<MayInteract>();
}
if let Some(interactive_id) = interact_collisions_inner(*second, *first, interactive_query2, player_query, parent_query) {
commands.entity(interactive_id).remove::<MayInteract>();
}
commands.entity(interactive_id).remove::<MayInteract>();
},
}
}
@ -78,66 +87,6 @@ pub fn setup_world(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
let tiles = [
( 0, ( 0, 0, 16, 1 )), // 1F floor
( 0, ( 0, 4, 16, 1 )), // 1F ceiling / 2F floor
( 0, ( 0, 8, 16, 1 )), // 2F ceiling
( 1, ( 0, 1, 1, 3 )), // 1F left wall
( 1, ( 0, 5, 1, 3 )), // 2F left wall
( 1, ( 15, 1, 1, 3 )), // 1F right wall
( 1, ( 15, 5, 1, 3 )), // 2F right wall
( 2, ( 4, 3, 1, 1 )), // 1F left door connector
( 2, ( 4, 7, 1, 1 )), // 2F left door connector
( 2, ( 11, 3, 1, 1 )), // 1F right door connector
( 2, ( 11, 7, 1, 1 )), // 2F right door connector
].into_iter().map(|(id, (x, y, w, h))| {
(id, URect::from_corners(uvec2(x, y), uvec2(x + w - 1, y + h - 1)))
}).collect::<Vec<(u16, URect)>>();
commands.spawn(tilemap::tilemap_bundle(&asset_server, tiles));
commands.spawn(player_bundle(&asset_server, vec2(meters(1.5), meters(1.))));
commands.spawn(door::door_bundle(&asset_server, vec2(meters(4.5), meters(1.)), false));
commands.spawn(door::door_bundle(&asset_server, vec2(meters(4.5), meters(5.)), false))
.with_child(lock::padlock_bundle(&asset_server, false));
commands.spawn(door::door_bundle(&asset_server, vec2(meters(11.5), meters(1.)), true))
.with_child(lock::padlock_bundle(&asset_server, true));
commands.spawn(door::door_bundle(&asset_server, vec2(meters(11.5), meters(5.)), true));
commands.spawn(stairs::stairs_bundle(
&asset_server,
vec2(meters(8.), meters(1.)),
Some(vec2(meters(2.), meters(4.))),
None,
));
commands.spawn(stairs::stairs_bundle(
&asset_server,
vec2(meters(8.), meters(5.)),
None,
Some(vec2(meters(-2.), meters(-4.))),
));
commands.spawn(container::container_bundle(
&asset_server,
vec2(meters(2.), meters(1.)),
uvec2(1, 1),
));
commands.spawn(container::container_bundle(
&asset_server,
vec2(meters(14.), meters(1.)),
uvec2(1, 1),
));
commands.spawn(container::container_bundle(
&asset_server,
vec2(meters(2.), meters(5.)),
uvec2(4, 4),
)).with_child(lockpick_bundle(&asset_server, uvec2(2, 2), false));
commands.spawn(container::container_bundle(
&asset_server,
vec2(meters(14.), meters(5.)),
uvec2(2, 2),
)).with_child(lockpick_bundle(&asset_server, UVec2::ZERO, true));
let level_handle = asset_server.load("levels/level.toml");
commands.insert_resource(LevelAssetHandle(level_handle));
}