Libgdx генерирует RogueLIke Dungeon — ошибка алгоритма

Я использовал Libgdx для создания подземелья из символов клавиатуры. Я решил распечатать массив в виде текстового файла.

Однако вот что я получил:

Я понял

Кроме того, это не соответствует

Иногда я получаю это

Я не понимаю, что не так? Я проверил свой алгоритм и не нашел ничего неправильного.

Вот мой код:

public class test1 extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;

    int X = 50;
    int Y = 25;

    ////////// # wall
    ////////// . ground
    char[][][] mapChars = new char[1000][1000][1000];

        private void genDung() {
        int clearance = 4;
        for (int i = 0; i < Y; i++) {
            for (int j = 0; j <= X; j++) {
                if(j == X)
                    mapChars[0][i][j] = '\n';
                else
                    mapChars[0][i][j] = '#';
            }
        }
        int roomCount = MathUtils.random(2, 2);
        int[] roomPosX = new int[roomCount];
        int[] roomPosY = new int[roomCount];
        int[] roomCenterPosX = new int[roomCount];
        int[] roomCenterPosY = new int[roomCount];
        int[] roomSizeX = new int[roomCount];
        int[] roomSizeY = new int[roomCount];

        for (int i = 0; i < roomCount; i++) {
            int attempts = 0;
            while(true) {
                boolean rePosition = false;
                roomPosX[i] = MathUtils.random(1, X-1);
                roomPosY[i] = MathUtils.random(1, Y-1);
                roomSizeX[i] = MathUtils.random(2, 12);
                roomSizeY[i] = MathUtils.random(2, 8);
                for(int j = 0; j <= i; j++) {
                    if(i != j) {
                        if(roomPosX[i] >= roomPosX[j] && roomPosX[i] <= (roomPosX[j] + roomSizeX[j] + clearance)) {
                            if(roomPosY[i] >= roomPosY[j] && roomPosY[i] <= (roomPosY[j] + roomSizeY[j] + clearance)) {
                                rePosition = true;
                                break;
                            }
                        }
                        if((roomPosX[i]+roomSizeX[i]) >= roomPosX[j] && (roomPosX[i]+roomSizeX[i]) <= (roomPosX[j] + roomSizeX[j] + clearance)) {
                            if((roomPosY[i]+roomSizeY[i]) >= roomPosY[j] && (roomPosY[i]+roomSizeY[i]) <= (roomPosY[j] + roomSizeY[j] + clearance)) {
                                rePosition = true;
                                break;
                            }
                        }
                        if((roomPosX[i]) >= roomPosX[j] && (roomPosX[i]) <= (roomPosX[j] + roomSizeX[j] + clearance)) {
                            if((roomPosY[i]+roomSizeY[i]) >= roomPosY[j] && (roomPosY[i]+roomSizeY[i]) <= (roomPosY[j] + roomSizeY[j] + clearance)) {
                                rePosition = true;
                                break;
                            }
                        }
                        if((roomPosX[i]+roomSizeX[i]) >= roomPosX[j] && (roomPosX[i]+roomSizeX[i]) <= (roomPosX[j] + roomSizeX[j] + clearance)) {
                            if((roomPosY[i]) >= roomPosY[j] && (roomPosY[i]) <= (roomPosY[j] + roomSizeY[j] + clearance)) {
                                rePosition = true;
                                break;
                            }
                        }
                    }
                    else if(roomPosX[j] + roomSizeX[j] >= X-1){
                        rePosition = true;
                    }
                    else if(roomPosY[j] + roomSizeY[j] >= Y-1){
                        rePosition = true;
                    }
                }
                attempts++;
                if(attempts >= 10000) break;
                if(!rePosition) break;
            }
        }

        for(int r = 0; r < roomCount; r++) {
            for (int a = roomPosX[r]; a <= (roomPosX[r] + roomSizeX[r]); a++) {
                for (int b = roomPosY[r]; b <= (roomPosY[r] + roomSizeY[r]); b++) {
                    mapChars[0][b][a] = '.';
                }
            }
        }

        Gdx.app.log("roomCount", String.valueOf(roomCount)+"\n\n\n");
        for(int i =0; i< roomCount; i++) {
            roomCenterPosX[i] = roomPosX[i] + roomSizeX[i]/2;
            roomCenterPosY[i] = roomPosY[i] + roomSizeY[i]/2;
            Gdx.app.log("room", String.valueOf(i)+"\n");
            Gdx.app.log("roomPosX", String.valueOf(roomPosX[i]));
            Gdx.app.log("roomPosY", String.valueOf(roomPosY[i]));
            Gdx.app.log("roomSizeX", String.valueOf(roomSizeX[i]));
            Gdx.app.log("roomSizeY", String.valueOf(roomSizeY[i])+"\n");
            Gdx.app.log("RoomCenterPosX", String.valueOf(roomCenterPosX[i]));
            Gdx.app.log("RoomCenterPosY", String.valueOf(roomCenterPosY[i])+"\n\n");
        }

        int difference = X;
        int[] roomNum = new int[2];
        for(int i = 0; i < roomCount; i++) {
            for(int j = 0; j < roomCount; j++) {
                if(i != j) {
                    if(abs(roomCenterPosX[i] - roomCenterPosX[j]) < difference) {
                        difference = abs(roomCenterPosX[i] - roomCenterPosX[j]);
                        roomNum[0] = i;
                        roomNum[1] = j;
                    }
                }
            }
        }
        Gdx.app.log("FarthestRooms", String.valueOf(roomNum[0]));
        Gdx.app.log("FarthestRooms", String.valueOf(roomNum[1]));

        int differenceX = X;
        int differenceY = Y;
        int[] connectRooms = new int[2];
//        int[] roomsConnected = new int[roomCount];

        connectRooms[0] = MathUtils.random(0, roomCount - 1);
//        roomsConnected[0] = connectRooms[0];

        int count;

        for(int i = 0; i < roomCount-1; i++) {
            int j;
            while(true) {
                connectRooms[1] = MathUtils.random(0, roomCount - 1);
/*                while (true) {
                    connectRooms[1] = MathUtils.random(0, roomCount - 1);
                    count = 0;
                    for (j = 0; j < i; j++) {
                        if (connectRooms[1] != roomsConnected[j] && connectRooms[0] != roomsConnected[j]){
                            count++;
                        }
                    }
                    if(count >= i-2)
                        break;
                }*/
                if(connectRooms[0] != connectRooms[1])
                    break;
            }
//            roomsConnected[i+1] = connectRooms[1];

            differenceX = roomCenterPosX[connectRooms[0]] - roomCenterPosX[connectRooms[1]];
            differenceY = roomCenterPosY[connectRooms[0]] - roomCenterPosY[connectRooms[1]];
            if(roomCenterPosX[connectRooms[0]] < roomCenterPosX[connectRooms[1]])
                differenceX *= -1;
            if(roomCenterPosY[connectRooms[0]] < roomCenterPosY[connectRooms[1]])
                differenceY *= -1;

            int k;

            try {
                if (differenceX > 0) {
                    for (k = 0; k < differenceX; k++) {
                        mapChars[0][roomCenterPosY[i]][roomCenterPosX[i] + k] = '.';
                    }
                } else if (differenceX < 0) {
                    for (k = 0; k > differenceX; k--) {
                        mapChars[0][roomCenterPosY[i]][roomCenterPosX[i] + k] = '.';
                    }
                } else k = 0;

                if (differenceY < 0) {
                    for (int z = 0; z > differenceY; z--) {
                        mapChars[0][roomCenterPosY[i] + z][roomCenterPosX[i] + k] = '.';
                    }
                } else if (differenceY > 0) {
                    for (int z = 0; z < differenceY; z++) {
                        mapChars[0][roomCenterPosY[i] + z][roomCenterPosX[i] + k] = '.';
                    }
                } else {
                }
            }
            catch (ArrayIndexOutOfBoundsException e) {
                Gdx.app.log("Non Fatal Exception", String.valueOf(e));
            }

            Gdx.app.log("Connect", String.valueOf(connectRooms[0]));
            Gdx.app.log("Connect", String.valueOf(connectRooms[1]));
            Gdx.app.log("DifferenceX", String.valueOf(differenceX));
            Gdx.app.log("DifferenceY", String.valueOf(differenceY)+"\n");

        }

        for(int q = 0; q < Y; q++) {
            mapChars[0][q][X] = '\n';
        }
        for(int w = 0; w < Y; w++) {
            mapChars[0][w][X-1] = '#';
        }
        for(int e = 0; e < Y; e++) {
            mapChars[0][Y-1][e] = '#';
        }

    }

    private void export() {
        if(Gdx.files.isLocalStorageAvailable()) {
            FileHandle fileHandle = Gdx.files.local("map.txt");
            if(Gdx.files.local("map.txt").exists())
                fileHandle.writeString("", false);
            for(int i = 0; i<= Y; i++) {
                for (int j = 0; j <= X; j++) {
                    fileHandle.writeString(""+mapChars[0][i][j] , true);
                }
            }
        }
    }

    @Override
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");

//        genMap();
//        for(int i = 0; i< 4; i++)
//            refineMap();
        genDung();
        export();
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(img, 0, 0);
        batch.end();

        if(Gdx.input.isTouched()) {
//            genMap();
//            for(int i = 0; i< 4; i++)
//                refineMap();
            genDung();
            export();
        }

    }
}

Я хочу, чтобы две комнаты каждый раз правильно соединялись. Как видите, в один раз комнаты соединены, в другой раз комнаты не соединены.

заранее спасибо


person Fish    schedule 30.03.2015    source источник
comment
вы получили только две отображаемые версии? Или есть еще разные?   -  person Zorian    schedule 30.03.2015
comment
Это единственная версия, genMap() и RefineMap() - это генерация пещер.   -  person Fish    schedule 30.03.2015
comment
Обратите внимание, что переменные difference* всегда должны быть положительными, а линии differenceX *= -1;, поэтому туннели всегда выполняются в положительном направлении. Код, вероятно, будет работать и без этого.   -  person kiheru    schedule 30.03.2015
comment
Вы не описали, что хотите, поэтому невозможно интерпретировать, что не так, или понять, что вы имеете в виду под непоследовательностью. Насколько я знаю, посмотрев на это, мне кажется, что это два совершенно прекрасных макета подземелья.   -  person Tenfour04    schedule 03.04.2015


Ответы (1)


Все это можно упростить и определенно нуждается в рефакторинге. Что касается соединения 2 комнат - внимательно проверьте этот пункт.

        differenceX = roomCenterPosX[connectRooms[0]] - roomCenterPosX[connectRooms[1]];
        differenceY = roomCenterPosY[connectRooms[0]] - roomCenterPosY[connectRooms[1]];
        if(roomCenterPosX[connectRooms[0]] < roomCenterPosX[connectRooms[1]])
            differenceX *= -1;
        if(roomCenterPosY[connectRooms[0]] < roomCenterPosY[connectRooms[1]])
            differenceY *= -1;

Как указал @kiheru, это эквивалентно Math.abs(roomCenterPosX[connectRooms[0]] - roomCenterPosX[connectRooms[1]]) (то же самое для Y). Таким образом, вы всегда «копаете» вправо и вниз, а не вверх или влево.

Отбросьте эту инверсию и получайте удовольствие от остальной части вашего алгоритма :)

person harshtuna    schedule 07.04.2015