# Applet beschleunigen



## Samus (3. Dez 2007)

Hallo zusammen,

ich hoffe hier einmal auf einen Hilfreichen Tip. Ich musste ein Multiplayer Pong Spiel als Applet programmieren und bin fast fertig... für die Grafiken nutze ich Graphics2D und hatte damit während der Programmierung wenig Probleme. Doch eines wumt mich bei der ganzen Sache etwas... das Applet ist unter umständen recht langsam auf einigen Rechnern, obwohl nicht wirklich sehr viel dargestellt wird... ich hab auch das Gefühl es hängt zusätzlich mit dem Betriebssystem zusammen, denn bei meinem Mac läufts flüssig, wobei es auf einem recht starken Windows Rechner stockt.

Nun meine Frage: Gibt es eine Möglichkeit, ohne alle Objekte neu erstellen zu müssen eine Art Hardwarebeschleunigung zu implementieren?? Oder das Ding auf eine andere Weise etwas schneller zu bekommen??? In meinem Fall hat es anscheinend wirklich nur mit dem Zeichnen der Objekte zu tun, da mein Server alle Rechenoperationen (wie die Ballkoordinaten und die KI) übernimmt.

Greez..

Samus


----------



## Wildcard (3. Dez 2007)

Java ist schon seit einigen Jahren Hardwarebeschleunigt. Auch reines Zeichnen kann sehr langsam sein wenn man es falsch implementiert.


----------



## Samus (3. Dez 2007)

Also wird das schon Hardwarebeschleunigt.... Wüsste jetzt aber nicht was ich wo nicht anständig zeichnen lasse... Meine Klassen Zeichnen sich selbst, also würde z.B. die Klasse Ball folgendermassen aussehen und in Main mit "ball.paint(g)" gezeichnet. 


```
public void paint (Graphics2D g, int x_pos, int y_pos, int ballStatus, int kollisionen)
	{
		
		switch (ballStatus) {			// Farbänderung des Balls (welchem Spieler gehört der Ball grad)
		case 0:
			// Spielball
			g.setColor (Color.white);
			g.fillOval ((int)(x_pos - radius), (int)(y_pos - radius), 2 * radius, 2 * radius);
			g.setColor (Color.black);
			g.fillOval ((int)(x_pos - radius/2), (int)(y_pos - radius/2),2 * radius/2, 2 * radius/2);
			g.drawOval((int)(x_pos - radius), (int)(y_pos - radius), radius*2, radius*2);
			
			// Ballanzeige
			g.setColor (Color.white);
			g.fillOval (390 - 40, 50 - 40, 80, 80);
			g.setColor (Color.black);
			g.fillOval (390 - 20, 50 - 20, 40, 40);
			g.drawOval(390 - 40, 50 - 40, 80, 80);
			break;
		case 1:
			// Spielball
			g.setColor(Color.blue);
			g.fillOval ((int)(x_pos - radius), (int)(y_pos - radius), 2 * radius, 2 * radius);
			g.setColor (Color.black);
			g.fillOval ((int)(x_pos - radius/2), (int)(y_pos - radius/2), 2 * radius/2, 2 * radius/2);
			g.drawOval((int)(x_pos - radius), (int)(y_pos - radius), radius*2, radius*2);
			
			// Ballanzeige
			g.setColor (Color.blue);
			g.fillOval (390 - 40, 50 - 40, 80, 80);
			g.setColor (Color.black);
			g.fillOval (390 - 20, 50 - 20, 40, 40);
			g.drawOval(390 - 40, 50 - 40, 80, 80);
			break;
		case 2:
			// Spielball
			g.setColor(Color.red);
			g.fillOval ((int)(x_pos - radius), (int)(y_pos - radius), 2 * radius, 2 * radius);
			g.setColor (Color.black);
			g.fillOval ((int)(x_pos - radius/2), (int)(y_pos - radius/2), 2 * radius/2, 2 * radius/2);
			g.drawOval((int)(x_pos - radius), (int)(y_pos - radius), radius*2, radius*2);
			
			
			// Ballanzeige
			g.setColor (Color.red);
			g.fillOval (390 - 40, 50 - 40, 80, 80);
			g.setColor (Color.black);
			g.fillOval (390 - 20, 50 - 20, 40, 40);
			g.drawOval(390 - 40, 50 - 40, 80, 80);
			break;
		case 3:
			// Spielball
			g.setColor (Color.white);
			g.fillOval ((int)(x_pos - radius), (int)(y_pos - radius), 2 * radius, 2 * radius);
			g.setColor (Color.red);
			g.fillOval ((int)(x_pos - radius/2), (int)(y_pos - radius/2), 2 * radius/2, 2 * radius/2);
			g.drawOval((int)(x_pos - radius), (int)(y_pos - radius), radius*2, radius*2);
			
			
			// Ballanzeige
			g.setColor (Color.white);
			g.fillOval (390 - 40, 50 - 40, 80, 80);
			g.setColor (Color.red);
			g.fillOval (390 - 20, 50 - 20, 40, 40);
			g.drawOval(390 - 40, 50 - 40, 80, 80);
			break;
		case 4:
			// Spielball
			g.setColor(Color.white);
			g.fillOval ((int)(x_pos - radius), (int)(y_pos - radius), 2 * radius, 2 * radius);
			g.setColor (Color.blue);
			g.fillOval ((int)(x_pos - radius/2), (int)(y_pos - radius/2), 2 * radius/2, 2 * radius/2);
			g.drawOval((int)(x_pos - radius), (int)(y_pos - radius), radius*2, radius*2);
			
			
			// Ballanzeige
			g.setColor (Color.white);
			g.fillOval (390 - 40, 50 - 40, 80, 80);
			g.setColor (Color.blue);
			g.setComposite(ac1);
			g.fillOval (390 - 20, 50 - 20, 40, 40);
			g.drawOval(390 - 40, 50 - 40, 80, 80);
			break;
		}
		g.setColor (Color.white);						// Farbe für Schrift
		g.setFont( new Font("Arial", Font.BOLD, 16));	// Font der Schrift
		g.drawString("" + kollisionen , 382, 55);		// Gibt die Energie des Balls aus
		
	}
```

Ich programmiere noch nicht ganz so lange mit Java und erst recht keine Applets... wie man wahrscheinlich am Code sehen kann . Währe das so in Orndung?? Oder könnt ihr anhand dieses Beispieles schon sehen was bei mir nicht so dolle ist???


----------



## Wildcard (3. Dez 2007)

Wie und wo rufst du paint bzw. repaint auf?


----------



## Samus (3. Dez 2007)

In der run() Methode meine "Main.java"... hier mal der Auszug: 



```
public void run(){
		while (true)
		{
			switch (status) {
			case 3:
				menu = false;
				lobby = false;
				name = false;
				if (kbinput == true) {
					user.moveTastatur();		// wird die Tastatur als Steuerung benutzt
				}
				else {						// Ansonsten halt die Maus
					user.moveMaus(y_pos_maus);
				}
				try {
						moonClient.sendeDaten("UserY:" + user.getYPos());
						moonClient.sendeDaten("MOVEBALL");
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				break;
			
			case 2:			
				lobby = true;
				try{														// ######################################
					chatClient = new ChatClient(Name);							// ######################################
					ChatServerStatus = "Chatserver online";			// ######################################
				}catch(IOException e ){										// ######################################
					ChatServerStatus = "Chatserver offline";
				}				
				setLobbyItems();
				menu = false;
				name = false;
				status = 10;
			break;

			case 1:
				menu = true;
				setMenuItems();
				lobby = false;
				name = false;
				status = 10;
			break;
			
			case 0:			
				name = true;
				setEingabeName();
				menu = false;
				lobby = false;
				status = 10;
					
			default:
				break;
				
		}
		
			try
			{	
				Thread.sleep(12);
			}

			catch (InterruptedException ex)
			{
				break;
			}
			repaint();     // AN DIESER STELLE!
		}
	}
```


----------



## Wildcard (3. Dez 2007)

Das sieht für mich so aus als hinge dein repaint Zyklus maßgeblich von den Antwortzeiten einer Socket Verbindung ab  ???:L


----------



## Samus (3. Dez 2007)

In meiner run() Methode wird alle 12 Millisekunden dem Server die Anweisung geschickt, die nächste Ballposition zu berechnen und zurückzugeben. Mein Klasse "Client" läuft in einem eigenen Thread und schaut ständig ob etwas reinkommt, was weiter verarbeitet werden kann, wie z.B. Ballkoordinaten. Wie gesagt macht der Client aber im Prinzip nichts anderes als sich die Parameter vom Server zu schnappen, und alle 12 Millisekunden die Grafiken mit neuen Koordinaten zu zeichnen... liegt es vieleicht an meiner paint() in Main oder am Double Buffering?? 



```
public void paint(Graphics2D g){
		
		long startTime = System.currentTimeMillis();
		
		if(!menu && !lobby && !name){
			ball.paint(g, moonClient.getXpos(), moonClient.getYpos(), moonClient.getBallStatus(), moonClient.getKollisionen());					// Zeichnen des Balls
			map.paint(g, moonClient.getXpos(), moonClient.getYpos(), moonClient.getYbot(), user.getYPos());
			user.paint(g);
		}
		//sterne.paint(g);				// Zeichnen der Sterne
		spielfeld.paint(g);				// Zeichnen des Spielfeldes
		//mond1.paint(g);					// Zeichnen Mond (Spieler1)
		//mond2.paint(g);					// Zeichnen Mond (Spieler2)
		
		if (menu) {
		paintMenu(g);
		}
		else if (!menu) {
			delMenuItems();
		}
		
		if (lobby) {
			paintLobby(g);
		}
		else if (!lobby) {
			delLobbyItems();
		}
		if (name) {
			paintName(g);
		}
		else if (!name) {
			delEingabeName();
		}

		
		

		try {
			startTime += delay;
			Thread.sleep(Math.max(0, startTime-System.currentTimeMillis()));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}


	/** Dubble Buffering & Antialiazing **/
	public void update (Graphics g)		// Verhindert das Flackern
	{
		// Initialisierung des DoubleBuffers
		if (dbImage == null)
		{
			dbImage = createImage (this.getSize().width, this.getSize().height);
			dbg = (Graphics2D)dbImage.getGraphics ();
		}

		// Bildschirm im Hintergrund lˆschen
		dbg.setColor (getBackground ());
		dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);

		// Auf gelˆschten Hintergrund Vordergrund zeichnen
		dbg.setColor (getForeground());
		paint (dbg);

		// Nun fertig gezeichnetes Bild Offscreen auf dem richtigen Bildschirm anzeigen
		g.drawImage (dbImage, 0, 0, this);
		
		
        // Antialiasing
		if (grafik) {
        dbg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
		}
		else {
			dbg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
			        RenderingHints.VALUE_ANTIALIAS_OFF);
		}

	}
```


----------



## Wildcard (3. Dez 2007)

Aus dem Socket zu lesen wird bei dir wohl eine synchrone Methode sein, d.h. das Programm läuft erst weiter wenn die Daten gelesen sind, was unter Umständen sehr viel länger als 12ms dauert.
Du solltest Datenempfang vom zeichnen entkoppeln und die Bewegung der Objekte interpolieren solange du keine neuen Informationen hast.


----------



## Samus (3. Dez 2007)

Vielen Dank für deine Mühen... der Client-Thread läuft nicht syncron... die Werte die ich vom Server empfange, werden in meiner ClientKlasse zwischengespeichert, somit haben meine Paint Methoden immer alle Parameter zur Verfügung um jederzeit zu zeichnen... 

Ich schau mir grad die Slick2D Geschichte an... vieleicht werd ich mal versuchen diese zu implementieren... oder würdest du mir abraten??


----------



## Wildcard (3. Dez 2007)

Samus hat gesagt.:
			
		

> Vielen Dank für deine Mühen... der Client-Thread läuft nicht syncron... die Werte die ich vom Server empfange, werden in meiner ClientKlasse zwischengespeichert, somit haben meine Paint Methoden immer alle Parameter zur Verfügung um jederzeit zu zeichnen...


Und was denkst du was sich verändern soll wenn sich die Werte zwischendurch nicht geändert haben?
Solange deine Bewegung einzig und alleine auf Netzwerktraffic basiert, hast du Ruckler drin.


----------



## Marco13 (4. Dez 2007)

Das Antialiasing bremst sicher. Ansonsten - du verwendest wohl AWT, wie es da mit Hardwarebeschleunigung aussieht, weiß ich grad nicht... solltest evtl. überlegen, Swing zu verwenden (das ist auch von Haus aus Double-Buffered). Und... du hast die paint-Methode des Balles gepostet. Aber da wird ja noch mehr gepaintet....

```
if(!menu && !lobby && !name){
         ball.paint(g, moonClient.getXpos(), moonClient.getYpos(), moonClient.getBallStatus(), moonClient.getKollisionen());               // Zeichnen des Balls
         map.paint(g, moonClient.getXpos(), moonClient.getYpos(), moonClient.getYbot(), user.getYPos());
         user.paint(g);
      }
      //sterne.paint(g);            // Zeichnen der Sterne
      spielfeld.paint(g);            // Zeichnen des Spielfeldes
      //mond1.paint(g);               // Zeichnen Mond (Spieler1)
      //mond2.paint(g);               // Zeichnen Mond (Spieler2)
      
      if (menu) {
      paintMenu(g);
```
(paintMenu?).


----------



## Wildcard (4. Dez 2007)

Marco13 hat gesagt.:
			
		

> Das Antialiasing bremst sicher.


Das sollte an die Render Pipeline der Grafikkarte weitergereicht werden. Auch wenn ich mir bei AWT ebenfalls nicht sicher bin.


----------

