# Mehrere Klassen auf JFrame



## .basti (20. Dez 2021)

Ich bin dabei ein kleines Spiel zu programmieren. Es gibt einen Spieler, ein Hindernis und eine Zähler, der hochgehen soll, wenn der Spieler das Hindernis berührt. Die Klassen an sich funktionieren. Nur ich verzweifle aktuell bisschen daran alle verschiedene Klassen auf einem Frame darzustellen. Manchmal wird nur eine angezeigt, manchmal gar keine. Ich hab schon bisschen was ausprobiert (anderes Layout usw.), aber das hat alles nicht so funktioniert wie ich es haben will. 
Hier noch die Codes:


```
import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class Main extends JFrame {
    JPanel panel = new JPanel();
    Spieler spieler = new Spieler();
    Zähler zähler = new Zähler();
    
    public Main() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(400,400);
        add(spieler);
        add(zähler); //wenn ich das so hinzufüge sieht man gar nichts mehr. ohen sieht man den Spieler allerdings
        
    }
    public static void main (String [] args) {
        Main main = new Main();
        main.setVisible(true);
    }
}
```

Hier die Klasse Main, in der das Frame erzeugt wird und im Endeffekt alles drauf gepackt werden soll. Ich hab hier noch ohne Layout gearbeitet weil alle Versuche schiefgingen.


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
    @SuppressWarnings("serial")
    public class Spieler extends JPanel implements KeyListener, ActionListener{
        Timer timer = new Timer(5,this);
        
        int x = 0, velX = 0, velY = 0, y = 0;
    public Spieler() {       
        timer.start();

        addKeyListener(this);
        setFocusable(true);
        setRequestFocusEnabled(false);
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
           g.drawRect(x,y,30,30);
        g.setColor(Color.PINK);
        g.fillRect(x,y,30,30);   
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(x < 0) {
                velX = 0;
                x = 0;
        }

        if(x > 370) {
                velX = 0;
                x = 370;
        }

        if(y < 0) {
                velY = 0;
                y = 0;
        }
        if(y > 341) {
                velY = 0;
                y = 341;
        }

        x = x + velX;
        y = y + velY;
            repaint();
        
    }
    @Override
    public void keyTyped(KeyEvent e) {
    
    }
    @Override
    public void keyPressed(KeyEvent e) {
         if(e.getKeyCode() == KeyEvent.VK_W) {
                velX = 0;
                velY = -1; 
         }
         if(e.getKeyCode() == KeyEvent.VK_S) {
                velX = 0;
                velY = 1;
         }
         if(e.getKeyCode() == KeyEvent.VK_A) {
                velX = -1;
                velY = 0;
         }
         if(e.getKeyCode() == KeyEvent.VK_D) {
                velX = 1;
                velY = 0;
         }
    }
    @Override
    public void keyReleased(KeyEvent e) {
         velX = 0;
         velY = 0;
    }
}
```
Hier die Klasse Spieler. Funktioniert auch.


```
import java.awt.Color;
import java.awt.Graphics;
import java.util.*;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Hindernis extends JPanel{
    Random rand = new Random();
    
    public Hindernis() {
        
    }
    public void paint(Graphics g) {
        g.setColor(Color.GREEN);
        g.fillRect(rand.nextInt(370),rand.nextInt(341),50,50);
    }
    
}
```
Hier die Klasse Hindernis, welche ein Rechteck zufällig auf dem Frame erzeugen soll. Funktioniert auch. 


```
import javax.swing.*;
@SuppressWarnings("serial")
public class Zähler extends JLabel{
     JTextField zähler = new JTextField();
     int p=0;
    public Zähler() {
        zähler.setBounds(300,0,100,50);
        zähler.setText("Punkte: "+p);   
        zähler.setVisible(true);
        zähler.setEditable(false);
    }
}
```
Der Zähler funktioniert auch. p wird genauer beschrieben später.

Also meine Frage lautet wie ich diese ganzen Klassen auf einen Frame darstellen kann.
LG


----------



## Blender3D (20. Dez 2021)

.basti hat gesagt.:


> Also meine Frage lautet wie ich diese ganzen Klassen auf einen Frame darstellen kann.


Das Stichwort lautet hier: Layout Manager  verwenden oder das Layout des Containers auf null zu setzten und die einzelnen Komponenten mit setBounds() zu platzieren. Mein Tipp wäre aber bei einem Spiel nur eine einzige Komponente zum Zeichnen verwenden und alles auf einem Graphics Objekt zeichnen. Trotzdem sollten der Zähler, Hindernis über eine eigne Klasse dargestellt werden.


----------



## .basti (20. Dez 2021)

Danke erstmal für deine Antwort, jedoch versteh ich das nicht ganz. Kannst du es noch mal genauer erklären?
Soll ich also lieber alles in der Klasse Spieler zeichnen lassen? Aber wofür brauch ich dann noch die anderen Klassen und wie mach das mit dem JTextField? 
Bin noch blutiger Anfänger 😅


----------



## Blender3D (21. Dez 2021)

.basti hat gesagt.:


> Danke erstmal für deine Antwort, jedoch versteh ich das nicht ganz. Kannst du es noch mal genauer erklären?
> Soll ich also lieber alles in der Klasse Spieler zeichnen lassen? Aber wofür brauch ich dann noch die anderen Klassen und wie mach das mit dem JTextField?
> Bin noch blutiger Anfänger 😅


Also so wie ich das verstanden habe möchtest Du eine Box mittels Tasten bewegen. Und mit Hindernissen kollidieren lassen.
Dazu brauchst Du erstmal kein JTextField.
Du benötigts Objekte die bewegt werden können und auf Kollisionen und Tastatureingaben reagieren können. Also könnte man zu erste ein Klasse dafür kreieren im allgemeinen nennt man so etwas Sprite . Als nächstes benötigst Du ein Klasse auf der die Sprites gezeichnet werden (z.B. JPanel ).
Für den Punktezähler kannst du dann ebenfalls eine eigene Klasse machen. Alle deine benötigten Klassen werden dann periodisch in deinem JPanel gezeichnet.
Hier ein Beispiel dafür. Eine grüne Box kann mit den Tasten *w,a,s,d* bewegt werden. Sobald man sie in die rote Box bewegt, wird sie wieder auf die Startposition gesetzt.


Der Code zum probieren.
[CODE lang="java" title="StartGame"]import javax.swing.JFrame;

public class StartGame {
    public static void main(String[] args) {
        GamePanel game = new GamePanel(400, 400);
        JFrame frame = new JFrame("Mein Spiel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(game);
        frame.setResizable(false);
        frame.pack();
        frame.addKeyListener(game.getKeyBoard());
        frame.setVisible(true);
        game.start();
    }
}[/CODE]
[CODE lang="java" title="GamePanel" highlight="61-63,68-71,98-101"]import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GamePanel extends JPanel implements Runnable {
    private final int KEY_UP = KeyEvent.VK_W;
    private final int KEY_DOWN = KeyEvent.VK_S;
    private final int KEY_LEFT = KeyEvent.VK_A;
    private final int KEY_RIGHT = KeyEvent.VK_D;
    private float SPEED_PLAYER = 3;
    private int PLAYER_START_X = 50;
    private int PLAYER_START_Y = 50;
    private BoxSprite player = new BoxSprite(30, 30);
    private BoxSprite obstacle = new BoxSprite(100, 30);
    private Thread animator;
    private boolean running = false;

    public GamePanel(int width, int height) {
        setPreferredSize(new Dimension(width, height));
        setFocusable(false);
        player.setPosition(PLAYER_START_X, PLAYER_START_Y);
        player.setColor(Color.GREEN);
        obstacle.setPosition(200, 200);
        obstacle.setColor(Color.RED);
        setBackground(Color.DARK_GRAY);
    }

    public KeyAdapter getKeyBoard() {
        return new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                if (code == KEY_UP)
                    setDirection(90);
                if (code == KEY_DOWN)
                    setDirection(270);
                if (code == KEY_LEFT)
                    setDirection(180);
                if (code == KEY_RIGHT)
                    setDirection(0);
            }

            @Override
            public void keyReleased(KeyEvent e) {
                player.setSpeed(0);
            }

            public void setDirection(float angle) {
                player.setSpeed(SPEED_PLAYER);
                player.setDirection(angle);
            }
        };
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        player.draw(g);
        obstacle.draw(g);
    }

    @Override
    public void run() {
        while (running) {
            update();
            repaint();
            sleep(12);
        }
    }

    public void sleep(int delay) {
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        stop();
        running = true;
        animator = new Thread(this);
        animator.start();
    }

    private void stop() {
        running = false;
        while (animator != null && animator.isAlive())
            ;
        animator = null;
    }

    private void update() {
        player.move();
        obstacle.move();
        if (player.isCollision(obstacle))
            player.setPosition(PLAYER_START_X, PLAYER_START_Y);
    }

}[/CODE]
[CODE lang="java" title="Sprite"]import java.awt.Rectangle;

public abstract class Sprite implements DrawAble {
    protected float x;
    protected float y;
    protected float dx;
    protected float dy;
    protected float speed;

    public abstract Rectangle getCollisionBox();

    public int getX() {
        return (int) x;
    }

    public float getExactX() {
        return x;
    }

    public int getY() {
        return (int) y;
    }

    public float getExactY() {
        return y;
    }

    public boolean isCollision(Sprite s) {
        return getCollisionBox().intersects(s.getCollisionBox());
    }

    public void move() {
        x += dx * speed;
        y += dy * speed;
    }

    public void setDirection(float angle) {
        double alpha = Math.toRadians(angle);
        dx = (float) Math.cos(alpha);
        dy = -(float) Math.sin(alpha);

    }

    public void setPosition(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

    @Override
    public String toString() {
        return String.format("[%.2f,.%.2f]", x, y);
    }

}[/CODE]
[CODE lang="java" title="BoxSprite"]import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

public class BoxSprite extends Sprite {
    private int width;
    private int height;
    private Color color;

    public BoxSprite(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public void draw(Graphics g) {
        g.setColor(color);
        g.fillRect(getX(), getY(), width, height);
    }

    @Override
    public Rectangle getCollisionBox() {
        return new Rectangle(getX(), getY(), width, height);
    }

    public void setColor(Color color) {
        this.color = color;
    }

}[/CODE]
[CODE lang="java" title="DrawAble"]import java.awt.Graphics;

public interface DrawAble {
    public void draw(Graphics g);
}[/CODE]
Kopiere den Code und versuche ihn nachzuvollziehen. Fragen kannst Du gerne hier stellen.


----------

