Warum flackert das Bild ? (Swing)

  • Themenstarter Themenstarter McMeier
  • Beginndatum Beginndatum
M

McMeier

Gast
Hallo,

ich hätte mal eine frage und zwar warum das Bild bei meinem Code flackert. Ich dachte Swing wäre Standardmäßig Doublebuffered. Ich habe sogar zusätzlich noch im Constructor meiner Klasse setDoubleBuffered(true); geschrieben. Hier mal der Code.
Java:
package graphics;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.text.DecimalFormat;
import java.util.Random;


import javax.swing.ImageIcon;
import javax.swing.JPanel;

import logical.*;

@SuppressWarnings("serial")
public class MainGraphics extends JPanel implements Runnable{
	
	long nTime=1;
	long oTime=2;
	double timeDif;
	double fps = 0;
	double frames;
	
	int length;
	int lx;
	int ly;
	boolean gameover = false;
	boolean second=false;
	boolean levelup;
	
	ImageIcon iii = new ImageIcon("bin/grass.jpg");
	ImageIcon iiiapl= new ImageIcon("bin/apple.png");
	Image img;
	Image apple;
	
	Color cl;
	
	Snake s = new Snake();
	Target t= new Target();
	
	Random rand = new Random();
	
	int a=0;
	int r = 0;
	
	Thread animator;
	DecimalFormat df = new DecimalFormat("#0.00");
	
	public MainGraphics()
	{
		img = iii.getImage();
		apple = iiiapl.getImage();

		setBackground(Color.BLACK);
		setDoubleBuffered(true);
		this.addKeyListener(s);
		
	}

    public void addNotify() {
        super.addNotify();
        animator = new Thread(this);
        animator.start();
    }

	public void paint( Graphics g )
	{
		super.paint(g);
		Graphics2D g2d= (Graphics2D)g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		g2d.setColor(t.getTargetColor());
		g2d.drawImage(apple,t.getTargetX(),t.getTargetY(),this);
		
		g2d.setColor(Color.darkGray);
		g2d.fillRect(0, 260, 300, 2);
		g2d.setColor(Color.lightGray);
		g2d.drawString("Score:"+s.getScore(), 5, 275);
		g2d.drawString("Lifes:"+s.getLives(), 245, 275);
		g2d.drawString("Level:"+s.getLevel(),170,275);
		
		while(length>=a){
			g2d.setColor(s.getSnakeColor());
			g2d.fillRoundRect(s.getx(a), s.gety(a), 6, 6, 4,4);
			a++;
		}
		if(levelup){
			g2d.setColor(Color.ORANGE);
			g2d.drawString("Level UP!!", lx, ly);
		}
		if(gameover==true){
			g2d.setColor(Color.DARK_GRAY);
			g2d.drawString("GAME OVER",110,130);
			g2d.drawString("Press \"R\" to Restart", 90, 140);
		}
	}
	
	private boolean secondOver(){
		oTime=nTime;
		nTime=System.nanoTime();
		timeDif+=(nTime-oTime)/1000000000.0;
		if(timeDif>0.01){
			second=true; 
			timeDif=0;
		}
		else
			second=false;
		return second;
	}
	
	public void run() 
	{	
		while(true)
		{	
			if(s.isLevelUp()){
				levelup=true;
				lx=120;
				ly=60;
			}
			if(secondOver()){
				ly+=1;
			}
			if(ly>120)
				levelup=false;
			a=1;
			length=s.getLength();
			gameover=s.isGameOver();
		
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
				
				this.update(getGraphics());
		}
	}	
}

Ach und mal noch ne Info, mit update.... hat es bisher nicht geflackert erst seit dem ich das mit dem Antialiasing habe. das musste aber sein weil sonst die RoundRects nicht richtig dargestellt werden...

Danke sehr
 
Hey!

[JAVA=138]this.update(getGraphics());[/code]

Das ist böse.

Du rufst darüber [JAPI]javax.swing.JComponent#paint(java.awt.Graphics)[/JAPI] direkt auf, das auch noch mit einem über [JAPI]javax.swing.JComponent#getGraphics()[/JAPI] geholten Graphics-Objekt. Außerdem ist das dann gar nicht im EDT. Probier es mal mit einem [JAPI]java.awt.Component#repaint()[/JAPI].
 
Wie schon gesagt:
Java:
this.update(getGraphics());
Sowas macht man nicht. repaint() ist da schon der richtige weg.

Man überschreibt in Swing auch die paintComponent Methode und nicht die paint Methode. Vielleicht löst das dein Problem ja schon.
 
@McMeier: Ich weiß nicht, ob das dein Problem als Ganzes löst, aber ich habe in deinem Code gesehen, dass du "ImageIcon" verwendest. Versuche stattdessen einmal die Klasse BufferedImage. Diese beugen dem "Flacker-Effekt" dadurch vor, dass sie (wie der Name schon sagt) einen doppelt großen Puffer verwenden. Verbraucht etwas mehr Hauptspeicher, allerdings flackern sie unter "Belastung" (Bewegung etc.) nicht.

Außerdem kannst du versuchen, nicht nur deine Bilder doppelt zu puffern, sondern gleich dein ganzes JFrame, falls die BufferedImages alleine das Problem nicht lösen. Dazu gibt es im JFrame (allgemeiner: in der Klasse "Window", von der dein JFrame erbt) die Methode createBufferStrategy(...). Diese übernimmt einen Integer, der angibt, wie viele Puffer du verwenden willst (standardmäßig wird 1 Puffer verwendet). Du könntest also sagen:

Java:
public class MyFrame extends JFrame{

   // constructor
   public MyFrame(...){
      ...
      // verwende doppelt gepufferte Grafiken um Flackern zu vermeiden
      this.createBufferStrategy(2);
      ...
   }

}


Damit sollte es klappen. Ich hatte das Problem bisher in Swing selbst noch nicht, kenne es aber von anderen Sprachen - dort wirkt das oftmals wahre Wunder 🙂


Gruß,


Alan
 
kann ich da jetzt einfach
Java:
public void paint(Graphics g)
durch
Java:
public void paintComponent(Graphics g)

ersetzen ?? wenn ja welche Methode muss ich dann in der Dauerschleife aufrufen?

Ach und übrigens das Image flackert Null nur die roundedRects. Und mit repaint() anstatt update wurde es noch schlimmer ....
 
Ja, statt paint überschreibst du paintComponent. Der Inhalt kann an sich gleich bleiben, nur den super aufruf musst du ändern.
 
hab jetzt paint in paintComponent umbenannt und die super methode geändert.
Habs in der Endlosschleife mit repaint und update probiert aber nichts hilft. flackert alles munter weiter:
bei update weniger bei repaint mehr. Und wenn ich das Antialiasing wegnehme nicht mehr....
 
Sorry ich muss jetzt dumm fragen was ein KSKB ist ?? Also ich weiß was die Abkürzung heißt aber noch was gemeint ist! ist das einfach Excutable Jar ????

Ich kann nämlich als Gast keine Datein hochladen !
 
Nein, du postest einfach den Code (möglichst kurz) an dem sich das Problem nachvollziehen lässt. Kompilierbar natürlich 😉
 
Ja Moment da muss ich alle Klassen posten damits funzt.
Java:
package graphics;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Window extends JFrame 
{
	MainGraphics mg;
		
	public Window()
	{
		setSize(301,313);
		setLocationRelativeTo(null);
		setResizable(false);
		setTitle("Snake v1.0");
		setDefaultCloseOperation(EXIT_ON_CLOSE);	

		mg = new MainGraphics();
		mg.setBounds(0, 0, 200, 30);
		add(mg);
		setVisible(true);
		mg.requestFocus(true);	
	}
	public static void main (String[] args){
		new Window();	
	}
		
}
Java:
package graphics;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.text.DecimalFormat;
import java.util.Random;


import javax.swing.ImageIcon;
import javax.swing.JPanel;

import logical.*;

@SuppressWarnings("serial")
public class MainGraphics extends JPanel implements Runnable{
	
	long nTime=1;
	long oTime=2;
	double timeDif;
	double fps = 0;
	double frames;
	
	int length;
	int lx;
	int ly;
	boolean gameover = false;
	boolean second=false;
	boolean levelup;
	
	ImageIcon iii = new ImageIcon("bin/grass.jpg");
	ImageIcon iiiapl= new ImageIcon("bin/apple.png");
	Image img;
	Image apple;
	
	Color cl;
	
	Snake s = new Snake();
	Target t= new Target();
	
	Random rand = new Random();
	
	int a=0;
	int r = 0;
	
	Thread animator;
	DecimalFormat df = new DecimalFormat("#0.00");
	
	public MainGraphics()
	{
		img = iii.getImage();
		apple = iiiapl.getImage();

		setBackground(Color.BLACK);
		setDoubleBuffered(true);
		this.addKeyListener(s);
	}

    public void addNotify() {
        super.addNotify();
        animator = new Thread(this);
        animator.start();
    }

    @Override
	public void paintComponent( Graphics g )
	{
    	super.paintComponent(g);
    	
		Graphics2D g2d= (Graphics2D)g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		g2d.setColor(t.getTargetColor());
		g2d.drawImage(apple,t.getTargetX(),t.getTargetY(),this);
		
		g2d.setColor(Color.darkGray);
		g2d.fillRect(0, 260, 300, 2);
		g2d.setColor(Color.lightGray);
		g2d.drawString("Score:"+s.getScore(), 5, 275);
		g2d.drawString("Lifes:"+s.getLives(), 245, 275);
		g2d.drawString("Level:"+s.getLevel(),170,275);
		
		while(length>=a){
			g2d.setColor(s.getSnakeColor());
			g2d.fillRoundRect(s.getx(a), s.gety(a), 6, 6, 4,4);
			a++;
		}
		if(levelup){
			g2d.setColor(Color.ORANGE);
			g2d.drawString("Level UP!!", lx, ly);
		}
		if(gameover==true){
			g2d.setColor(Color.DARK_GRAY);
			g2d.drawString("GAME OVER",110,130);
			g2d.drawString("Press \"R\" to Restart", 90, 140);
		}
	}
	
	private boolean secondOver(){
		oTime=nTime;
		nTime=System.nanoTime();
		timeDif+=(nTime-oTime)/1000000000.0;
		if(timeDif>0.01){
			second=true; 
			timeDif=0;
		}
		else
			second=false;
		return second;
	}
	
	public void run() 
	{	
		while(true)
		{	
			if(s.isLevelUp()){
				levelup=true;
				lx=120;
				ly=60;
			}
			if(secondOver()){
				ly+=1;
			}
			if(ly>120)
				levelup=false;
			a=1;
			length=s.getLength();
			gameover=s.isGameOver();
		
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			update(this.getGraphics());
		}
	}	
}
Java:
package logical;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class Snake implements Runnable,KeyListener{
	
	private static final long serialVersionUID = 1L;
	
	char input='R';
	int kCode;
	int x1 = 1;
	int y1 = 1;
	int i;
	int e=0;
	int z=0;
	
	public static int[]xarr= new int[1000];
	public int[]yarr= new int[1000];
	 
	int slength=10; 
	int sleep = 120;
	int score = 0;
	int lifes = 3;
	int level =1;
	int movement=7;
	int size=5;
	int levelx;
	int levely;
	boolean gameover;
	boolean got = true;
	boolean com = true;
	boolean sl = true;
	boolean turbo=false;
	boolean levelup=false;
	
	Random r = new Random();
	Target t = new Target();
	Color col;
	
	public Snake()
	{
		Thread sn = new Thread(this);
		sn.start();
	}

	@Override
	public void keyPressed(KeyEvent e)
	{
		kCode=e.getKeyCode();
		
		if(kCode==KeyEvent.VK_UP    && input!='D' && com==true)	{input='U';com=false;}
		if(kCode==KeyEvent.VK_DOWN  && input!='U' && com==true)	{input='D';com=false;}
		if(kCode==KeyEvent.VK_LEFT  && input!='R' && com==true)	{input='L';com=false;}
		if(kCode==KeyEvent.VK_RIGHT && input!='L' && com==true)	{input='R';com=false;}
		if(kCode==KeyEvent.VK_R)								{respawn();gamereset();}
		if(kCode==KeyEvent.VK_SPACE)							{turbo=true;}
	}
	public void keyReleased(KeyEvent e){
		kCode=e.getKeyCode();
		
		if(kCode==KeyEvent.VK_SPACE)							{turbo=false;}
	}
	
	@Override
	public void keyTyped(KeyEvent e)
	{
		kCode=e.getKeyCode();
		
		if(kCode==KeyEvent.VK_UP    && input!='D' && com==true)	{input='U';com=false;}
		if(kCode==KeyEvent.VK_DOWN  && input!='U' && com==true)	{input='D';com=false;}
		if(kCode==KeyEvent.VK_LEFT  && input!='R' && com==true)	{input='L';com=false;}
		if(kCode==KeyEvent.VK_RIGHT && input!='L' && com==true)	{input='R';com=false;}
		if(kCode==KeyEvent.VK_R)								{respawn();gamereset();}
	}

	
	@Override
	public void run() 
	{
		col=Color.WHITE;
		t.start();
		setOutOfBounds(0);
		while(true)
		{
			if(lifes<=0)
				gameover=true;
			
			else{
				levelup= false;
				if(slength>=30){
					slength=10;
					if(sleep>=50);
						sleep-=10;
					setOutOfBounds(1);
					level++;
					levelup=true;
				}
				
				t.setParam(xarr, yarr, slength);
				
				if		(input=='U'){y1-=movement;}
				else if	(input=='D'){y1+=movement;}
				else if	(input=='L'){x1-=movement;}
				else if	(input=='R'){x1+=movement;}
				
				com=true;
				i=0;
				while(i<slength-1)
				{
					if(x1==xarr[i]&&y1==yarr[i]){
						lifes-=1;		
						if(lifes>=1){
							respawn();
						}
					}
					i++;
				}
				
				if(x1<0||y1<0||x1>290||y1>255){
					lifes-=1;
					if(lifes>=1){
						respawn();
					}
				}
				e=0;
				if(t.getTargetX()+15>=x1&&x1>=t.getTargetX()-5&&t.getTargetY()+15>=y1&&y1>=t.getTargetY()-5||got==true){
					got = true;
					score+=t.calculateScore();
					slength++;
					col=t.getTargetColor();
					t.gotTarget();
				}
				i=0;
				while(i<slength-1)
				{
					xarr[i]=xarr[i+1];
					yarr[i]=yarr[i+1];
					i++;
				}
				xarr[slength-1]=x1;
				yarr[slength-1]=y1;
				if(got){
					xarr[slength-2]=x1;
					yarr[slength-2]=y1;
					got=false;
				}
			}
			try {
				if(turbo)
					Thread.sleep(sleep-(sleep/3));
				else
					Thread.sleep(sleep);
			} catch (InterruptedException e) {
			e.printStackTrace();
			}
		}
	}
		
	public void setOutOfBounds(int starting){
		for (z=starting; z<100; z++){
			xarr[z] = -20;
			yarr[z] = -20;
		}
	}
	public void respawn(){
		yarr= new int[1000];
		xarr= new int[1000];
		x1=y1=1;
		input='R';
		setOutOfBounds(0);
	}
	public void gamereset(){
		lifes=3;
		score=0;
		level=1;
		slength=10;
		sleep=100;
		gameover=false;
	}
	public int getSize(){
		return size;
	}
	public int getx(int f){
		return xarr[f-1];
	}
	public int gety(int f){
		return yarr[f-1];
	}
	public int getLength(){
		return slength;
	}
	public int getScore(){
		return score;
	}
	public Color getSnakeColor(){
		return col;
	}
	public int getLives(){
		return lifes;
	}
	public int getLevel(){
		return level;
	}
	public boolean isGameOver(){
		return gameover;
	}
	public boolean isLevelUp(){
		return levelup;
	}
}
Java:
package logical;

import java.awt.Color;
import java.util.Random;


public class Target implements Runnable{
	
	Random r = new Random();
	int[]xarr;
	int[]yarr;
	int slength;
	int score;
	
	int e =0;
	public static int tx=-10;
	public static int ty=-10;
	int new_x;
	int new_y;
	int red;
	int green;
	int blue;
	
	boolean newone=false;
	boolean equal;
	public static Color tcol;
	
	public Target(){
	}
	  
	public void start(){
		Thread tt = new Thread(this);
		tt.start();
	}
	
	@Override
	public void run() {
		while(true){
			   if(newone==true)
			   {	
				   red=r.nextInt(246)+10;
				   blue=r.nextInt(246)+10;
				   green=r.nextInt(246)+10;
				   
				   tcol= new Color(red,blue,green);
				   equal=true;
				   while(equal==true)
				   {	
					   equal=false;
					   tx = 8+(r.nextInt(270));
					   ty = 8+(r.nextInt(235));
					   while(e<=slength)
					   {
						   if(tx<=xarr[e]+5&&tx>=xarr[e]-5&&ty<=yarr[e]+5&&ty>=yarr[e]-5)
							   equal=true;
						   e++;
					   }
					   e=0;
				   }
				   newone=false;
			   }
			   try {
				Thread.sleep(99);
			   } catch (InterruptedException err) {
				   System.out.print("error"+err);
			   }
		}
	}
	
	public int calculateScore(){
		score =Math.abs(red-green);
		score+=Math.abs(red-blue);
		score+=Math.abs(green-blue);
		score/=3;
		
		return score;
	}
	public void gotTarget(){
		newone=true;
	}
	public void setParam(int[] x,int[] y,int length){
		xarr=x;
		yarr=y;
		slength=length;
	}
	public Color getTargetColor(){
		return tcol;
	}
	public int getTargetX(){
		return tx;
	}
	public int getTargetY(){
		return ty;
	}
}
 
Das K in KSKB steht für kurz 😉

Aber nunja, bei mir flackert da gar nichts.
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
Ubuntu 11.10
 
Zuletzt bearbeitet von einem Moderator:
Man muss das mal ne weile Spielen bis die Schlange um die 20 25 Punkte hat dann flackert die Schlange auch.

Und meine JavaVersion ist auch auf dem neusten STand. Und Mein Pc ist jetzt auch nicht der langsamste.
 
Also ich hab jetzt auch in der Schleife anstatt update repaint wies mir gesagt wurde aber es flackert immer noch wie sonnst was.

Und createBufferStrategy geht nicht.
 
Ich bin immer noch am selben Problem.

Ich könnte ja das Antialiasing ausschalten, aber da sehen die RoundedRects ziemliuch bescheiden aus.


Mfg
 

Zurück
Oben