Flackern trotz Offscreen Image / Doublebuffer, (+ Frage zu Pixelvergleich)

Zul

Mitglied
Hallo zusammen, ich brauche Hilfe bei der Verwendung von Offscreen Images und habe einige Fragen dazu. Ich hoffe, ihr könnt mir helfen. :)


Momentan versuche ich ein kleines Spiel zu programmieren (so eine Art primitives 2D Rollenspiel, in dem man bis jetzt noch nichts machen kann).
Dazu habe ich ein 2dimensionales Array erstellt, das für die Darstellung der Welt dient, indem ich in jedem Tupel abspeicher, welches Bild dort gemalt werden soll.
Java:
private Tiles[][] world;
Dazu verwende ich BufferedImages, die ich im Konstruktor einlese. Meine Klasse, in der gezeichnet werden soll, ist ein JPanel. Ich habe das ganze nun zuerst ohne Offscreen Images realisiert und das Flackern hielt sich auch in Grenzen. Alles wird per repaint() in der Klasse, die ein Objekt dieses JPanels erstellt, alle 30ms neu gezeichnet.

Java:
public void paint(Graphics g) {
		super.paint(g);
		
		Graphics2D g2d = (Graphics2D)g;

		for (int j = game.getMapY1(); j < game.getMapY2() && j < world[0].length; j++) {
			for (int i = game.getMapX1(); i < game.getMapX2() && i < world.length; i++) {
				if(world[i][j].getTerrain()!=null){
					if (world[i][j].getTerrain() == "grass"){
						g.drawImage(grass, i * TILESIZE + game.getViewX(), j * TILESIZE
								+ game.getViewY(), null);
					}
				}
			}
		}

		//usw

}
(game.getMapY1() ist hier der obere Rand des sichtbaren Bereichs, game.getMapY2(), der untere. Dasselbe mit X für linken und rechten Rand. game.getView.. sorgt für das Verschieben des sichtbaren Ausschnitts der Welt.)

Dann kam mir die dumme Idee, Lichtquellen in der Welt zu benutzen und damit fing mein Ärger an und dort liegt auch mein Problem.

Da ich nämlich 1) statische Lichtquellen einbauen wollte, habe ich zusätzlich in jedem Tupel festgelegt, ob dort eine Lichtquelle sein soll oder nicht. Entsprechend bin ich nochmals das ganze Array durchgegangen und habe entweder ein halbtransparentes schwarzes Bildchen über das alte Bild gemalt oder ein schwarzes, beinahe vollkommen transparentes, damit das alte Bild darunter noch gut zu sehen ist.
So weit, so gut. Aber damit war ich leider nicht zufrieden. Da der Charakter nahezu ständig im Dunkeln tappte, 2) sollte es auch bei ihm hell sein. Deshalb habe ich ein komplett schwarzes Bild, was zur Mitte hin transparent wird über das gesamte Panel gezeichnet (der Charakter steht immer in der Mitte vom Panel).
Dabei habe ich jedoch nicht bedacht, dass ich die Dunkelheit mit 1) und 2) doppelt gemalt habe und auch die transparenten Stellen einmal übermalt werden.

Darum habe ich mir überlegt, dass ich die Dunkelheit mitsamt den transparenten Stellen aus 1) zuerst auf ein Offscreen Image zeichne und dann alle Pixel mit dem Bild aus 2) vergleiche, jeweils den helleren Pixel wähle und das neu entstandene Bild über das Panel zeichne. Und wo ich gerade eh dabei bin, ein Offscreen Image zu erstellen, hatte ich auch vor, das bisherige Bild zuerst auf so ein Offscreen Image zu zeichnen und danach erst auf das Panel.

--

An dieser Stelle muss ich sagen, dass mein Panel fast 600x400 groß ist und ihr spätestens hier schon aufhören könnt soviel Text zu lesen, wenn ihr denkt, dass das ganze viel zu viele Rechnungen benötigt, um den ganzen Vorgang ca. alle 30ms zu wiederholen. :(

--

Wenn es jedoch möglich ist, freue ich mich schonmal.:)

Ich habe dann folgende Images und Graphics-Objekte erstellt:
Java:
private BufferedImage offScreen1;
private Graphics2D off1;
private BufferedImage offScreen2;
private Graphics2D off2;
im Konstruktor:
Java:
offScreen1= new BufferedImage(544,416,BufferedImage.TYPE_INT_ARGB);
off1= offScreen1.createGraphics();
offScreen2= new BufferedImage(544,416,BufferedImage.TYPE_INT_ARGB);
off2= offScreen2.createGraphics();
(komische Größe, ich weiß;))

Alles was vorher mit 'g.draw' anfing, habe ich mit durch 'off1.draw' ersetzt, am Anfang der paint()-Methode rufe ich jetzt noch
Java:
off1.clearRect(0,0,544,416);
und am Ende
Java:
g.drawImage(offScreenImageDay,0,0,null);
auf.

1. Problem: Das funktioniert - aber leider nur beinahe. Denn gezeichnet wird zwar auf diese Art und Weise, jedoch kommt es ab und zu immer noch vor, dass das Bild flackert und ich weiß nicht, woran das liegt, denn eigentlich wird ja nur noch ein einziges Bild gezeichnet und nicht mehr viele kleine. Muss ich vielleicht die update-methode überschreiben? Irgendwo habe ich sowas mal gelesen. :(

2. Problem: Das andere Offscreen Image (offScreen2), dass ein halb transparentes Schwarzes Bild mit "transparenten Löchern" darstellt, kann ich nicht über das erste malen, da der Hintergrund des Graphics-Objektes nicht transparent ist. Gibt es dafür eine Möglichkeit?

3. Problem: Falls das alles mal klappen sollte, bin ich nicht ganz sicher, wie ich die einzelnen Pixel der Bilder vergleichen kann. ???:L

Am meisten stört mich momentan das Geflacker...
Ich hoffe, ich habe nicht zuviel geschrieben oder versuche etwas zu absurdes zu realisieren. Vielleicht könnt ihr mir ja helfen. :)


Lieben gruß, Zul
 

Zul

Mitglied
Hmm, okay.. Ich glaube, dass das Flackern verschwunden ist, nachdem ich statt der paint-Methode die paintComponent-Mehode überschrieben habe. :oops:

Und das zweite Offscreen-Image scheint auch zu funktionieren, wenn ich vor
Java:
off2.clearRect(0,0,544,416);
Java:
off2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
aufrufe.
 
Zuletzt bearbeitet:

Zul

Mitglied
Ja, schon Pixel. Ich dachte, ich halte es schlicht und nehme nur 2-3 Bilder, die ich selbst erstellt habe, wo die Mitte transparent ist und es nach außen hin dunkler wird. So etwa:
h2qd995h.png

Die kann ich dann in ein Tile speichern und alle Tiles, die es überdeckt, werden auch als belegt gesetzt. Alle übrigen bekommen ein Bild welches nur dunkel ist. Damit habe ich ein Bild, welches die Umgebung abdunkelt und nur an festgelegten Stellen transparent ist und somit den Eindruck erweckt, dass es dort hell ist.
Da der Charakter aber wenigstens den Boden direkt unter sich sehen soll - auch im Dunkeln - möchte ich zusätzlich obiges Bild in groß über das gesamte Panel zeichnen.
Problem ist, dass ich die Dunkelheit dann doppelt eingefügt habe, darum möchte ich jedes Pixel von den beiden Bildern vergleichen und nur jeweils das hellere zeichnen.

Lese momentan gerade das verlinkte Thema. Danke. ;)
 

Marco13

Top Contributor
Ja so ein statisches Bild macht nur bedingt Sinn... Schau vielleicht doch mal das KSKB aus dem verlinkten Thread an, vielleicht ist das doch nicht so weit weg, von dem was du vorhast...
 

Zul

Mitglied
Jo, das gefällt mir sehr gut. Sieht auch viel eleganter aus als ein ständiger Pixelvergleich. Ich werde versuchen, das auf diese Weise zu lösen. Danke dir! :)
 

Zul

Mitglied
Huhu, also die Vorgehensweise aus deinem KSKB funktioniert gut. Wenn ich da noch herausfinde, ob ich den Übergang vielleicht noch ein klein wenig "unschärfer" hinbekomme und wie ich da noch noch andere Formen verwenden kann, wäre ich sehr zufrieden. :)

Es flackert übrigens wieder!? Ich weiß nicht, ob es vorher Glück war oder ob es wieder da ist, aber ich habe eigentlich nichts verändert.. hier ein Stück Wiese, wo manchmal eine andere Bodentextur darunter durchflackert.
w4y2tn9r.png

Edit: Und auch der schwarze Hintergrund kommt noch manchmal zum Vorschein.:(
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Ja, du hast zwei Offsscreen Images? Es wäre gut, wenn man an einem Stück code genauer sehen würde, wie die verwendet werden.
 

Zul

Mitglied
Jo, bitte schön. :)

Java:
public void paintComponent(Graphics g) {
		
		super.paintComponent(g);
		
		Graphics2D g2d = (Graphics2D)g;
		
		// 1. Offscreen
		day.clearRect(0,0,544,416);
		day.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, lightFactor));
		
		
		/*
		 * Gelaende
		 */
		for (int j = game.getMapY1(); j < game.getMapY2() && j < world[0].length; j++) {
			for (int i = game.getMapX1(); i < game.getMapX2() && i < world.length; i++) {
				if(world[i][j].getTerrain()!=null){
					if (world[i][j].getTerrain() == "grass"){
						day.drawImage(grass, i * TILESIZE + game.getViewX(), j * TILESIZE
								+ game.getViewY(), null);
					}else if (world[i][j].getTerrain() == "sand"){
						day.drawImage(sandOnly, i * TILESIZE + game.getViewX(), j * TILESIZE
								+ game.getViewY(), null);
					}
					// usw
				}
			}
		}

		/*
		 * Objekte und Umgebung
		 */
		for (int j = game.getMapY1(); j < player.getTilePositionY() && j < world[0].length; j++) {
			for (int i = game.getMapX1(); i < game.getMapX2() && i < world.length; i++) {
				
				if(world[i][j].getObject()!=null){
					day.drawImage(drawObject(i,j),i * TILESIZE + game.getViewX(), j * TILESIZE
								+ game.getViewY() - (drawObject(i, j).getHeight()-TILESIZE), null);
				}
				
				if(world[i][j].getEnvironment()!=null){
					day.drawImage(drawEnvironment(i,j),i * TILESIZE + game.getViewX(), j * TILESIZE
							+ game.getViewY() - (drawEnvironment(i, j).getHeight()-TILESIZE), null);
				}
			}
			// usw
		}

		// [...]

		// 2. Offscreen
		night.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
		night.clearRect(0, 0, 544,416);
		
		drawLights();

		// Zeichnen auf Panel
		g.drawImage(offScreenImageDay,0,0,null);
		g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, sunLight));
		g.drawImage(offScreenImageNight,0,0,null);
}

Java:
	private void drawLights(){
        night.setComposite(AlphaComposite.Src);
        night.setColor(new Color(0,0,16,240));
        night.fillRect(0,0,getWidth(),getHeight());
 
        for (int j = game.getMapY1(); j < game.getMapY2() && j < world[0].length; j++) {
			for (int i = game.getMapX1(); i < game.getMapX2() && i < world.length; i++) {
				if(world[i][j].getLight()){
					drawLight(night, new Point(i * TILESIZE + game.getViewX() + TILESIZE/2, j * TILESIZE
							+ game.getViewY() + TILESIZE/2),world[i][j].getLightRadius());
				}
			}
		}
        drawLight(night, characterPoint,75);
        
//      night.dispose();
    }
 
    private void drawLight(Graphics2D g, Point pt, int radius){
        g.setComposite(AlphaComposite.DstOut);
        Point2D center = new Point2D.Float(pt.x, pt.y);
        float[] dist = {0.0f, 1.0f};
        Color[] colors = {new Color(255,255,255,255), new Color(0,255,0,0) };
        RadialGradientPaint p = new RadialGradientPaint(center, (float)radius, dist, colors, CycleMethod.NO_CYCLE);
        g.setPaint(p);
        g.fillOval(pt.x-radius,pt.y-radius,radius*2,radius*2);
    }

An Stellen, wo nur Bodentextur gemalt wird, sieht man beim Flackern den schwarzen Panel-Hintergrund und an Stellen, wo zusätzlich noch etwas drübergezeichnet ist, sieht man die Bodentextur darunter. Also immer die darunterliegende Ebene. Ich wusste nicht, dass beim Offscreen noch die "Schichten" existieren vom mehrmaligem Zeichnen an derselben Stelle.

Die Bildfehler treten allerdings auch nur dann ab und zu auf, wenn man sich mit dem Charakter bewegt. Wenn ich nichts tue, habe ich jedenfalls noch keine feststellen können.
Bei der Bewegung starte ich einen Thread, der den Bildausschnitt alle 30ms um 2 Pixel verschiebt - repaint wird ebenfalls alle 30ms aufgerufen. Momentan wühle ich wegen Threads synchronisieren rum, falls es daran liegt. :(

Und danke nochmal für deine Geduld.
 

Marco13

Top Contributor
OK, das sieht recht kompliziert aus, aber beim Überfliegen sieht man zumindest nichts "falsches". Was aber kritisch sein könnte, ist, was du am Ende gesagt hast: Wenn ein anderer Thread "den Bildausschnitt verschiebt" (was auch immer das genau bedeutet) dann könnte es sein, dass der Klasse, die das ganze zeichnet, während des Zeichnens die Daten, die sie zeichnen soll, "unter dem Hintern weg" verschoben werden, und deswegen was falsches rauskommt.

NUR (NUR NUR NUR!) um das zu testen (und um es danach ggf. SOFORT wieder Rückgängig zu machen und ggf. anders zu lösen!) könnte man sowas machen wie
Java:
public void paintComponent(Graphics g) 
{
    synchronized(game)
    {
        doPaintComponentSync(g); 
    }
}

private void doPaintComponentSync(Graphics g)
{
    super.paintComponent(g);
    ...
    // Wie vorher...
}


// Dort wo die Bewgung durchgeführt wird
void move()
{
    // vorher:
    //doMovement(2,2);

   // Nachher
   synchronized(game)
   {
        doMovement(2,2);
   }
}

(Oh-ho... vielleicht sollte ich das nicht so vorschlagen...)
 

Zul

Mitglied
Jo, das funktioniert. Spitze! :)

Ähm, eine Frage noch. Kann ich den Übergang bei der "Taschenlampe" noch fließender machen? Ich habe bereits mit dem Gradient rumgespielt, allerdings nicht sonderlich erfolgreich.
 

Marco13

Top Contributor
Dann sollte man sich jetzt überlegen, wie man es RICHTIG machen könnte. paintComponent und irgendwas anderes in dieser Form zu synchronizen ist die Holzhammer-Methode...

Um den RadialGradientPaint "fließender" zu machen, müßtest du wohl
float[] dist = {0.0f, 1.0f};
Color[] colors = {new Color(255,255,255,255), new Color(0,255,0,0) };
in feinere Zwischenschritte Unterteilen, GROB sowas wie
float[] dist = {0.0f, 0.25f, 1.0f};
Color[] colors = {new Color(255,255,255,255), new Color(128,255,128,128), new Color(0,255,0,0) };
um der (in der Natur gegebenen) quadratischen Attenuation näher zu kommen
 

Zul

Mitglied
Das mit dem RadialGradientPaint werde ich austesten, danke. :)


Zu dem Synchronisieren: meine Move-Klasse erbt von Thread und wird aufgerufen, wenn man eine der Pfeiltasten drückt. Dann wird das Bild in 2-Pixel-Schritten in die entsprechende Richtung verschoben um die Bewegung zu simulieren. Also "Pfeil rechts", Bild wird nach links verschoben.

Sollte ich das ganze lieber mit aktivem Rendern lösen und das JPanel in einem eigenen Thread ständig neu zeichnen und dann das repaint aus der run-Methode vom Spiel rausnehmen? Wäre das besser, statt paintComponent zu synchronisieren?
 

Marco13

Top Contributor
Naja, man kann sich da tausende Lösungen überlegen, je nachdem, wie ausgefeilt das sein soll. Eine immernoch recht pragmatischen Lösung (von der man NICHT pauschal sagen kann ob sie hier angebracht wäre oder nicht!) wäre, die Änderungen, die sich auf zu zeichnende Dinge beziehen, mit SwingUtilities.invokeLater auf den EDT zu legen - sofern nicht wiederum ein anderer Thread auch noch diese Daten braucht...
 

Crian

Top Contributor
Es ist immer schlau, die Dinge die man darstellen will, vor dem Darstellen zu kopieren und die Kopie darstellen, dann kann dir kein anderer Thread irgendwas unter dem Hintern wegändern und du sparst die Synchronisation.
 

bERt0r

Top Contributor
Move-Klasse erbt von Thread und wird aufgerufen, wenn man eine der Pfeiltasten drückt.
Das finde ich eher etwas suboptimal. Wenn ich einmal alle 4 Richtungstasten drücke starte ich 4 Threads? Move ist sowieso kein Name für eine Klasse, eher für eine Funktion. Ich würde die Tastenabfrage einfach in der Mainloop machen.
 

Marco13

Top Contributor
Es ist immer schlau, die Dinge die man darstellen will, vor dem Darstellen zu kopieren und die Kopie darstellen, dann kann dir kein anderer Thread irgendwas unter dem Hintern wegändern und du sparst die Synchronisation.

Ja, so ist das: Pauschale Aussagen sind IMMER falsch :D Wenn das, was man visualisieren will, über "Spielzeug-Beispiele" hinausgeht, ist ein Kopieren pro Zeichenoperation nicht mehr tragbar. Ich habe da schon interessante Konstrukte gesehen...
Java:
void paintSuff(Collection<T> collection)
{
    try
    {
        for (T t : collection) paint(t);
    }
    catch (ConcurrentModificationException e)
    {
        paintStuff(collection); // Try again...
    }
}
Und auch wenn es mir (und wohl vielen anderen auch) bei sowas kalt den Rücken rauf und runter läuft: Es hat seine Rechtfertigung... (Trotzdem würde ich das so auch niemandem unbedacht empfehlen... ;) )
 

Michael...

Top Contributor
Zu dem Synchronisieren: meine Move-Klasse erbt von Thread und wird aufgerufen, wenn man eine der Pfeiltasten drückt.
...
Sollte ich das ganze lieber mit aktivem Rendern lösen und das JPanel in einem eigenen Thread ständig neu zeichnen und dann das repaint aus der run-Methode vom Spiel rausnehmen? Wäre das besser, statt paintComponent zu synchronisieren?
Das "Synchronisationsproblem" ist mir nicht ganz klar. Was soll da synchronisiert werden? Im Prinzip gibt es ja nur die GameLoop in der Daten verändert werden. Wenn die Daten nicht (immer) korrekt dargestellt werden, sollte das doch kaum auffallen, da ohnehin mehrmals pro Sekunde neu gezeichnet wird.
Dann wird das Bild in 2-Pixel-Schritten in die entsprechende Richtung verschoben um die Bewegung zu simulieren. Also "Pfeil rechts", Bild wird nach links verschoben.
Habe mal Deine Spielidee mit meinem GameDemo Code kombiniert. Die Steuerung funktioniert mittels KeyBindings (Tasten A, W, D). Es werden hierbei "Flags" gesetzt, die in der Gameloop ausgewertet werden. Allerdings bewegt sich hier die Figur statt des Hintergrunds und das Rendering erfolgt passiv nur durch Überschreiben der paintComponent.
Java:
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

@SuppressWarnings("serial")
public class TorchGame extends JPanel {
	private static int width = 600;
	private static int height = 600;
	private BufferedImage bgImage;
	private Color shadowColor = new Color(0, 0, 0, 200);
	private Color baseLight = new Color(255, 255, 0, 120);
	private Color playerColor = new Color(80, 0, 80);
	
	private Player player;
	private boolean move, left, right;

	private Candle[] candles;

	public TorchGame() {
		initEnvironment();
		setKeyBindings();
		this.setPreferredSize(new Dimension(width, height));
		
		//start game loop
		new Thread(new Runnable() {
			int shadowLevel = 200;
			int vec = 1;
			public void run() {
				while(true) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					calculateNextPos();
					// daytime loop
					shadowLevel += vec*2;
					if (shadowLevel<0) {
						shadowLevel=0;
						vec = 1;
					}
					else if	(shadowLevel>255) {
						shadowLevel=255;
						vec = -1;
					}
					setShadowLevel(shadowLevel);
				}
			}
		}).start();
	}
	
	//initialize game environment
	private void initEnvironment() {
		player = new Player(width/2, height/2);
		createBackground();
		candles = new Candle[width/50];
		for (int i = 0; i < candles.length; i++) {
			int dia = (int) (Math.random() * 150) + 50;
			int x = (int) (Math.random() * (width - dia - 10)) + 10;
			int y = (int) (Math.random() * (height - dia - 10)) + 10;
			candles[i] = new Candle(x, y, dia);
		}
	}
	
	// create random background image
	private void createBackground() {
		bgImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = bgImage.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setColor(Color.LIGHT_GRAY);
		g.fillRect(0, 0, width, height);
		g.setStroke(new BasicStroke(5));
		for (int i = 0; i < width/40; i++) {
			int dia = (int) (Math.random() * 100) +10;
			int w = dia;
			int x = (int) (Math.random() * (width - dia - 10)) + 10;
			int y = (int) (Math.random() * (height - dia - 10)) + 10;
			if(dia%3==0) {
				g.setColor(Color.ORANGE);
				w *=.75;
			}
			else
				g.setColor(Color.BLUE);
			if (dia%2==0)
				g.drawRect(x, y, dia, w);
			else
				g.drawOval(x, y, dia, w);
		}
		g.dispose();
	}
	
	private void setKeyBindings() {
		InputMap map = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
		//player control move forward
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "go");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "stop");
		getActionMap().put("go", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				move = true;
			}
		});
		getActionMap().put("stop", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				move = false;
			}
		});
		//player control right
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "stopRight");
		getActionMap().put("right", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				right = true;
				left = false;
			}
		});
		getActionMap().put("stopRight", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				right = false;
			}
		});
		//player control left
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "stopLeft");
		getActionMap().put("left", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				left = true;
				right = false;
			}
		});
		getActionMap().put("stopLeft", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				left = false;
			}
		});
		
		// reset environment and player position
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0), "refresh");
		getActionMap().put("refresh", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				initEnvironment();
			}
		});
	}
	
	private void calculateNextPos(){
		if (right)
			player.turnRight();
		else if (left)
			player.turnLeft();
		if (move) {
			player.move(10);
			int x = player.getX();
			int y = player.getY();
			if(x<0 || y<0 || x>width || y >height)
				player.setBack(20);
		}
		repaint();
	}
	
	public void setShadowLevel(int level) {
		shadowColor = new Color(0, 0, 0, level);
		baseLight = new Color(255, 255, 0, 120*level/255);
		repaint();
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(bgImage, 0, 0, null);
		Graphics2D g2 = (Graphics2D) g.create();
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(baseLight);
		g2.fillRect(0, 0, width, height);
		// painting candle bases
		g2.setColor(Color.RED);
		for (Candle candle : candles) {
			g2.fillOval(candle.getCenterX() - 5, candle.getCenterY() - 5, 10, 10);
		}
		
		// painting player
		g2.translate(player.getX(), player.getY());
		g2.rotate(Math.toRadians(player.getDir()));
		g2.setColor(shadowColor);
		g2.fillOval(-18, -15, 30, 30);
		g2.setColor(playerColor.brighter());
		g2.fillOval(-15, -15, 30, 30);
		g2.setColor(playerColor);
		g2.fillOval(-12, -12, 24, 24);
		g2.translate(5, 8);
		g2.fillRect(-5, -5, 25, 5);
		g2.dispose();

		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		g2 = image.createGraphics();
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(shadowColor);
		g2.fillRect(0, 0, width, height);

		// painting candle lights
		g2.setComposite(AlphaComposite.DstOut);
		for (Candle candle : candles) {
			g2.setPaint(candle.getPaint());
			g2.fillOval(candle.getX(), candle.getY(), candle.getDiameter(), candle.getDiameter());
		}

		// painting torch light
		g2.setComposite(AlphaComposite.DstOut);
		g2.translate(player.getX(), player.getY());
		g2.rotate(Math.toRadians(player.getDir()));
		g2.translate(35, 0);
		g2.setPaint(getTorchPaint(-10, 0, 50));
		g2.fillOval(-50, -40, 100, 80);

		g2.dispose();

		g.drawImage(image, 0, 0, null);
	}
	
	private Color[] torchColors = { new Color(0, 255, 0, 255), new Color(0, 255, 0, 255), new Color(0, 255, 0, 0) };

	private RadialGradientPaint getTorchPaint(int x, int y, int radius) {
		return new RadialGradientPaint(x, y, radius, new float[] { 0f, .5f, 1f }, torchColors);
	}
	
	class Player {
		private Point pos;
		private int dir;

		public Player(int x, int y) {
			pos = new Point(x, y);
			dir = 0;
		}

		public void move(int steps) {
			pos.x += Math.cos(Math.toRadians(dir)) * steps;
			pos.y += Math.sin(Math.toRadians(dir)) * steps;
		}
		
		public void setBack(int steps) {
			pos.x -= Math.cos(Math.toRadians(dir)) * steps;
			pos.y -= Math.sin(Math.toRadians(dir)) * steps;
		}

		public void turnRight() {
			dir = (dir + 10) % 360;
		}

		public void turnLeft() {
			dir = (dir - 10) % 360;
		}

		public int getX() {
			return pos.x;
		}

		public int getY() {
			return pos.y;
		}

		public int getDir() {
			return dir;
		}
	}
	
	class Candle {
		private Point position;
		private int dia;
		private Paint paint;
		private Color[] lightColors = { new Color(0, 0, 0, 220), new Color(0, 0, 0, 150), new Color(0, 0, 0, 220), new Color(0, 0, 0, 0) };

		public Candle(int x, int y, int dia) {
			this.position = new Point(x, y);
			this.dia = dia;
			this.paint = createPaint(x, y, dia / 2);
		}

		public int getX() {
			return position.x - dia / 2;
		}

		public int getY() {
			return position.y - dia / 2;
		}

		public int getCenterX() {
			return position.x;
		}

		public int getCenterY() {
			return position.y;
		}

		public int getDiameter() {
			return dia;
		}

		public Paint getPaint() {
			return paint;
		}

		private RadialGradientPaint createPaint(int centerX, int centerY, int radius) {
			return new RadialGradientPaint(centerX, centerY, radius, new float[] { 0f, 20f/dia, .7f, 1f }, lightColors);
		}
	}

	public static void main(String[] s) {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		final TorchGame panel = new TorchGame();
		frame.add(panel, BorderLayout.CENTER);
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
}
 

Zul

Mitglied
@Michael: Habe mir gerade deine GameDemo angeguckt. Gefällt mir sehr gut. :) Vor allem die Bewegung.


Ich hatte ja leider vorgesehen, dass keine diagonalen Bewegungen möglich sind. Man kann nur nach links, rechts, oben oder unten. Und immer wenn eine dieser Pfeiltasten gedrückt wird, die entsprechende Kachel begehbar ist und gerade keine Bewegung stattfindet, wird ein
Code:
boolean isMoving
auf true gesetzt, die Bewegung ausgeführt und sobald die Kachel erreicht ist, wieder auf false. So ist auch sichergestellt, dass immer nur ein Bewegungs-Thread gestartet wird. Wenn dieser abgeschlossen ist, wird direkt der nächste gestartet, falls noch eine Taste gedrückt (gehalten) wird. Die Steuerung funktioniert eigentlich ganz gut denke ich. :oops:

Die Spielfigur befindet sich dabei immer in der Mitte des Bildschirms, sodass sich eigentlich nicht sie, sondern der Ausschnitt der Spielwelt sich verschiebt. Das mache ich mit
Code:
game.setViewX()
und
Code:
game.setViewY()
während des Bewegens. Und auf diese Werte greife ich halt auch beim Zeichnen (fast überall) zurück (s.o.). Das müssten dann die beiden Problemwerte sein, denke ich. Die Bildfehler prasseln ja auch gar nicht am laufenden Band auf den Bildschirm ein, aber auch das gelegentliche hat mich schon sehr gestört, wenn man es doch leicht vermeiden kann.

Naja, und mit dem synchronized funktioniert das momentan. Im JPanel:
Java:
synchronized(this){
	doPaintComponentSync(g); 
}
im Move-Thread an der Stelle wo der Bildschirm um x/y verschoben wird:
Java:
synchronized(game.getWorldPanel()){
	// [...]
	if (destinationX > currentX) {
				currentX += speed;
				player.setPositionX(currentX);
				game.setViewX(-speed);
			}else if (destinationX < currentX) {
				currentX -= speed;
				player.setPositionX(currentX);
				game.setViewX(speed);
			}else if (destinationY > currentY) {
				currentY += speed;
				player.setPositionY(currentY);
				game.setViewY(-speed);
			}else if (destinationY < currentY) {
				currentY -= speed;
				player.setPositionY(currentY);
				game.setViewY(speed);
			}
	// [...]
}

Hmm, wenn das mit dem 'synchronized' nicht so schön ist, muss ich mir mal Gedanken machen, wie man das sonst noch lösen kann...

@Marco13: Danke für den Tipp. Ich werde mich mal genauer zu SwingUtilities.invokeLater informieren. Ich kenne das nur ganz grob. :(

Ich freu mich, dass ihr versucht mir zu helfen. :)
Zul
 

Michael...

Top Contributor
im Move-Thread an der Stelle wo der Bildschirm um x/y verschoben wird:
Java:
synchronized(game.getWorldPanel()){
	// [...]
	if (destinationX > currentX) {
				currentX += speed;
				player.setPositionX(currentX);
				game.setViewX(-speed);
			}else if (destinationX < currentX) {
				currentX -= speed;
				player.setPositionX(currentX);
				game.setViewX(speed);
			}else if (destinationY > currentY) {
				currentY += speed;
				player.setPositionY(currentY);
				game.setViewY(-speed);
			}else if (destinationY < currentY) {
				currentY -= speed;
				player.setPositionY(currentY);
				game.setViewY(speed);
			}
	// [...]
}
Wenn ich das richtig verstanden habe, hast Du keine permanente GameLoop, sondern willst nur den Schritt von einer Position zur nächsten animiert darstellen!? Dann passt das schon für die Bewegung einen Thread zu starten. Sollte hier dann aber nicht irgendwie
Code:
while(destinationX > currentX)
o.ä. stehen.
Außerdem kann man ja anhand der Spielerposition und der Vorgabe, dass der Spieler in der Mitte des Fensters dargestellt werden soll, die Position des Spielfeldes berechnen und dieses entsprechend darstellen. Daher würde ich die Position des Spielfeldes nicht aktiv setzen --> weniger Daten zu synchronisieren.
 

Michael...

Top Contributor
Java:
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

@SuppressWarnings("serial")
public class TorchGame2 extends JPanel {
	private static int width = 400;
	private static int height = 400;
	private BufferedImage bgImage;
	private Color shadowColor = new Color(0, 0, 0, 200);
	private Color baseLight = new Color(255, 255, 0, 120);
	private Color playerColor = new Color(80, 0, 80);
	
	private Player player;
	private boolean move, left, right;

	private Candle[] candles;

	public TorchGame2() {
		initEnvironment();
		setKeyBindings();
		this.setPreferredSize(new Dimension(width, height));
		
		//start game loop
		new Thread(new Runnable() {
			int shadowLevel = 200;
			int vec = 1;
			public void run() {
				while(true) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					calculateNextPos();
					// daytime loop
					shadowLevel += vec*2;
					if (shadowLevel<0) {
						shadowLevel=0;
						vec = 1;
					}
					else if	(shadowLevel>255) {
						shadowLevel=255;
						vec = -1;
					}
					setShadowLevel(shadowLevel);
				}
			}
		}).start();
	}
	
	//initialize game environment
	private void initEnvironment() {
		player = new Player(width*3/2, height*3/2);
		createBackground();
		candles = new Candle[width*3/50];
		for (int i = 0; i < candles.length; i++) {
			int dia = (int) (Math.random() * 150) + 50;
			int x = (int) (Math.random() * (width*3 - dia - 10)) + 10;
			int y = (int) (Math.random() * (height*3 - dia - 10)) + 10;
			candles[i] = new Candle(x, y, dia);
		}
	}
	
	// create random background image
	private void createBackground() {
		bgImage = new BufferedImage(width*3, height*3, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = bgImage.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setColor(Color.LIGHT_GRAY);
		g.fillRect(0, 0, bgImage.getWidth(), bgImage.getHeight());
		g.setStroke(new BasicStroke(5));
		for (int i = 0; i < bgImage.getWidth()/40; i++) {
			int dia = (int) (Math.random() * 100) +10;
			int w = dia;
			int x = (int) (Math.random() * (bgImage.getWidth() - dia - 10)) + 10;
			int y = (int) (Math.random() * (bgImage.getHeight() - dia - 10)) + 10;
			if(dia%3==0) {
				g.setColor(Color.ORANGE);
				w *=.75;
			}
			else
				g.setColor(Color.BLUE);
			if (dia%2==0)
				g.drawRect(x, y, dia, w);
			else
				g.drawOval(x, y, dia, w);
		}
		g.setColor(Color.YELLOW);
		g.drawRect(0, 0, bgImage.getWidth(), bgImage.getHeight());
		g.dispose();
	}
	
	private void setKeyBindings() {
		InputMap map = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
		//player control move forward
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "go");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "stop");
		getActionMap().put("go", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				move = true;
			}
		});
		getActionMap().put("stop", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				move = false;
			}
		});
		//player control right
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "stopRight");
		getActionMap().put("right", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				right = true;
				left = false;
			}
		});
		getActionMap().put("stopRight", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				right = false;
			}
		});
		//player control left
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "stopLeft");
		getActionMap().put("left", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				left = true;
				right = false;
			}
		});
		getActionMap().put("stopLeft", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				left = false;
			}
		});
		
		// reset environment and player position
		map.put(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0), "refresh");
		getActionMap().put("refresh", new AbstractAction() {
			public void actionPerformed(ActionEvent evt) {
				initEnvironment();
			}
		});
	}
	
	private void calculateNextPos(){
		if (right)
			player.turnRight();
		else if (left)
			player.turnLeft();
		if (move) {
			player.move(10);
			int x = player.getX();
			int y = player.getY();
			if(x<0 || y<0 || x> bgImage.getWidth()|| y >bgImage.getHeight())
				player.setBack(20);
		}
		repaint();
	}
	
	public void setShadowLevel(int level) {
		shadowColor = new Color(0, 0, 0, level);
		baseLight = new Color(255, 255, 0, 120*level/255);
		repaint();
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		
		int pX = player.getX();
		int pY = player.getY();
		
		Graphics2D g2 = (Graphics2D) g.create();
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.translate(width/2-pX, height/2-pY);
		g2.drawImage(bgImage, 0, 0, null);
		g2.dispose();
		
		g2 = (Graphics2D) g.create();
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(baseLight);
		g2.fillRect(0, 0, width, height);
		// painting candle bases
		g2.translate(width/2-pX, height/2-pY);
		g2.setColor(Color.RED);
		for (Candle candle : candles) {
			g2.fillOval(candle.getCenterX() - 5, candle.getCenterY() - 5, 10, 10);
		}
		
		// painting player
		g2.translate(player.getX(), player.getY());
		g2.rotate(Math.toRadians(player.getDir()));
		g2.setColor(shadowColor);
		g2.fillOval(-18, -15, 30, 30);
		g2.setColor(playerColor.brighter());
		g2.fillOval(-15, -15, 30, 30);
		g2.setColor(playerColor);
		g2.fillOval(-12, -12, 24, 24);
		g2.translate(5, 8);
		g2.fillRect(-5, -5, 25, 5);
		g2.dispose();

		BufferedImage image = new BufferedImage(bgImage.getWidth(), bgImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
		g2 = image.createGraphics();
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(shadowColor);
		g2.fillRect(0, 0, image.getWidth(), image.getHeight());

		// painting candle lights
		g2.setComposite(AlphaComposite.DstOut);
		for (Candle candle : candles) {
			g2.setPaint(candle.getPaint());
			g2.fillOval(candle.getX(), candle.getY(), candle.getDiameter(), candle.getDiameter());
		}

		// painting torch light
		g2.setComposite(AlphaComposite.DstOut);
		g2.translate(player.getX(), player.getY());
		g2.rotate(Math.toRadians(player.getDir()));
		g2.translate(35, 0);
		g2.setPaint(getTorchPaint(-10, 0, 50));
		g2.fillOval(-50, -40, 100, 80);

		g2.dispose();
		
		g2 = (Graphics2D) g.create();
		g2.translate(width/2-pX, height/2-pY);
		g2.drawImage(image, 0, 0, null);
		g2.dispose();
	}
	
	private Color[] torchColors = { new Color(0, 255, 0, 255), new Color(0, 255, 0, 255), new Color(0, 255, 0, 0) };

	private RadialGradientPaint getTorchPaint(int x, int y, int radius) {
		return new RadialGradientPaint(x, y, radius, new float[] { 0f, .5f, 1f }, torchColors);
	}
	
	class Player {
		private Point pos;
		private int dir;

		public Player(int x, int y) {
			pos = new Point(x, y);
			dir = 0;
		}

		public void move(int steps) {
			pos.x += Math.cos(Math.toRadians(dir)) * steps;
			pos.y += Math.sin(Math.toRadians(dir)) * steps;
		}
		
		public void setBack(int steps) {
			pos.x -= Math.cos(Math.toRadians(dir)) * steps;
			pos.y -= Math.sin(Math.toRadians(dir)) * steps;
		}

		public void turnRight() {
			dir = (dir + 10) % 360;
		}

		public void turnLeft() {
			dir = (dir - 10) % 360;
		}

		public int getX() {
			return pos.x;
		}

		public int getY() {
			return pos.y;
		}

		public int getDir() {
			return dir;
		}
	}
	
	class Candle {
		private Point position;
		private int dia;
		private Paint paint;
		private Color[] lightColors = { new Color(0, 0, 0, 220), new Color(0, 0, 0, 150), new Color(0, 0, 0, 220), new Color(0, 0, 0, 0) };

		public Candle(int x, int y, int dia) {
			this.position = new Point(x, y);
			this.dia = dia;
			this.paint = createPaint(x, y, dia / 2);
		}

		public int getX() {
			return position.x - dia / 2;
		}

		public int getY() {
			return position.y - dia / 2;
		}

		public int getCenterX() {
			return position.x;
		}

		public int getCenterY() {
			return position.y;
		}

		public int getDiameter() {
			return dia;
		}

		public Paint getPaint() {
			return paint;
		}

		private RadialGradientPaint createPaint(int centerX, int centerY, int radius) {
			return new RadialGradientPaint(centerX, centerY, radius, new float[] { 0f, 20f/dia, .7f, 1f }, lightColors);
		}
	}

	public static void main(String[] s) {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		final TorchGame2 panel = new TorchGame2();
		frame.add(panel, BorderLayout.CENTER);
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
}
 

Zul

Mitglied
Jo, hab
Code:
while (destinationX != currentX || destinationY != currentY);
als Abbruchbedingung.

Hmm, bin ja noch nicht so fortgeschritten mit Java, deswegen habt bitte Nachsicht. ;)
Hier wird doch festgelegt, wo der gesamte Hintergrund gezeichnet wird, oder?
Java:
g2.translate(width/2-pX, height/2-pY);
Java:
int pX = player.getX();
int pY = player.getY();

Und das wird bei move == true gesetzt. Anders habe ich es ja eigentlich auch nicht gemacht (glaube ich), nur dass ich einen neuen Thread starte und deswegen manchmal gezeichnet wird, während x und y neu gesetzt wird. Oder habe ich etwas nicht verstanden? ???:L
 

Michael...

Top Contributor
Hier wird doch festgelegt, wo der gesamte Hintergrund gezeichnet wird, oder?
Java:
g2.translate(width/2-pX, height/2-pY);
Ja hier wird das Graphics Objekt des Panels so verschoben, dass z.B. das Hintergrundbild lagerichtig zur Figur gezeichnet wird.
Und das wird bei move == true gesetzt. Anders habe ich es ja eigentlich auch nicht gemacht (glaube ich), nur dass ich einen neuen Thread starte und deswegen manchmal gezeichnet wird, während x und y neu gesetzt wird.
Bei move==true wird nichts gesetzt. In meinem Bsp. wird grundsätzlich alle 100ms neu gezeichnet. In deinem Fall soll - wenn ich Dein Konzept richtig verstanden habe - nur bei der Bewegung von einer Kachel zur nächsten animiert werden. Das heißt während der Bewegung darf sich die Zielposition (steckt die in x und y?) eigentlich gar nicht verändert werden. Wenn es aber zulässig ist, dass der Anwender bereits in der Bewegung zur nächsten Kachel die nächste Zielkachel "anvisieren" kann, dann müsste man die Zielpostition in einem (synchronisierten) Puffer speichern.
 

Zul

Mitglied
Wenn man 'W' drückt, wird doch move = true gesetzt und wenn das der Fall ist, wird die move-Methode von Player aufgerufen, in der die Koordinaten des Punktes des Spielers verändert werden, die wiederum als Variablen zum Ausrichten des Graphics Objekts dienen.

In meinem Projekt wird (und soll) ebenfalls regelmäßig gezeichnet werden - unabhängig davon, ob der Spieler sich bewegt oder nicht. Jedoch lager ich die Bewegungsberechnung in einem Thread aus, in dem ich sagen wir mal pX und pY festlege. Wenn dann das Bild allerdings gerade in dem Augenblick gezeichnet wird, wo einer der Werte neu berechnet wird flackert das Bild kurz auf.

Naja... vielleicht habe ich das ganze auch einfach ganz dumm programmiert... :(
Mit dem synchronized funktioniert es zumindestens.
 

Michael...

Top Contributor
In meinem Projekt wird (und soll) ebenfalls regelmäßig gezeichnet werden - unabhängig davon, ob der Spieler sich bewegt oder nicht. Jedoch lager ich die Bewegungsberechnung in einem Thread aus, in dem ich sagen wir mal pX und pY festlege.
Warum wird die Bewegungsberechnung in einen eigenen Thread ausgelagert? Warum wird das nicht in dem Thread/ der GameLoop gemacht die das Neuzeichnen anfordert?
 

Zul

Mitglied
Ich dachte, ich stopfe die run-Methode nicht ganz so voll, wenn die Bewegungsberechnung auch in einem eigenen Thread abgewickelt werden kann. >300 loc woanders unterzubringen erschien mir sinnvoll um den Überblick zu behalten.


Das Thema hat sich erstmal erledigt denke ich. Habe momentan auch nicht die Zeit dafür. Nochmal danke für die Lösung für das Licht, Marco13. ;)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T Flackern trotz DoubleBuffering AWT, Swing, JavaFX & SWT 8
K AWT flackern trotz buffering AWT, Swing, JavaFX & SWT 4
K Flackern trotz Double-Buffering AWT, Swing, JavaFX & SWT 10
S animation Flackern trotz doppelpufferung wieso? AWT, Swing, JavaFX & SWT 2
L JButton flackern - Programm hängt sich auf AWT, Swing, JavaFX & SWT 3
G Applet Applet Komponenten flackern AWT, Swing, JavaFX & SWT 10
G Swing Flackern nach Override von paintComponent() AWT, Swing, JavaFX & SWT 3
S Swing Flackern und ausbrechen bei neuzeichnung AWT, Swing, JavaFX & SWT 7
J Flackern wie mit BufferedImage beheben AWT, Swing, JavaFX & SWT 4
V Applet JApplet Flackern durch Repaint AWT, Swing, JavaFX & SWT 11
L Swing Flackern in Frame bei erstem Klick AWT, Swing, JavaFX & SWT 19
R Flackern beim JPanel-Übermalen AWT, Swing, JavaFX & SWT 9
P SWT SWT flackern beheben AWT, Swing, JavaFX & SWT 9
D Undecorated JFrame ohne Flackern resizen AWT, Swing, JavaFX & SWT 21
sylo Flackern des Mauszeigers bei DND AWT, Swing, JavaFX & SWT 4
G ColorReader, bei Fadenkreuz zeichnen mit repaint() flackern AWT, Swing, JavaFX & SWT 19
eQuest Swing Snake repaint() "flackern" AWT, Swing, JavaFX & SWT 13
J Flackern in JEditorPane() AWT, Swing, JavaFX & SWT 14
JRTHEFROG Auflösungsabhängiges Flackern von Bildschirmmasken AWT, Swing, JavaFX & SWT 3
B JFrame flackern durch setSize() AWT, Swing, JavaFX & SWT 8
N Flackern beim neuzeichnen von JPanel AWT, Swing, JavaFX & SWT 19
S Falsche Position, Elemente erscheinen nicht, Flackern AWT, Swing, JavaFX & SWT 6
U Flackern verhindern AWT, Swing, JavaFX & SWT 5
J Flackern beim ersten laden von JPanel AWT, Swing, JavaFX & SWT 4
T Labels verschieben / Flackern AWT, Swing, JavaFX & SWT 2
K Bekomme (u.a) javafx.fxml.LoadException trotz "korrektem" Code AWT, Swing, JavaFX & SWT 8
M editorPane bleibt zu klein trotz setPage AWT, Swing, JavaFX & SWT 6
V JavaFX Button Controller Fehler, trotz Erfolg in einem anderem Code? AWT, Swing, JavaFX & SWT 7
A Swing Buttons werden trotz setVisible nicht dargestellt AWT, Swing, JavaFX & SWT 14
B Frame hängt sich auf trotz invokeLater AWT, Swing, JavaFX & SWT 1
G Komponenten vergrößern sich nicht trotz Layoutmanager AWT, Swing, JavaFX & SWT 24
U Swing NullPointerException trotz Referenz auf Textfield & Button AWT, Swing, JavaFX & SWT 6
K JavaFX Tableview mit fxml ohne Aktualiserung trotz Thread AWT, Swing, JavaFX & SWT 13
A trotz setSize keine breite AWT, Swing, JavaFX & SWT 4
M Trotz richtiger Daten, falsches Bild wird gezeichnet?! AWT, Swing, JavaFX & SWT 4
0 JTextPane copy/paste trotz editable(false) ? AWT, Swing, JavaFX & SWT 10
C Applet java.security.AccessControlException trotz signierten Jar AWT, Swing, JavaFX & SWT 7
J Swing JWindow flackert trotz Doppelpufferung AWT, Swing, JavaFX & SWT 2
B Swing JButton flackert trotz DoubleBufferings AWT, Swing, JavaFX & SWT 11
S Swing JTable RowSorter trotz RowFilter abschalten? AWT, Swing, JavaFX & SWT 2
T Fenster wird trotz repaint() und revalidate() nicht sofort neu gezeichnet AWT, Swing, JavaFX & SWT 6
R [gelöst]Fenster schließen - trotz Endlosschleife in der Paint-Methode? AWT, Swing, JavaFX & SWT 3
B JProgressbar wird nicht aktualisert, trotz Threads AWT, Swing, JavaFX & SWT 6
F Java heap space error trotz -Xmx512m AWT, Swing, JavaFX & SWT 9
O JFrame permanet im Vordergrund trotz Alt+Tab AWT, Swing, JavaFX & SWT 2
@ JPanel: kein paintComponent() trotz repaint() AWT, Swing, JavaFX & SWT 4
G Tabellenköpfe trotz Scrollpane ausschalten AWT, Swing, JavaFX & SWT 5
T JFrame#setSize trotz maximiert AWT, Swing, JavaFX & SWT 4
T Animation will nicht trotz Thread. AWT, Swing, JavaFX & SWT 14
S JFrame trotz undecorated vergroessern AWT, Swing, JavaFX & SWT 3
N Trotz richtiger ListSelectionMode kann ich keine Zeile sel? AWT, Swing, JavaFX & SWT 4
S Unterschiedliche Optik trotz gleicher Look and Feel Code? AWT, Swing, JavaFX & SWT 11
T repaint wird trotz Thread nicht ausgeführt AWT, Swing, JavaFX & SWT 5
G Leider trotz allem kein Icon :( Brauche Hilfe AWT, Swing, JavaFX & SWT 3
M 2D-Grafik Offscreen-Rendern von Bildern AWT, Swing, JavaFX & SWT 2
E Warum ist offscreen (mit Image) schneller? AWT, Swing, JavaFX & SWT 11
P Antialiasing in einem Offscreen-Image AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben