Improved Doorway Placement
Changed MazeDesigner to prune out some unnecessary doorways at random by removing edges from the room graph. Previous mazes allowed all side paths to exist, which resulted in a kind of circular layout. Although that was disorienting to people at first, if you realized it was a circle, it became simple to navigate through the maze. This update makes branching paths more common.
This commit is contained in:
@@ -126,4 +126,9 @@ public class DisjointSet<T>
|
|||||||
return (firstRoot == secondRoot);
|
return (firstRoot == secondRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
mapping.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ public class MazeDesigner
|
|||||||
// Cut out random subgraphs from the adjacency graph
|
// Cut out random subgraphs from the adjacency graph
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores = createMazeSections(rooms, random);
|
ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores = createMazeSections(rooms, random);
|
||||||
|
|
||||||
// Remove unnecessary passages through floors/ceilings
|
// Remove unnecessary passages through floors/ceilings and some from the walls
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> core : cores)
|
for (IGraphNode<PartitionNode, DoorwayData> core : cores)
|
||||||
{
|
{
|
||||||
minimizeVerticalPassages(core, rooms, random);
|
pruneDoorways(core, rooms, random);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MazeDesign(root, rooms, cores);
|
return new MazeDesign(root, rooms, cores);
|
||||||
@@ -459,7 +459,7 @@ public class MazeDesigner
|
|||||||
return cores;
|
return cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void minimizeVerticalPassages(IGraphNode<PartitionNode, DoorwayData> core,
|
private static void pruneDoorways(IGraphNode<PartitionNode, DoorwayData> core,
|
||||||
DirectedGraph<PartitionNode, DoorwayData> rooms, Random random)
|
DirectedGraph<PartitionNode, DoorwayData> rooms, Random random)
|
||||||
{
|
{
|
||||||
// We receive a node for one of the rooms in a section of the maze
|
// We receive a node for one of the rooms in a section of the maze
|
||||||
@@ -467,13 +467,15 @@ public class MazeDesigner
|
|||||||
// still allowing any room to be reachable from any other room.
|
// still allowing any room to be reachable from any other room.
|
||||||
// In technical terms, we receive a node from a connected subgraph
|
// In technical terms, we receive a node from a connected subgraph
|
||||||
// and we need to remove as many Y_AXIS-type edges as possible while
|
// and we need to remove as many Y_AXIS-type edges as possible while
|
||||||
// preserving connectedness.
|
// preserving connectedness. We also want to randomly remove some of
|
||||||
|
// the other doorways without breaking connectedness.
|
||||||
|
|
||||||
// An efficient solution is to assign nodes to disjoint sets based
|
// An efficient solution is to assign nodes to disjoint sets based
|
||||||
// on their components, ignoring all Y_AXIS edges, then iterate over
|
// on their components, ignoring all Y_AXIS edges, then iterate over
|
||||||
// a list of those edges and remove them if they connect two nodes
|
// a list of those edges and remove them if they connect two nodes
|
||||||
// in the same set. Otherwise, merge their sets and keep the edge.
|
// in the same set. Otherwise, merge their sets and keep the edge.
|
||||||
// This is similar to algorithms for spanning trees.
|
// This is similar to algorithms for spanning trees. The same
|
||||||
|
// idea applies for the other doorways with some chance added.
|
||||||
|
|
||||||
// First, list all nodes in the subgraph
|
// First, list all nodes in the subgraph
|
||||||
IGraphNode<PartitionNode, DoorwayData> current;
|
IGraphNode<PartitionNode, DoorwayData> current;
|
||||||
@@ -540,6 +542,38 @@ public class MazeDesigner
|
|||||||
rooms.removeEdge(passage);
|
rooms.removeEdge(passage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeat the pruning process with X_AXIS and Z_AXIS doorways
|
||||||
|
// In this case, unnecessary edges might be kept at random
|
||||||
|
components.clear();
|
||||||
|
targets.clear();
|
||||||
|
|
||||||
|
for (IGraphNode<PartitionNode, DoorwayData> room : subgraph)
|
||||||
|
{
|
||||||
|
components.makeSet(room);
|
||||||
|
}
|
||||||
|
for (IGraphNode<PartitionNode, DoorwayData> room : subgraph)
|
||||||
|
{
|
||||||
|
for (IEdge<PartitionNode, DoorwayData> passage : room.outbound())
|
||||||
|
{
|
||||||
|
if (passage.data().axis() == DoorwayData.Y_AXIS)
|
||||||
|
{
|
||||||
|
components.mergeSets(passage.head(), passage.tail());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targets.add(passage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.shuffle(targets, random);
|
||||||
|
for (IEdge<PartitionNode, DoorwayData> passage : targets)
|
||||||
|
{
|
||||||
|
if (!components.mergeSets(passage.head(), passage.tail()) && random.nextBoolean())
|
||||||
|
{
|
||||||
|
rooms.removeEdge(passage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user