Zufallsdungeon in Baumstruktur [Wände fehlen]

T

Telrion

Gast
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 ;)

Java:
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
 
T

Telrion

Gast
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 :D
 

Fu3L

Top Contributor
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.
 
T

Telrion

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

Java:
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("");
    }
    
}

Java:
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
 
T

Telrion

Gast
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

Top Contributor
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.
 
T

Telrion

Gast
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 :D
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 :)
 
T

Telrion

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

Fu3L

Top Contributor
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

Mitglied
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
 
T

Telrion

Gast
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 :D

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.
 
T

Telrion

Gast
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?
 

Neue Themen


Oben