Skip to content

Commit

Permalink
example: use rect_builder buffer instead of row-specific current_rect…
Browse files Browse the repository at this point in the history
…s in spawn_wall_collisions (#147)

* example/improve-spawn_wall_collision

* clippy fix
  • Loading branch information
janos-r committed Dec 24, 2022
1 parent ed4a0f9 commit 45303f3
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 34 deletions.
58 changes: 25 additions & 33 deletions examples/platformer/systems.rs
Expand Up @@ -84,14 +84,13 @@ pub fn spawn_wall_collision(
) {
/// Represents a wide wall that is 1 tile tall
/// Used to spawn wall collisions
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Hash)]
#[derive(Clone, Eq, PartialEq, Debug, Default, Hash)]
struct Plate {
left: i32,
right: i32,
}

/// A simple rectangle type representing a wall of any size
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Hash)]
struct Rect {
left: i32,
right: i32,
Expand All @@ -115,7 +114,7 @@ pub fn spawn_wall_collision(
if let Ok(grandparent) = parent_query.get(parent.get()) {
level_to_wall_locations
.entry(grandparent.get())
.or_insert(HashSet::new())
.or_default()
.insert(grid_coords);
}
});
Expand Down Expand Up @@ -145,8 +144,7 @@ pub fn spawn_wall_collision(
let mut row_plates: Vec<Plate> = Vec::new();
let mut plate_start = None;

// + 1 to the width so the algorithm "terminates" plates that touch the right
// edge
// + 1 to the width so the algorithm "terminates" plates that touch the right edge
for x in 0..width + 1 {
match (plate_start, level_walls.contains(&GridCoords { x, y })) {
(Some(s), false) => {
Expand All @@ -165,40 +163,34 @@ pub fn spawn_wall_collision(
}

// 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();
let mut previous_rects: HashMap<Plate, Rect> = HashMap::new();

// an extra empty row so the algorithm "terminates" the rects that touch the top
// edge
// an extra empty row so the algorithm "finishes" the rects that touch the top edge
plate_stack.push(Vec::new());

for (y, row) in plate_stack.iter().enumerate() {
let mut current_rects: HashMap<Plate, Rect> = HashMap::new();
for plate in row {
if let Some(previous_rect) = previous_rects.remove(plate) {
current_rects.insert(
*plate,
Rect {
top: previous_rect.top + 1,
..previous_rect
},
);
} else {
current_rects.insert(
*plate,
Rect {
bottom: y as i32,
top: y as i32,
left: plate.left,
right: plate.right,
},
);
for (y, current_row) in plate_stack.into_iter().enumerate() {
for prev_plate in &prev_row {
if !current_row.contains(prev_plate) {
// remove the finished rect so that the same plate in the future starts a new rect
if let Some(rect) = rect_builder.remove(prev_plate) {
wall_rects.push(rect);
}
}
}

// Any plates that weren't removed above have terminated
wall_rects.append(&mut previous_rects.values().copied().collect());
previous_rects = current_rects;
for plate in &current_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| {
Expand Down
2 changes: 1 addition & 1 deletion src/utils.rs
Expand Up @@ -86,7 +86,7 @@ pub fn calculate_transform_from_entity_instance(

let translation = ldtk_pixel_coords_to_translation_pivoted(
entity_instance.px,
level_height as i32,
level_height,
size,
entity_instance.pivot,
);
Expand Down

0 comments on commit 45303f3

Please sign in to comment.