# Flüssige Bewegung



## TobiD (8. Apr 2008)

Hi Leute, ich bekomms einfach nicht hin dass sich mein Männchen flüssig bewegt, ich hoff ihr könnt mir weiterhelfen: 
	
	
	
	





```
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;

public class SuperMario extends Applet implements KeyListener, Runnable
{
  private int laenge=80, breite=50, xPos=20,yPos=480-laenge;
  Image status0;
  private Image dbImage;
  private Graphics dbg;
  private int l=0,r=0;
  
  public void init()
  {
    setSize(640,480);
    status0=getImage(getCodeBase(),"status0.jpg");
    this.addKeyListener(this);
  }
  
  public void start()
  {
    Thread th=new Thread(this);
    th.start();
  }
  
  public void run()
  {
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    while(true)
    {
      try
      {
        if(l>0)
        {
          xPos-=1;
          l--;
        }
        else if(r>0)
        {
          xPos+=1;
          r--;
        }
        Thread.sleep(20);
        repaint();
      }
    
      catch(InterruptedException ex)
      {
        //nothing
      }
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    }
  }
  
  public void paint(Graphics g)
  {
    zeichneMario(g,xPos,yPos,0);
  }
  
  public void zeichneMario(Graphics g,int x,int y,int status)
  {
    g.drawImage(status0,x,y, this);
  }
  
  public void keyPressed(KeyEvent e){
    if(e.getKeyCode()==e.VK_A)
    {
      l=5;
      e.consume();
    }
    if(e.getKeyCode()==e.VK_D)
    {
      r=5;
      e.consume();
    }
  }
  public void keyTyped(KeyEvent e){}
  public void keyReleased(KeyEvent e){}
  
  public void update(Graphics g)
  {
  dbImage = createImage (this.getSize().width, this.getSize().height);
  dbg=dbImage.getGraphics();
  dbg.setColor(getBackground());
  dbg.fillRect(0,0,this.getSize().width,this.getSize().height);
  dbg.setColor(getForeground());
  paint(dbg);
  g.drawImage (dbImage, 0, 0, this);
  }

}
```

Das ist der Code.. Hab keine Ahnung wie man dass machen soll. :?: 
Also das bild ist 50pixel breit und 80 pixel hoch,
ich hoff ihr habt ne Ahnung wie das geht,
Tobias  :###


----------



## Marco13 (8. Apr 2008)

Erstmal der Standard-Verweis auf Quaxli's Tutorial:
http://www.java-forum.org/de/viewtopic.php?p=390813

Die genaue Ursache für irgendwelche Ruckler zu finden... :? Die Priorität für den Thread in jedem Schleifendurchlauf zu setzen ist wohl nicht notwendig. Aber sonst... Naja ... Ein bißchen "gefährlich" kann dieses Konstrukt sein, das du zum Bewegen verwendest: Wenn eine Taste gedrückt wird, wird 'r' auf 5 gesetzt. Der Thread arbeitet das 'r' ab, bis es 0 ist, und "hört dann auf". Es gibt keine Garantie dafür, dass die Schleife im Thread nicht 10 mal druchlaufen wird, bis der nächste KeyEvent kommt. Sinnvoller wäre vermutlich, ein flag zu setzen, und die Bewegung erst "ausklingen" zu lassen, wenn die Taste losgelassen wurde... sowas wie

```
private boolean moveR = false;

  public void keyPressed(KeyEvent e)
  {
    if(e.getKeyCode()==e.VK_D)
    {
      moveR = true;
      r = 5;
    }
  }

  public void keyReleased(KeyEvent e)
  {
    if(e.getKeyCode()==e.VK_D)
    {
      moveR = false;
    }
  }


  public void run()
  {
    ...
        else if(r>0)
        {
          xPos+=1;
          if (!moveR) r--;
        }
   ....
}
```
(ähnich wie auch im Oben verlinkten Tutorial beschrieben)

Aber ob das der Grund dafür ist, dass es bei dir nicht "flüssig" ist...  ???:L Ganz allgemein: Selbst wenn du 50fps hast, wird sich die Figur pro sekunde nur etwa 1 cm bewegen - mit einer größeren Schrittweite, wie  xPos+=*5*; wäre die Bewegung zumindest _schneller_  :? (und mit  sowas wie r=10 im keyPressed und und xPos+=r; in der run klingt sie quadratisch ab   hat aber mit der Flüssigkeit nichts zu tun  :roll: )


----------



## Quaxli (9. Apr 2008)

Marco13 hat gesagt.:
			
		

> Erstmal der Standard-Verweis auf Quaxli's Tutorial:
> http://www.java-forum.org/de/viewtopic.php?p=390813



Danke.   

Ich würde vermuten, daß das Ruckeln daran liegt, daß für jeden Schleifendurchlauf xPos um genau 1 vermindert oder erhöht wird. Es ist aber so, daß die Schleife nie die gleiche Zeit für einen Durchlauf benöitgt. Eine gängige Lösung dafür ist, die Zeit für den Schleifendurchlauf zu messen und die Bewegung in Abhängigkeit davon zu setzen. Seit Java 1.5 geht das mit System.nanoTime() in entsprechend feiner Auflösung.

Für die Bewegung verwende ich immer folgende Methode:


```
public void move(long delta) {
		 
    if(dx!=0){
      x += dx*(delta/1e9);
    }
    
    if(dy!=0){
      y += dy*(delta/1e9);
    }

	}
```

Dabei ist delta die Zeit in Nanosekunden, die seit dem letzten Methodenaufruf vergangen ist. dx und dy sind die Veränderungen der x- und y-Position und haben für langsame Bewegungen einen Wert von ca. 50. Wenn ich nun eine Bewegung bis zum Stillstand verlangsamen möchte, muß ich das nicht wie Du über einen Zähler machen, sonder verringere an geeigneter Stelle den Wert von dx oder dy bis er Null ist.


----------



## Gast (9. Apr 2008)

Was bitte ist 1e9?


----------



## Quaxli (9. Apr 2008)

1000000000


----------



## Gast (9. Apr 2008)

Achso, danke. Hab ich irgendwie noch nie irgendwo gesehen. (oder immer übersehen)


----------



## TobiD (9. Apr 2008)

Ok, danke erstmal. Ich werd mich einfach mal an qualix vorschlag versuchen. Das Männchen soll man halt so bewegen wie zum Beispiel Super Mario in SuperMario .
Mfg
Tobias


----------



## TobiD (9. Apr 2008)

So, also ich hab's jetzt mal bei mir reingewurschtelt, aber ich denk mal ich hab nicht ganz verstanden was Qualix gemint hat: 
	
	
	
	





```
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;

public class SuperMario extends Applet implements KeyListener, Runnable
{
  private int laenge=80, breite=50, xPos=20,yPos=480-laenge;
  Image status0;
  private Image dbImage;
  private Graphics dbg;
  private boolean moveR = false, moveL=false;
  private int l=0,r=0;
  
  private long delta=System.nanoTime();
  
  public void init()
  {
    setSize(640,480);
    status0=getImage(getCodeBase(),"status0.jpg");
    this.addKeyListener(this);
  }
  
  public void start()
  {
    Thread th=new Thread(this);
    th.start();
  }
  
  public void run()
  {
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    while(true)
    {
      try
      {
        if(l>0)
        {
          xPos -= l*(delta/1000000000);
          if (!moveL) l--;
        }
        else if(r>0)
        {
          xPos += r*(delta/1000000000);
          if (!moveR) r--;
        }

        Thread.sleep(20);
        repaint();
      }
    
      catch(InterruptedException ex)
      {
        //nothing
      }
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    }
  }
  
  public void paint(Graphics g)
  {
    zeichneMario(g,xPos,yPos,0);
    g.drawString(""+delta,20,20);
  }

  
  public void zeichneMario(Graphics g,int x,int y,int status)
  {
    g.drawImage(status0,x,y, this);
  }
  
  public void keyPressed(KeyEvent e)
  {
    if(e.getKeyCode()==e.VK_D)
    {
      moveR = true;
      r = 5;
    }

    if(e.getKeyCode()==e.VK_A)
    {
      moveL = true;
      l = 5;
    }
  }

  public void keyReleased(KeyEvent e)
  {
    if(e.getKeyCode()==e.VK_D)
    {
      moveR = false;
    }

    if(e.getKeyCode()==e.VK_A)
    {
      moveL = false;
    }
  }

  public void keyTyped(KeyEvent e){}
  
  public void update(Graphics g)
  {
  dbImage = createImage (this.getSize().width, this.getSize().height);
  dbg=dbImage.getGraphics();
  dbg.setColor(getBackground());
  dbg.fillRect(0,0,this.getSize().width,this.getSize().height);
  dbg.setColor(getForeground());
  paint(dbg);
  g.drawImage (dbImage, 0, 0, this);
  }

}
```

Wenn ich jetzt einmal auf nach links klickt ist die Figur sofort verschwunden. Wenn ich dass delta noch mal durch 1000 oder so teil bewegt sie sich langsam aber es ruckelt immer noch. Und nu?? :autsch:


----------

