# Objekte bewegen lassen



## Spin (26. Apr 2009)

Hallo , ich habe mal wieder ein neues Problem.

Irgendwie reagiert mein Programm nicht auf meine Tastatreingabe.


```
boolean up = false;
    boolean down = false;
    boolean left = false;
    boolean right = false;
    int speed =50; //Geschwindigkeit


public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            up =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            left =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            down =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            right =true;
        }
    }


 public void checkKeys()
    {
        if(up)
        {
            copter.setVerticalSpeed(-speed);
        }
        if(down)
        {
            copter.setVerticalSpeed(speed);
        }
        if(right)
        {
            copter.setHorizontalspeed(speed);
        }
        if(left)
        {
            copter.setHorizontalspeed(-speed);
        }
        if(!up && !down)
        {
            copter.setVerticalSpeed(0);
        }
        if(!left && !right)
        {
            copter.setHorizontalspeed(0);
        }
    }
}
```

[Edit _Ebenius_] So langsam kannst Du doch auch mal selbst [noparse]
	
	
	
	





```
[/noparse]-Tags benutzen, oder?[/COLOR]

Ich verstehe es nicht, warum es nicht funktioniert. Wenn ich die CursorTaste up drücke, dann soll er auf true schalten , danach weiß das Programm in der Methode checkKeys(), dass sie up ausfürhen kann.

Da sagt sie speed = -50.

Das heißt sie geht in x Wert nach Oben. Wir sagen ja : x/y =0/0 von oben links aus gesehen. Das heißt wenn ich -50 habe, dann gehe ich nach oben. Aber irgendwie scheint das nicht zu funktionieren.

:/

Vielleicht weiß ja jemanden einen Ratschlag. *doubt*
```


----------



## Schandro (26. Apr 2009)

> Aber irgendwie scheint das nicht zu funktionieren.


Könnten wir bitte einen Filter ins Forum einbauen, dass wenn jemand diesen Satz schreibt ne Fehlermeldung aufpoppt wo drauf steht:
"Bitte komplette Fehlermeldung posten."
?

Zu deinem Problem:
Wird die Methode checkKeys irgendwo aufgerufen?


----------



## 0x7F800000 (26. Apr 2009)

Spin hat gesagt.:


> Hallo , ich habe mal wieder ein neues Problem.


kann sein, aber zumindest deine probleme mit code tags scheinen uralt zu sein... Ist das irgendwie unheilbar? :noe:


> Ich verstehe es nicht, warum es nicht funktioniert.


tolle Fehlerbeschreibung 
Was man schonmal sagen kann:
vor "keyPressed" fehlt schonmal die @Override Annotation...
Ab welcher stelle funktioniert es denn nicht? 
-reagiert das prog absolut nicht auf tasten? (dann hast du evtl. einfach nur vergessen den Listener an die componente anzuhängen?)
-reagiert es auf tasten, klemmt aber immer bei "up"? (dann vergisst du eventuell, die button-flags auf false zurückzusetzen, d.h. alle deine tasten funktionieren exakt 1 mal, und danach sind für immer und ewig alle flags true)
-verarbeitet es die flags nicht korrekt? (dann zeig die methode, die diese behandelt...)



> Das heißt sie geht in x Wert nach Oben. Wir sagen ja : x/y =0/0 von oben links aus gesehen. Das heißt wenn ich -50 habe, dann gehe ich nach oben. Aber irgendwie scheint das nicht zu funktionieren.


Ist zwar alles schön und gut, aber hat's was mit dem problem zu tun? ???:L


----------



## Spin (26. Apr 2009)

Hallo, ich merke gerade, wodran ich arbeiten muss, wenn ich hier ein Thema eröffne 
An meinen Code-Tags und an den Fehlermeldungen .

Meistens habe ich keine Fehlermeldungen, die mir die IDE anzeigt, da ich diese schnell selbst lösen kann. Also habe ich nichts rot unterstrichen.

Mein Programm reagiert garnicht auf die Tasten.

Componenten habe ich den Listener hinzugefügt: frame.addKeyListener(this);

Methoden werden alle aufgerufen:

```
public void run() // implementieren der Run Methode , damit wir unser Spielschleife in einen eigenen Thread
                        // laufen lassen können
    { while(spiel_run)
      {
          computeDelta(); // Zeit berechnen für den Schleifendurchlauf
          checkKeys(); // abfrage von Tastatur
          doLogic(); // Logik Operationen
          moveObjects(); // Objekte bewegen lassen
          repaint();
```


Override Notation braucht man ja nicht extra mit hinschreiben  Bei mir werden sie alle regelrecht überschrieben.


Ach bevor ich das mach : ich poste euch einfach mal alles:



```
package dspiel;

/**
 *
 * @author Spin
 */

/*Hauptklasse + Initialisierung*/
import java.io.IOException;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Vector;
import javax.imageio.ImageIO;
public class Spielfeld extends JPanel implements Runnable,KeyListener {

    private static final long serialVersionID =1L;
    boolean spiel_run = true; // definieren ein boolean, damit die Spielschleife elegant beendet werden kann

    long delta =0; // errechnen der Zeit für den letzten Durchlauf
    long last = 0; // Speicherung der letzten Systemzeit
    long fps =0; // errechnug der Bildrate (frames per second)

    ObjekteBewegen copter;
    Vector<ObjekteBewegen> actors;

    // Steuern der Figur
    boolean up = false;
    boolean down = false;
    boolean left = false;
    boolean right = false;
    int speed =50; //Geschwindigkeit












    private void doLogic() {
        for(Moveable mov:actors)
        {
            mov.doLogic(delta);
        }
    }


    
    private BufferedImage[] loadpics(String path,int pics) throws IOException  // Methode bekommt Speicherort und Anzahl der Einzelbilder übergeben
    {
        BufferedImage[] a = new BufferedImage[pics]; // erzeugen : in der Größe dr Einzelbilder
         BufferedImage source = null;// Image zum Laden des ganzen Bildes

        URL pic_url = getClass().getClassLoader().getResource(path); // ermitteln der URL mit Speicherort

    try{source = ImageIO.read(pic_url);} // Laden des Bildes
    catch(IllegalArgumentException e){ System.err.println("Leseprobleme");}

        for(int i=0;i<pics;i++)
        { // getSubImage() -->Quellbild wird in die Anzahl der angegebenen Einzelbilder zerlegt
         a[i] = source.getSubimage(i*source.getWidth()/pics, 0,source.getWidth()/pics, source.getHeight());
        }
        return a;
    }

    private void moveObjects() {
         for(Moveable mov:actors)
        {
            mov.doLogic(delta);
        }
    }



   

    /*Konstrukto soll Breite und Höhe enthalten*/
    public Spielfeld(int breite , int hoehe) throws IOException
    {
        /*hinterlegen des Codes um ein Fenster zu erzeugen*/
        this.setPreferredSize(new Dimension(breite,hoehe)); // übergeben der Größe an Spielfeld
        JFrame frame = new JFrame("Spielfeld");
        frame.setLocation(100, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Frame kann nicht über x geschlossen werden
        frame.add(this);
        frame.addKeyListener(this);
        frame.pack(); // Fenster wird an die gewünschte Größe angepasst
        frame.setVisible(true);
        initialisieren();

    }
    private void initialisieren() throws IOException
    {
        last = System.nanoTime(); // Ausgabe der Zeit, wie lange die Methode zum ausführen braucht

        actors = new Vector<ObjekteBewegen>(); // Vectorobjekt
        BufferedImage[] heli = this.loadpics("pics/heli.gif",4);
        copter = new ObjekteBewegen(heli,400,300,100,this); // Bildwechselrate von 100ms
        actors.add(copter); // an den Vector packen
        Thread t = new Thread(this);
        t.start();
    }
    public void run() // implementieren der Run Methode , damit wir unser Spielschleife in einen eigenen Thread
                        // laufen lassen können
    { while(spiel_run)
      {
          computeDelta(); // Zeit berechnen für den Schleifendurchlauf
          checkKeys(); // abfrage von Tastatur
          doLogic(); // Logik Operationen
          moveObjects(); // Objekte bewegen lassen
          repaint();
        try
        {
            Thread.sleep(10);
        }
        catch(InterruptedException e)
        {}
      }
    }
    private void computeDelta()
    {
        delta = System.nanoTime() - last; // Erechnen der Zeit der Schleife in Nanosekunden
        last = System.nanoTime(); // Speicherung der aktuellen Systemzeit

        fps= ((long) 1e9/delta);  // Errechnug der Framerate
    }
    public void paintComponent(Graphics g) // überschreiben um individuelle Zeichenoperationen vorzunehmen
    { super.paintComponent(g); // dadurch wird per Methoden aufruf Graphics an alle Objekte weitergegeben

      g.setColor(Color.red);
      g.drawString("FPS:" +Long.toString(fps),20, 10);

      if(actors != null)
      {
         for(Drawable draw: actors)
         {
             draw.drawObjects(g);
         }
      }
    }

 

    public static void main(String[]args) throws IOException
    {
        new Spielfeld(800,600);
    }

    public void keyTyped(KeyEvent e) {
          if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            up =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            left =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            down =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            right =true;
        }
    }
    

    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            up =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            left =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            down =true;
        }
        if(e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            right =true;
        }
    }


    public void keyReleased(KeyEvent e) {  // Bewegung rückgängig machen
      if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            up =false;
        }
        if(e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            left =false;
        }
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            down =false;
        }
        if(e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            right =false;
        }
}

    public void checkKeys()
    {
        if(up)
        {
            copter.setVerticalSpeed(-speed);
        }
        if(down)
        {
            copter.setVerticalSpeed(speed);
        }
        if(right)
        {
            copter.setHorizontalspeed(speed);
        }
        if(left)
        {
            copter.setHorizontalspeed(-speed);
        }
        if(!up && !down)
        {
            copter.setVerticalSpeed(0);
        }
        if(!left && !right)
        {
            copter.setHorizontalspeed(0);
        }
    }
}
```


----------



## 0x7F800000 (26. Apr 2009)

öööhm...
so spontan fällt mir eigentlich erstmal nur auf, dass keyTyped wesentlich mehr kram beinhaltet, als ein leeres {} klammerpaar.
Das mach doch keinen Sinn. Wenn der benutzer eine taste kurz drückt und loslässt, werden ja die ereignisse
-pressed
-released
-typed
gesendet.
Damit werden die flags dauernd auf true gesetzt, wenn ich das richtig verstehe... Ich würde den ganzen code aus keyTyped vollständig weglassen.

Ansonsten wäre was kompilierbares schön^^ Zum beispiel könntest du die paint-methoden der ganzen gegenstände durch weiße quadrate ersetzen, damit man die bilder nicht zu laden braucht... Und ohne Moveable & Co Interfaces kann man mit dem code auch nicht viel anfangen... Sieht eigentlich recht vernünftig aus.


----------



## Tobias (26. Apr 2009)

Und ohne @Override wirst du so Fehler wie "keyPessed" erst nach langem Suchen finden. Nutze die Werkzeuge, die dir zur Verfügung gestellt werden!


----------



## Schandro (26. Apr 2009)

da fehlt die "ObjekteBewegen" Klasse. (komischer Name).

Allgemeiner Tipp: Debugge, dafür reichen meist ein paar System.out.ptintl an den richtigen Stellen um den Fehler immer weiter einzugrenzen.

Und schreib besser immer @Override dazu.


----------



## Ebenius (27. Apr 2009)

Spin hat gesagt.:


> Hallo, ich merke gerade, wodran ich arbeiten muss, wenn ich hier ein Thema eröffne
> An meinen Code-Tags und an den Fehlermeldungen .


[off topic] Hilft Dir dieser FAQ-Beitrag vielleicht? [thread=81529]Wie man Fragen richtig stellt[/thread]

Ebenius


----------



## Spin (27. Apr 2009)

Hier ist meine andere Klasse, mit der ich das Objekt bewegen lasse.


```
package dspiel;

/**
 *
 * @author Spin
 */
import java.awt.*;
import java.awt.geom.Rectangle2D; // dadurch x und y Parameter
import java.awt.image.BufferedImage;
public class ObjekteBewegen extends Rectangle2D.Double implements Moveable,Drawable {
    
    private double dx;// vertikale Veränderung
    private double dy;

    long delay; // umschalten zwischen den Bilder zu steuern
    long animation=0; // Zeit kumullieren
    Spielfeld parent; // Referenz auf Spielfeld
    BufferedImage[] pics; // Speichern der Animation
    int currentpics =0; // Zähler für das aktuell anzuzeigene Bild

    public ObjekteBewegen(BufferedImage[] i,double x, double y,long delay, Spielfeld p)
    {
        pics = i;
        this.x=x;
        this.y=y;
        this.delay=delay;
        this.width =pics[0].getWidth(); // Holen der Breite und Höhe des ersten Bildes
        this.height = pics[0].getHeight();
        parent =p;
    }


    public void doLogic(long delta) { // bekommt die Dauer des letzten Schleifendurchlaufs

        animation += (delta/1000000); // wir bekommen nanosekunden: bequemer sind Millisekunden für Animation
        if(animation > delay) // Ist der Wert der Variable animation größer als der voreingestellte Animationswert
                             // setzen wir animation wieder auf 0 und rufen computeAnimation() auf, über die das nächste Bild ermittelt wird
        {
            animation =0;
            computeAnimation();
        }
    }
        private void computeAnimation()
        {
            currentpics++;

            if(currentpics>=pics.length)  // erhöhen , wenn das ende erreicht wurde, wieder auf 0
            {
                currentpics =0;
            }


    }

    public void move(long delta) {

        /* Wenn unsere Delta-Werte nicht null sind, dann verändern wir die Position
         * abhängig von der Zeit , die der letzte Durchlauf unserer Spielschleife gebraucht hat*/

        if(dx!=0)
        {
           x+= dx*(delta/1e9);
            
        }
         if(dy!=0)
        {
            x+= dy*(delta/1e9);
        }
    }

    public void drawObjects(Graphics g) {
       g.drawImage(pics[currentpics], (int) x,(int) y, null);  // Graphics niemals mit getGraphic holen
    }

    /**
     * @return the dx
     */
    public double getHorizontalSpeed() {
        return dx;
    }

    /**
     * @param dx the dx to set
     */
    public void setHorizontalspeed(double dx) {
        this.dx = dx;
    }

    /**
     * @return the dy
     */
    public double getVerticalSpeed() {
        return dy;
    }

    /**
     * @param dy the dy to set
     */
    public void setVerticalSpeed(double dy) {
        this.dy = dy;
    }

}
```


Aus Key Typed habe ich es nun rausgenommen.

Nun könnt ihr es auch einmal kompilieren. Ihr müsstet nur den Pfad zu einen eigenen 30 x 30 Pixel Bild ändern. Ich habe ja ein BufferedImage benutzt. Vielleicht sollte ich es mal mit einen einzelnen Bild versuchen.

Findet ihr hier spontan einen Fehler. Ich frage mich einfach nur, warum mein Programm nicht auf Tastatur Events reagiert.

Habe das Interface + Methoden. In den Methoden die Abfrage geschrieben + Auslösung.

:autsch:


----------



## Quaxli (27. Apr 2009)

Der Fehler ist in der komisch benamsten Klasse ObjekteBewegen 


```
if(dx!=0)
        {
           x+= dx*(delta/1e9);
            
        }
         if(dy!=0)
        {
            x+= dy*(delta/1e9);
        }
```

Wenn dy nicht Null ist, solltest Du das zu y hinzuaddieren nicht zu x. Also:


```
if(dy!=0)
        {
            y+= dy*(delta/1e9);
        }
```

Hab' gerade gesehen, daß Schilder wieder funktionieren:
[DUKE]Danke an die Admins![/DUKE]


----------



## Spin (27. Apr 2009)

Ok, danke, dass habe ich nun geändert, jedoch bewegt er sich immer noch nicht.
Vielleicht weiß noch jemand ein Tipp. :/


```
public interface Moveable {

    public void doLogic(long delta); // für Kollisionen
    public void move(long delta); // eigentliche Bewegung

}
```


Das mein Interface .


----------



## Quaxli (27. Apr 2009)

Kann es sein, daß Dein Objekt nicht in dem Vector actors enthalten ist?


----------



## Spin (27. Apr 2009)

Hey 

Quaxli ....ich habe mir das ganze Tut aus deiner Signatur nun runtergeladen und suche selbst nach dem Fehler 

Danke^^


----------



## Quaxli (28. Apr 2009)

Bei mir gibt's aber keine Klasse "ObjektBewegen".


----------



## Quaxli (28. Apr 2009)

Tja, wie man sieht, auch abschreiben will gelernt sein 

Folgende Fehler habe ich gefunden.

1. In Klasse ObjekteBewegen, den von gestern hier nochmal:


```
if(dy!=0){
            y+= dy*(delta/1e9);  //dy muß auf y addiert werden
        }
```

2. In Klasse Spielfeld: Du hast für Dein Objekt niemals die move-Methode aufgerufen.


```
private void moveObjects() {
		for (Movable mov : actors) {
			//mov.doLogic(delta); 
			mov.move(delta);   //<-- Beweg mich
		}
	}
```

Ich vermute mal, daß Du die doLogic-Methode kopiert hast und dann nicht richtig korrigiert.
Mit diesen Änderungen läuft es jetzt. Ich würde Dir noch empfehlen, Dich zu entscheiden, ob Du Deine Klassen deutsch oder englisch benennst. Momentan krieg ich da etwas Augenkrebs, wenn Du einerseits eine Klasse Spielfeld hast, die Interfaces aber Moveable und Drawable heißen.

Weiterhin viel Spaß


----------



## Spin (28. Apr 2009)

Danke dir 

Ich muss mich da echt mal entscheiden 
Aber habe nun mal alles compiliert und das game funktioniert. Gehe nun schritt für schritt alles durch.

Doch nur abschreiben und ausführen bringt nichts. Magst du mir das Interface Moveable genau erklären?


```
private void moveObjects() {
        for (Movable mov : actors) {
            //mov.doLogic(delta); 
            mov.move(delta);   //<-- Beweg mich
        }
    }
```


Was passiert da eigentlich genau?


----------



## Quaxli (29. Apr 2009)

Das könntest/solltest Du aber wirklich nachlesen. Aber sei's drum: Einfach ausgedrückt werden alle Objekte aus dem Vector, als ein Objekt Moveable behandelt (obwohl man ein Interface ja eigentlich nicht instanziieren kann). Dabei wird die move-Methode aufgerufen und der bei jedem Objekt individuell hinterlegt Code ausgeführt, egal ob das jetzt das ist, was Du hinterlegt hast oder die Berechnung eines schiefen Wurfs, etc.
Durch das Interface wird garantiert, daß alle Objekte über den gleichen Methodenaufruf bewegt werden können und keine Unterscheidung getroffen werden muß.


----------

