user3793935
user3793935

Reputation: 489

Draw a coordinate System on JPanel

I wrote a random Dungeon generator, that gives me coordinates like this(S= Start):

enter image description here

Now I would like to print my coordinates on a JPane (or whatever is common for that), but I have no clue where to start ;-(

I saw that I can paint something like rectangles or triangles on a JPane, so I tried to overwrite the paintComponent Method for the Graphics Object with my Console Output function (that is exactly the same, except that I draw instead of print())

@Override
    public void paintComponent (Graphics g) {

    boolean tmpKoordinateExistiert = false;
    boolean tmpSpielerKoordiante = false;

    for(int y =0;y <=20; y++) {
        for(int x = 0; x <=20; x++) {
            if(this.sindKoordinatenEinTreffer(x,y,this.spielerKoordinaten.x,this.spielerKoordinaten.y)) {
                tmpSpielerKoordiante = true;
            }else {                 
                for(Point p: this.koordinatenListe) {

                    if(this.sindKoordinatenEinTreffer(x,y,p.x,p.y)) {
                        tmpKoordinateExistiert = true;
                    }

                }
            }           
            if(tmpSpielerKoordiante) {
                g.drawOval(x+10, y+10, 1, 1);
                tmpSpielerKoordiante = false;
            }else if(!tmpKoordinateExistiert) {
                    this.repaint();
                    }else {
                        g.drawRect(x+10, y+10, 1, 1);
                        tmpKoordinateExistiert = false;
                    }       

        }
        System.out.println("");
    }
}

but I only get a veeery smal version of the original thing:enter image description here

What can I do to change that? (Sorry, if that is a stupid question, but I sit here for hours and I'm to blind to find the right solution)

enter image description here

If I increase the size of the rectangles / ovals I get: The whole Dungeon generator Class:

 package de.projekt.dungeon;

    import java.awt.Point;
    import java.util.ArrayList;
    import java.util.Random;

    import de.projekt.gui.MiniMap;
    import de.projekt.map.DungeonMap;


    public class DungeonGenerator {
        /**
         * startposition des Dungeons
         * Kann im Norden, Sueden, osten, Westen liegen (Random)
         */
        private Point start;
        private Point aktuelleKoordinaten;

        /**
         * Liste aller Dungeonfelder (bzw. die Koordinaten von denen)
         */
        ArrayList<Point> koordinatenListe ; 

        public ArrayList<Point> getKoordinatenListe() {
            return koordinatenListe;
        }

        public Point getStart() {
            return start;
        }
        /**
         * 0 = Norden, 1 = Westen, 2 = Sueden, 3 = Osten
         */
        private int himmelsrichtung;
        private Random rHimmelsrichtung;
        private Random neueKoordinaten;
        private int xFaktor = 0;
        private int yFaktor = 0;
        private Random tmpz = new Random();
        /**
         * Standardkonstruktor, es werden alles Objekte instanziert, die 
         * fuer den DungeonGenerator noetig sind.
         * 
         * himmelsrichtung ergibt sich aus einer Zahl zwischen 0-4.
         * Dadurch wird Random entschieden, an welcher Stelle der Dungeon startet.
         * (N,S,O,W)
         * Es wird fuer jeden Startpunkt ein Faktor gesetzt, mit dem im Generator die 
         * x/y Koordinate multipliziert wird. Dadurch wird sichergestellt, das man nicht im
         * Osten startet, und der Dungeon dann in eben diese Richtung generiert wird.
         * 
         * Der Startpunkt wird als erste Koordinate der KoordinatenListe hinzugefuegt.
         * Anschliessend beginnt das generieren.
         * 
         * Spaeter koennte man die Mapgroeße ueber das ueberladen des Konstruktors Variabel machen,
         * Falls das dann Sinn ergibt.
         * 
         * Jeder Dungeon (Stockwerk?) hat genau eine Map!
         */
        public DungeonGenerator(int anzahlMaximalKoordinaten){
            this.koordinatenListe = new ArrayList<Point>();
            this.rHimmelsrichtung = new Random();
            this.neueKoordinaten = new Random();
            this.start = new Point();

            this.himmelsrichtung = this.rHimmelsrichtung.nextInt(3);
            switch(this.himmelsrichtung){
                // Norden
                case(0): this.start.x = 10;
                         this.start.y = 0;
                         this.yFaktor = 1;
                    break;
                // Westen
                case(1): this.start.x = 0;
                         this.start.y = 10;
                         this.xFaktor = 1;
                    break;
                // Sueden
                case(2): this.start.x = 10;
                         this.start.y = 20;
                         this.yFaktor = -1;
                    break;
                // Osten
                case(3): this.start.x = 20;
                         this.start.y = 10;
                         this.xFaktor = -1;
                    break;
            }
            koordinatenListe.add(this.start);
            this.aktuelleKoordinaten = new Point(this.start);

            this.startGenerate(anzahlMaximalKoordinaten);
        }

        /**
         * Generiere den Dungeon und uebergebe den Dungeon(Koordinaten) an die Map.
         * (Auch SpielerAnfangskoordinaten)
         */
        private void startGenerate(int anzahlMaximalKoordinaten) {
            this.generateDungeon(this.start.x, this.start.y, 0, anzahlMaximalKoordinaten);      
        }
        /**
         * Gebe das zu dem Dungeon gehoerige Mapobjekt zurueck.
         * @return Rueckgabe der Map
         */
        public DungeonMap getMap() {
            return null;
            //return map;
        }

        /**
         * Hier werden die Koordinaten generiert.
         *
         * Derzeit werden y Koordinaten bevorzugt. (da X nur incr/decr wird, wenn Y == 0 --> Nur eine 50% Chance)
         * 
         * Die Methode wird abgebrochen, sollte eine Wand erreicht werden.
         * Die Methode ruft sich ansonsten sooft auf, bis die aktuelle Koordinatenmenge der Maximalen Koordinatenanzahl entspricht
         *  
         * @param x aktuelle x Koordinate
         * @param y aktuelle y Koordinate
         * @param aktuelleKoordinatenMenge Wieviele Koordinaten umfasst der Dungeon derzeit
         * @param anzahlMaximalKoordinaten Wieviele "Spielfelder(Koordinaten)" hat der Dungeon maximal
         */
        private void generateDungeon(int x, int y,int aktuelleKoordinatenMenge, int anzahlMaximalKoordinaten) {

            int tempX = 0;
            int tempY = 0;

            while(tempX == 0 && tempY== 0) {
                tempX = this.neueKoordinaten.nextInt(2);
                tempY = this.neueKoordinaten.nextInt(2);
            }
            // gehen wir evtl links oder rechts usw., mal sehen
            int tmp = this.tmpz.nextInt(3)-1;

            // Erlaube es, auf der X / Y Achse zurueckzugehen, fuer verzweigungen
            if(this.yFaktor == -1){
                this.xFaktor =  tmp;
            }
            if(this.yFaktor == 1){
                this.xFaktor =  tmp;
            }
            if(this.xFaktor == -1){
                this.yFaktor =  tmp;
            }
            if(this.xFaktor == 1){
                this.yFaktor =  tmp;
            }
            // Wenn ich zuerst Nach Y abfrage, wird Y bevorzugt, wenn ich zuerst nach X abfrage halt X
            // wenn ich einfach ein Random 0/1 vorklatsche, und nach 0 / 1 Abfrage, dann ist das Ergebniss
            // nicht von zuerst X / Y abhaengig.
            int randomRichtung = this.neueKoordinaten.nextInt(2);

            if(randomRichtung == 0) {
                if(tempY==1) {  
                    y = y + (1 * this.yFaktor);
                }else if(tempX == 1) {
                    x = x + (1 * this.xFaktor);
                }
            }else {
                if(tempX==1) {  
                    x = x + (1 * this.xFaktor);
                }else if(tempY == 1) {
                    y = y + (1 * this.yFaktor);
                }
            }

            // Anomalie, bin betrunken, forsche spaeter
            if(x == -1)
                x=0;
            // lul?
            if(y == -1)
                y=0;

            this.aktuelleKoordinaten = new Point(x,y);
            //System.out.println("aktuelleKoordinaten: " +this.aktuelleKoordinaten);
            this.koordinatenListe.add(this.aktuelleKoordinaten);

            if((this.aktuelleKoordinaten.x == 20 && this.start.x !=20) 
              || this.aktuelleKoordinaten.y == 20 && this.start.y !=20
              || this.aktuelleKoordinaten.x == 0 && this.start.x !=0
              || this.aktuelleKoordinaten.y == 0 && this.start.y !=0) {
                return;
            }

            aktuelleKoordinatenMenge++;
            if(aktuelleKoordinatenMenge <= anzahlMaximalKoordinaten) {
                this.generateDungeon(x, y,aktuelleKoordinatenMenge, anzahlMaximalKoordinaten);
            }   else
                return;

        }



    }


My Gui Class:
    package de.projekt.gui;

    import java.awt.BorderLayout;
    import java.awt.Dimension;

    import javax.swing.JFrame;

    public class Gui extends JFrame{
        MiniMap miau = new MiniMap();
        private static final int N = 256;

        public  Gui() {
            this.setSize(400,400);
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
            this.setLayout(new BorderLayout());
            this.add(this.miau);


        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(2 * N, 2 * N);
        }


}

And my output Class:

  package de.projekt.gui;

    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.util.ArrayList;

    import javax.swing.JPanel;

    import de.projekt.dungeon.DungeonGenerator;
    import de.projekt.map.DungeonMap;

    public class MiniMap extends JPanel{

        private ArrayList<Point> koordinatenListe ; 
        private Point spielerKoordinaten;
        private DungeonGenerator map;

        MiniMap(){
            this.map = new DungeonGenerator(400);
            this.spielerKoordinaten = this.map.getStart();
            this.koordinatenListe = this.map.getKoordinatenListe();
        }


        @Override
        public void paintComponent (Graphics g) {
            super.paintComponent(g);


            boolean tmpKoordinateExistiert = false;
            boolean tmpSpielerKoordiante = false;

            for(int y =0;y <=20; y++) 

{
            for(int x = 0; x <=20; x++) {
                if(this.sindKoordinatenEinTreffer(x,y,this.spielerKoordinaten.x,this.spielerKoordinaten.y)) {
                    tmpSpielerKoordiante = true;
                }else {                 
                    for(Point p: this.koordinatenListe) {

                        if(this.sindKoordinatenEinTreffer(x,y,p.x,p.y)) {
                            tmpKoordinateExistiert = true;
                        }

                    }
                }           
                if(tmpSpielerKoordiante) {
                    g.drawOval(x, y, 10, 10);
                    tmpSpielerKoordiante = false;
                }else if(!tmpKoordinateExistiert) {
                        this.repaint();
                        }else {
                            g.drawRect(x+10, y+10, 10, 10);
                            tmpKoordinateExistiert = false;
                        }       

            }
            System.out.println("test");
        }
        System.out.println("enhde");
    }






    public void setStartPunkt(Point startPunkt) {
        this.spielerKoordinaten = startPunkt;
    }

    public ArrayList<Point> getKoordinatenListe() {
        return koordinatenListe;
    }

    public void setKoordinatenListe(ArrayList<Point> koordinatenListe) {
        this.koordinatenListe = koordinatenListe;
    }
    /**
     * Da ein Koordinatenvergleich mindestens 2 mal gebraucht wird, in einer Methode
     * @param x aktueller x Wert der Schleife
     * @param y aktueller y Wert der Schleife
     * @param koordx koordinaten vom Punkt
     * @param koordy koordinaten vom Punkt
     * @return
     */
    private boolean sindKoordinatenEinTreffer(int x, int y, int koordx, int koordy) {
        if(x == koordx && y == koordy) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * Erstmal nur eine Testausgabe usw. in der Konsole, halt bis wir GUI's haben
     */
    public void printTest() {

    }

}

Upvotes: 0

Views: 954

Answers (2)

user3793935
user3793935

Reputation: 489

The solution from MadProgrammer (but with my code):

@Override
public void paintComponent (Graphics g) {
    super.paintComponent(g);



    Graphics2D g2d = (Graphics2D) g.create();

    boolean tmpKoordinateExistiert = false;
    boolean tmpSpielerKoordiante = false;
    int shapesizeY = 0;
    for(int y =0;y <=20; y++) {
        int shapesizeX = 0;
        for(int x = 0; x <=20; x++) {
            if(this.sindKoordinatenEinTreffer(x,y,this.spielerKoordinaten.x,this.spielerKoordinaten.y)) {
                tmpSpielerKoordiante = true;
            }else {                 
                for(Point p: this.koordinatenListe) {

                    if(this.sindKoordinatenEinTreffer(x,y,p.x,p.y)) {
                        tmpKoordinateExistiert = true;
                    }

                }
            }           
            if(tmpSpielerKoordiante) {
                paintStart(g2d, shapesizeX, shapesizeY);
                tmpSpielerKoordiante = false;
            }else if(!tmpKoordinateExistiert) {
                    paintSpace(g2d, shapesizeX, shapesizeY);
            }else {
                paintHash(g2d, shapesizeX, shapesizeY);


                tmpKoordinateExistiert = false;
            }
            shapesizeX += CELL_SIZE;


        }
        shapesizeY += CELL_SIZE;

    }

}

 protected void paintSpace(Graphics2D g2d, int x, int y) {
     g2d.setColor(Color.DARK_GRAY);
     g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
 }
 protected void paintHash(Graphics2D g2d, int x, int y) {
     g2d.setColor(Color.LIGHT_GRAY);
     g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
 }

 protected void paintStart(Graphics2D g2d, int x, int y) {
     g2d.setColor(Color.LIGHT_GRAY);
     g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
     g2d.setColor(Color.RED);
     g2d.fillOval(x, y, CELL_SIZE, CELL_SIZE);
 }

Thank you so much, good Sir!

Upvotes: 0

MadProgrammer
MadProgrammer

Reputation: 347184

The smallest rendering unit is a pixel, which is, for argument sake, a little square which 1x1 in size.

When rendering something, you need to make your shape large enough to be visible for your needs, yes, you could use a pixel, but if you're like me and have spent to much time staring at a screen, you're probably going blind, so you might want something which is a little bigger.

When doing this, you also need to offset the location of the shape so it doesn't overwrite something else which is painted.

So, for example, if you have a square is 10x10, which is painted at 10x20, the next element will need to be at 20x20 to painted in the next column or 10x30 to painted on the next row, as an example.

Now, I've just hacked the maze/model together, as it's basically irrelevant to the question and demonstrated the concept of painting columns and rows of information.

Maze

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        private String[] maze = {
            "..........#S##........",
            "..........##.#........",
            "...........#.#........",
            ".............#........",
            ".....##......#........",
            "....#####.###.........",
            "#####.###.#####.......",
            "....###.########......",
            "......####.####.......",
            "......####..###.......",
            "......#####..###......",
            "......#####...##......",
            "......######..........",
            ".......######.........",
            ".......######.........",
            ".......#######........",
            "........#######.......",
            "........###...........",
            "........###...........",
            "......................",
        };

        protected static final int CELL_SIZE = 10;

        public TestPane() {
            setBackground(Color.DARK_GRAY);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(22 * CELL_SIZE, 21 * CELL_SIZE);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int y = 0;
            for (String line : maze) {
                int x = 0;
                for (char element : line.toCharArray()) {
                    switch (element) {
                        case '.': 
                            paintSpace(g2d, x, y);
                            break;
                        case '#': 
                            paintHash(g2d, x, y);
                            break;
                        case 'S': 
                            paintStart(g2d, x, y);
                            break;
                    }
                    x += CELL_SIZE;
                }
                y += CELL_SIZE;
            }
            g2d.dispose();
        }

        protected void paintSpace(Graphics2D g2d, int x, int y) {
            g2d.setColor(Color.DARK_GRAY);
            g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
        }

        protected void paintHash(Graphics2D g2d, int x, int y) {
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
        }

        protected void paintStart(Graphics2D g2d, int x, int y) {
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.fillRect(x, y, CELL_SIZE, CELL_SIZE);
            g2d.setColor(Color.RED);
            g2d.fillOval(x, y, CELL_SIZE, CELL_SIZE);
        }
    }

}

Now, if you need something which is not maintained in a linear manner, or need to randomly update some part of it. You'd need to translate the model coordinates to the physical coordinates.

Based on the example above, if I wanted to paint an element at row 5, column 15, I'd just need to multiple those two points by CELL_SIZE to give me the physical coordinates

Upvotes: 3

Related Questions