# Schlieren und Ruckeln, weiss nicht mehr weiter....



## nitsche (1. Nov 2010)

Moinsen,
ich habe ne Frage, und zwar weiss ich da im Moment echt nicht mehr weiter, auch etliche Forenbeiträge etc. haben mir (nur teilweise) weitergeholfen. Deswegen frag ich jetzt mal in die Runde. Ich bin dabei (um endlich in Java besser zu werden), ein Spiel zu programmieren.

Im Augenblick bewegt sich nur ein roter Balken im Spiel, d.h. linke Pfeiltaste bewegt sich nach links, rechts ist klar.

Nun hab ich das Problem, das die CPU Auslastung natürlich extrem hoch ist , wegen der Endlosschleife, und das ganze Spiel nicht so recht flüssig läuft. Des weiteren hab ich Schlirren auf dem Bildschirm beim Bewegen.

Hat jemand ne Idee?

gameLoop() ist die Schleife und stösst bei jedem Durchlauf moveMouth an und zeichnet danach das Spiel (der Mund, ist dann ein Bild)

Die Funktion breeze() ist zu ignorieren.

ticks, sind die Zeiteinheiten seit dem letztem Durchlauf


```
/**
  *
  * Beschreibung
  *
  * @version 1.0 vom 31.10.2010
  * @author
  */


import java.awt.image.*;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;

public class Torte extends JFrame {
  // Anfang Attribute
  double mouthPos;
  int mouthWidth=100;
  BufferedImage mouthImage;
  
  int windowWidth=600;
  int windowHeight=600;
  // Ende Attribute
  
  int airMouth=0;
  int airLung=400;

  final int airLungMax=400;
  final int airMouthMax=100;
  
  final int barMaxSize=200;
  
  boolean keyLeftPressed=false;
  boolean keyRightPressed=false;
  boolean keySpacePressed=false;
  
  boolean gameRunning=true;
  int fps;

  BufferStrategy bf;

  public Torte(String title) {
    super(title);
    
    // Init
    mouthPos=windowWidth/2-mouthWidth/2;
     try{
        mouthImage = ImageIO.read( new File( "mouth.png" ) );

     }catch(Exception E){
        System.out.println(E.getMessage());
     }
     
    // Frame-Initialisierung
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) { gameRunning=false;dispose(); }
    });
    
    addKeyListener(new KeyListener() {
    
      public void keyPressed(KeyEvent e) {
        checkKey(e.getKeyCode(),true);
      }
      
      public void keyReleased(KeyEvent e) {
        checkKey(e.getKeyCode(),false);
      }
      
      public void keyTyped(KeyEvent e) {
      }
    });

    setSize(600,600);
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    setResizable(false);
    setVisible(true);
    
    createBufferStrategy(2);
    bf=this.getBufferStrategy();
    
    gameLoop();
  }
  
  public void gameLoop(){
  
   long lastTick=System.nanoTime();
   long currentTick=System.nanoTime();
   long ticks=0;

    while(gameRunning){
      currentTick = System.nanoTime();
      ticks = (currentTick - lastTick);
      lastTick=currentTick;
      fps = (int) (((long) 1e9)/(ticks));
      
      moveMouth(ticks);
      drawGame();
      

    }
  }
  
  public void checkKey(int keyCode,boolean pressed){
    switch(keyCode){
      case 32:
      keySpacePressed=pressed;
      break;
      
      case 37:
      keyLeftPressed=pressed;
      break;
      
      case 39:
      keyRightPressed=pressed;
      break;
    }
  }
  
  public void drawGame(){
    Graphics g = null;
    g = bf.getDrawGraphics();
    
    g.setColor( new Color(255, 255, 255) );
    g.fillRect( 1, 1, windowWidth , windowHeight);

    int tmp;
    if(airLung>0){
      tmp=barMaxSize/(airLungMax/airLung);
    }else{
      tmp=0;
    }
    
    g.setColor( new Color(0, 255, 0) );
    g.fillRect( 11, 40, tmp , 20);
    g.setColor( new Color(255, 0 , 0) );
    
    if(airMouth>0){
      tmp=barMaxSize/(airMouthMax/airMouth);
    }else{
      tmp=0;
    }
    g.fillRect( 11, 70, tmp, 20);
    
    g.setColor( Color.BLACK );
    g.drawRect(10,39, barMaxSize+1, 21);
    g.drawRect(10,69, barMaxSize+1, 21);

    g.drawImage(mouthImage, (int) mouthPos, 120, null);

    g.dispose();
    bf.show();

    Toolkit.getDefaultToolkit().sync();
  }
  
  public void breeze(){
     if(keySpacePressed){
       if(airMouth < airMouthMax){
         airMouth++;
       }
     }
  }

  public void moveMouth(long ticks){

     if(keyLeftPressed){
        mouthPos-=ticks/3000000.0;

        if(mouthPos < 1){
          mouthPos=1;
        }

     }else if(keyRightPressed){
        mouthPos+=ticks/3000000.0;
        
        if(mouthPos > getSize().width-mouthWidth){
          mouthPos=getSize().width-mouthWidth;
        }
     }
  }


  public static void main(String[] args) {
    new Torte("Torte");
  }
}
```


----------



## Antoras (1. Nov 2010)

Also, bei dir ist da schon einmal eine ganze Menge kaputt.

Als erstes lässt sich der Prozess nicht mehr richtig beenden. Lösung:

```
setDefaultCloseOperation(EXIT_ON_CLOSE); // damit kann das Frame über den Fenster-Close-Button beendet werden
```

Die Lösung mit dem BufferStrategy ist schlecht. Zeichne lieber auf ein JPanel und hole dir dessen Graphics-Objekt:

```
pnlDraw = new JPanel() {
  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    // use g
  }
};
```
Damit umgehst du schon einmal viele Hürden was die Darstellung betrifft.

In deiner Game-Loop benötigst du einen Timeout:

```
try {
  Thread.sleep(10);
} catch (InterruptedException e) {
  e.printStackTrace();
}
```

Ein User hier aus dem Forum hat ein gutes Tutorial für Spieleentwicklung geschrieben. Guck dir das mal an.


----------



## Leifa (2. Nov 2010)

Antoras hat gesagt.:


> Die Lösung mit dem BufferStrategy ist schlecht.



Wie meinst Du das?

Ist BufferStrategy grundsätzlich schlecht, oder nur für gewisse Zwecke? Ich bin nämlich diesem Tutorial gefolgt, wo es mit BufferStrategy gelöst wird, und ich bin mit den Ergebnissen sehr zufrieden, auch was die Auslastung angeht.


----------



## Empire Phoenix (2. Nov 2010)

Für aktives rendering ist das jetzt nciht so schlecht mit der bufferstrategie.
Du könntest die auslastung mit ner festen framerate senken.

Thread.sleep(Wartezeit-ZeitfürLetztenSchleifendutchlauf) 
(Abfangen das nur positive zeiten gewartet werden)


----------



## Antoras (2. Nov 2010)

BufferStrategy ist nicht schlecht - ich bezog das auf den Wissenstand des TO für den es in diesem Fall schlecht ist, da die Lösung mit einem JPanel für den Anfang einfacher zu verstehen ist.


----------



## Quaxli (8. Nov 2010)

Also bei mir läuft das Beispiel oben ja recht flüssig. Keine Schlieren, nix. :bahnhof:
Evtl. liegt es am Image? Ich hab halt mal ein beliebiges rein kopiert, da ich das im Programm verwendete natürlich nicht hatte.

Ich habe aber trotzdem mal ein bißchen an dem Programm rumgefrickelt und u. a. einen 2. Thread reingebastelt. Guck halt mal, ob es bei Dir besser läuft und falls ja, kannst Du ja mal gucken wo ich geschraubt habe.


```
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
public class Torte extends JFrame implements Runnable{
	private static final long	serialVersionUID	= 1L;
	
	// Anfang Attribute
  double mouthPos;
  double mouthSpeed = 150;
  
  BufferedImage mouthImage;
  
  int windowWidth=600;
  int windowHeight=600;
  // Ende Attribute
  
  int airMouth=0;
  int airLung=400;
 
  final int airLungMax=400;
  final int airMouthMax=100;
  
  final int barMaxSize=200;
  
  boolean keyLeftPressed=false;
  boolean keyRightPressed=false;
  boolean keySpacePressed=false;
  
  boolean gameRunning=true;
  int fps;
 
  BufferStrategy bf;
 
  public Torte(String title) {
    super(title);
    
    // Init
     try{
        mouthImage = ImageIO.read(getClass().getClassLoader().getResource("pics/mouth.PNG"));
 
     }catch(Exception E){
        System.out.println(E.getMessage());
     }
     mouthPos=windowWidth/2-mouthImage.getWidth()/2;
     
    addKeyListener(new KeyListener() {
    
      public void keyPressed(KeyEvent e) {
        checkKey(e.getKeyCode(),true);
      }
      
      public void keyReleased(KeyEvent e) {
        checkKey(e.getKeyCode(),false);
      }
      
      public void keyTyped(KeyEvent e) {
      }
    });
 
    setSize(600,600);
    setLocationRelativeTo(null);
    setResizable(false);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
    
    createBufferStrategy(2);
    bf=this.getBufferStrategy();
    
    Thread th = new Thread(this);
    th.start();
  }
  
  
  public void checkKey(int keyCode,boolean pressed){
    
  	switch(keyCode){
      case KeyEvent.VK_SPACE:
        keySpacePressed=pressed;
        break;
      
      case KeyEvent.VK_LEFT:
        keyLeftPressed=pressed;
        break;
      
      case KeyEvent.VK_RIGHT:
        keyRightPressed=pressed;
        break;
      
      case KeyEvent.VK_UP:
      	mouthSpeed+=10;
      	break;
      	
      case KeyEvent.VK_DOWN:
      	mouthSpeed-=10;
      	break;
      
      
    }
  }
  
  public void drawGame(){
  	
  	if(!isVisible()){
  		return;
  	}
  	
    Graphics g = null;
    g = bf.getDrawGraphics();
    
    g.setColor( new Color(255, 255, 255) );
    g.fillRect( 1, 1, windowWidth , windowHeight);
 
    int tmp;
    if(airLung>0){
      tmp=barMaxSize/(airLungMax/airLung);
    }else{
      tmp=0;
    }
    
    g.setColor( new Color(0, 255, 0) );
    g.fillRect( 11, 40, tmp , 20);
    g.setColor( new Color(255, 0 , 0) );
    
    if(airMouth>0){
      tmp=barMaxSize/(airMouthMax/airMouth);
    }else{
      tmp=0;
    }
    g.fillRect( 11, 70, tmp, 20);
    
    g.setColor( Color.BLACK );
    g.drawRect(10,39, barMaxSize+1, 21);
    g.drawRect(10,69, barMaxSize+1, 21);
 
    g.drawImage(mouthImage, (int) mouthPos, 120, null);
    g.setColor(Color.RED);
    g.drawString("FPS: "+Integer.toString(fps),250,50);
    g.drawString("Speed: "+Double.toString(mouthSpeed),250,100);
 
    g.dispose();
    bf.show();
 
    Toolkit.getDefaultToolkit().sync();
  }
  
  public void moveMouth(long ticks){
 
     if(keyLeftPressed){
        mouthPos= mouthPos - mouthSpeed*(ticks/1e9);
 
        if(mouthPos < 1){
          mouthPos=0;
        }
 
     }else if(keyRightPressed){
    	 mouthPos= mouthPos + mouthSpeed*(ticks/1e9);
        
        if(mouthPos > getWidth()-mouthImage.getWidth()){
          mouthPos=getWidth()-mouthImage.getWidth();
        }
     }
  }
 
 
  public static void main(String[] args) {
    new Torte("Torte");
  }

	public void run() {
		
	   long lastTick=System.nanoTime();
	   long currentTick=System.nanoTime();
	   long ticks=0;
	 
	    while(isVisible()){
	    	
	      currentTick = System.nanoTime();
	      ticks = (currentTick - lastTick);
	      lastTick=currentTick;
	      fps = (int) (((long) 1e9)/(ticks));
	      
	      try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
	      
	      moveMouth(ticks);
	      drawGame();
	      
	 
	    }
		
		
	}
}
```


----------

