Skip to content

Instantly share code, notes, and snippets.

@Hellzbellz123
Created April 1, 2024 02:39
Show Gist options
  • Save Hellzbellz123/e7c09811d806a3dd7b83ce90c0635850 to your computer and use it in GitHub Desktop.
Save Hellzbellz123/e7c09811d806a3dd7b83ce90c0635850 to your computer and use it in GitHub Desktop.
// TODO: rethink this code too only spawn 1 hallway per room
// maybe try this apporach again now that the room ids are
pub fn plan_hallways_two(
mut cmds: Commands,
mut dungeon_root: Query<&mut DungeonSettings, With<DungeonContainerTag>>,
room_query: Query<(&GlobalTransform, &mut PlacedRoom), With<DungeonRoomTag>>,
mut exit_query: Query<(&GlobalTransform, &mut RoomExit)>,
) {
let mut settings = dungeon_root.single_mut();
let mut hallways: Vec<PlacedHallWay> = Vec::new();
let mut rng = ThreadRng::default();
for (_, working_room) in &room_query {
info!("working on room {}", working_room.name);
let Some(wanted_start) = working_room
.exits
.iter()
.filter(|f| {
!exit_query
.get(**f)
.expect("room exit missing component")
.1
.hallway_connected
})
.map(|f| (*f, exit_query.get(*f).expect("exit missing components")))
.choose(&mut rng)
else {
warn!("all room exits were full");
continue;
};
let Some(end_room) = &room_query
.iter()
.filter(|f| {
// end room should not be start room
f.1.id != working_room.id &&
// // end room should not be room already having a hallway
// hallways.iter().all(|h| f.1.id != h.connected_rooms.0 || f.1.id != h.connected_rooms.1) &&
// end room should have more than 1 exit
f.1.exits.len() > 1 &&
// end exit should not one that already has a hallway attached
f.1.exits
.iter()
.any(|f| {exit_query.get(*f).expect("msg").1.hallway_connected == false})
})
.min_by(|a, b| {
let distance1 = a.1
.position
.distance_squared(wanted_start.1 .0.translation().truncate().as_ivec2());
let distance2 = b.1
.position
.distance_squared(wanted_start.1 .0.translation().truncate().as_ivec2());
distance1.cmp(&distance2)
}) else {continue};
let Some(wanted_end) = end_room
.1
.exits
.iter()
.filter(|f| {
exit_query
.get(**f)
.expect("room exit missing component")
.1
.hallway_connected
== false
})
.map(|f| (*f, exit_query.get(*f).expect("msg")))
.min_by(|a, b| {
let distance1 =
a.1 .0
.translation()
.distance_squared(wanted_start.1 .0.translation());
let distance2 =
b.1 .0
.translation()
.distance_squared(wanted_start.1 .0.translation());
distance1.total_cmp(&distance2)
})
else {
continue;
};
let length = wanted_start
.1
.0
.translation()
.distance_squared(wanted_end.1 .0.translation()) as f32;
hallways.push(PlacedHallWay {
start_pos: wanted_start.1 .0.translation().truncate().as_ivec2(),
end_pos: wanted_end.1 .0.translation().truncate().as_ivec2(),
distance: length,
connected_rooms: (wanted_start.1 .1.parent, wanted_end.1 .1.parent),
});
if let Ok(changed_exits) = exit_query.get_many_mut([wanted_start.0, wanted_end.0]) {
for mut exit in changed_exits {
exit.1.hallway_connected = true
}
}
}
settings.positioned_hallways = hallways;
cmds.insert_resource(NextState(Some(GeneratorState::PlaceHallwayRoots)));
}
// TODO: rethink this code too only spawn 1 hallway per room
pub fn plan_hallways_one(
mut cmds: Commands,
mut dungeon_root: Query<&mut DungeonSettings, With<DungeonContainerTag>>,
room_query: Query<(&GlobalTransform, &mut PlacedRoom), With<DungeonRoomTag>>,
mut exit_query: Query<(&GlobalTransform, &mut RoomExit)>,
) {
let mut settings = dungeon_root.single_mut();
let mut hallways: Vec<PlacedHallWay> = Vec::new();
let unused_exits = exit_query
.iter()
.map(|f| f.1)
.map(|f| f.clone())
.collect::<Vec<RoomExit>>();
let mut exit_pairs = Vec::new();
let mut distances = Vec::new();
// Calculate distances between all exits
for i in 0..unused_exits.len() {
for j in 0..unused_exits.len() {
let exit1 = &unused_exits[i];
let exit2 = &unused_exits[j];
let room1 = room_query
.iter()
.find(|f| f.1.id == exit1.parent)
.expect("msg");
let room2 = room_query
.iter()
.find(|f| f.1.id == exit2.parent)
.expect("msg");
if room2.1.exits.len().le(&2) && room1.1.exits.len().le(&2) {
continue;
}
if exit1.parent.eq(&exit2.parent) {
info!("functionally same exits, skipping");
continue;
}
let distance: i32 = exit1.position.distance_squared(exit2.position);
distances.push((i, j, distance));
}
}
// Sort distances
distances.sort_by(|a, b| a.2.partial_cmp(&b.2).unwrap());
// Pair by distance
let mut paired_set = Vec::new();
for pair in distances {
let (idx1, idx2, _) = pair;
let exit1 = unused_exits[idx1].clone();
let exit2 = unused_exits[idx2].clone();
if exit_pairs.iter().any(|(a, b): &(RoomExit, RoomExit)| {
a.parent == exit1.parent || b.parent == exit1.parent //|| a.parent == exit2.parent || b.parent == exit2.parent
}) {
continue;
}
if !paired_set.contains(&idx1) && !paired_set.contains(&idx2) {
exit_pairs.push((unused_exits[idx1].clone(), unused_exits[idx2].clone()));
paired_set.push(idx1);
paired_set.push(idx2);
}
}
for (wanted_start, wanted_end) in exit_pairs {
hallways.push(PlacedHallWay {
start_pos: wanted_start.position,
end_pos: wanted_end.position,
distance: wanted_start.position.distance_squared(wanted_end.position) as f32,
connected_rooms: (wanted_start.parent, wanted_end.parent),
});
if let Some((_, mut start)) = exit_query
.iter_mut()
.find(|(_, exit)| **exit == wanted_start)
{
start.hallway_connected = true
}
if let Some((_, mut end)) = exit_query.iter_mut().find(|(_, exit)| **exit == wanted_end) {
end.hallway_connected = true
}
}
settings.positioned_hallways = hallways;
cmds.insert_resource(NextState(Some(GeneratorState::PlaceHallwayRoots)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment