# KeyListener hält nicht mit



## Reality (21. Okt 2004)

Hi,
ich experimentiere etwas rum und ich steuere gerade eine Bombermanfigur über die Tastatur.
Wenn ich jedoch eine Taste gedrückt halte, dauert es immer ca. 0,5 sec. bis die Aktion dauerhaft ausgeführt wird (keyPressed). Ich habe es schon mit einer zusätzlichen Methode (keyTyped) versucht, aber das ging auch nicht.

Weiß jemand Rat?

Liebe Grüße
Reality


----------



## Beni (21. Okt 2004)

Multithreading :wink:

Wenn eine Taste gedrückt wird, setzt du irgendeine boolsche Variable auf true, wenn die Taste wieder losgelassen wird, setzt du auch die Variable auf false.

Du hast nun einen Thread, der z.B. alle 20 Millisekunden guckt, ob die Variable true ist, und falls ja, dann wird die Figur bewegt.


----------



## thE_29 (21. Okt 2004)

naja, wenn du es schon so machst, würde ich es mit einem timer machen, der blockiert dir halt net die gui oder friert dir was ein 

außerdem sind die timer netter zu handhaben


----------



## Reality (21. Okt 2004)

Hey Beni,
hast du mir in den Quellcode geschaut? :lol: 
Ich mach´s ja mit Multithreading und boolschen Variablen:


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

public class Main extends JFrame implements Runnable{
  final static FullScreen fullScreen = new FullScreen();
  static boolean play = true;

  private static boolean player_right = false;
  private static boolean player_left = false;
  private static boolean player_up = false;
  private static boolean player_down = false;
  private static boolean player_dies = false;

  private static Image lastImage;

  private static int x = 50;
  private static int y = 200;

  int player1 = 0;

  private Graphics dbg;
  private Image img;

  Thread t = new Thread(this);

  Player player;
  static Steuerung steuerung;

  static ImageLoader il;
  Main(){
    il = new ImageLoader();
    player = new Player();
    steuerung = new Steuerung(this);
    lastImage = il.player_stay_right;
  }

  public static void main(String[] args) {
    Main window = new Main();

    window.addKeyListener(new KeyAdapter(){

      public void keyPressed(KeyEvent ke){

        switch(ke.getKeyCode()){
          case KeyEvent.VK_ESCAPE:
            fullScreen.restoreScreen();
            play = false;
            break;

          case KeyEvent.VK_UP:
            player_up = true;
            y -= 2;
            break;

          case KeyEvent.VK_LEFT:
            player_left = true;
            x -= 2;
            break;

          case KeyEvent.VK_RIGHT:
            player_right = true;
            x += 2;
            break;

          case KeyEvent.VK_DOWN:
            player_down = true;
            y += 2;
            break;

          case KeyEvent.VK_ENTER:
            player_dies = true;
            break;
        }
      }

      public void keyReleased(KeyEvent ke){
        switch(ke.getKeyCode()){
          case KeyEvent.VK_UP:
            lastImage = il.player_stay_up;
            player_up = false;
            break;

          case KeyEvent.VK_RIGHT:
            lastImage = il.player_stay_right;
            player_right = false;
            break;

          case KeyEvent.VK_LEFT:
            lastImage = il.player_stay_left;
            player_left = false;
            break;

          case KeyEvent.VK_DOWN:
            lastImage = il.player_stay_down;
            player_down = false;
            break;
        }
      }
    });

    window.runGame();
  }

  void runGame(){
    setBackground(Color.BLUE);
    setForeground(Color.WHITE);
    setFont(new Font("Dialog", Font.PLAIN, 20));

    DisplayMode displayMode;
    displayMode = new DisplayMode(1024, 768, 32, DisplayMode.REFRESH_RATE_UNKNOWN);

    fullScreen.setFullScreen(displayMode, this);

    t.start();
  }

  public void paint(Graphics g){
    if(g instanceof Graphics2D){
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    }

    g.drawString("Hello World", x, y);
    if(play){
      if (player_right)
        steuerung.movePlayerRight(g, x, y);

      else if (player_up)
        steuerung.movePlayerUp(g, x, y);

      else if (player_left)
        steuerung.movePlayerLeft(g, x, y);

      else if (player_down)
        steuerung.movePlayerDown(g, x, y);

      else if (player_dies) {
        steuerung.playerDies(g, x, y);
      }

      else
        g.drawImage(lastImage, x, y, this);
    }
  }

  public void update(Graphics g){
    if(img == null){
      img = createImage(1024, 768);
      dbg = img.getGraphics();
    }

    dbg.setColor(Color.BLUE);
    dbg.fillRect(0, 0, 1024, 768);

    dbg.setColor (Color.WHITE);
    paint(dbg);
    g.drawImage(img, x, y, this);
  }

  public void run(){

    while(play){
      t.setPriority(Thread.MIN_PRIORITY);


      try{
        Thread.sleep( 20 );
      }
      catch( InterruptedException ex ){}

      t.setPriority(Thread.MAX_PRIORITY);
      repaint();
    }

  }
}
```

@the_29: Timer? Wozu soll das gut sein? Meine GUI friert mir nicht ein, es ist ja nur die Reaktion. Wenn ich jetzt die Rechts-Taste drücke, dann geht die Figur 2 Pixel nach rechts und nach einer halben Sekunde erst, fängt er kontinuirlich an zu gehen.

Liebe Grüße
Reality


----------



## Beni (21. Okt 2004)

Nö, das ist nicht ganz das, an was ich dachte 

Ich dachte an sowas:

```
public class Game extends Frame implements Runnable {
  private boolean left = false;
  private int x, y;

  public Game(){
    new Thread( this ).start();
  }

  public void keyPressed( KeyEvent e ){
    switch( e.getKeyCode ){
      case KeyEvent.VK_LEFT: 
        left = true;
        break;
    }
  }

  public void keyReleased( KeyEvent e ){
    switch( e.getKeyCode ){
      case KeyEvent.VK_LEFT: 
        left = false;
        break;
    }
  }

  public void paint( Graphics g ){
    g.drawImage(img, x, y, this); 
  }

  public void run(){
    while( play ){
      try{
        Thread.sleep( 20 );
      }
      catch( InterruptedException ex ){}

      if( left ){
        x -= 2;
      }

      repaint(); 
    }
  }
}
```


----------



## Reality (21. Okt 2004)

Man, danke!!!!


----------



## macfreakz (22. Okt 2004)

ich muss zu deinem Code noch etwas sagen: 

Es ist nicht "sauber" programmiert. Es muss einen Struktur geben, sozusagen sauberes OOP und Konzept !

Es fehlen: 
 - Controller
 - Beobachter / Beobachteter
 - Kamera
 - Karte

1. Controller
Controller verbindet View und Model und übermittelt die Daten zwischen beiden. 
Ohne Controller wirst du Probleme haben, wenn dein Spiel komplexer wird!

2. Beobachter / Beobachteter
Es ist wirklich sehr praktisch, wenn die View automatisch aktualisiert wird, wenn ein Wert in der Klasse Player geändert wird. Am besten gleich implementieren! 

3. Kamera
Es muss ein Kamera geben, das aufs Spielfeld richtet. Die Positionen werden relativ zum Kamera berechnet. Dann hast du viele Vorteile: du kannst das Spielfeld scrollen oder ähnliches! Einfach eine Klasse implementieren mit Kameraposition, etc. ... 

4. Karte
Auf der Karte "leben" Player und sonstige Objekte. Sie sollen im Container liegen und deine Verwaltung von Objekte wird leichter und einfacher. Dabei kannst du Karteinformation auf der Display anzeigen. 

Wenn du diese Vorgaben erfüllst, ist dein Spiel wirklich professionell aufgebaut! 
Noch Fragen? 

ciaooo


----------



## Roar (22. Okt 2004)

ach er hat doch gesagt er experimentiert nur rum... du willst nich wissen wie mein code aussieht wenn ich "experimentiere"  
aber dein kommentar is trotzdem gut


----------



## thE_29 (22. Okt 2004)

jo das ist schon richtig was macfreaks schreibt, nur dauert wahrscheinlich die Entwicklung des Konzepts länger, als das eigentliche Spiel zum Programmieren 

Also wenn man was "großes" machen will, braucht man zuerst ein Konzept, aber für mini Spiele/Programme zum testen/probieren braucht man nicht so ein grundlegendes Konzept! 

Aber kommentieren net vergessen, sonst kennst du dich 1e Woche später damit nima aus :bae:


----------



## Reality (22. Okt 2004)

Hi,
habe 2 Probleme die vielleicht sogar an JAVA selbst liegen:

1. Wenn ich mit der Figur an den linken oder oberen Rand laufe und wieder zurückkehre, dann bleibt immer ein komischer Fleck am Rand kleben.

2. Die Animation sieht mir trotz DoubleBuffering nicht flüssig aus.

Wer es mal testen will:
http://mitglied.lycos.de/masterchan/Bomberman.rar

In der JAR-Datei ist auch der Source-Code. Und die Klasse Player braucht ihr euch nicht anzuschauen. Die benutze ich momentan nicht.

@macfreakz: Danke, um Design kümmere ich mich erst später.

Liebe Grüße
Reality


----------



## Beni (22. Okt 2004)

Ich weiss nicht, was 1 verursacht, aber zu 2: benutz mal ein VolatileImage (Component.createVolatileImage(...)), manchmal kann das schneller werden.

P.S. also das Design macht man _bevor_ der Code geschrieben wird... oder man lässt es gleich ganz weg :wink:


----------



## Reality (22. Okt 2004)

Hi Beni,
ich weiß nicht, wie ich mit den Argumenten von createVolatileImage ein Bild laden kann.



> VolatileImage createVolatileImage(int width, int height)
> Creates a volatile off-screen drawable image to be used for double buffering.
> VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps)
> Creates a volatile off-screen drawable image, with the given capabilities.



Ich hab´s einfach mal so gemacht:


```
VolatileImage player_walk_right_1;
player_stay_right =  (VolatileImage) (new ImageIcon(path + "/Bombermans/Player 1/31.gif").getImage());
```

Es wird kompiliert, jedoch wird zur Laufzeit eine Exception ausgelöst:



> java.lang.ClassCastException
> 
> at ImageLoader.<init>(ImageLoader.java:57)
> 
> ...



Wie mache ich das jetzt? ???:L 

Liebe Grüße
Reality


----------



## Beni (22. Okt 2004)

Ich meinte eigentlich für den Buffer :wink:

Das Bild, das in deiner _Main.update( Graphics g )_ steht.


----------



## Reality (22. Okt 2004)

Aso! 
Nun, ich hab das mal implementiert und entweder ist der Unterschied nur sehr schwer bemerkbar oder es gibt keinen.
Trotzdem danke! 

Problem 1 macht mir auch noch sehr zu schaffen, da das ja eine Einarbeitung zu meiner Jahresprojektarbeit ist und ich kann doch nicht so befleckte Stellen vorstellen. 

Liebe Grüße
Reality


----------



## Reality (25. Okt 2004)

Hi,
ich will einen weißen Kasten mit String ausgeben. Problem:

1. Der weiße Kasten erscheint nicht dort, wo er sollte.
2. Wenn ich mit der Figure wandere, wandert der weiße Kasten mit String mit.

Und so sieht die zusätzliche Methode in der Main-Klasse aus:


```
void showSpeech(Graphics g) {
    int width;
    int height;
    width = this.getWidth();
    height = this.getHeight();

    g.setColor(Color.WHITE);
    g.fillRect(width - 1000, height - 500, width - 90, height - 90);

    g.setColor(Color.BLACK);
    g.drawString("Das ist ein Test!", width - 500, height - 100);
  }
```

Aufgerufen wird die Methode in der Paint-Methode.

Liebe Grüße
Reality


----------

