# Zufallsdungeon in Baumstruktur [Wände fehlen]



## Telrion (31. Mai 2012)

Hey Leute,

ich bin gerade im 2 Semester für Bioinformatik und habe in Java die Aufgabe ein Rogue Like Game zu schreiben. Dazu muss ich bis zum Juli einen Meilenstein einreichen der besagt, dass ein randomgenerierter Dungeon vorhanden sein muss. Desweiteren muss dieser Dungeon als Baum programmiert sein.
Ich weiß, dass es wahrscheinlich nicht der schönste Code ist, aber da ich erst seit Anfang des Semesters in Java programmiere bin ich recht zufrieden.

Nun zu meinem Problem, ich habe den Debugger in Netbeans schon durchlaufen lassen und laut diesem wird mein Dungeon wunderbar geteilt, allerdings zeichnet mir das Programm nur eine einzige Wand.
Ich hoffe irgendjemand mit mehr Erfahrung kann mir behilflich sein, dass meine Wände gezogen werden. Allerdings bitte keine großen Vorschläge außerhalb des Wandproblems, soll ja Eigenarbeit bleiben 


```
public class DungeonFactory {

    //y = Hoehe; x = Breite
    private char[][] rootRoom;
    private int x;
    private int y;
    private Node root;

    public DungeonFactory(int x, int y) {
        this.x = x;
        this.y = y;
        this.rootRoom = new char[y][x];
    }

    //generiert den "Anfangsfraum"
    public char[][] generate() {

        for (int i = 0; i < this.y; i++) {
            for (int j = 0; j < this.x; j++) {

                if (i == 0 || i == this.y - 1 || j == 0 || j == this.x - 1) {
                    this.rootRoom[i][j] = '\u2588';
                } else {
                    this.rootRoom[i][j] = ' ';
                }
            }
        }

        //setze die Wurzel
        root = new Node(rootRoom, 0, 0);
        return rootRoom;
    }

    public class Node {

        private char[][] room;
        private int x;
        private int y;
        private Node child1;
        private Node child2;
        private Leaf leaf;
        private int homogen;
        private int splitHori;
        private int splitVerti;
        private int space;

        // y und x sind die Eckpunkte um die Einzeraume spaeter wieder
        // zusammen zu setzen
        public Node(char[][] room, int x, int y) {

            this.x = x;
            this.y = y;
            this.room = room;

            // rufe im Knoten die Splitfunktion bis zur Abbruchbedingung auf
            split(this);


        }

        public final void split(Node node) {

            space = room.length * room[0].length;


            //space = Abbruchbedingung
            if (space >= 50) {
                leaf = null;
                if ((room.length / room[0].length) > 1) {
                    splitHori();

                    //Definiere fÃ¼r jede Splitmoeglichkeit die Groessen der Raeume 1 und 2
                    char[][] room1 = new char[splitHori][room[0].length];
                    char[][] room2 = new char[room.length - splitHori][room[0].length];

                    // zeichne die Raeume 1 und 2
                    for (int i = 0; i < splitHori; i++) {
                        for (int j = 0; j < room1[0].length; j++) {
                            room1[i][j] = room[i][j];
                        }
                    }

                    for (int i = splitHori; i < room2.length; i++) {
                        for (int j = 0; j < room2[0].length; j++) {
                            room2[i][j] = room[i][j];
                        }
                    }

                    // weise die Raume den Kindern zu
                    child1 = new Node(room1, node.getY(), node.getX());
                    child2 = new Node(room2, node.getY() + splitHori, node.getX());

                } else if ((room[0].length / room.length) > 1) {
                    splitVerti();

                    char[][] room1 = new char[room.length][splitVerti];
                    char[][] room2 = new char[room.length][room[0].length - splitVerti];

                    for (int i = 0; i < room1.length; i++) {
                        for (int j = 0; j < splitVerti; j++) {
                            room1[i][j] = room[i][j];
                        }
                    }

                    for (int i = 0; i < room2.length; i++) {
                        for (int j = splitVerti; j < room2[0].length; j++) {
                            room2[i][j] = room[i][j];
                        }
                    }


                    child1 = new Node(room1, node.getY(), node.getX());
                    child2 = new Node(room2, node.getY(), node.getX() + splitVerti);

                } else {
                    //Ausgleich zwischen Horizontalem und Vertikalem Split
                    homogen = (int) (Math.random() * 2 + 1);
                    if (homogen == 1) {
                        splitHori();

                        char[][] room1 = new char[splitHori][room[0].length];
                        char[][] room2 = new char[room.length - splitHori][room[0].length];

                        for (int i = 0; i < splitHori; i++) {
                            for (int j = 0; j < room1[0].length; j++) {
                                room1[i][j] = room[i][j];
                            }
                        }

                        for (int i = splitHori; i < room2.length; i++) {
                            for (int j = 0; j < room2[0].length; j++) {
                                room2[i][j] = room[i][j];
                            }
                        }

                        child1 = new Node(room1, node.getY(), node.getX());
                        child2 = new Node(room2, node.getY() + splitHori, node.getX());

                    } else {

                        splitVerti();

                        char[][] room1 = new char[room.length][splitVerti];
                        char[][] room2 = new char[room.length][room[0].length - splitVerti];

                        for (int i = 0; i < room1.length; i++) {
                            for (int j = 0; j < splitVerti; j++) {
                                room1[i][j] = room[i][j];
                            }
                        }

                        for (int i = 0; i < room2.length; i++) {
                            for (int j = splitVerti; j < room2[0].length; j++) {
                                room2[i][j] = room[i][j];
                            }
                        }


                        child1 = new Node(room1, node.getY(), node.getX());
                        child2 = new Node(room2, node.getY(), node.getX() + splitVerti);
                    }
                }

            } else {

                leaf = new Leaf(room, this.x, this.y);
            }

        }

        
        //Methode fuer den Vertikalen und den Horizontalen Split
        public char[][] splitHori() {

            int balance = (int) (room.length * 0.2);
            splitHori = (int) (Math.random() * (room.length - 2 * balance) + balance);

            for (int j = 0; j < room.length; j++) {
                for (int i = 0; i < room[0].length; i++) {
                    this.room[splitHori][i] = '\u2588';
                }
            }
            return room;
        }

        public char[][] splitVerti() {
            int balance = (int) (room[0].length * 0.2);
            splitVerti = (int) (Math.random() * (room[0].length - 2 * balance) + balance);

            for (int j = 0; j < room.length; j++) {
                for (int i = 0; i < room[0].length; i++) {
                    this.room[j][splitVerti] = '\u2588';
                }
            }

            return room;
        }

        
        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

    class Leaf {

        private char[][] room;
        private int x;
        private int y;

        public Leaf(char[][] room, int x, int y) {
            this.room = room;
            this.y = y;
            this.x = x;
        }
    }
}
```

Falls noch Informationen benötigt werden, bin dieses Wochenende bei RaR, würde dann ab Dienstag Antworten.

Danke schonmal im vorraus 

Telrion


----------



## Quaxli (31. Mai 2012)

Ein lauffähiges Beispiel, mit dem man rumspielen kann, wäre da aber schon hilfreich...


----------



## Telrion (4. Jun 2012)

Sooo zurück von RaR 

Was genau meinst du mit einem lauffähigem Beispiel? Oo
Ich mein wenn ich eins hätte oder kennen würde, stünde ich ja nicht vor meinem momentanen Problem


----------



## Fu3L (4. Jun 2012)

Was Quaxlie meint, ist eine Variante, die wirklich ausführbar ist. Wo zwar das Ergebnis nicht stimmt, aber man zumindest selbst die Werte ein wenig verändern und das Resultat der Veränderung sehen kann.


----------



## Telrion (4. Jun 2012)

Also wenn ich das richtig verstanden habe, muss ich also alle Quellcodes Kopieren die etwas mit meinem Dungeon zutun haben richtig?


```
import Controller.DungeonFactory.DungeonFactory;
import Controller.DungeonFactory.DungeonFactory.Node;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JTextPane;

public class DungeonFrame extends JFrame {

    private JTextPane pane;
    private DungeonFactory dungeonFac;
    private char[][] map;
    private Font font;
    private Node node;

    public DungeonFrame() {
        super();
        this.init();
    }

    public void init() {
        font = new Font("Courier New", Font.PLAIN, 12);
        setSize(800, 600);
        setLocationRelativeTo(null);

        this.pane = new JTextPane();
        this.pane.setFont(this.font);
        this.pane.setEditable(false);
        this.add(pane);
        this.clearScreen();

        this.dungeonFac = new DungeonFactory(50, 50);
        this.map = this.dungeonFac.generate();
//        this.node.split(map);
        
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        this.render();
        
        this.setVisible(true);


    }

    private void render() {
        this.clearScreen();
        String content = "";
        for (int i = 0; i < this.map.length; i++) {
            for (int j = 0; j < this.map[0].length; j++) {
                content = content + this.map[i][j];
            }
        
        content = content + "\n";
    }

    this.pane.setText (content);
}
    
    
private void clearScreen(){
        this.pane.setText("");
    }
    
}
```


```
import View.*;

public class Game {


    public Game() {

          DungeonFrame df = new DungeonFrame();
    }

    public static void main(String[] args) {

        new Game();


    }
}
```

Das wären die drei.
Die DungeonFactory, die DungeonFrame für das Fenster und das zeichnen und die Game zum ausführen.
Tut mir Leid, wenn das alles etwas kompliziert und unbeholfen von mir aufgezogen wird, aber ich bin was sowas angeht zum ersten mal in einem Forum unterwegs.
Ich hoffe Ihr könnt mir trotzdem helfen 

LG

Telrion


----------



## Telrion (5. Jun 2012)

Ich hab mir das ganze nun noch mehrmals intensiv angeguckt und hab mal gezeichnet was der Debugger mir ausgibt, das sieht schon ziemlich gut aus, nur irgendwie zeichnet mir mein Programm nur die Erste Wand und keine andere. Die Wände nach der Ersten stehen also aber werden nicht gezeichnet. Hat wirklich niemand eine Idee?


----------



## Fu3L (6. Jun 2012)

Bevor du die Hoffnung aufgibst: Ich gucks mir morgen mal an. Letzten Tage wenig Zeit gehabt


----------



## Fu3L (7. Jun 2012)

Also ich bekomme eine Umrandung und hin und wieder eine weitere Spalte mit Wänden, die an unterschiedlicher Position entstehen kann. Insgesamt werden etwa 160 Nodes erzeugt und ich kann etwa 160 Wandtiles zählen (bzw. mit Paint.net ermitteln).
Der Fehler wird also in der Aufspaltung der Nodes liegen. Ich hoffe, das hilft schonmal weiter.


----------



## Telrion (7. Jun 2012)

Mhm das wundert mich, ich hab mal mit Hilfe des Debuggers einen 25x25 Dungeon per Hand gezeichnet, der sah eigentlich schon ganz gut aus. Problem war hier nur, dass er mir nur die Umrandung und die erste "spaltende Wand" angezeigt hat, quasie child 1 und child 2. Die anderen childs existierten jedoch in den Variablen.
Hab den Test auch mehrfach durchgeführt, immer mit dem Ergebnis: Umrandung + erste "splitWand" und der rest nur in den Variablen existent.
Kann durchaus sein, dass ich da einen Denkfehler habe, aber da mein Tutor auch recht ratlos ist und nicht versteht warum es nicht läuft, liegt meine ganze Hoffnung bei euch 
Mein Denkansatz: Entweder ist es wirklich ein reiner Fehler beim Zeichnen, oder die childs der childs werden nicht richtig übergeben. Wundert mich aber dann warum es bei den ersten beiden klappt.
Falls du noch etwas herausfinden kannst, ich bin für alle Vorschläge offen und danke schonmal, dass du es dir überhaupt angeguckt hast


----------



## Telrion (7. Jun 2012)

Wie hast du denn die Nodes ermittelt, bei mir waren es irgendwie wesentlich weniger, sprich im Debugger Oo


----------



## Fu3L (7. Jun 2012)

Hab ne statische Klassenvariable eingebaut und bei jedem erzeugten Node im Konstruktor um 1 hochgezählt  Ich habs allerdings nicht genau genug nachvollzogen, kann sein, dass auch einige weggeworfen werden danach.

Und ich gehe doch richtig in der Annahme, dass jedes Tile der Wand (man sieht ja leichte Unterteilungen) einem Node entspricht?


----------



## bwbg (7. Jun 2012)

OT: Welchen Sinn (von der Aufgabenstellung mal abgesehen) macht es, für das Spielfeld (die Kacheln) eine Baumstruktur zu verwenden? Die einzelnen Kacheln liegen diskret und direkt adressierbar in einem Array vor. Eine Baumstruktur bringt hier keine Laufzeitverbesserung - ganz im Gegenteil.

Um große Spielfelder zu verwalten, fiele mir als Organisationsstruktur (Auslagern/Persistenz) eine einfache Aufteilung in Chunks ein.

Grüße... bwbg


----------



## Telrion (7. Jun 2012)

Hey bwbg das mit der Baumstrucktur ist eine Vorgabe unseres Dozenten, er sagt mit der Baumstruktur wird die ganze Geschichte später besser zu Speichern und zu Laden sein. 
Naja da ich wie gesagt erst seit ca. 3 Monaten Java kennenlerne und nebenbei ja auch noch anderen Kram studieren muss, dachte ich mir folgst du der Anweisung des Dozenten einfach mal 

So zu Fu3l, mein Node ist ja als public Node(char[][] room, int x, int y) definiert, die Wand des neuen rooms erstelle ich durch die split Methoden, dann weise ich das ganze den childs zu und zeichne den neuen Raum in der split Methode. also ist nicht jedes Tile ein Node sondern eigentlich bilden die Unterräume mit dem oberen linken Eckpunkt (der zum späteren richtigen zusammenbau helfen soll) die Nodes.


----------



## Telrion (8. Jun 2012)

Ok ich bin etwas weiter gekommen glaub ich.
Ich vermute, dass das Hauptproblem ist, dass nur das gezeichnet wird, was im root also im Mutterraum liegt, da in der generate() nur die root vorkommt. Da dies nur die Unterteilung für die ersten beiden childs ist, würde das Problem erklärt sein. Das child danach ist ja quasie nicht mehr child vom root sondern chid vom child. Bin momentan schon am basteln, irgendwelche Vorschläge von euch?


----------

