public List <BSPLeaf> GetEndLeaflets() { List <BSPLeaf> actives = new List <BSPLeaf>(); List <BSPLeaf> ends = new List <BSPLeaf>(); for (int i = 0; i < leaflets.Length; i++) { actives.Add(leaflets[i]); } while (actives.Count > 0) { BSPLeaf leaf = actives[actives.Count - 1]; if (leaf.leaflets.Length > 0) { actives.Add(leaf.leaflets[0]); actives.Add(leaf.leaflets[1]); } else { ends.Add(leaf); } actives.Remove(leaf); } return(ends); }
public BSPLeaf(int _x, int _y, int _width, int _height, BSPLeaf _parent) { x = _x; y = _y; width = _width; height = _height; parent = _parent; hasRoom = false; centre = new Vector3(x + width / 2f, 0, y + height / 2f); centre2D = new Vector2(x + width / 2f, y + height / 2f); quad = GameObject.CreatePrimitive(PrimitiveType.Quad); quad.transform.position = new Vector3(x + (width * 0.5f), -1f, y + (height * 0.5f)); quad.transform.localScale = new Vector3(width, height, 1f); quad.transform.Rotate(new Vector3(90f, 0, 0)); quad.GetComponent <Renderer> ().material.color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 0.25f); quad.gameObject.name = x + " - " + y; quad.gameObject.transform.parent = GameObject.Find("debugQuads").transform; // Debug.DrawLine (new Vector3 (x + (width * 0.5f), -1f, y + (height * 0.5f)), Vector3.zero, Color.red, 100f); if (parent != null) { // Debug.DrawLine (centre, parent.centre, Color.red, 100f); Corridor corridor = new Corridor(new Vector2(Mathf.Abs(centre2D.x - parent.centre2D.x), Mathf.Abs(centre2D.y - parent.centre2D.y)), (centre2D + parent.centre2D) / 2f, 1f); } }
public static EmptyGrid ProcessMap(EmptyGrid map, BinarySpacePartitioningSettings settings) { // Random Generator Random.State initialState = Random.state; if (settings.useFixedSeed) { Random.InitState(settings.seed.GetHashCode()); } else { Random.InitState(Time.time.ToString().GetHashCode()); } // Set root BSPLeaf root = new BSPLeaf(0, 0, map.width - 1, map.height - 1); // Space Partition root.Split(ref settings); // Get terminal leaves List <BSPLeaf> list = new List <BSPLeaf>(); root.GetLeaves(ref list); List <Vector2> midpoints = new List <Vector2>(); // Recursive Division if (settings.useOnlyRecursiveDivision) { // Fill initial for (int y = 0; y < map.height; y++) { for (int x = 0; x < map.width; x++) { map.values[x, y] = Cell.CreateCell(CellType.Floor); } } DrawBSPRoom(ref map.values, ref midpoints, ref settings, root); } else { // Room placement on map foreach (BSPLeaf leaf in list) { DrawRectangularRoom(ref map.values, ref midpoints, ref settings, leaf); } } if (settings.hasCleanup) { CleanUpRoomPlacement(ref map.values, ref map.width, ref map.height); } Random.state = initialState; return(map); }
public bool Split() { // If this leaf already has children, skip it if (firstChild != null || secondChild != null) { return(false); } // 50:50 chance of splitting leaf horizontally bool splitH = Random.Range(0f, 1f) < 0.5f; // If the width is >25% larger than height, we split vertically // If the height is >25% larger than the width, we split horizontally if (width > height && width / height >= 1.25f) { splitH = false; } else if (height > width && height / width >= 1.25f) { splitH = true; } // Determine the max height/width of child leaf int max = (splitH ? height : width) - MIN_LEAF_SIZE; // If we can't generate a large enough room, break if (max <= MIN_LEAF_SIZE) { return(false); } // Generate split int split = Random.Range(MIN_LEAF_SIZE, max); if (splitH) { firstChild = new BSPLeaf(x, y, width, split, this); secondChild = new BSPLeaf(x, y + split, width, height - split, this); } else { firstChild = new BSPLeaf(x, y, split, height, this); secondChild = new BSPLeaf(x + split, y, width - split, height, this); } if (quad != null) { GameObject.Destroy(quad); quad = null; } // We've successfully split the leaf return(true); }
public Room(Vector2 _size, Vector2 _pos, BSPLeaf _parent) { size = _size; pos = _pos; parent = _parent; GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad); quad.transform.position = new Vector3(pos.x, 0, pos.y); quad.transform.localScale = new Vector3(size.x, size.y, 1f); quad.transform.Rotate(new Vector3(90f, 0f, 0f)); quad.GetComponent <Renderer> ().material.color = Color.white; quad.gameObject.name = "Room"; quad.gameObject.transform.parent = GameObject.Find("bspTree").transform; }
public BSPLeaf(int _x1, int _y1, int _x2, int _y2, float _minDiv, float _maxDiv, Color _debugColor, int totalIteration, int currentIteration) { x1 = Mathf.Min(_x1, _x2); y1 = Mathf.Min(_y1, _y2); x2 = Mathf.Max(_x1, _x2); y2 = Mathf.Max(_y1, _y2); x = (int)Mathf.Lerp(x1, x2 - 1, 0.5f); y = (int)Mathf.Lerp(y1, y2 - 1, 0.5f); splitMode = Mathf.Abs(x1 - x2) < Mathf.Abs(y1 - y2); if (currentIteration >= totalIteration) { leaflets = new BSPLeaf[0]; debugColor = _debugColor; } else { _debugColor = new Color(Random.Range(0.5f, 1f), Random.Range(0.5f, 1f), Random.Range(0.5f, 1f)); leaflets = new BSPLeaf[2]; float s = Random.Range(_minDiv, _maxDiv); split = Mathf.RoundToInt((float)(splitMode ? y2 - y1 : x2 - x1) * s); split += (Random.value > 0.5f ? 1 : -1) * (1 - (split % 2)); //split += 1 - (split%2); if (splitMode) { leaflets[0] = new BSPLeaf(x1, y1, x2, y1 + split, _minDiv, _maxDiv, _debugColor, totalIteration, currentIteration + 1); leaflets[1] = new BSPLeaf(x1, y1 + split + 1, x2, y2, _minDiv, _maxDiv, _debugColor, totalIteration, currentIteration + 1); leaflets[0].PositionNearPoint(new Vector2Int(x, y1 + split)); leaflets[1].PositionNearPoint(new Vector2Int(x, y1 + split)); } else { leaflets[0] = new BSPLeaf(x1, y1, x1 + split, y2, _minDiv, _maxDiv, _debugColor, totalIteration, currentIteration + 1); leaflets[1] = new BSPLeaf(x1 + split + 1, y1, x2, y2, _minDiv, _maxDiv, _debugColor, totalIteration, currentIteration + 1); leaflets[0].PositionNearPoint(new Vector2Int(x1 + split, y)); leaflets[1].PositionNearPoint(new Vector2Int(x1 + split, y)); } } }
private static void CM_TestInLeaf(BSPLeaf leaf) { int k; BSPBrush b; BSPBrush[] leafbrushes; if (leaf.num_brushes == 0) { return; } if (((int)trace_contents & (int)leaf.contents) == 0) { return; } //trace line against all brushes in the leaf leafbrushes = leaf.Brushes; for (k = 0; k < leafbrushes.Length; k++) { b = leafbrushes[k]; if (b.checkcount == checkcount) { continue; } b.checkcount = checkcount; if (((int)b.contents & trace_contents) == 0) { continue; } CM_TestBoxInBrush(trace_start, ref trace_trace, b); if (trace_trace.fraction == 0) { return; } } }
private static void CM_TraceToLeaf(BSPLeaf leaf) { int k; BSPBrush b; BSPBrush[] leafbrushes; if (((int)leaf.contents & trace_contents) == 0) { return; } //trace line against all brushes in the leaf leafbrushes = leaf.Brushes; for (k = 0; k < leaf.num_brushes; k++) { b = leafbrushes[k]; //a lame method to avoid rechecks for brushes that are in multiple leafs if (b.checkcount == checkcount) { continue; } b.checkcount = checkcount; if (((int)b.contents & trace_contents) == 0) { continue; } CM_ClipBoxToBrush(trace_start, trace_end, ref trace_trace, b); if (trace_trace.fraction == 0) //didn't move at all, so we can return { return; } } }
private void CreateRooms() { root = new BSPLeaf(0, 0, (int)treeSize.x, (int)treeSize.y, null); leaves.Add(root); bool didSplit = true; while (didSplit) { didSplit = false; for (int i = 0; i < leaves.Count; i++) { // If we haven't already split this leaf if (leaves [i].firstChild == null && leaves [i].secondChild == null) { // Attempt to split it if (leaves [i].Split()) { // If successful, add it's children to the list of leaves leaves.Add(leaves [i].firstChild); leaves.Add(leaves [i].secondChild); didSplit = true; } } } } root.CreateRooms(); GameObject baseQuad = GameObject.CreatePrimitive(PrimitiveType.Quad); baseQuad.transform.position = new Vector3(treeSize.x / 2f, -2f, treeSize.y / 2f); baseQuad.transform.localScale = new Vector3(treeSize.x, treeSize.y, 0f); baseQuad.transform.Rotate(new Vector3(90f, 0f, 0f)); baseQuad.GetComponent <Renderer> ().material.color = Color.black; }
void DigCorridors(BSPLeaf baseLeaf, int size, int minSpace) { List <BSPLeaf> actives = new List <BSPLeaf>(); actives.Add(baseLeaf); while (actives.Count > 0) { BSPLeaf leaf = actives[actives.Count - 1]; if (leaf.leaflets.Length > 0) { BSPLeaf start = leaf.leaflets[0]; BSPLeaf end = leaf.leaflets[1]; actives.Add(start); actives.Add(end); int dx = end.x - start.x; int dy = end.y - start.y; int midX = (start.x2 + end.x1) / 2; int spaceX = end.x1 - start.x2; if (dx < 0) { midX = (start.x1 + end.x2) / 2; spaceX = start.x1 - end.x2; } int midY = (start.y2 + end.y1) / 2; int spaceY = end.y1 - start.y2; if (dy < 0) { midY = (start.y1 + end.y2) / 2; spaceY = start.y1 - end.y2; } bool mode = Mathf.Abs(dx) > Mathf.Abs(dy); if (mode && spaceX < minSpace && spaceX >= 0) { mode = false; } if (!mode && spaceY < minSpace && spaceY >= 0) { mode = true; } if (!mode) { if (dx >= 0) { for (int x = start.x; x <= midX; x++) { DigMap(x, start.y, size, false); } } else { for (int x = end.x; x <= midX; x++) { DigMap(x, end.y, size, false); } } if (dy >= 0) { for (int y = start.y; y <= end.y; y++) { DigMap(midX, y, size, false); } } else { for (int y = end.y; y <= start.y; y++) { DigMap(midX, y, size, false); } } if (dx >= 0) { for (int x = midX; x <= end.x; x++) { DigMap(x, end.y, size, false); } } else { for (int x = midX; x <= start.x; x++) { DigMap(x, start.y, size, false); } } } else { if (dy >= 0) { for (int y = start.y; y <= midY; y++) { DigMap(start.x, y, size, false); } } else { for (int y = end.y; y <= midY; y++) { DigMap(end.x, y, size, false); } } if (dx >= 0) { for (int x = start.x; x <= end.x; x++) { DigMap(x, midY, size, false); } } else { for (int x = end.x; x <= start.x; x++) { DigMap(x, midY, size, false); } } if (dy >= 0) { for (int y = midY; y <= end.y; y++) { DigMap(end.x, y, size, false); } } else { for (int y = midY; y <= start.y; y++) { DigMap(start.x, y, size, false); } } } } actives.Remove(leaf); } }
public void Split(ref BinarySpacePartitioningSettings settings) { if (!AbleToSplit(ref settings)) { return; } int whereToSplit; if (splitOrientationIsVertical) { if (settings.canShareSingleWall) { whereToSplit = Random.Range(0 + settings.minSplitSizeVertical - 1, SizeX - settings.minSplitSizeVertical + 1); Left = new BSPLeaf(bounds.xMin, bounds.zMin, whereToSplit, SizeZ); Right = new BSPLeaf(bounds.xMin + whereToSplit, bounds.zMin, SizeX - whereToSplit, SizeZ); if (CanSplit(whereToSplit, true, ref settings)) { Left.Split(ref settings); } if (CanSplit(SizeX - whereToSplit, true, ref settings)) { Right.Split(ref settings); } } else { whereToSplit = Random.Range(0 + settings.minSplitSizeVertical - 1, SizeX - settings.minSplitSizeVertical + 1); Left = new BSPLeaf(bounds.xMin, bounds.zMin, whereToSplit, SizeZ); Right = new BSPLeaf(bounds.xMin + whereToSplit + 1, bounds.zMin, SizeX - whereToSplit - 1, SizeZ); if (CanSplit(whereToSplit, true, ref settings)) { Left.Split(ref settings); } if (CanSplit(SizeX - whereToSplit - 1, true, ref settings)) { Right.Split(ref settings); } } } else { if (settings.canShareSingleWall) { whereToSplit = Random.Range(0 + settings.minSplitSizeHorizontal - 1, SizeZ - settings.minSplitSizeHorizontal + 1); Left = new BSPLeaf(bounds.xMin, bounds.zMin, SizeX, whereToSplit); Right = new BSPLeaf(bounds.xMin, bounds.zMin + whereToSplit, SizeX, SizeZ - whereToSplit); if (CanSplit(whereToSplit, false, ref settings)) { Left.Split(ref settings); } if (CanSplit(SizeZ - whereToSplit, false, ref settings)) { Right.Split(ref settings); } } else { whereToSplit = Random.Range(0 + settings.minSplitSizeHorizontal - 1, SizeZ - settings.minSplitSizeHorizontal + 1); Left = new BSPLeaf(bounds.xMin, bounds.zMin, SizeX, whereToSplit); Right = new BSPLeaf(bounds.xMin, bounds.zMin + whereToSplit + 1, SizeX, SizeZ - whereToSplit - 1); if (CanSplit(whereToSplit, false, ref settings)) { Left.Split(ref settings); } if (CanSplit(SizeZ - whereToSplit - 1, false, ref settings)) { Right.Split(ref settings); } } } }
private static void DrawRectangularRoom(ref Cell[,] map, ref List <Vector2> midpoints, ref BinarySpacePartitioningSettings settings, BSPLeaf leaf, CellType roomWallsCell = CellType.Wall, CellType roomFloorCell = CellType.Floor) { int roomsMinWidth = settings.roomsMinWidth - 1; int roomsMinHeight = settings.roomsMinHeight - 1; int roomWidth; int roomHeight; if (settings.useRoomsMaxSizeValues) { roomWidth = Random.Range(roomsMinWidth, settings.roomsMaxWidth); roomHeight = Random.Range(roomsMinHeight, settings.roomsMaxHeight); } else { roomWidth = Random.Range(roomsMinWidth, leaf.SizeX + 1); roomHeight = Random.Range(roomsMinHeight, leaf.SizeZ + 1); } int xOffset = Random.Range(0, leaf.SizeX - roomWidth); int zOffset = Random.Range(0, leaf.SizeZ - roomHeight); for (int z = leaf.bounds.zMin + zOffset + 1; z < leaf.bounds.zMin + zOffset + roomHeight; z++) { for (int x = leaf.bounds.xMin + xOffset + 1; x < leaf.bounds.xMin + xOffset + roomWidth; x++) { map[x, z] = Cell.CreateCell(roomFloorCell); } } for (int x = leaf.bounds.xMin + xOffset; x <= leaf.bounds.xMin + xOffset + roomWidth; x++) { map[x, leaf.bounds.zMin + zOffset] = Cell.CreateCell(roomWallsCell); map[x, leaf.bounds.zMin + zOffset + roomHeight] = Cell.CreateCell(roomWallsCell); } for (int z = leaf.bounds.zMin + zOffset; z <= leaf.bounds.zMin + zOffset + roomHeight; z++) { map[leaf.bounds.xMin + xOffset, z] = Cell.CreateCell(roomWallsCell); map[leaf.bounds.xMin + xOffset + roomWidth, z] = Cell.CreateCell(roomWallsCell); } midpoints.Add(new Vector2(leaf.bounds.xMin + xOffset + roomWidth / 2, leaf.bounds.zMin + zOffset + roomHeight / 2)); }
private BrushContents GetPointContents(Vector3 point) { BSPLeaf l = Utils.NodePointSearch(BSPFile.headnode, point / scale); return(l.contents); }
public static BrushContents GetPointContents(Vector3 point) { BSPLeaf l = NodePointSearch(BSPFile.headnode, point / Globals.scale.Value); return(l.contents); }
private static void CM_BoxTrace(out TraceT trace, Vector3 start, Vector3 end, Vector3 mins, Vector3 maxs, BSPNode headnode, int brushmask) { checkcount++; trace_trace = new TraceT { fraction = 1, surface = new SurfaceT() }; trace = trace_trace; trace_start = start; trace_end = end; trace_contents = brushmask; Vector3[] bounds = new Vector3[] { mins, maxs }; for (int k = 0; k < 8; k++) { trace_offsets[k] = new Vector3(); } for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { trace_offsets[i][j] = bounds[i >> j & 1][j]; } } //check for position test special case if (start == end) { BSPLeaf[] leafs = new BSPLeaf[1024]; int numleafs; Vector3 c1, c2; //M increase bounds size c1 = start + mins - Vector3.one; c2 = start + maxs + Vector3.one; numleafs = CM_BoxLeafs_Headnode(c1, c2, ref leafs, 1024, headnode, out BSPNode topnode); for (int i = 0; i < numleafs; i++) { CM_TestInLeaf(leaf_list[i]); if (trace_trace.allsolid) { break; } } trace_trace.endpos = start; return; } //check for point special case if (mins == Vector3.zero && maxs == Vector3.zero) { trace_ispoint = true; trace_extents = Vector3.zero; } else { trace_ispoint = false; trace_extents = new Vector3(Mathf.Max(-mins[0], maxs[0]), Mathf.Max(-mins[1], maxs[1]), Mathf.Max(-mins[2], maxs[2])); } //general sweeping through world CM_RecursiveHullCheck(headnode, 0, 1, start, end); if (trace_trace.fraction == 1) { trace_trace.endpos = end; } else { trace_trace.endpos = Vector3.Lerp(start, end, trace_trace.fraction); } }
void GenerateMap() { tree = new BSPLeaf(0, 0, width, height, minimumDivision, maximumDivision, Color.white, totalDivisions, 0); tree.Trim(2); for (int i = 0; i < tileObjects.Count; i++) { Destroy(tileObjects[i]); } tileObjects.Clear(); List <BSPLeaf> leaflets = tree.GetEndLeaflets(); map = new Tile[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { map[x, y] = new Tile(true, false); } } DigCorridors(tree, 1, 3); for (int i = 0; i < leaflets.Count; i++) { BSPLeaf leaf = leaflets[i]; Vector2 trueCenter = new Vector2(Mathf.Lerp(leaf.x1, leaf.x2 - 1, 0.5f), Mathf.Lerp(leaf.y1, leaf.y2 - 1, 0.5f)); for (int x = leaf.x1; x < leaf.x2; x++) { for (int y = leaf.y1; y < leaf.y2; y++) { map[x, y].solid = false; map[x, y].focus = true; map[x, y].focalPoint = trueCenter; } } } //TrimSingleWidthLines(); for (int i = 0; i < leaflets.Count; i++) { BSPLeaf leaf = leaflets[i]; int leafwidth = leaf.x2 - leaf.x1; int leafheight = leaf.y2 - leaf.y1; int leafstyle = Random.Range(Mathf.Min(tileStylesCount, 1), tileStylesCount); bool[,] objects = GenerateCompositeObject(leafwidth, leafheight, 3); for (int x = 0; x < leafwidth; x++) { for (int y = 0; y < leafheight; y++) { if (objects[x, y]) { map[leaf.x1 + x, leaf.y1 + y].solid = true; map[leaf.x1 + x, leaf.y1 + y].style = leafstyle; } } } int singleTileReplacement = Random.Range(0, singleTilePrefabs.Length); if (singleTileReplacement > 0) { List <Vector2Int> singles = new List <Vector2Int>(); for (int x = leaf.x1; x < leaf.x2; x++) { for (int y = leaf.y1; y < leaf.y2; y++) { if (map[x, y].solid && !TileIsSolid(x + 1, y) && !TileIsSolid(x - 1, y) && !TileIsSolid(x, y + 1) && !TileIsSolid(x, y - 1)) { singles.Add(new Vector2Int(x, y)); } } } for (int s = 0; s < singles.Count; s++) { map[singles[s].x, singles[s].y].solid = false; var p = (GameObject)Instantiate(singleTilePrefabs[singleTileReplacement], new Vector3(singles[s].x, singles[s].y, 0), Quaternion.identity); tileObjects.Add(p); } } } ComputeAdjacence(); ConstructMap(); }
private static void DrawBSPRoom(ref Cell[,] map, ref List <Vector2> midpoints, ref BinarySpacePartitioningSettings settings, BSPLeaf leaf, CellType roomWallsCell = CellType.Wall, CellType roomFloorCell = CellType.Floor) { if (leaf.Left != null && leaf.Right != null) { if (leaf.splitOrientationIsVertical) { int passageAt = Random.Range(leaf.Left.bounds.zMin, leaf.Left.bounds.zMin + leaf.Left.SizeZ + 1); int divideCellIndex = leaf.Left.bounds.xMin + leaf.Left.SizeX; for (int z = leaf.bounds.zMin; z <= leaf.bounds.zMin + leaf.SizeZ; z++) { if (passageAt != z) { map[divideCellIndex, z] = Cell.CreateCell(roomWallsCell); } else { map[divideCellIndex, z] = Cell.CreateCell(roomFloorCell); } } } else { int passageAt = Random.Range(leaf.Left.bounds.xMin, leaf.Left.bounds.xMin + leaf.Left.SizeX + 1); int divideCellIndex = leaf.Left.bounds.zMin + leaf.Left.SizeZ; while (passageAt == divideCellIndex) { passageAt = Random.Range(leaf.Left.bounds.xMin, leaf.Left.bounds.xMin + leaf.Left.SizeX + 1); } for (int x = leaf.bounds.xMin; x <= leaf.bounds.xMin + leaf.SizeX; x++) { if (passageAt != x) { map[x, divideCellIndex] = Cell.CreateCell(roomWallsCell); } else { map[x, divideCellIndex] = Cell.CreateCell(roomFloorCell); } } } DrawBSPRoom(ref map, ref midpoints, ref settings, leaf.Left, roomWallsCell, roomFloorCell); DrawBSPRoom(ref map, ref midpoints, ref settings, leaf.Right, roomWallsCell, roomFloorCell); } else { return; } }