# Programmieren eines Spieles



## Xknight (9. Sep 2020)

Hallo,
ich habe hier ein Spiel  programmiert und brauche eure Hilfe dabei, denn ich überhaupt nicht was ich hier falsch gemacht habe. Immer wieder tritt diese Fehler Meldung bei mir auf.




/*
import javax.swing.*;

public class Maze {
    public Maze() {
        JFrame f = new JFrame();
        f.setTitle("The Maze Game");
        f.add(new Board());
        f.setSize(500, 400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new Maze();


    }
}
*/

/*
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Board extends JPanel implements ActionListener {

    private Timer timer;

    private Map m;
    private Player p;
    private boolean win = false;
    private String Message = "";

    private Font font = new Font("Levent", Font.BOLD, 48);

    public Board() {

        m = new Map();
        p = new Player();
        addKeyListener(new A1());
        setFocusable(true);

        timer = new Timer(25, this);
        timer.start();
    }

    public void actionPerformed(ActionEvent e) {
       if(m.getMap(p.getTileX(), p.getTileY()).equals("f")) {
           Message = "Winner";
           win = true;
       }

        repaint();
    }

    public void paint(Graphics g) {
        super.paint(g);
        if(!win) {
        for(int y = 0; y < 14; y++) {
            for(int x = 0; x < 14; x++) {
                if(m.getMap(x ,y).equals("d")) {
                    g.drawImage(m.getDesert(), x * 64, y* 36, null );
                }
                if(m.getMap(x ,y).equals("w")) {
                    g.drawImage(m.getWall(), x * 64, y* 36, null );
            }
        }
    }
        g.drawImage(p.getPlayer(), p.getTileX() * 64, p.getTileY() * 32, null );
}
        if(win) {
            g.setColor(Color.RED);

            g.setFont(font);

            g.drawString(Message, 150, 300);
        }        

}

    public class A1 extends KeyAdapter{

        public void keyPressed(KeyEvent e) {
           int keycode = e.getKeyCode();

           if(!m.getMap(p.getTileX(), p.getTileY() -1).equals("w")){
           if(keycode == KeyEvent.VK_W) {
               p.move(0, -1);
               }
           }

           if(!m.getMap(p.getTileX(), p.getTileY() +1).equals("w")) {
             if(keycode == KeyEvent.VK_S) {
                p.move(0, 1);
                       }
           }

           if(!m.getMap(p.getTileX() - 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_A) {
               p.move( -1, 0);  
             }
           }

           if(!m.getMap(p.getTileX() + 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_D) {
                 p.move(1, 0);
             }

        }


        }
    }
}
*/

import java.awt.*;
import java.io.*;
import java.util.*;

import javax.swing.ImageIcon;

public class Map {

    private Scanner sc;

    private String[] Map = new String[14];

    private Image desert, finish, wall;

    public Image getDesert() {
        return desert;
    }

    public Image getFinish() {
        return finish;
    }

    public Image getWall() {
        return wall;
    }


    public Map() {

        ImageIcon img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//desert.jfif");
        desert = img.getImage();
        img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//wall.jfif");
        wall = img.getImage();
        img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//finish.png");
        finish = img.getImage();

        openFile();
        readFile();
        closeFile();
    }

    public String getMap(int x, int y) {
        String index = Map[y].substring(x, x+1);
        return index;
    }


    public void openFile() {

        try {
          sc = new Scanner(new File("C://ptsd2020-papa//src-code//MazeGameUI//things//Map.txt"));  
        }catch(Exception e) {
            System.out.println("error");
        }
    }

    public void readFile() {
        while(sc.hasNext()) {
            for(int i = 0; i<14; i++) {
                Map_ = sc.next();
            }
        }
    }

    public void closeFile() {
        sc.close();
    }
}

*/

/*
import java.awt.*;

import javax.swing.ImageIcon;

public class Player {

   private int tileX, tileY;

   private Image player;

    public Player() {

        ImageIcon img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//dummy.jfif");
        player = img.getImage();



        tileX = 1;
        tileY = 1;
    }

    public Image getPlayer() {
        return player;
    }



    public int getTileX() {
        return tileX;
    }

    public int getTileY() {
        return tileY;
    }

    public void move(int dx, int dy) {



        tileX += dx;
        tileY += dy;




    }
}
*/

/*
Exception in thread "main" java.lang.NullPointerException
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Map.readFile(Map.java:60)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Map.<init>(Map.java:40)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Board.<init>(Board.java:21)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Maze.<init>(Maze.java:9)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Maze.main(Maze.java:16)
*/_


----------



## kneitzel (9. Sep 2020)

Code bitte in Code-Tags posten (Über dem Eingabefeld auf die "..." gehen und Code auswählen. In das Popup kann man dann den Code kopieren).

Ansonsten wäre wichtig:
Was ist die Zeile 60 in Map.java? In der Zeile kommt die NPE.

Vermutlich ist Zeile 60: `while(sc.hasNext()) {`
Dann hat das Erstellen des Scanners nicht geklappt weil es die Datei nicht gibt und er ist da schon mit einer Exception ausgestiegen. Diese fängst Du aber und gibst nur "error" aus. Sprich: Du hattest vorher schon eine "error" Ausgabe? ==> Gib nicht nur "error" aus sondern immer die Exception und den Stacktrace! 

Dann als Hinweis: Es reicht ein / als Trenner der Verzeichnisse. Das \\ kommt nur daher, dass das \ das sogenannte Escape Zeichen ist um Sonderzeichen in einem String anzugeben. Daher ist \\ schlicht für ein \ da. (Sprich: System.out.println("\\"); gibt einfach nur \ aus!)


----------



## Xknight (9. Sep 2020)

Danke für deine Antwort. Aber ich habe die Map.txt datei schon erstellt, wo es eigentlich ausgeben sollte.


----------



## Xknight (9. Sep 2020)

```
[CODE]
[CODE]import java.awt.*;
import java.io.*;
import java.util.*;

import javax.swing.ImageIcon;

public class Map {
  
    private Scanner sc;
    
    private String[] Map = new String[14];
    
    private Image desert, finish, wall;
    
    public Image getDesert() {
        return desert;
    }
    
    public Image getFinish() {
        return finish;
    }
    
    public Image getWall() {
        return wall;
    }
    
  
    public Map() {
      
        ImageIcon img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//desert.jfif");
        desert = img.getImage();
        img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//wall.jfif");
        wall = img.getImage();
        img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//finish.png");
        finish = img.getImage();
        
        openFile();
        readFile();
        closeFile();
    }
    
    public String getMap(int x, int y) {
        String index = Map[y].substring(x, x+1);
        return index;
    }
    
    
    public void openFile() {
        
        try {
          sc = new Scanner(new File("C://ptsd2020-papa//src-code//MazeGameUI//things//Map.txt")); 
        }catch(Exception e) {
            System.out.println("error");
        }
    }
    
    public void readFile() {
        while(sc.hasNext()) {
            for(int i = 0; i<14; i++) {
                Map[i] = sc.next();
            }
        }
    }
    
    public void closeFile() {
        sc.close();
    }
}
```


```
import java.awt.*;

import javax.swing.ImageIcon;

public class Player {
    
   private int tileX, tileY;
  
   private Image player;
    
    public Player() {
      
        ImageIcon img = new ImageIcon("C://ptsd2020-papa//src-code//MazeGameUI//things//dummy.jfif");
        player = img.getImage();
        

        
        tileX = 1;
        tileY = 1;
    }
    
    public Image getPlayer() {
        return player;
    }
    

    
    public int getTileX() {
        return tileX;
    }
    
    public int getTileY() {
        return tileY;
    }
    
    public void move(int dx, int dy) {
        

        
        tileX += dx;
        tileY += dy;
        
        
        
        
    }
}
```

Hier sind noch mal die Klassen.
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Board extends JPanel implements ActionListener {

    private Timer timer;

    private Map m;
    private Player p;
    private boolean win = false;
    private String Message = "";

    private Font font = new Font("Levent", Font.BOLD, 48);

    public Board() {

        m = new Map();
        p = new Player();
        addKeyListener(new A1());
        setFocusable(true);

        timer = new Timer(25, this);
        timer.start();
    }

    public void actionPerformed(ActionEvent e) {
       if(m.getMap(p.getTileX(), p.getTileY()).equals("f")) {
           Message = "Winner";
           win = true;
       }

        repaint();
    }

    public void paint(Graphics g) {
        super.paint(g);
        if(!win) {
        for(int y = 0; y < 14; y++) {
            for(int x = 0; x < 14; x++) {
                if(m.getMap(x ,y).equals("d")) {
                    g.drawImage(m.getDesert(), x * 64, y* 36, null );
                }
                if(m.getMap(x ,y).equals("w")) {
                    g.drawImage(m.getWall(), x * 64, y* 36, null );
            }
        }
    }
        g.drawImage(p.getPlayer(), p.getTileX() * 64, p.getTileY() * 32, null );
}
        if(win) {
            g.setColor(Color.RED);

            g.setFont(font);

            g.drawString(Message, 150, 300);
        }       

}

    public class A1 extends KeyAdapter{

        public void keyPressed(KeyEvent e) {
           int keycode = e.getKeyCode();

           if(!m.getMap(p.getTileX(), p.getTileY() -1).equals("w")){
           if(keycode == KeyEvent.VK_W) {
               p.move(0, -1);
               }
           }

           if(!m.getMap(p.getTileX(), p.getTileY() +1).equals("w")) {
             if(keycode == KeyEvent.VK_S) {
                p.move(0, 1);
                       }
           }

           if(!m.getMap(p.getTileX() - 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_A) {
               p.move( -1, 0); 
             }
           }

           if(!m.getMap(p.getTileX() + 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_D) {
                 p.move(1, 0);
             }

        }


        }
    }
}
[/CODE]
import javax.swing.*;

public class Maze {
    public Maze() {
        JFrame f = new JFrame();
        f.setTitle("The Maze Game");
        f.add(new Board());
        f.setSize(500, 400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new Maze();


    }
}
[/CODE]


----------



## BestGoalkeeper (9. Sep 2020)

Hm mal Java-Code-Tags verwendet, mal nur Code-Tags, mal gar keine Tags und dann die Vorschau nicht genutzt. Zudem die Fehlermeldungen nicht ausreichend geschildert. Diese Frage genügt den Anforderungen nicht.
Lies dir mal "Vor dem ersten Posten bitte lesen" durch...


----------



## kneitzel (9. Sep 2020)

Ok, jetzt konnte man abzählen: Zeile 60 scheint tatsächlich die beschriebene Zeile zu sein. sc ist also wohl null. Das OpenFile() wird somit beim Öffnen eine Exception geworfen haben die Du nur in Form einer "error" Ausgabe zu sehen bekommen hast.

==> Vermutlich stimmt somit der Pfad nicht.

Der Explorer zeigt keine Dateiendungen an -> Mein Tipp wäre, auch bekannte Endungen anzeigen zu lassen! Oder in einer Eingabeaufforderung das einmal entsprechend zu prüfen.



BestGoalkeeper hat gesagt.:


> Hm mal Java-Code-Tags verwendet, mal nur Code-Tags, mal gar keine Tags und dann die Vorschau nicht genutzt.



Er hat die nur leider versehentlich verschachtelt beim Einfügen. Der erste Code hat noch paar `[CODE]`, die dann unten leider fehlen ...


----------



## Xknight (9. Sep 2020)

```
import javax.swing.*;

public class Maze {
    public Maze() {
        JFrame f = new JFrame();
        f.setTitle("The Maze Game");
        f.add(new Board());
        f.setSize(500, 400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new Maze();
        
        
    }
}
```


----------



## Xknight (9. Sep 2020)

```
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Board extends JPanel implements ActionListener {
    
    private Timer timer;
    
    private Map m;
    private Player p;
    private boolean win = false;
    private String Message = "";
    
    private Font font = new Font("Levent", Font.BOLD, 48);
    
    public Board() {
      
        m = new Map();
        p = new Player();
        addKeyListener(new A1());
        setFocusable(true);
        
        timer = new Timer(25, this);
        timer.start();
    }
    
    public void actionPerformed(ActionEvent e) {
       if(m.getMap(p.getTileX(), p.getTileY()).equals("f")) {
           Message = "Winner";
           win = true;
       }
        
        repaint();
    }
    
    public void paint(Graphics g) {
        super.paint(g);
        if(!win) {
        for(int y = 0; y < 14; y++) {
            for(int x = 0; x < 14; x++) {
                if(m.getMap(x ,y).equals("d")) {
                    g.drawImage(m.getDesert(), x * 64, y* 36, null );
                }
                if(m.getMap(x ,y).equals("w")) {
                    g.drawImage(m.getWall(), x * 64, y* 36, null );
            }
        }
    }
        g.drawImage(p.getPlayer(), p.getTileX() * 64, p.getTileY() * 32, null );
}
        if(win) {
            g.setColor(Color.RED);
            
            g.setFont(font);
            
            g.drawString(Message, 150, 300);
        }       
      
}
    
    public class A1 extends KeyAdapter{
        
        public void keyPressed(KeyEvent e) {
           int keycode = e.getKeyCode();
          
           if(!m.getMap(p.getTileX(), p.getTileY() -1).equals("w")){
           if(keycode == KeyEvent.VK_W) {
               p.move(0, -1);
               }
           }
          
           if(!m.getMap(p.getTileX(), p.getTileY() +1).equals("w")) {
             if(keycode == KeyEvent.VK_S) {
                p.move(0, 1);
                       }
           }
            
           if(!m.getMap(p.getTileX() - 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_A) {
               p.move( -1, 0); 
             }
           }
          
           if(!m.getMap(p.getTileX() + 1, p.getTileY() ).equals("w")) {
             if(keycode == KeyEvent.VK_D) {
                 p.move(1, 0);
             }
            
        }
        
    
        }
    }
}
```


----------



## Xknight (9. Sep 2020)

```
Exception in thread "main" java.lang.NullPointerException
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Map.readFile(Map.java:60)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Map.<init>(Map.java:40)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Board.<init>(Board.java:21)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Maze.<init>(Maze.java:9)
    at MazeGameUI/de.uni_koblenz.ptsd.PAPA.mazegameui.Maze.main(Maze.java:16)
```


Bei Map in Zeile 60 wollte ich die txt Datei Map auslesen in dem Ordner things welches Im Ordner ptsd2020-papa//src-code//MazeGameUI//things befindet und habe es so angegeben. Sollte ich noch ganz am Anfang Desktop auch als Dateipfad angegebn, weil der Ordner ptsd2020-papa auf meinem Desktop befindet. Bei Map Zeile 40 wollte ich die Methode readFile ausführen. Bei Board zeile 21 habe ich eine new Map erzeugen wollen. Bei Maze Zeile 9 sollte die ganzen Methoden aus der Klasse Board ausgfeführt werden. Bei Maze Zeile 16 sollte das Spiel gestartet werden.


----------



## kneitzel (9. Sep 2020)

Dann ist das doch die Bestätigung: Wenn der Ordner nicht auf c:\ liegt sondern auf dem Desktop, dann musst Du den Pfad auch entsprechend angeben.

Wobei Du Dich auch evtl. mit Ressourcen beschäftigen solltest. Dann liegen die Dateien in einem Order. Je nach IDE / Build Tool kann es unterschiedlich sein. Und dann gibst Du die Dateien nicht mehr als kompletten Pfad an sondern lädst die Ressourcen über den ClassLoader bzw. die Class. getResourceAsStream(...) wäre z.B. der Aufruf für einen InputStream.

Dann wäre das z.B. ein
`sc = new Scanner(Map.class.getResourceAsStream("/Map.txt"));`
(So die Map.txt direkt im resource Ordner liegen sollte.)


----------



## Xknight (9. Sep 2020)

Das heißt, dass durch die Methode get.ResourceAsStream ein InputStream erzeugt wird, welches die Datei dann ausliest. Aber die Map.txt Datei liegt in dem Ordner things welches im Ordner MazeGameUI befindet. Und der MazeGameUI Ordner ist im Ordner src-code drin, welches im Ordner ptsd2020-papa ist. Müsste ich dann diesen Pfad am Ende des Aufrufes getResourceAsStream nicht noch angeben?


----------



## kneitzel (9. Sep 2020)

Das ist ein Thema, das Du dir erarbeiten musst. Ich habe keine Ahnung, mit welchen Tools Du arbeitest oder nicht. Die Ressourcen liegen dann in einem klar definierten Ordner des Projekts und nicht einfach auf dem Desktop oder so.

Bei Gradle und Maven ist es üblich, eine Verzeichnisstruktur zu haben mit src/main/java und src/main/resources bzw src/test/java und src/test/resources für DInge, die zu den Unit-Tests gehören.
Eclipse 08/15 Projekte unterscheiden da nicht. Da gibt es in der Regel einen Ordner src, in das man einfach alles rein schmeisst.
...

Der wichtige Punkt dabei ist aber immer: Man hat eine Ordnerstruktur für das Projekt und da spielt es dann auch keine Rolle, wo der Projektordner liegt. Das Projekt kann unter Documents, auf dem Desktop in c:\projects oder sonst wo liegen...

Das Thema kannst Du angehen und ich würde es Dir empfehlen. Aber natürlich kannst Du auch erst einmal mit kompletten, festen Pfaden arbeiten.
Da wäre aber dann mein Tipp: Prüfe die Pfade! Du kannst z.B. mit der Maus einen Ordner oder eine Datei aus dem Explorer in die Eingabeaufforderung ziehen und schon hast Du den genauen Pfad. Damit vermeidest Du so Probleme bei der Pfadangabe.


----------



## Xknight (9. Sep 2020)

Danke für deine Tips. Dann muss ich mir das noch erarbeiten. Aber wie kann ich eine Datei aus meinem Explorer in die Eingabeaufforderung ziehen?


----------



## kneitzel (9. Sep 2020)

Per drag and drop. Öffne beide Fenster, dann click eine Datei oder Ordner an und zieh sie auf das Eingabeaufforderung-Fenster.

Dann erscheint der Pfad der Datei sozusagen als Eingabe.


----------



## Xknight (9. Sep 2020)

Danke


----------



## MoxxiManagarm (9. Sep 2020)

Aus meiner Sicht ist das Problem dieses Stück Code


```
public void readFile() {
        while(sc.hasNext()) {
            for(int i = 0; i<14; i++) {
                Map[i] = sc.next();
            }
        }
    }
```

1. Du fragst den Scanner erst ob 1 ein next hat, verwendest aber 14 mal next. Der Scanner rutscht mit jedem next um ein token weiter. Nach der. 0. Iteration innerhalb der for-Schleife ist nicht mehr sichergestellt, dass der Scanner ein next hat
2. Dein String-Array "Map" heißt genauso wie deine Klasse "Map".  Bitte benenne Attribute immer im lowerCamelCase.
3. Es ist hier nicht sichergestellt, dass "sc" überhaupt initialisiert ist.


----------



## Xknight (10. Sep 2020)

Du meinst, ich soll den scanner initialisieren und den String Array neu bennen, wenn ich es richtig verstanden habe. Aber am Anfang der Klasse habe ich doch den Scanner definiert.


----------



## mihe7 (11. Sep 2020)

Es geht einfach darum, dass Du in der Methode nicht sicher weißt, ob sc wirklich nicht null ist. In Java gibt es übrigens Benennungskonventionen, an die man sich halten sollte: Variablen schreibt man in lowerCamelCase, Typnamen in UpperCamelCase.

Ich würde die Klasse auch nicht Map benennen, aus dem einfachen Grund, dass Java bereits eine Klasse mit diesem Namen kennt (java.util.Map) -> MazeMap oder ähnliches.

Dann könnte man noch über das Design sprechen. Was ist die Aufgabe von (Maze)Map? Macht die Klasse evtl. zu viel? Warum sind dort Bilder enthalten? Warum ist das Einlesen enthalten?


----------



## Xknight (11. Sep 2020)

Die Aufgabe von der Klasse (Maze)Map ist es durch das Einlesen der Bilder ein Labyrinth in die Textdatei Map abzubilden. Und auf die Frage, ob die Klasse eventuell zu viel macht, dass weiß ich von meiner Seite aus nicht.


----------



## mihe7 (11. Sep 2020)

Xknight hat gesagt.:


> Die Aufgabe von der Klasse (Maze)Map ist es durch das Einlesen der Bilder ein Labyrinth in die Textdatei Map abzubilden.


OK, dann zwei weitere Fragen:

1. Wozu hast Du dann eine Methode getMap, die einen String zurückgibt, wenn Du Bilder haben willst?
2. Muss das Einlesen denn in dieser Klasse erledigt werden? 

Zu 2.: Du beschreibst zwei Aufgaben. Einmal das Einlesen und einmal das Abbilden.


----------



## Xknight (11. Sep 2020)

Ich habe es mir so gedacht, dass das Einlesen schon in der Methode ausgeführt werden soll, weil die Bilder desert und wall das Feld bilden sollen und die Bilder dann im Array ausgegeben werden sollen wodurch dann das Feld in der Map.txt Datei als Labyrinth erscheinen soll.


----------



## mihe7 (11. Sep 2020)

Ja, das habe ich auch so verstanden, nur beantwortet das nicht meine Fragen. Worauf ich hinaus wollte ist, dass Deine Klasse zu viel macht. Ich kann Dir nachher mal ein Beispiel zusammenbasteln, wenn du willst.


----------



## Xknight (11. Sep 2020)

Es wäre sehr dankbar wenn du mir mal ein Beispiel zeigen würdest. Ich dachte mir dabei wenn die Bilder in einem Array sind, müsste ich auch die getmap Methode verwenden.


----------



## mihe7 (12. Sep 2020)

Sorry, musste gestern weg. Da Probleme dieser Art immer wieder mal kommen, mach ich mal aus dem ganzen Spiel eine längere Geschichte und poste das in einem eigenen Thread, den ich dann hier verlinke. Dauert noch ein wenig.


----------



## Xknight (12. Sep 2020)

Es wäre sehr nett,  wenn sie ihr Beispiel hier als ein eigener Thread verlinken würden.


----------



## mihe7 (12. Sep 2020)

Noch nicht ganz fertig: https://www.java-forum.org/thema/wie-man-einfache-spiele-programmieren-kann.189417/


----------

