mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Document tunnel generation
This commit is contained in:
parent
c7ce2b773c
commit
8a02a943f4
@ -29,14 +29,6 @@ pub struct GnarlingFortification {
|
|||||||
tunnels: Tunnels,
|
tunnels: Tunnels,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Tunnels {
|
|
||||||
start: Vec3<i32>,
|
|
||||||
end: Vec3<i32>,
|
|
||||||
branches: Vec<(Vec3<i32>, Vec3<i32>)>,
|
|
||||||
path: Vec<Vec3<i32>>,
|
|
||||||
terminals: Vec<Vec3<i32>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum GnarlingStructure {
|
enum GnarlingStructure {
|
||||||
Hut,
|
Hut,
|
||||||
VeloriteHut,
|
VeloriteHut,
|
||||||
@ -115,16 +107,8 @@ impl GnarlingFortification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tunnel_length_range = (12.0, 27.0);
|
let tunnel_length_range = (12.0, 27.0);
|
||||||
let (branches, path, terminals) = rrt(start, end, is_valid_edge, tunnel_length_range, rng)
|
let tunnels =
|
||||||
.unwrap_or((Vec::new(), Vec::new(), Vec::new()));
|
Tunnels::new(start, end, is_valid_edge, tunnel_length_range, rng).unwrap_or_default();
|
||||||
|
|
||||||
let tunnels = Tunnels {
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
branches,
|
|
||||||
path,
|
|
||||||
terminals,
|
|
||||||
};
|
|
||||||
|
|
||||||
let num_points = (wall_radius / 15).max(5);
|
let num_points = (wall_radius / 15).max(5);
|
||||||
let outer_wall_corners = (0..num_points)
|
let outer_wall_corners = (0..num_points)
|
||||||
@ -1933,114 +1917,151 @@ fn harvester_boss<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
|||||||
.with_asset_expect("common.entity.dungeon.gnarling.harvester", rng)
|
.with_asset_expect("common.entity.dungeon.gnarling.harvester", rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[derive(Default)]
|
||||||
fn rrt<F>(
|
struct Tunnels {
|
||||||
start: Vec3<i32>,
|
start: Vec3<i32>,
|
||||||
end: Vec3<i32>,
|
end: Vec3<i32>,
|
||||||
is_valid_edge: F,
|
branches: Vec<(Vec3<i32>, Vec3<i32>)>,
|
||||||
radius_range: (f32, f32),
|
path: Vec<Vec3<i32>>,
|
||||||
rng: &mut impl Rng,
|
terminals: Vec<Vec3<i32>>,
|
||||||
) -> Option<(Vec<(Vec3<i32>, Vec3<i32>)>, Vec<Vec3<i32>>, Vec<Vec3<i32>>)>
|
}
|
||||||
where
|
|
||||||
F: Fn(Vec3<i32>, Vec3<i32>) -> bool,
|
|
||||||
{
|
|
||||||
let mut nodes = Vec::new();
|
|
||||||
let mut node_index: usize = 0;
|
|
||||||
|
|
||||||
// HashMap<ChildNode, ParentNode>
|
impl Tunnels {
|
||||||
let mut parents = HashMap::new();
|
/// Attempts to find a path from a `start` to the `end` using a rapidly
|
||||||
|
/// exploring random tree (RRT). A point is sampled from an AABB extending
|
||||||
|
/// slightly beyond the start and end in the x and y axes and below the
|
||||||
|
/// start in the z axis to slightly below the end. Nodes are stored in a
|
||||||
|
/// k-d tree for quicker nearest node calculations. A maximum of 7000
|
||||||
|
/// points are sampled until the tree connects the start to the end. A
|
||||||
|
/// final path is then reconstructed from the nodes. Returns a `Tunnels`
|
||||||
|
/// struct of the RRT branches, the complete path, and the location of
|
||||||
|
/// dead ends. Each branch is a tuple of the start and end locations of
|
||||||
|
/// each segment. The path is a vector of all the nodes along the
|
||||||
|
/// complete path from the `start` to the `end`.
|
||||||
|
fn new<F>(
|
||||||
|
start: Vec3<i32>,
|
||||||
|
end: Vec3<i32>,
|
||||||
|
is_valid_edge: F,
|
||||||
|
radius_range: (f32, f32),
|
||||||
|
rng: &mut impl Rng,
|
||||||
|
) -> Option<Self>
|
||||||
|
where
|
||||||
|
F: Fn(Vec3<i32>, Vec3<i32>) -> bool,
|
||||||
|
{
|
||||||
|
let mut nodes = Vec::new();
|
||||||
|
let mut node_index: usize = 0;
|
||||||
|
|
||||||
let mut kdtree = KdTree::new();
|
// HashMap<ChildNode, ParentNode>
|
||||||
let start = start.map(|a| (a + 1) as f32);
|
let mut parents = HashMap::new();
|
||||||
let end = end.map(|a| (a + 1) as f32);
|
|
||||||
|
|
||||||
let min = Vec3::new(start.x.min(end.x), start.y.min(end.y), start.z.min(end.z));
|
let mut kdtree = KdTree::new();
|
||||||
let max = Vec3::new(start.x.max(end.x), start.y.max(end.y), start.z.max(end.z));
|
let startf = start.map(|a| (a + 1) as f32);
|
||||||
|
let endf = end.map(|a| (a + 1) as f32);
|
||||||
|
|
||||||
kdtree.add(&[start.x, start.y, start.z], node_index).ok()?;
|
let min = Vec3::new(
|
||||||
nodes.push(start);
|
startf.x.min(endf.x),
|
||||||
node_index += 1;
|
startf.y.min(endf.y),
|
||||||
let mut connect = false;
|
startf.z.min(endf.z),
|
||||||
|
|
||||||
for _i in 0..7000 {
|
|
||||||
let radius: f32 = rng.gen_range(radius_range.0..radius_range.1);
|
|
||||||
let radius_sqrd = radius.powi(2);
|
|
||||||
if connect {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let sampled_point = Vec3::new(
|
|
||||||
rng.gen_range(min.x - 20.0..max.x + 20.0),
|
|
||||||
rng.gen_range(min.y - 20.0..max.y + 20.0),
|
|
||||||
rng.gen_range(min.z - 20.0..max.z - 7.0),
|
|
||||||
);
|
);
|
||||||
|
let max = Vec3::new(
|
||||||
|
startf.x.max(endf.x),
|
||||||
|
startf.y.max(endf.y),
|
||||||
|
startf.z.max(endf.z),
|
||||||
|
);
|
||||||
|
|
||||||
|
kdtree
|
||||||
|
.add(&[startf.x, startf.y, startf.z], node_index)
|
||||||
|
.ok()?;
|
||||||
|
nodes.push(startf);
|
||||||
|
node_index += 1;
|
||||||
|
let mut connect = false;
|
||||||
|
|
||||||
|
for _i in 0..7000 {
|
||||||
|
let radius: f32 = rng.gen_range(radius_range.0..radius_range.1);
|
||||||
|
let radius_sqrd = radius.powi(2);
|
||||||
|
if connect {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let sampled_point = Vec3::new(
|
||||||
|
rng.gen_range(min.x - 20.0..max.x + 20.0),
|
||||||
|
rng.gen_range(min.y - 20.0..max.y + 20.0),
|
||||||
|
rng.gen_range(min.z - 20.0..max.z - 7.0),
|
||||||
|
);
|
||||||
|
let nearest_index = *kdtree
|
||||||
|
.nearest_one(
|
||||||
|
&[sampled_point.x, sampled_point.y, sampled_point.z],
|
||||||
|
&squared_euclidean,
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.1 as usize;
|
||||||
|
let nearest = nodes[nearest_index];
|
||||||
|
let dist_sqrd = sampled_point.distance_squared(nearest);
|
||||||
|
let new_point = if dist_sqrd > radius_sqrd {
|
||||||
|
nearest + (sampled_point - nearest).normalized().map(|a| a * radius)
|
||||||
|
} else {
|
||||||
|
sampled_point
|
||||||
|
};
|
||||||
|
if is_valid_edge(
|
||||||
|
nearest.map(|e| e.floor() as i32),
|
||||||
|
new_point.map(|e| e.floor() as i32),
|
||||||
|
) {
|
||||||
|
kdtree
|
||||||
|
.add(&[new_point.x, new_point.y, new_point.z], node_index)
|
||||||
|
.ok()?;
|
||||||
|
nodes.push(new_point);
|
||||||
|
parents.insert(node_index, nearest_index);
|
||||||
|
node_index += 1;
|
||||||
|
}
|
||||||
|
if new_point.distance_squared(endf) < radius.powi(2) {
|
||||||
|
connect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = Vec::new();
|
||||||
let nearest_index = *kdtree
|
let nearest_index = *kdtree
|
||||||
.nearest_one(
|
.nearest_one(&[endf.x, endf.y, endf.z], &squared_euclidean)
|
||||||
&[sampled_point.x, sampled_point.y, sampled_point.z],
|
|
||||||
&squared_euclidean,
|
|
||||||
)
|
|
||||||
.ok()?
|
.ok()?
|
||||||
.1 as usize;
|
.1 as usize;
|
||||||
let nearest = nodes[nearest_index];
|
kdtree.add(&[endf.x, endf.y, endf.z], node_index).ok()?;
|
||||||
let dist_sqrd = sampled_point.distance_squared(nearest);
|
nodes.push(endf);
|
||||||
let new_point = if dist_sqrd > radius_sqrd {
|
parents.insert(node_index, nearest_index);
|
||||||
nearest + (sampled_point - nearest).normalized().map(|a| a * radius)
|
path.push(endf);
|
||||||
} else {
|
let mut current_node_index = node_index;
|
||||||
sampled_point
|
while current_node_index > 0 {
|
||||||
};
|
current_node_index = *parents.get(¤t_node_index).unwrap();
|
||||||
if is_valid_edge(
|
path.push(nodes[current_node_index]);
|
||||||
nearest.map(|e| e.floor() as i32),
|
|
||||||
new_point.map(|e| e.floor() as i32),
|
|
||||||
) {
|
|
||||||
kdtree
|
|
||||||
.add(&[new_point.x, new_point.y, new_point.z], node_index)
|
|
||||||
.ok()?;
|
|
||||||
nodes.push(new_point);
|
|
||||||
parents.insert(node_index, nearest_index);
|
|
||||||
node_index += 1;
|
|
||||||
}
|
}
|
||||||
if new_point.distance_squared(end) < radius.powi(2) {
|
|
||||||
connect = true;
|
let mut terminals = Vec::new();
|
||||||
|
let last = nodes.len() - 1;
|
||||||
|
for (node_id, node_pos) in nodes.iter().enumerate() {
|
||||||
|
if !parents.values().any(|e| e == &node_id) && node_id != 0 && node_id != last {
|
||||||
|
terminals.push(node_pos.map(|e| e.floor() as i32));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut path = Vec::new();
|
let branches = parents
|
||||||
let nearest_index = *kdtree
|
.iter()
|
||||||
.nearest_one(&[end.x, end.y, end.z], &squared_euclidean)
|
.map(|(a, b)| {
|
||||||
.ok()?
|
(
|
||||||
.1 as usize;
|
nodes[*a].map(|e| e.floor() as i32),
|
||||||
kdtree.add(&[end.x, end.y, end.z], node_index).ok()?;
|
nodes[*b].map(|e| e.floor() as i32),
|
||||||
nodes.push(end);
|
)
|
||||||
parents.insert(node_index, nearest_index);
|
})
|
||||||
path.push(end);
|
.collect::<Vec<(Vec3<i32>, Vec3<i32>)>>();
|
||||||
let mut current_node_index = node_index;
|
let path = path
|
||||||
while current_node_index > 0 {
|
.iter()
|
||||||
current_node_index = *parents.get(¤t_node_index).unwrap();
|
.map(|a| a.map(|e| e.floor() as i32))
|
||||||
path.push(nodes[current_node_index]);
|
.collect::<Vec<Vec3<i32>>>();
|
||||||
}
|
|
||||||
|
|
||||||
let mut terminals = Vec::new();
|
Some(Self {
|
||||||
let last = nodes.len() - 1;
|
start,
|
||||||
for (node_id, node_pos) in nodes.iter().enumerate() {
|
end,
|
||||||
if !parents.values().any(|e| e == &node_id) && node_id != 0 && node_id != last {
|
branches,
|
||||||
terminals.push(node_pos.map(|e| e.floor() as i32));
|
path,
|
||||||
}
|
terminals,
|
||||||
}
|
|
||||||
|
|
||||||
let branches = parents
|
|
||||||
.iter()
|
|
||||||
.map(|(a, b)| {
|
|
||||||
(
|
|
||||||
nodes[*a].map(|e| e.floor() as i32),
|
|
||||||
nodes[*b].map(|e| e.floor() as i32),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<(Vec3<i32>, Vec3<i32>)>>();
|
}
|
||||||
let path = path
|
|
||||||
.iter()
|
|
||||||
.map(|a| a.map(|e| e.floor() as i32))
|
|
||||||
.collect::<Vec<Vec3<i32>>>();
|
|
||||||
|
|
||||||
Some((branches, path, terminals))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user