我最初试图遵循此算法在C#中创建一个简单的roguelike地牢。但是我想我太愚蠢了,因为我的结果总是杂乱无章。
然后,我切换到我自己的算法,该算法产生的效果不佳,但可以半识别为地下城。
如链接文章中所述,是否有人有以BSP方式执行此操作的示例?最好不要被大量的游戏详细信息/库调用所困扰,因为(再次)我很愚蠢。
(如果您特别受虐狂,并且希望我发布我拥有的代码,可以,但是我认为这对于SO问题来说太过分了。)
这还没有链接房间,但是它使用所描述的算法生成了不错的地牢。(不幸的是,它是在Java中,但是我尝试添加一些注释来阐明正在执行的操作。)
public static class Rectangle { private static int MIN_SIZE = 5; private static Random rnd = new Random(); private int top, left, width, height; private Rectangle leftChild; private Rectangle rightChild; private Rectangle dungeon; public Rectangle(int top, int left, int height, int width) { this.top = top; this.left = left; this.width = width; this.height = height; } public boolean split() { if( leftChild != null ) //if already split, bail out return false; boolean horizontal = rnd.nextBoolean(); //direction of split int max = (horizontal ? height : width ) - MIN_SIZE; //maximum height/width we can split off if( max <= MIN_SIZE ) // area too small to split, bail out return false; int split = rnd.nextInt( max ); // generate split point if( split < MIN_SIZE ) // adjust split point so there's at least MIN_SIZE in both partitions split = MIN_SIZE; if( horizontal ) { //populate child areas leftChild = new Rectangle( top, left, split, width ); rightChild = new Rectangle( top+split, left, height-split, width ); } else { leftChild = new Rectangle( top, left, height, split ); rightChild = new Rectangle( top, left+split, height, width-split ); } return true; //split successful } public void generateDungeon() { if( leftChild != null ) { //if current are has child areas, propagate the call leftChild.generateDungeon(); rightChild.generateDungeon(); } else { // if leaf node, create a dungeon within the minimum size constraints int dungeonTop = (height - MIN_SIZE <= 0) ? 0 : rnd.nextInt( height - MIN_SIZE); int dungeonLeft = (width - MIN_SIZE <= 0) ? 0 : rnd.nextInt( width - MIN_SIZE); int dungeonHeight = Math.max(rnd.nextInt( height - dungeonTop ), MIN_SIZE );; int dungeonWidth = Math.max(rnd.nextInt( width - dungeonLeft ), MIN_SIZE );; dungeon = new Rectangle( top + dungeonTop, left+dungeonLeft, dungeonHeight, dungeonWidth); } } }
这是一个测试类来演示其用法:
import java.util.ArrayList; import java.util.Random; public class GenerateDungeon { private static Random rnd = new Random(); public static void main(String[] args) { ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>(); // flat rectangle store to help pick a random one Rectangle root = new Rectangle( 0, 0, 60, 120 ); // rectangles.add( root ); //populate rectangle store with root area while( rectangles.size() < 19 ) { // this will give us 10 leaf areas int splitIdx = rnd.nextInt( rectangles.size() ); // choose a random element Rectangle toSplit = rectangles.get( splitIdx); if( toSplit.split() ) { //attempt to split rectangles.add( toSplit.leftChild ); rectangles.add( toSplit.rightChild ); } } root.generateDungeon(); //generate dungeons printDungeons(rectangles); //this is just to test the output } private static void printDungeons(ArrayList<Rectangle> rectangles) { byte [][] lines = new byte[60][]; for( int i = 0; i < 60; i++ ) { lines[ i ] = new byte[120]; for( int j = 0; j < 120; j++ ) lines[ i ][ j ] = -1; } byte dungeonCount = -1; for( Rectangle r : rectangles ) { if( r.dungeon == null ) continue; Rectangle d = r.dungeon; dungeonCount++; for( int i = 0; i < d.height; i++ ) { for( int j = 0; j < d.width; j++ ) lines[ d.top + i ][ d.left+ j ] = dungeonCount; } } for( int i = 0; i < 60; i++ ) { for( int j = 0; j < 120; j++ ) { if( lines[ i ][ j ] == -1 ) System.out.print( '.'); else System.out.print( lines[ i ][ j ] ); } System.out.println(); } } }