Objecte bewegen mit Tastatur

Nico1999

Aktives Mitglied
Java:
package main;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable{
    final int orginalTileSize = 16;
    final int scale=3;
    public final int tileSize = orginalTileSize * scale;
    final int maxScreenCol = 16;
    final int maxScreenRow = 12;
    final int screenWidth = tileSize* maxScreenCol;
    final int screenHeight = tileSize* maxScreenRow;
    int FPS=60;
    
    Thread gameThread;
    KeyHandler keyH= new KeyHandler();
    
    GamePanel(){
        this.setPreferredSize(new Dimension(screenWidth,screenHeight));
        this.setBackground(Color.black);
        this.setDoubleBuffered(true);
        this.addKeyListener(keyH);
        this.setFocusable(true);
        startGameThread();
        
        
    }
    int playerx = 100;
    int playery = 100;
    int speed =4 ;
    
    public void startGameThread() {
        gameThread=new Thread(this);
        gameThread.start();
    }
    @Override
    public void run() {
        while (gameThread != null) {
            update();
            repaint();
        }
        
        
    }
    public void update() {
        if(keyH.upPressed == true) {
            playery-=speed;
            System.out.println("moin");
            
        }else if(keyH.downPressed == true) {
            playery+=speed;
            
        }else if(keyH.rightPressed == true) {
            playerx+=speed;
            
        }else if(keyH.leftPressed == true) {
            playerx-=speed;
            
        }
        
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 =(Graphics2D) g;
        g2.setColor(Color.white);
        g2.fillRect(playerx, playery, tileSize, tileSize);
        g2.dispose();
    }

}


package main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class KeyHandler implements KeyListener {
    public boolean upPressed, downPressed, rightPressed, leftPressed;

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int code =e.getKeyCode();
        if(code==KeyEvent.VK_W) {
            upPressed=true;
        }
        if(code==KeyEvent.VK_S) {
            downPressed=true;
        }
        if(code==KeyEvent.VK_A) {
            leftPressed=true;
        }
        if(code==KeyEvent.VK_D) {
            rightPressed=true;
        }
        
    }

    @Override
    public void keyReleased(KeyEvent e) {
        
        int code =e.getKeyCode();
        if(code==KeyEvent.VK_W) {
            upPressed=false;
        }
        if(code==KeyEvent.VK_S) {
            downPressed=false;
        }
        if(code==KeyEvent.VK_A) {
            leftPressed=false;
        }
        if(code==KeyEvent.VK_D) {
            rightPressed=false;
        }
        
    }
    

}
package main;

import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        JFrame window = new JFrame();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.setTitle("MMORPG");
        window.setLocationRelativeTo(null);
        window.setVisible(true);
        GamePanel gp = new GamePanel();
        window.add(gp);
        window.pack();
    }

}

hi ich versuche einfach ein rechteck auf den bildschirm mit w a s d zu bewegen. Das Ding ist es hat auch schonmal geklappt, aber jetzt halt gar nichtmehr. wenn ich starte erscheint das Rechteck aber ich kanns nicht bewegen oder verschwinden lassen (noch kein fps drinnen). ich such heute schon den ganzen Tag warum finde den Fehler aber ums verrecken nicht.
Danke schonma für eure Hilfe
 
Du musst window.setVisible(true); nach window.add(gp); und window.pack(); in Main.main() aufrufen. Also ganz am Ende der main() Methode. Dann funktioniert es.
Das nächste Problem, was du haben wirst, ist dann natürlich, dass die Schleife viel zu schnell läuft und nur bei einem ganz kurzen Antippen einer Taste das Rechteck bereits mehrere Tausend Einheiten in eine Richtung wandern wird.
 
Du musst window.setVisible(true); nach window.add(gp); und window.pack(); in Main.main() aufrufen. Also ganz am Ende der main() Methode. Dann funktioniert es.
Das nächste Problem, was du haben wirst, ist dann natürlich, dass die Schleife viel zu schnell läuft und nur bei einem ganz kurzen Antippen einer Taste das Rechteck bereits mehrere Tausend Einheiten in eine Richtung wandern wird.
danke das hätte ich nie gefunden und das mit zu schnell weiß ich wollte nur nicht unnötig viel code machen wos doch eh schon voll viel war.
noch kurze frage gibts noch irgentwas wo es wichtig ist das es am ende steht ?
 
Aber evtl. doch noch ein paar andere Punkte, die interessant sein können (hängt immer davon ab, wie man alles aufbauen möchte und was für ein Verhalten man erwartet)

- Fokus kann ein Problem sein, Ggf. kann es also notwendig sein, den Fokus zu setzen. Das wäre hier z.B. in der main per
`gp.requestFocus();
möglich. Das kann man auch prinzipiell ausprobieren - einfach die Reihenfolge lassen und das einmal ans Ende setzen.

Sowas kann hilfreich sein, wenn man mit Situationen umgehen muss, wo ein Fokus auch mal temporär woanders sein soll.

- Man könnte sich auch überlegen, dass man so einen KeyListener statt ans Panel an das Frame hängt. Das Frame ist auf jeden Fall aktiv und würde die Key Events bekommen. Das wäre dann hier z.B. per
window.addKeyListener(gp.keyH);
in der main Methode möglich.

Aber das sind nur mögliche Ideen, die bewertet werden müssen. Das eigentliche Probleme (weshalb ich das Editieren ursprünglich abgebrochen hatte und das obere weggelöscht hatte) bei Dir ist, dass das Sichtbar setzen immer am Ende erfolgen sollte, nachdem dem die UI aufgebaut wurde. (Wenn das nicht gehen sollte weil ein Fenster umgebaut wurde oder so: da gibt es dann auch andere Alternativen!)
 
Und evtl. ist es auch interessant, wenn man ggf, ganz auf den KeyListener verzichtet. Swing kennt auch eine erweiterte Möglichkeit gegenüber der KeyListener Möglichkeit auf AWT: InputMap und ActionMap

Das Problem mit dem Focus wird dabei deutlich besser gelöst und man hat eine Trennung zwischen Input und Actions.

InputMap: Eine InputMap ist eine Map von einer Eingabe hin zu einem Action Key. Das kann ein beliebiges Object sein, z.B. String Literale.
Die InputMap kann man dann von einem Element holen und dabei angeben, wann die benutzt werden soll. Darunter sind dann z.B. WHEN_FOCUSED aber auch WHEN_IN_FOCUSED_WINDOW was ja jetzt das ist, was Du vermutlich willst.

Damit kann man für das W z.B. in der InputMap hinterlegen:
Java:
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("pressed W"), "start up");
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "stop up");

Jetzt muss man natürlich noch die Actions hinterlegen:
Code:
        this.getActionMap().put("start up", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                upPressed = true;
                System.out.println("W Pressed!");
            }
        });

        this.getActionMap().put("stop up", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                upPressed = false;
                System.out.println("W Released!");
            }
        });

Was dann in Deinem Code zu etwas führen kann, das dann so in der Art aussieht (Nur Taste W berücksichtigt, die Variablen des KeyListeners sind in das Panel gewandert):
Java:
package main;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;

import javax.swing.*;

public class GamePanel extends JPanel implements Runnable{
    final int orginalTileSize = 16;
    final int scale=3;

    public boolean upPressed, downPressed, rightPressed, leftPressed;
    public final int tileSize = orginalTileSize * scale;
    final int maxScreenCol = 16;
    final int maxScreenRow = 12;
    final int screenWidth = tileSize* maxScreenCol;
    final int screenHeight = tileSize* maxScreenRow;
    int FPS=60;

    Thread gameThread;

    GamePanel(){
        this.setPreferredSize(new Dimension(screenWidth,screenHeight));
        this.setBackground(Color.black);
        this.setDoubleBuffered(true);
        this.setFocusable(true);

        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("pressed W"), "start up");
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "stop up");

        this.getActionMap().put("start up", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                upPressed = true;
                System.out.println("W Pressed!");
            }
        });

        this.getActionMap().put("stop up", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                upPressed = false;
                System.out.println("W Released!");
            }
        });

        startGameThread();
    }

    int playerx = 100;
    int playery = 100;
    int speed =4 ;

    public void startGameThread() {
        gameThread=new Thread(this);
        gameThread.start();
    }

    @Override
    public void run() {
        while (gameThread != null) {
            update();
            repaint();
        }
    }
    public void update() {
        if(upPressed == true) {
            playery-=speed;
        }else if(downPressed == true) {
            playery+=speed;
        }else if(rightPressed == true) {
            playerx+=speed;
        }else if(leftPressed == true) {
            playerx-=speed;
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 =(Graphics2D) g;
        g2.setColor(Color.white);
        g2.fillRect(playerx, playery, tileSize, tileSize);
        g2.dispose();
    }

}

Und weil ich es gerade sehe: Dein g2 ist nur die Instanz g, die Du bekommst. Das ist ja kein neu erstelltes Objekt. Damit sollte da kein Dispose aufgerufen werden. Das wäre nur dann notwendig, wenn Du das Graphics Objekt selbst erstellt hättest. Das nur als generellen Hinweis.
 

Zurück
Oben