# Spielfeld aus verschiedenen Kacheln



## Schlagdraufunschluss_124 (12. Jun 2017)

Hi! Seit einiger Zeit versuch ein Spielfeld aus verschieden Kacheln(z.B. Gras, Wasser,...) zu programmieren. Dabei bin ich auf folgendes Problem gestoßen: Zuersteinmal les ich aus einer Textfile in der Helper-Klasse heraus, welche Kachelart das Programm zeichen muss(z.B. 1 für Gras , 0 für nichts, 2 für Sand, etc). Da die Position der Kacheln ja statisch ist, und nie verändert wird, benutze ich hierfür 2 for-Schleifen in der Label-Klasse. Danach kommt eine Switch-Case-Verzweigung, wo ich die Kachelart auswerte.Hierfür brauch ich ja die Zahlen aus der Textfile, aber immer wenn ich das Programm starte, zeigt mir das Sysout vor der Case Verzweigung immer entweder nur eine 1, eine 2 oder eine 0 an, obwohl die Zahlen in der Textfile sich verändern.Ich bräuchte also irgendwas, was meine Zahl in der Case Verzweigung aktualisiert.Weiß irgendjemand von euch da was??
PS: (Ich bin totaler Anfänger, also kann es sein, dass ich auch einen totalen Stuss zusammengeschrieben habe)



```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JLabel;

public class Label extends JLabel {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        System.out.println("kachelnummer:" + var.kachelnummer);

       
        for (int x = 0; x <= var.spielfeldbreite; x++) {
            for (int y = 0; y <= var.spielfeldhöhe; y++) {

                switch (var.kachelnummer) {
                case 0:
                    g.fillRect(x * 50, y * 50, 50, 50);
                    break;
                case 1:
                    g.drawImage(var.igras, x * 50, y * 50, 50, 50, null);
                    break;
                case 2:
                    g.drawImage(var.iworld, x * 50, y * 50, 50, 50, null);
                    break;
                default:System.out.println("Default!");
                }
                repaint();
            }

        }
    }

}
```

Hier die Utility-Klasse:


```
import java.io.File;
import java.util.Scanner;

public class Utility {

    public Utility() {
        try {
            var.tilesc = new Scanner(new File("Resources/GameData/Level_01.txt"));

            while (var.tilesc.hasNextLine()) {
                var.scanner = true;
                /*
                 * var.spielfeldhöhe++;
                 *
                 * if (var.tilesc.hasNext()) { var.spielfeldbreite++;
                 *
                 * }
                 */
                System.out.println("Br:" + var.spielfeldbreite + "\tHö:" + var.spielfeldhöhe);
                var.leveltiles = var.tilesc.next();
                var.kachelnummer = Integer.parseInt(var.leveltiles);
                System.out.println("Suche:" + var.kachelnummer);

            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Could not read File!");
        }
    }

}
```


----------



## Robat (13. Jun 2017)

Du überschreibst ja deine kachelnummer Variable immer. Anstatt nur ein int wert zu nehmen würde ich die Zahlen in ein Array einlesen und dann in deiner for Schleife immer auf das Array an der momentanen Stelle prüfen.


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Ok, könntest Du mir den Code schicken, weil ich checks irgendwie nicht...


----------



## Robat (13. Jun 2017)

Was genau verstehst du denn nicht? Wenn ich dir den fertigen Code schicke hast du ja keinen Lerneffekt.. 
Verstehst du denn was das Problem ist? Also warum dein Code momentan nicht funktioniert?


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Also ich schätze mal das Problem ist, dass meine Variable nur einmal abgerufen wird..-Deswegen das Array oder?

Hier hab die Zahlen jetzt mal in ein Array gepackt.


```
import java.io.File;
import java.util.Scanner;

public class Utility {

    public Utility() {
        try {
            var.tilesc = new Scanner(new File("Resources/GameData/Level_01.txt"));

            while (var.tilesc.hasNextLine()) {
               
               
                var.zahlenstring = var.tilesc.nextLine();
                var.splittedstring= var.zahlenstring.split(" ");
                var.kachelnummer= new int [var.splittedstring.length];
                for(int i =0; i<var.splittedstring.length;i++){
                var.kachelnummer[i] = Integer.parseInt(var.splittedstring[i]);
                System.out.println("Suche:" + var.kachelnummer[i]);
                }
               

            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Could not read File!");
        }
    }

}
```

Allerdings weiß ich noch nicht wie ich das Array bzw. wo ich die For Schleife in meiner Label Class verarbeiten soll...
Bei meinem Code gibts gerade immer ein Crash..


```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JLabel;

public class Label extends JLabel {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // System.out.println("kachelnummer:" + var.kachelnummer);

        for (int x = 0; x <= var.spielfeldbreite; x++) {
            for (int y = 0; y <= var.spielfeldhöhe; y++) {
                for (int i = 0; i <= var.splittedstring.length; i++) {
                    System.out.println("Kachelnummer:"+var.kachelnummer[i]);

                    switch (var.kachelnummer[i]) {
                    case 0:
                        g.fillRect(x * 50, y * 50, 50, 50);
                        break;
                    case 1:
                        g.drawImage(var.igras, x * 50, y * 50, 50, 50, null);
                        break;
                    case 2:
                        g.drawImage(var.iworld, x * 50, y * 50, 50, 50, null);
                        break;
                    default:
                        System.out.println("Default!");
                    }
                    repaint();
                }
            }

        }
    }

}
```


----------



## Robat (13. Jun 2017)

Ich würde das ganze etwas anders aufbauen, was dir die Arbeit später erleichtern sollte.

Dein Array `kachelnummer` würde ich als 2D Array anlegen. So kannst du es direkt als dein Spielfeld interpretieren. Anhand der Zahl an der Stelle [x][y] kannst du auch direkt bestimmen was an der Stelle [x][y] gezeichnet werden soll.
Beim einlesen liest du also Zeile für Zeile ein (was also deiner x Koordinate entsprechen würde) und splittest dann an einem Delimiter. Diese gehst du dann bspw. mit einer for-Schleife durch und hast somit deine y Koordinate.

Beim zeichnen kannst du jetzt ganz einfach deine 2 for-Schleifen benutzen um zu zeichnen. Vorher gleichst du dann mit deinem 2D Array ab was an dieser Stelle für eine Zahl steht.

*Offtopic: *Wie bist du auf die Idee mit der Variablen-Klasse gekommen? Ist eigentlich recht ungewöhnlich für eine OOP Sprache wie Java.


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Mmh, aber wie weiß dann das Programm welche Kachel es zeichnen muss?Und ich hab noch nicht ganz verstanden wie ich aus der Textfile mit der Nummer der Kachelart meine x-Position und dadurch auch meine y-Pos. bestimmen kann.
Und wie soll ich das 2 dimensionale Array genau einlesen

PS:Ich dachte dadurch wirds übersichtlicher...


----------



## Robat (13. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> PS:Ich dachte dadurch wirds übersichtlicher...


Naja mMn erreichst du damit eher das Gegenteil. Ein Aspekt von OOP ist ja, dass es Objekte gibt und jedem Objekt bestimmte Attribute zugewiesen werden können. Somit ist ganz klar (und logisch) dass ein Klasse Katze kein Attribut hat, welches die Anzahl der Räder am Auto beschreibt. Mit einer seperaten Klasse hast du alle Variablen in einer Klasse. Wenn du jetzt mehrere Variablen hast die das gleiche Aussagen, aber zu unterschiedlichen Anwendungen gehören, kann das verwirren.

Hier mal ein kleiner Pseudocode.

Feld.txt

```
0 0 0 0 
0 1 2 0
0 2 1 0
0 0 0 0
```

Dann gibt es - wenn ich mich auf deine var Klasse beziehe - ein Array wo du die Typen drin speicherst.

```
public void readFile()
{
     int lineCount = 0;
     Scanner scanner = new Scanner(new File("..."));
     while(hasNextLine())
     {
           String lineParts[] = nextLine().split(" ");
          for each lineParts
          {
               vars.fieldArray[lineCount][i] = lineParts[i];
          }
     }
}
```

Wenn du dann zeichnest kannst du es ja machen wie gehabt.
2 for-Schleifen durchlaufen und mit einer switch-case schauen was du zeichnen musst. 
Dazu schaust du einfach was in dem Array an stelle [x][y] steht:

```
for(int x = 0; x < vars.fieldArray.length; x++)
    for(int y = 0; y < vars.fieldArray[x].length; y++)
        switch(vars.fieldArray[x][y])
        {
              case "0": g.draw(...); break;
              ....
        }
```


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

In ein Interger muss ich's aber trotzdem noch konvertieren, oder?


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Sorry, dass ich grad so auf dem Schlauch stehe, aber jz überschreibt er mir mein Array wenn ich versuche die Zahlenstrings in Integers umzuwandeln.
Und meinst du mit " for each lineparts" die nummern einer einzelnen Zeile oder die, der ganzen Textfile?


----------



## Robat (13. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Und meinst du mit " for each lineparts"


Jedes Element im Array `lineparts` durchlaufen.


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Er überschreibts leider aber immer meinen String array beim Einlesen

```
var.splittedstring = var.tilesc.nextLine().split(" ");
               
               
               
                var.kachelnummer = new int[var.splittedstring.length];
                for (int i = 0; i < var.splittedstring.length; i++) {
                    var.kachelnummer[i] = Integer.parseInt(var.splittedstring[i]);
                    //System.out.println("Suche:" + var.kachelnummer[i]);
                }
```


----------



## Robat (13. Jun 2017)

Du machst ja auch noch nicht das, was ich oben geschrieben habe 
Mach aus `kachelnummer` doch erstmal ein 2D-Array


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Mit welcher Länge?
So etwa?

```
var.kachelnummer = new int[var.splittedstring.length][];
```


----------



## Robat (13. Jun 2017)

Hier mal fix was zusammen geschrieben (ungetestet).

```
List<int[]> rows = new ArrayList<>();

try
{
    Scanner scanner = new Scanner(new File("level1.txt"));

    while (scanner.hasNextLine())
    {
        // neue Zeile einlesen
        String zahlenString = scanner.nextLine();

        // einzelne Spalten der Zeile extrahieren
        String[] lineArray = zahlenString.split(" ");

        // Array für eine Zeile [Länge ist die Anzahl der Spalten]
        int[] intArray = new int[lineArray.length];

        for (int i = 0; i < lineArray.length; i++)
        {
            // Jedes Elemnt von einen String in ein int wandeln
            intArray[i] = Integer.parseInt(lineArray[i]);
        }
        // Zeile der Liste hinzufügen
        rows.add(intArray);
    }

    // gameField Array initialisieren. (Anzahl der Zeilen bekommen wir aus der rows Liste
    var.gameField = new int[rows.size()][];

    // die einzelnen Zeilen in das Array kopieren
    for (int i = 0; i < rows.size(); i++)
    {
        var.gameField[i] = rows.get(i);
    }
}
catch (FileNotFoundException ex)
{
    ex.printStackTrace();
}
```
Danach solltest du ein Array haben was dem Inhalt deiner Datei entsprechen sollte.. bspw so:

```
0 0 0 0 0 0 0 0 0
0 1 1 2 1 1 1 1 0
0 1 1 1 2 1 1 1 0
0 1 1 1 2 1 1 1 0
0 1 1 1 2 1 1 1 0
0 0 0 0 0 0 0 0 0
```

Jetzt kannst du in der `paintComponent(Graphics g)` Methode dieses Array einfach durchlaufen und mit einer switch-case prüfen was gezeichnet werden soll.
Wenn der Wert in dem Array 0 ist wird meinetwegen eine Wand gezeichnet, wenn 1 Gras, sonst Weg. Oder wie auch immer.


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Hab ich gemacht... Ich schätze mal die Utility Klasse fuktioniert. Aber ich hab ein Problem bei den For schleifen in meiner paint-Methode


```
for (int x = 0; x < var.spielfeld.length; x++) {
            for (int y = 0; y <var.spielfeld[x].length; y++) {
              
              

                    switch (var.spielfeld[x][y]) {
                    case 0:
                        g.fillRect(x * 50, y * 50, 50, 50);
                        break;
                    case 1:
                        g.drawImage(var.igras, x * 50, y * 50, 50, 50, null);
                        break;
                    case 2:
                        g.drawImage(var.iworld, x * 50, y * 50, 50, 50, null);
                        break;
                    default:
                        System.out.println("Default!");
                    }
                    repaint();
              
            }
          

        }
```

PS: Wie soll ich des eigentlich sonst machen anstatt der Variablen Klasse?


----------



## Robat (13. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Aber ich hab ein Problem bei den For schleifen in meiner paint-Methode


Geht das noch genauer? 



Schlagdraufunschluss_124 hat gesagt.:


> PS: Wie soll ich des eigentlich sonst machen anstatt der Variablen Klasse?


Dein Projekt ordentlich in Klassen aufteilen, wo jede Klasse über die Variablen bescheid weiß für die sie verantwortlich ist.


----------



## Schlagdraufunschluss_124 (13. Jun 2017)

Wenn du damit was anfangen kannst...


```
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
   at Label.paintComponent(Label.java:18)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JLayeredPane.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paintToOffscreen(Unknown Source)
   at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
   at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
   at javax.swing.RepaintManager.paint(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
   at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
   at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
   at java.awt.Container.paint(Unknown Source)
   at java.awt.Window.paint(Unknown Source)
   at javax.swing.RepaintManager$4.run(Unknown Source)
   at javax.swing.RepaintManager$4.run(Unknown Source)
   at java.security.AccessController.doPrivileged(Native Method)
   at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
   at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.access$1200(Unknown Source)
   at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
   at java.awt.event.InvocationEvent.dispatch(Unknown Source)
   at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
   at java.awt.EventQueue.access$500(Unknown Source)
   at java.awt.EventQueue$3.run(Unknown Source)
   at java.awt.EventQueue$3.run(Unknown Source)
   at java.security.AccessController.doPrivileged(Native Method)
   at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
   at java.awt.EventQueue.dispatchEvent(Unknown Source)
   at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
   at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
   at Label.paintComponent(Label.java:18)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at javax.swing.JLayeredPane.paint(Unknown Source)
   at javax.swing.JComponent.paintChildren(Unknown Source)
   at javax.swing.JComponent.paintToOffscreen(Unknown Source)
   at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
   at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
   at javax.swing.RepaintManager.paint(Unknown Source)
   at javax.swing.JComponent.paint(Unknown Source)
   at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
   at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
   at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
   at java.awt.Container.paint(Unknown Source)
   at java.awt.Window.paint(Unknown Source)
   at javax.swing.RepaintManager$4.run(Unknown Source)
   at javax.swing.RepaintManager$4.run(Unknown Source)
   at java.security.AccessController.doPrivileged(Native Method)
   at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
   at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
   at javax.swing.RepaintManager.access$1200(Unknown Source)
   at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
   at java.awt.event.InvocationEvent.dispatch(Unknown Source)
   at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
   at java.awt.EventQueue.access$500(Unknown Source)
   at java.awt.EventQueue$3.run(Unknown Source)
   at java.awt.EventQueue$3.run(Unknown Source)
   at java.security.AccessController.doPrivileged(Native Method)
   at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
   at java.awt.EventQueue.dispatchEvent(Unknown Source)
   at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
   at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.run(Unknown Source)
```

Was mir aufgefallen ist, wenn ich ein sysout vor der case-switch mache kommt da bei var.spielfeld.length = 0 raus. Liegt es vielleicht daran?


----------



## Schlagdraufunschluss_124 (14. Jun 2017)

?


----------



## Harry Kane (14. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> ?


*seufz* Ein push ohne jede weitere Information.
Hier mal ein bisserl Feedback:

1.      Bei Fehlermeldungen nicht nur den stack trace mitposten, sondern auch den Code zeigen, wo der Fehler auftritt und die genaue Zeile markieren. Wenn du schon die Vermutung hast, dass der Fehler in der vars-Klasse liegen könnte, dann zeige auch die Klasse! Woher soll ein Aussenstehender wissen, was da passiert?
2.      Nicht von JLabel ableiten, sondern von JComponent. JLabels dienen zum Anzeigen von Text und/oder Icons, und nicht von einer komplexeren Welt.
3.      Deine Arbeitsteilung zwischen Utility und deiner vars-Klasse ist unschön und nicht intuitiv. Um vars mit Leben zu füllen, musst du den Konstruktor von Utility aufrufen. Die so erzeugte neue Utility-Instanz hat aber abgesehen davon, dass sie vars mit Leben befüllt, keinen Nutzwert. Sie ist einfach eine Erweiterung von Object ohne eigene Methoden oder Variablen. Vor allen Dingen „var.tilesc“ ist Murks. Ein normaler Scanner, der in Utility (oder in einer nützlicheren Klasse) instanziiert wird, tut es genauso. Zu vars hast du gar nix geschrieben. Heisst die Klasse vars, und hat sie nur statische Attribute? Von so einer Architektur kann ich nur abraten. Scheint mir ein Beispiel für ein Gott-Klasse (ein Antipattern) zu sein.
4.      Du hast ein repaint in deiner paintComponent drin -> Endlosschleife!


----------



## Schlagdraufunschluss_124 (15. Jun 2017)

Sorry, war vielleicht ein bisschen unrast von mir....
Hier die var Klasse :


```
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class var {

   static JFrame mainfraim;
   static JLabel mainlabel;
   static Scanner tilesc;

   static int framewidht = 1000, frameheight = 1000;
   static String zahlenstring;
   static String[] splittedString;
   static int [] zeilenAnzahl;

   static int[][] spielfeld;
   static List<int[]> zeile = new ArrayList<>();
   static int länge;
   static int spielfeldbreite = 0, spielfeldhöhe = 2;
   static BufferedImage igras, iworld;
   static boolean scanner;

   public var() {
       try {
           igras = ImageIO.read(new File("Resources/Textures/gras01.png"));
           iworld = ImageIO.read(new File("Resources/Textures/rpg.png"));

       } catch (IOException e) {
           System.out.println("Bild konnte nicht geladen werden!");
           e.printStackTrace();
       }
   }

}
```
Aber ich denke nicht, dass es direkt an meiner var Klasse liegt sondern lediglich an der "Übergabe" von der Utility klasse an meine paint methode, da ja in der Utility Klasse ja alles richtig ausgelesen wird.Wie muss ich des also übergeben? Mit einem Konstruktor?


----------



## Harry Kane (15. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Aber ich denke nicht, dass es direkt an meiner var Klasse liegt sondern lediglich an der "Übergabe" von der Utility klasse an meine paint methode, da ja in der Utility Klasse ja alles richtig ausgelesen wird.Wie muss ich des also übergeben?


Was willst du wem übergeben?
var.spielfeld wird im gezeigten Code nicht instanziiert. Deswegen vermute ich, dass beim Aufruf von var.spielfield.length die NPE fliegt. Diese Vermutung steht leider im Widerspruch zu


Schlagdraufunschluss_124 hat gesagt.:


> wenn ich ein sysout vor der case-switch mache kommt da bei var.spielfeld.length = 0 raus.


Zu deiner var-Klasse: wie oben vermutet, ein Sammelsurium von statischen Objekten ohne wirklichen Mehrwert. Wenn du für einen Einlesevorgang einen Scanner benötigst, kannst du ihn direkt dort instanziieren, wo du ihn brauchst, anstatt ihn über var.tilesc zu holen.splittedString und zeilenanzahl sehen für mich auch so aus, als bräuchte man sie nur beim Einlesen. Und obwohl var nur statische bzw. Klassenvariablen hat, muss trotzdem der Konstruktor aufgrufen werden, damit igras und iworld initialisiert werden.


----------



## Schlagdraufunschluss_124 (15. Jun 2017)

Naja, ich dachte eben, dass er ,wenn var .spielfeld.lenght =0 ist, dass die Variablen (also das Array spelielfeld) noch nicht in paint Methode noch nicht "deklariert" hat und sie so noch im "Ursprungszustand " sind. Also dachte ich ich muss das Array (vielleicht mit einem konstruktor) übergeben, sodass die paint  Methode Attribute hat womit sie etwas anfangen kann...Würde das das Problem lösen oder weißt Du woran es hängt und wie man das lösen kann?


----------



## Harry Kane (16. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Würde das das Problem lösen oder weißt Du woran es hängt und wie man das lösen kann?


Steht in meinem Beitrag. Mal abgesehen davon, dass du dir offensichtlich kaum Mühe beim Formulieren deines Beitrages gegeben hast, hast du meinen Beitrag offenbar nicht verstanden.
Wenn eine Variable nicht deklariert ist, lässt sich der Code gar nicht erst kompilieren. Und var.spielfeld (oder meinetwegen auch spelielfeld) ist als statische Variable in der var-Klasse deklariert, wird aber im bisher gezeigten Code nicht initialisiert und ist dementsprechend null. Das bedeutet nicht, das etwas den Zahlenwert null hat! Wenn var.spielfeld aber null ist, wird die Abfrage von var.spielfeld.length eine NullPointerException auslösen und nicht den Zahlenwert 0 zurückliefern.
Lösung: var.spielfeld initialisieren. Da Arrays eine feste Größe haben, und diese Größe vor dem Einlesen der Datei noch nicht bekannt ist, solltest du die Werte bei Einlesen der Datei zunächst in einer dynamischen Datenstruktur (dyamisch im Sinne von "variabler Größe", Näheres dazu s. Beitrag von @Robat) speichern, und aus der Datenstruktur nach dem Einlesen ein Array machen.
Mittelfristig solltest du allerdings dein var-Klasse wegschmeissen und wie von @Robat angedeutet, die Arbeitsteilung zwischen den Klassen verbessern:
Eine Klasse (TileReader oder TileImporter) zum Einlesen der Datei und zur Erzeugung des int[][] arrays.
Eine weitere Klasse (TileModel), die das int[][] array von TileReader kapselt und über eine intuitive API benutzbar macht, z. B. mit Methoden getRowCount(), getColumnCount() und Image getTileAt(int row, int col). TileReader sollte in einer geeigneten Methode (z. B. readTiles()) eine Instanz von TileModel zurückliefern.
Eine dritte Klasse (TileView), die eine Referenz auf eine Instanz von TileModel hält, daraus die Tiles abfragt und sie zeichnet. Diese dritte Klasse würde so ähnlich aussehen wie deine Label-Klasse, sollte alerdings von JComponent abgeleitet sein.
Die Hauptklasse sollte Referenzen auf eine Instanz von TileReader und TileView halten, und z. B. bei Klick auf einen JButton per JFileChooser dem Benutzer die Möglichkeit geben, eine Datei auszuwählen, die ausgewählte Datei an den die Methode readTiles() von TileReader zu übergeben, und die von readTiles() zurückgelieferte Instanz per setter an die Instanz von TileView zu übergeben. TileView muss sich dann neu zeichnen.


----------



## Schlagdraufunschluss_124 (16. Jun 2017)

Ich dachte mein Array gamefield oder auch spielfeld wird in der Utility Klasse initialisiert:


```
for (int i = 0; i < rows.size(); i++)
    {
        var.gameField[i] = rows.get(i);
    }
```


----------



## Harry Kane (16. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Ich dachte mein Array gamefield oder auch spielfeld wird in der Utility Klasse initialisiert


In deinem bisher geposteten Code hat die Klasse var keine Variable gamefield. Die taucht nur in dem Schnipsel von @Robat auf. Mir ist schleierhaft, mit welchem Code du gerade arbeitest. Und solange ich nicht weiss, mit welchem Code du gerade arbeitest, und welche Fehlermeldung in welcher Klasse und Zeile geworfen wird, ist jeder weitere Kommentar von mir wohl überflüssig.


----------



## Schlagdraufunschluss_124 (16. Jun 2017)

```
import java.io.File;
import java.util.Scanner;

public class Utility {
static int count=0;
    public Utility() {
        try {
            var.tilesc = new Scanner(new File("Resources/GameData/Level_01.txt"));

            while (var.tilesc.hasNextLine()) {
               
                var.zahlenstring = var.tilesc.nextLine();
                var.splittedString= var.zahlenstring.split(" ");
                var.zeilenAnzahl = new int[var.splittedString.length];
               
                for (int i=0; i<var.zeilenAnzahl.length;i++){
                    var.zeilenAnzahl[i]=Integer.parseInt(var.splittedString[i]);
                }
                var.zeile.add(var.zeilenAnzahl);
                for(int f:var.zeilenAnzahl){
                    System.out.println("Zeilen "+f);
                    }
           
                var.spielfeld = new int [var.zeile.size()][];
                for (int i = 0; i < var.zeile.size(); i++)
                {
                    var.spielfeld[i] = var.zeile.get(i); // Initialisierung ?
```
Ich hab ja extra deswegen "gamefield !oder auch! speilfeld" geschrieben...


----------



## Harry Kane (16. Jun 2017)

Schlagdraufunschluss_124 hat gesagt.:


> Ich hab ja extra deswegen "gamefield !oder auch! speilfeld" geschrieben.


Dann schreib den richtigen Variablennamen hin und nicht zwei Alternativen. Wenn sich die Benennung gegenüber früheren Codeschnipseln geändert hat, bitte darauf hinweisen. Ansonsten macht es keinen Spass, zu helfen.
Falls der Code nach wie vor Probleme macht, kannst du ja nochmal was posten, und zwar bitte, wie in einem früheren Post von mir gewünscht, mit stack trace, und mit aktuellem Code und markierter Zeile, wo der Fehler auftritt.


----------



## Schlagdraufunschluss_124 (16. Jun 2017)

Natürlich macht der Code nach wie vor Probleme....


```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JLabel;

public class Label extends JLabel {

   private static final long serialVersionUID = 1L;

   protected void paintComponent(Graphics g) {
       super.paintComponent(g);

       Graphics2D g2d = (Graphics2D) g;
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    

       for (int x = 0; x < var.spielfeld.length; x++) { // Hier kommts zum stillstand(Ich kann nicht einmal var.speilfeld.lenght per sysout ausgeben) -> NullPointerExeption-> Was meinst du mit dynamisch?
           for (int y = 0; y <var.spielfeld[x].length; y++) {
               System.out.println("kachelnummer:" + var.spielfeld[x][y]);
            

                   switch (var.spielfeld[x][y]) {
                   case 0:
                       g.fillRect(x * 50, y * 50, 50, 50);
                       break;
                   case 1:
                       g.drawImage(var.igras, x * 50, y * 50, 50, 50, null);
                       break;
                   case 2:
                       g.drawImage(var.iworld, x * 50, y * 50, 50, 50, null);
                       break;
                   default:
                       System.out.println("Default!");
                   }
                   repaint();
            
           }
        

       }
   }

}
```

Hab übrigens noch ne Frage: Wenn ich var. spielfeld ausgebe in ner for Schleife, dann kommt so ein Quark heraus:

Inhalt[I@378fd1ac
Liegt das daran,weil ich es falsch ausgebe oder daran,dass etwas nicht stimmt?


```
for (int i = 0; i <  var.spielfeld.length; i++)
               {
                   System.out.println("Inhalt"+var.spielfeld);
               
               }
```


----------



## Harry Kane (16. Jun 2017)

Dann ist var.spielfeld wohl null, d. h. zu em Zeitpunkt, an dem die paintComponent() aufgerufen wird, nicht initialisiert. Quick and dirty Lösung: zu Beginn der paintComponent() prüfen, ob var.spielfeld null ist. Wenn ja, mit return aus der Methode raus.
Der "Quark" ist die Ausgabe, wen toString() auf einem Array aufgrufen wird. Wenn du es schöner haben möchtest:

```
Arrays.toString(var.spielfeld[i])
```


----------



## Schlagdraufunschluss_124 (16. Jun 2017)

Danke für den Tipp mit dem Array, leider funzt die paint Methode noch nicht so ganz: Zwar kommt kein stack trace und keine NPE, aber spielfeld bleibt immer noch null.
Zum test habe ich einen sysout gemacht in abfrage.... Es wird zwei mal ausgegeben...

Console: 
Hii
Hii



```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JLabel;

public class Label extends JLabel {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(var.spielfeld==null){                               // Hier die abfrage
            System.out.println("Hii");
            return ;
       
        }

        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

     
        System.out.println("Länge" + var.spielfeld.length);
        for (int x = 0; x < var.spielfeld.length; x++) {
            for (int y = 0; y < var.spielfeld[x].length; y++) {
                System.out.println("kachelnummer:" + var.spielfeld[x][y]);

                switch (var.spielfeld[x][y]) {
                case 0:
                    g.fillRect(x * 50, y * 50, 50, 50);
                    break;
                case 1:
                    g.drawImage(var.igras, x * 50, y * 50, 50, 50, null);
                    break;
                case 2:
                    g.drawImage(var.iworld, x * 50, y * 50, 50, 50, null);
                    break;
                default:
                    System.out.println("Default!");
                }
                repaint();

            }

        }
       
    }

}
```


----------



## Harry Kane (17. Jun 2017)

Wie oft paintComponent aufgerufen wird, kannst du nicht beeinflussen. Damit dein Konstrukt überhaupt funktioniert, musst du erst new Utility aufrufen, damit var gefüllt wird (wie oben schonmal erwähnt, halte ich es für Unfug, den Konstruktor einer Klasse aufzurufen, damit statische Vartiablen einer anderen Klasse gesetzt werden), dann dein Label instanziieren, in die Gui packen, und dann die Gui sichtbar machen.
Wenn zuerst die Gui gebaut und sichtbar gemacht wird (also die paintComponent von Label schon aufgerufen wurde), und dann var gefüllt wird, bekommt Label davon nichts mit. Du müsstest nach dem Befüllen von var ein Neuzeichnen von Label erwzwingen (z. B. das Fenster in dem Label steckt, kurzzeitig verstecken und dann wieder in den Vordergrund holen).
Du hast übrigens keine der Tipps umgesetzt, die dir hier gegeben wurden. Z. B. hast du immer noch ein repaint() in der paintComponent drin. Das wird zu einer Endlosschleife führen: repaint() sorgt dafür, dass die Komponente bei der nächsten Gelegenheit neu gezeichnet wird, beim Neuzeichnen wird paintComponent aufgerufen, die ruft repaint() auf, usw.
Ich klinke mich mal aus, den so macht das keinen Spass.


----------



## Schlagdraufunschluss_124 (17. Jun 2017)

Ich hab jetzt mein Problem selber gelöst(Ist vielleicht nicht schön,funtioniert aber).
PS: Es ging mir nie darum mein Code zu einem Pattern zu machen. Ich bin wie schon oben geschrieben ein totaler Anfänger, und da nutzt es einem nichts wenn geschrieben wird, dass man in dieser Methode das istanzieren muss, um dort das Array zu kapseln und es zu einer intuitiven API machen und eine dynamische Datenstruktur aufzubauen oder wie auch immer.
Und Entschuldigung, wenn ich das mit dem repaint vergessen habe...  immerhin habe ich vergeblich auf eine simple Lösung des Problems gewartet. Stadessen sagt ihr mir,dass ich mein Code besser strukturieren soll, was ja durchaus berechtigt ist, jedoch bei dem einfachen Projekt nie zur Frage stand...

Aber trotzdem Danke, dass ihr mir mit dem Array einlesen geholfen habt, das hat zumindest meine Utility Klasse zum laufen gebracht...

Hier der Code:

```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JLabel;

public class Label extends JLabel {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(var.spielfeld==null){
            new Utility();
            System.out.println("Hii");
            System.out.println("SPPPPPPP"+var.spielfeld.length);
            return ;
      
        }

        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // System.out.println("Länge:"+var.spielfeld.length[1][1]);

      
        System.out.println("Länge" + var.spielfeld.length);
        for (int x = 0; x < var.spielfeld.length; x++) {
            for (int y = 0; y < var.spielfeld[x].length; y++) {
                System.out.println("kachelnummer:" + var.spielfeld[x][y]);

                switch (var.spielfeld[x][y]) {
                case 0:
                    g.fillRect(y * 50, x* 50, 50, 50);
                    break;
                case 1:
                    g.drawImage(var.igras, y * 50, x * 50, 50, 50, null);
                    break;
                case 2:
                    g.drawImage(var.iworld, y * 50, x * 50, 50, 50, null);
                    break;
                default:
                    System.out.println("Default!");
                }
              

            }

        }
      
    }

}
```


----------



## Harry Kane (17. Jun 2017)

Gibt halt solche und solche. Manche wollen lernen, wie es richtig geht, manche wollen halt nur, dass das, was sie sich irgendwie zusammengeschustert haben, irgendwie funktioniert. Bei einer von den beiden Varianten bin ich gerne bereit zu helfen.


----------



## Schlagdraufunschluss_124 (17. Jun 2017)

Versteh das nicht falsch, ich will auch lernen wies richtig geht (bin im übrigen gerade dabei deine Ratschläge umzusetzen -> Noch mal die Frage: was meinst du mit dynamischer Struktur?), aber so versteh ichs als Anfänger nicht wirklich. Und ohne Erfolg und immer beim Starten des Fensters nur ein ST zu sehen motiviert auf dauer halt nicht sooo.


----------



## Harry Kane (18. Jun 2017)

In < 2 h von " das nutzt nichts" zu "ich bin dabei es umzusetzen" ?
Und was ich unter "dynamisch" verstehe, ist dort erklärt, wo ich den Begriff verwendet habe. Beispielcode gibts von @Robat .


----------

