WHAT HAPPENED AFTER A LONG STREAM
Player movement :D Uh..miguel not paralysed Failed to flip miguel when turning Please help
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
utils::{HashMap, HashSet},
|
||||
};
|
||||
use bevy_ecs_ldtk::prelude::*;
|
||||
use bevy_rapier2d::{
|
||||
dynamics::RigidBody,
|
||||
geometry::{Collider, Friction},
|
||||
};
|
||||
|
||||
#[derive(Default, Component)]
|
||||
pub struct Wall;
|
||||
@@ -8,3 +15,148 @@ pub struct Wall;
|
||||
pub struct WallBundle {
|
||||
wall: Wall,
|
||||
}
|
||||
pub fn spawn_wall_collision(
|
||||
mut commands: Commands,
|
||||
wall_query: Query<(&GridCoords, &Parent), Added<Wall>>,
|
||||
parent_query: Query<&Parent, Without<Wall>>,
|
||||
level_query: Query<(Entity, &LevelIid)>,
|
||||
ldtk_projects: Query<&Handle<LdtkProject>>,
|
||||
ldtk_project_assets: Res<Assets<LdtkProject>>,
|
||||
) {
|
||||
/// Represents a wide wall that is 1 tile tall
|
||||
/// Used to spawn wall collisions
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default, Hash)]
|
||||
struct Plate {
|
||||
left: i32,
|
||||
right: i32,
|
||||
}
|
||||
|
||||
/// A simple rectangle type representing a wall of any size
|
||||
struct Rect {
|
||||
left: i32,
|
||||
right: i32,
|
||||
top: i32,
|
||||
bottom: i32,
|
||||
}
|
||||
let mut level_to_wall_locations: HashMap<Entity, HashSet<GridCoords>> = HashMap::new();
|
||||
wall_query.iter().for_each(|(&grid_coords, parent)| {
|
||||
if let Ok(grandparent) = parent_query.get(parent.get()) {
|
||||
level_to_wall_locations
|
||||
.entry(grandparent.get())
|
||||
.or_default()
|
||||
.insert(grid_coords);
|
||||
}
|
||||
});
|
||||
|
||||
if !wall_query.is_empty() {
|
||||
level_query.iter().for_each(|(level_entity, level_iid)| {
|
||||
if let Some(level_walls) = level_to_wall_locations.get(&level_entity) {
|
||||
let ldtk_project = ldtk_project_assets
|
||||
.get(ldtk_projects.single())
|
||||
.expect("Project has to be loaded at this point");
|
||||
|
||||
let level = ldtk_project
|
||||
.as_standalone()
|
||||
.get_loaded_level_by_iid(&level_iid.to_string())
|
||||
.expect("Spawned level should exist in LDtk project");
|
||||
|
||||
let LayerInstance {
|
||||
c_wid: width,
|
||||
c_hei: height,
|
||||
grid_size,
|
||||
..
|
||||
} = level.layer_instances()[0];
|
||||
|
||||
let mut plate_stack: Vec<Vec<Plate>> = Vec::new();
|
||||
|
||||
for y in 0..height {
|
||||
let mut row_plates: Vec<Plate> = Vec::new();
|
||||
let mut plate_start = None;
|
||||
|
||||
for x in 0..width + 1 {
|
||||
match (plate_start, level_walls.contains(&GridCoords { x, y })) {
|
||||
(Some(s), false) => {
|
||||
row_plates.push(Plate {
|
||||
left: s,
|
||||
right: x - 1,
|
||||
});
|
||||
plate_start = None;
|
||||
}
|
||||
(None, true) => plate_start = Some(x),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
plate_stack.push(row_plates);
|
||||
}
|
||||
// combine "plates" into rectangles across multiple rows
|
||||
let mut rect_builder: HashMap<Plate, Rect> = HashMap::new();
|
||||
let mut prev_row: Vec<Plate> = Vec::new();
|
||||
let mut wall_rects: Vec<Rect> = Vec::new();
|
||||
|
||||
// an extra empty row so the algorithm "finishes" the rects that touch the top edge
|
||||
plate_stack.push(Vec::new());
|
||||
|
||||
for (y, current_row) in plate_stack.into_iter().enumerate() {
|
||||
for prev_plate in &prev_row {
|
||||
if !current_row.contains(prev_plate) {
|
||||
//remove rect so the same plate starts a new rectangle
|
||||
if let Some(rect) = rect_builder.remove(prev_plate) {
|
||||
wall_rects.push(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
for plate in ¤t_row {
|
||||
rect_builder
|
||||
.entry(plate.clone())
|
||||
.and_modify(|e| e.top += 1)
|
||||
.or_insert(Rect {
|
||||
bottom: y as i32,
|
||||
top: y as i32,
|
||||
left: plate.left,
|
||||
right: plate.right,
|
||||
});
|
||||
}
|
||||
prev_row = current_row;
|
||||
}
|
||||
commands.entity(level_entity).with_children(|level| {
|
||||
// Spawn colliders for every rectangle..
|
||||
// Making the collider a child of the level serves two purposes:
|
||||
// 1. Adjusts the transforms to be relative to the level for free
|
||||
// 2. the colliders will be despawned automatically when levels unload
|
||||
for wall_rect in wall_rects {
|
||||
level
|
||||
.spawn_empty()
|
||||
.insert(Collider::cuboid(
|
||||
(wall_rect.right as f32 - wall_rect.left as f32 + 1.)
|
||||
* grid_size as f32
|
||||
/ 2.,
|
||||
(wall_rect.top as f32 - wall_rect.bottom as f32 + 1.)
|
||||
* grid_size as f32
|
||||
/ 2.,
|
||||
))
|
||||
.insert(RigidBody::Fixed)
|
||||
.insert(Friction::new(1.0))
|
||||
.insert(Transform::from_xyz(
|
||||
(wall_rect.left + wall_rect.right + 1) as f32 * grid_size as f32
|
||||
/ 2.,
|
||||
(wall_rect.bottom + wall_rect.top + 1) as f32 * grid_size as f32
|
||||
/ 2.,
|
||||
0.,
|
||||
//this averages xy so it in center yes )
|
||||
))
|
||||
.insert(GlobalTransform::default());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
pub struct WallPlugin;
|
||||
|
||||
impl Plugin for WallPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, spawn_wall_collision)
|
||||
.register_ldtk_int_cell::<WallBundle>(1) //dirt
|
||||
.register_ldtk_int_cell::<WallBundle>(3); //stone
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user