# Wie kann ich das Zeichnen der Grafik feiner machen?



## Stefan1200 (5. Mrz 2005)

Ich habe vor kurzem ein weiteres Spiel angefangen zu programmieren.
Es ist ein Lander Clone, also man bewegt in 2D Grafik ein kleines Raumschiff vom Landepad zum Ziel.
Ansich läuft es so, wie ich das gerne hätte. Aber eine Sache ist etwas unschön und unperformant.
Was Grafiken Zeichnen angeht, bin ich doch eher Anfänger, programmiere ja sonst nur Anwendungen oder Spiele, die auch mit normalen Swing Komponenten schick aussehen.

Folgendes Problem: Wenn sich das Schiff langsam bewegt, dann bewegt es sich alle 200 ms einen Pixel in die gewünschte Richtung. Je schneller, je mehr Pixel alle 200 ms. Nun könnt Ihr euch bestimmt vorstellen, das es ziemlich ruckelt, wenn man eine höhere Geschwindigkeit drauf hat. Gleichzeitig ist die CPU Belastung recht hoch. Auf meiner 2600er CPU bei Java 1.4.2 mal eben 80%, unter Java 1.5 immerhin noch 50%. Wie könnte ich die "Grafik Engine" (ich weiß, klingt besser als sie wirklich ist...) verbessern, das die Bewegungen wesentlich feiner aussehen, ohne das die CPU Belastung noch mehr steigt?

Mein jetziger Source (nur das, was mit Zeichnen zu tun hat).
Hinweis: bufferedImage ist das Bild vom Level.
             Das TheDrawPanel wird alle 200ms neu gezeichnet.

Für jeden Hinweis bin ich dankbar.


```
private void refreshStatusBar(Graphics2D g2D)
	{
		g2D.setColor(Color.BLACK);
		g2D.setComposite(acHalf);
		g2D.fillRect(0,0,SCREEN_WIDTH, 30);
		g2D.setComposite(acFull);
		g2D.setFont(fontSmall);
		g2D.setColor(Color.LIGHT_GRAY);
		g2D.drawString("Pathfinder Engine Test", 1,20);
		g2D.setFont(fontStatus);
		g2D.setColor(Color.blue);

		g2D.drawString("Speed X: " + getSpeed(speedX) + "  Speed Y: " + getSpeed(speedY), 500, 22);
		if (fuel <= 10)
		{
			g2D.setColor(Color.RED);
		}
		g2D.drawString("Fuel: " + Integer.toString(fuel), 900, 22);

		g2D.setFont(fontSmall);
		g2D.setColor(Color.RED);
	}

	class TheDrawPanel extends JPanel
	{
		public void paintComponent(Graphics gNormal)
		{
			Graphics2D g = (Graphics2D)gNormal;
			//g.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
			g.drawImage(bufferedImage, 0, 0, null);

			if (timer.isRunning())
			{
				calcNewPos();
			}

			if (timer.isRunning())
			{
				if (checkCollision())
				{
					setCrashed(g);
				}
				else if (won)
				{
					drawShip(g);
					setWon(g);
				}
				else if (!crashed && (fuel > 0))
				{
					drawShip(g);

					if (left && !landed)
					{
						g.drawImage(biFlameRight, posx + SHIP_SIZE_X, posy, null);
					}
					if (right && !landed)
					{
						g.drawImage(biFlameLeft, posx - flameLeftSizeX, posy, null);
					}
					if (up)
					{
						g.drawImage(biFlameBottom, posx + (SHIP_SIZE_X / 2) - (flameBottomSizeX / 2), posy + SHIP_SIZE_Y, null);
					}
					if (down && !landed)
					{
						g.drawImage(biFlameTop, posx + (SHIP_SIZE_X / 2) - (flameTopSizeX / 2), posy - flameTopSizeY, null);
					}
				}
				else
				{
					drawShip(g);
				}
			}
			else if (won)
			{
				drawShip(g);
				setWon(g);
			}
			else if (crashed)
			{
				drawShip(g);
				g.setColor(Color.BLACK);
				g.setComposite(acHalf);
				g.fillRect(190,350,SCREEN_WIDTH-190-255, 100);
				g.setComposite(acFull);
				g.setColor(Color.red);
				g.drawImage(biShipCrashed, posx, posy, null);
				g.setFont(fontBig);
				g.drawString("Crashed", 420, 380);
				g.drawString("Would you like to restart level? (y/n)", 220, 410);
				g.drawString("ESC to quit game!", 355, 440);
				g.setFont(fontSmall);
			}
			else
			{
				drawShip(g);
			}

			refreshStatusBar(g);
		}
	}

	private void drawShip(Graphics2D g)
	{
		if (leftShip)
		{
			g.drawImage(biShipLeft, posx, posy, null);
		}
		else
		{
			g.drawImage(biShipRight, posx, posy, null);
		}
	}

	private void calcNewPos()
	{
		if (left)
		{
			if (fuel >= 1)
			{
				++speedX;
				--fuel;
			}
		}
		else if (!right)
		{
			if (speedX > 0)
			{
				if (fuel >= 1)
				{
					--speedX;
					--fuel;
				}
			}
		}
		if (right)
		{
			if (fuel >= 1)
			{
				--speedX;
				--fuel;
			}
		}
		else if (!left)
		{
			if (speedX < 0)
			{
				if (fuel >= 1)
				{
					++speedX;
					--fuel;
				}
			}
		}
		posx -=speedX;

		if (up)
		{
			if (fuel >= 2)
			{
				--fuel;
				--fuel;
				++speedY;
				++speedY;
				++speedY;
			}
			else if (fuel >= 1)
			{
				--fuel;
				++speedY;
				++speedY;
			}
		}
		else
		{
			--speedY;
		}
		if (down)
		{
			if (fuel >= 1)
			{
				--speedY;
				--fuel;
			}
		}
		else if (!up)
		{
			if (speedY < 0)
			{
				++speedY;
			}
		}

		if (!landed)
		{
			--speedY;
		}
		posy -=speedY;
	}
```


----------



## DarKestSun (23. Mrz 2005)

vielleicht hab ichs ja überlesen, aber benutzt du dubble-buffering?
gerade unter swing is das leicht anzuwenden.


----------



## klom (23. Mrz 2005)

Wenn du nur alle 200 ms einen Update und Render-Vorgang auslöst muss es ja ruckeln, das sind doch nur 5 Frames die Sekunde. Ich kann mich bislang nicht beklagen, was die Geschwindigkeit von Java angeht, sogar auf meinem Laptop ein P2/166 laufen die Animationen halbwegs flüssig. Vielleicht hilft es ja auch wenn du einen Thread startest. Ich habe mich bislang immer an das Grundschema von Davison (http://fivedots.coe.psu.ac.th/~ad/jg/) gehalten. Damit kann man auf den Rechner sogar Jump & Run Games vernünftig darstellen, auch wenn bedingt durch Win98 nur ca. 50 Frames erreicht werden.


----------



## Stefan1200 (30. Mrz 2005)

@klom: Das Problem ist nur, wenn ich die Zeit auf unter 100ms senke, crasht mein Spiel sogar auf einem 2600+, wegen zu hoher Last (?!?).

Und mit den 200ms wird mein Spiel sogar auf 400MHz Rechnern sehr langsam.


----------



## DarKestSun (31. Mrz 2005)

versuch mal das ganze ohne paint auszuführen, also nur testen ob auch ohne zeichnen alles ruckelt

dann hast du irgendwo zu viel aufwand

liegst am zeichnen, dann musst du double buffering verwenden, ich hatte ohne auch schon flimmer - probleme.
findest überall mit stichwort double buffering.

unter swing einfach   object.setDoubleBuffered(true);


----------



## Wildcard (31. Mrz 2005)

DarKestSun hat gesagt.:
			
		

> liegst am zeichnen, dann musst du double buffering verwenden, ich hatte ohne auch schon flimmer - probleme.
> findest überall mit stichwort double buffering.
> 
> unter swing einfach object.setDoubleBuffered(true);


Swing ist standartmäßig doppelt gepuffert. Solange man das nicht willentlich ändert ist das völlig unnötig!


----------



## DarKestSun (3. Apr 2005)

achso

generell würd ich sowas sowieso nich unter swing machen, das gute alte awt ist (hab ich jedenfalls gelernt) schneller als swing, es sei denn es geht um buttons, menüs...

und awt muss erst gepuffert werden, aber dann darf da nix mehr flimmern


----------



## Stefan1200 (21. Apr 2005)

DarKestSun hat gesagt.:
			
		

> versuch mal das ganze ohne paint auszuführen, also nur testen ob auch ohne zeichnen alles ruckelt



Das ist mir jetzt erst aufgefallen. Habe ich das falsch verstanden, oder ist dein Satz wirklich witzig? ;-)
Wie soll ich denn sehen, obs ruckelt, wenn ich nichts zeichne?


----------



## klom (21. Apr 2005)

Wir hatten doch schon mal gesprochen das du selber bestimmen solltest, wann gezeichnet wird da Java ansonsten die Eigenart hat das paint() zu übergehen wenn es zu oft hintereinander ausgeführt wird.


----------



## Guest (21. Apr 2005)

Im übrigen sei nochmals auf Kapitel 2 verwiesen: http://fivedots.coe.psu.ac.th/~ad/jg/


----------

