Hey Leute und zwar versuche ich gerade ein 2D Spiel zu Programmieren aber die Figur will sich nicht nach links oder rechts bewegen :(

Nenad2001

Mitglied
Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.Timer;

public class Frame extends JFrame implements ActionListener , KeyListener {

final private int screenWitdh = 800;
final private int screenHeight = 500;
private int maxJumpHeight;
private int jumpHeight;
private int gravitation;
private int spielerSpeed;
private int senkRechteGeschwindkeit;
private boolean isJumping;
private boolean isMovingLeft;
private boolean isMovingRight;
private boolean isShooting;
private Timer timer;
private List<Projektil> projektile;


Spieler spieler;   
Boden boden;   
Decke decke;
SeiteLinks links;
SeiteRechts rechts;


public Frame() {

    this.setSize(screenWitdh, screenHeight);
    this.setTitle("Shooting Game");
    this.setLayout(null);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.addKeyListener(this);
    this.setResizable(false);
    this.setLocationRelativeTo(null);
    this.setVisible(true);
    
    spieler = new Spieler(50 , 50 , 50 , 350);
    boden = new Boden(200, 800 , 0 , 400);
    decke =  new Decke(50 , 800 , 0 , 0);
    links = new SeiteLinks(355 ,10 , 5 , 50);
    rechts = new SeiteRechts(355 ,  50 , 785, 50);
    
    senkRechteGeschwindkeit = 15;
    maxJumpHeight = 50;
    jumpHeight = 20;
    gravitation = 20;
    spielerSpeed = 30;
    timer = new Timer(10, this);
    timer.start();
     projektile = new ArrayList<>();
}
    
    


public void paint(Graphics g) {
      super.paint(g);
      Graphics2D g2D = (Graphics2D) g;
    
      g2D.setPaint(Color.BLUE);
      g2D.drawRect(0, 0, screenWitdh, screenHeight);
      g2D.fillRect(0, 0, screenWitdh, screenHeight);

      g2D.setPaint(Color.BLACK);
      g2D.drawRect(spieler.getSpielerX(), spieler.getSpielerY(), spieler.getBreiteSpieler(), spieler.getHöheSpieler());
      g2D.fillRect(spieler.getSpielerX(), spieler.getSpielerY(), spieler.getBreiteSpieler(), spieler.getHöheSpieler());

      g2D.setPaint(Color.GREEN);
      g2D.drawRect(boden.getBodenx(), boden.getBodenY(), boden.getBreite(), boden.getHöhe());;
      g2D.fillRect(boden.getBodenx(), boden.getBodenY(), boden.getBreite(), boden.getHöhe());;

      g2D.setPaint(Color.WHITE);
      g2D.drawRect(decke.getDeckeX(), decke.getDeckeY(), decke.getBreite(), decke.getHöhe());
      g2D.fillRect(decke.getDeckeX(), decke.getDeckeY(), decke.getBreite(), decke.getHöhe());
      
      g2D.setPaint(Color.GREEN);
      g2D.drawRect(links.getSeiteLinksX(), links.getSeiteLinksY(), links.getBreite(), links.getHöhe());
      g2D.fillRect(links.getSeiteLinksX(), links.getSeiteLinksY(), links.getBreite(), links.getHöhe());
      
       g2D.setPaint(Color.GREEN);
      g2D.drawRect(rechts.getSeiteRechtsX(), rechts.getSeiteRechtsY(), rechts.getBreite(), rechts.getHöhe());
      g2D.fillRect(rechts.getSeiteRechtsX(), rechts.getSeiteRechtsY(), rechts.getBreite(), rechts.getHöhe());
    

      g2D.setPaint(Color.RED);
      for (Projektil projektil : projektile) {
          g2D.drawRect(projektil.getX(), projektil.getY(), projektil.getBreite(), projektil.getHöhe());
          g2D.fillRect(projektil.getX(), projektil.getY(), projektil.getBreite(), projektil.getHöhe());
      }

}






    @Override
    public void actionPerformed(ActionEvent e) {
        timer.start();
        Springen();
        MoveLeft();
        MoveRight();
        Kolision();   
        repaint();
       shoot();
    }


    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
        isMovingLeft = false;
        
        }
        if(e.getKeyChar() == KeyEvent.VK_D) {
        isMovingRight = false;
        }
        if(e.getKeyChar() == KeyEvent.VK_SPACE) {
        isJumping = true;   
        }
        if(e.getKeyChar() == KeyEvent.VK_ENTER) {
        isShooting = true;   
        }
        
    }

    
    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
            isMovingLeft = true;   
            
        }
            if(e.getKeyChar() == KeyEvent.VK_D) {
            isMovingRight = true;
            
            }
            if(e.getKeyChar() == KeyEvent.VK_SPACE) {
            isJumping = true;   
            
            }
            if(e.getKeyChar() == KeyEvent.VK_ENTER) {
            isShooting = true;   
            
            }
             repaint();   
    }
        
    
    @Override
    public void keyReleased(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
            isMovingLeft = false;
                
        }
            if(e.getKeyChar() == KeyEvent.VK_D) {
            isMovingRight = false;
            }
            if(e.getKeyChar() == KeyEvent.VK_SPACE) {
            isJumping = false;
            }
            if(e.getKeyChar() == KeyEvent.VK_ENTER) {
            isShooting = true;
            }
        
    }

    
public void Springen() {
    
if(isJumping ) {
spieler.setspielerY(spieler.getSpielerY() - jumpHeight - gravitation);

}

}
    
            



public void MoveLeft() {
    
if(isMovingLeft) {
    spieler.setspielerX(spieler.getSpielerX() -  spielerSpeed);
System.out.println("linksgedrückt");
}

}

public void MoveRight() {
    timer.start();
    if (isMovingRight) {
        spieler.setspielerX(spieler.getSpielerX() + spielerSpeed);
   System.out.println("rechtsgedrückt");
    }
    


}








public void Kolision() {

if( spieler.getSpielerY() < decke.getDeckeY() || spieler.getSpielerX() < decke.getDeckeX()) {
System.out.println("Du hast die decke getroffen");   
spieler.setspielerY(350);
}

if(spieler.getSpielerX() < links.getSeiteLinksX() && spieler.getSpielerX() > rechts.getSeiteRechtsX()) {
spieler.setspielerY(350);
}



}




// das ist bullshit das ist von chatgpt
public void shoot() {
    int projektilX = spieler.getSpielerX() + spieler.getBreiteSpieler() / 2;
    int projektilY = spieler.getSpielerY() + spieler.getHöheSpieler() / 2;
    int projektilSpeed = 5;

    Projektil projektil = new Projektil(projektilX, projektilY, projektilSpeed);
    projektile.add(projektil);
}





}
 
Eine deiner Methoden moverecht oder links ruft du ja gar nicht auf, wenn eine Taste gedrückt wird.
Die Ausgabe auf der Konsole wird somit auch nicht kommen.
 
Wo hast du das?
Du hast den listener, arber auf eine view hast du denn nicht gesetzt. Der wird mit sicherheit nie aufgrufen.
 
Wo hast du das?
Du hast den listener, arber auf eine view hast du denn nicht gesetzt. Der wird mit sicherheit nie aufgrufen.
Achso tut mir leid ich dachte weil die Jump Methode auch klappt müssen die auch funktionieren weil die ja im selben listener stehen. Kannst du mir das genauer erklären wie ich das löse wäre echt korrekt 🙂
 
Also der Code ist extrem schwer lesbar, da Du alles in einer Klasse hast und dazu die Interfaces so überschreibst, so dass die Methoden halt unlesbare Namen haben. Hinzu kommt, dass Du Dich teilweise nicht an die Naming Conventions hältst. (Methoden fangen bitte alle klein an!)

Der Aufbau ist ja:
  • Deine Game-Loop hast Du mit dem Timer und der actionPerformed Methode. Das, was hier etwas auffällt: Warum startest Du den Timer öfters? Einmal gestartet sollte es doch ok sein.
  • Durch die Tastendrücke setzt Du dann Variablen, die in der Gameloop dann ausgewertet werden.

Was auffällt, ist die keyPressed Methode. Da setzt Du die move Variablen auf false. Das Jump wird wohl klappen, da Du da dort ein true setzt.

Du solltest Dir die Beschreibung ansehen von KeyEvent: KeyEvent (Java SE 17 & JDK 17) (oracle.com)
Dort findest Du die Reihgenfolge, die die Events ausgelöst werden:
KEY_PRESSED
KEY_TYPED (is only generated if a valid Unicode character could be generated.)
KEY_RELEASED

Ich vermute, dass Du bei den A / D Tasten sofort ein KEY_PRESSED bekommst, was die Variable erst auf true setzt. Es kommt aber auch direkt ein KEY_TYPED und da setzt Du es dann direkt wieder auf false.
Wenn der Timer dann kommt, dann ist die Variable halt direkt auf false.

Ich schreibe noch im Anschluss ein paar Tipps für Veränderungen - das mache ich aber in einem anderen Post, damit erst einmal der Hinweis auf den eigentlichen Fehler (aus meiner Sicht) gepostet ist und da nicht in falsche Richtung weiter analysiert wird.
 
a) Wie kann man sowas finden? Was man da immer machen kann, ist ein "Tracing für Anfänger" - wir machen einfach deutlich mir Ausgaben. Also einfach in den Methoden jeweils ausgeben, was gemacht wird. Also etwas wie:
Java:
    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
            isMovingLeft = false;
            System.out.println("keyTyped: A. isMovingLeft = false");
        }
        
        if(e.getKeyChar() == KeyEvent.VK_D) {
            isMovingRight = false;
            System.out.println("keyTyped: D. isMovingRight = false");
        }

Dann kannst Du es testen und solltest dann in der Ausgabe sehen, wann welches Event kommt (oder eben nicht!)

b) Lesbareren Code mit Hilfe von Lambda Expressions / Method references:

Statt in der Klasse ActionListener zu implementieren kannst Du
  • dieses implements heraus nehmen
  • Die Methode umbenennen - das kann dann z.B. einfach gameLoop oder so sein.
  • Das wird dann in dem Timer so gesetzt: timer = new Timer(10, this::gameLoop); (Dann hättest Du eine Methodenreferenz angegeben) oder als: timer = new Timer(10, () -> this.gameLoop()); (Dann hättest Du eine Lambda Expression)

Dadurch wird dann klar, dass die Methode die GameLoop ist und so.

Das funktioniert aber nur bei sogenannten funktionalen Interfaces. KeyListener ist kein funktionales Interface, daher geht es da leider nicht. Aber damit es da deutlich besser lesbarer ist, wäre eine eigene Klasse nur dafür evtl. interessant.
 
a) Wie kann man sowas finden? Was man da immer machen kann, ist ein "Tracing für Anfänger" - wir machen einfach deutlich mir Ausgaben. Also einfach in den Methoden jeweils ausgeben, was gemacht wird. Also etwas wie:
Java:
    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
            isMovingLeft = false;
            System.out.println("keyTyped: A. isMovingLeft = false");
        }
        
        if(e.getKeyChar() == KeyEvent.VK_D) {
            isMovingRight = false;
            System.out.println("keyTyped: D. isMovingRight = false");
        }

Dann kannst Du es testen und solltest dann in der Ausgabe sehen, wann welches Event kommt (oder eben nicht!)

b) Lesbareren Code mit Hilfe von Lambda Expressions / Method references:

Statt in der Klasse ActionListener zu implementieren kannst Du
  • dieses implements heraus nehmen
  • Die Methode umbenennen - das kann dann z.B. einfach gameLoop oder so sein.
  • Das wird dann in dem Timer so gesetzt: timer = new Timer(10, this::gameLoop); (Dann hättest Du eine Methodenreferenz angegeben) oder als: timer = new Timer(10, () -> this.gameLoop()); (Dann hättest Du eine Lambda Expression)

Dadurch wird dann klar, dass die Methode die GameLoop ist und so.

Das funktioniert aber nur bei sogenannten funktionalen Interfaces. KeyListener ist kein funktionales Interface, daher geht es da leider nicht. Aber damit es da deutlich besser lesbarer ist, wäre eine eigene Klasse nur dafür evtl. interessant.
Danke für deine Tipps nur das Problem war selbst als ich moveleft und right auf true gesetzt hat war es trotzdem falsch hatte chatgpt nach rat gefragt haha 😂
 
a) Wie kann man sowas finden? Was man da immer machen kann, ist ein "Tracing für Anfänger" - wir machen einfach deutlich mir Ausgaben. Also einfach in den Methoden jeweils ausgeben, was gemacht wird. Also etwas wie:
Java:
    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar() == KeyEvent.VK_A) {
            isMovingLeft = false;
            System.out.println("keyTyped: A. isMovingLeft = false");
        }
        
        if(e.getKeyChar() == KeyEvent.VK_D) {
            isMovingRight = false;
            System.out.println("keyTyped: D. isMovingRight = false");
        }

Dann kannst Du es testen und solltest dann in der Ausgabe sehen, wann welches Event kommt (oder eben nicht!)

b) Lesbareren Code mit Hilfe von Lambda Expressions / Method references:

Statt in der Klasse ActionListener zu implementieren kannst Du
  • dieses implements heraus nehmen
  • Die Methode umbenennen - das kann dann z.B. einfach gameLoop oder so sein.
  • Das wird dann in dem Timer so gesetzt: timer = new Timer(10, this::gameLoop); (Dann hättest Du eine Methodenreferenz angegeben) oder als: timer = new Timer(10, () -> this.gameLoop()); (Dann hättest Du eine Lambda Expression)

Dadurch wird dann klar, dass die Methode die GameLoop ist und so.

Das funktioniert aber nur bei sogenannten funktionalen Interfaces. KeyListener ist kein funktionales Interface, daher geht es da leider nicht. Aber damit es da deutlich besser lesbarer ist, wäre eine eigene Klasse nur dafür evtl. interessant.
Hast du sonst noch Tipps zu Verbesserungen im Code das würde mir sehr helfen 😀?
 
Also der Code ist extrem schwer lesbar, da Du alles in einer Klasse hast und dazu die Interfaces so überschreibst, so dass die Methoden halt unlesbare Namen haben. Hinzu kommt, dass Du Dich teilweise nicht an die Naming Conventions hältst. (Methoden fangen bitte alle klein an!)

Der Aufbau ist ja:
  • Deine Game-Loop hast Du mit dem Timer und der actionPerformed Methode. Das, was hier etwas auffällt: Warum startest Du den Timer öfters? Einmal gestartet sollte es doch ok sein.
  • Durch die Tastendrücke setzt Du dann Variablen, die in der Gameloop dann ausgewertet werden.

Was auffällt, ist die keyPressed Methode. Da setzt Du die move Variablen auf false. Das Jump wird wohl klappen, da Du da dort ein true setzt.

Du solltest Dir die Beschreibung ansehen von KeyEvent: KeyEvent (Java SE 17 & JDK 17) (oracle.com)
Dort findest Du die Reihgenfolge, die die Events ausgelöst werden:


Ich vermute, dass Du bei den A / D Tasten sofort ein KEY_PRESSED bekommst, was die Variable erst auf true setzt. Es kommt aber auch direkt ein KEY_TYPED und da setzt Du es dann direkt wieder auf false.
Wenn der Timer dann kommt, dann ist die Variable halt direkt auf false.

Ich schreibe noch im Anschluss ein paar Tipps für Veränderungen - das mache ich aber in einem anderen Post, damit erst einmal der Hinweis auf den eigentlichen Fehler (aus meiner Sicht) gepostet ist und da nicht in falsche Richtung weiter analysiert wird.
Habe mehrere Klassen aber halt nur für die getter und Wetter der gezeichneten Objekte
 
Tipp schaue dir mal an wann die Methode keyTyped aufgrufen wird und wie du da deine Variable isMovingLeft setzt.
Die Methode wird vom System aufgrufen wenn ein Zeichen von der Tastatur erkannt wurde.

Ich hatte mir deine imports nicht angesehen nicht gesehen das du den timer von swing benutzt.
Somit sollte der Listener actionPerformed aufgrufen werden.
 
Zuletzt bearbeitet:
Tipp schaue dir mal an wann die Methode keyTyped aufgrufen wird und wie du da deine Variable isMovingLeft setzt.
Die Methode wird vom System aufgrufen wenn ein Zeichen von der Tastatur erkannt wurde.

Ich hatte mir deine imports nicht angesehen nicht gesehen das du den timer von swing benutzt.
Somit sollte der Listener actionPerformed aufgrufen werden.
Danke die für denn tipp 👍🏻
 

Zurück
Oben