# Hilfe bei Performanceverbesserung



## Major_Sauce (14. Nov 2014)

Guten Abend allerseits,

ich bin gerade am verzweifeln, da ich schon Tage damit verbracht habe, meine paint Methode zu optimieren und trotzdem habe ich hin und wieder kleine "laggs" oder auch größere Ruckler.

Ich versuche mal dier den dazugehörigen Code zusammenzufassen und ihn hier zu posten, vielleich kann sich das ja mal einer anschauen und mir ein bisschen helfen, wäre echt super.

Ach ja, es geht hier um ein kleines Spiel, desswegen müssen da auch möglichst keine Ruckler drin sein.

Der Code:

Main.class : https://code.stypi.com/majorsauce/Game/Main.java
Screen.class : https://code.stypi.com/majorsauce/Game/Screen.java
World.class : https://code.stypi.com/majorsauce/Game/World.java
Tile.class : https://code.stypi.com/majorsauce/Game/Tile.java
SpriteSheet.class : https://code.stypi.com/majorsauce/Game/SpriteSheet.java
Block.class : https://code.stypi.com/majorsauce/Game/Block.java
BlockType.class : https://code.stypi.com/majorsauce/Game/BlockType.java

Wär schön wenn da mal einer drüber schauen könnte 

mfg Major


----------



## Androbin (15. Nov 2014)

Hallo Major_Sauce,
wir alle würden dir natürlich gerne helfen, aber es ist doch etwas sehr mühsam, den ganzen Code durchzuschauen, völlig ohne weitere Erklärungen.
Darum würde ich dich an dieser Stelle bitten, vorerst lediglich besagte "paint"-Methode zu posten (
	
	
	
	





```
-Tags nicht vergessen!), damit wir uns erst mal ein Bild machen können.
Danach kannst du ja immer noch erklären, wie die anderen Klassen darin verwebt sind und die jeweils passenden Code-Abschnitte posten.

Mit freundlichen Grüßen,
Androbin
```


----------



## Major_Sauce (15. Nov 2014)

Ich werds später mal versuchen, das problem ist nur dass ich keine richtige paint methode habe, sondern beim Programmstart ein BufferedImage erstelle, dann einen int[] array für die Pixel des BufferedImage erstelle, und dann in verschiedenen Klassen diesen Array verändere. Am ende wird dann nur dieses BufferedImage wirklich gezeichnet, und dadurch wird das halt alles ein wenig verzweigt. Aber ich kann gerne versuchen alles so weit wie möglich zusammenzufassen.

Werde ich dann später mal machen, habe im moment leider noch was zu tun.

mfg Major_Sauce


----------



## Major_Sauce (16. Nov 2014)

So, ich werde hier mal alle codeschnipsel, die zum zeichnen verwendet werden, einfügen und kommentieren.

Noch kurz zur Regelmäßigkeit der repaints, diese kommen immer im (fast) selben Abstand(60 fps), daran kann das ruckeln nicht liegen.

Hier erst mal die render-Methode selbs : 


```
public void render(){
		BufferStrategy bs = getBufferStrategy();
		if(bs == null){
			createBufferStrategy(3);
			return;
		}
		Graphics2D g = (Graphics2D)bs.getDrawGraphics();
		g.drawRect(0, 0, WIDTH, HEIGHT);
		
		for(int x = 0; x < world.getXSize(); x++){
			for(int y = 0; y < world.getYSize(); y++){
				world.renderBlockAt(x, y, screen);
			}
		}
		
		g.drawImage(image, 0, 0, null);
		g.dispose();
		
		bs.show();
		
	}
```

mein Screen ist ein BufferedImage, aus welchem ein int[] Array ausgelesen wurde, der die daten des pixels beinhaltet (hauptsächlich die Farbe). Dieser wird dann beim rendern verändert, und die Graphics  malen das BufferedImage dann auf den Bildschirm.

Hier ist die methode, mit der ein Tile gerendert wird, dies wird bei world.renderBlockAt(x, y, screen) im endeffekt ausgeführt :


```
public void renderTile(Tile tile, int xPos, int yPos, boolean mirrorX, boolean mirrorY){
		xPos -= xOffset;
		yPos -= yOffset;
		int xColor = 0, yColor = 0;
		if(xPos + tile.getWidth() < 0 || xPos > width)return;
		if(yPos + tile.getHeight() < 0 || yPos > height)return;
		
		for(int xCurr = 0; xCurr < tile.getWidth(); xCurr++){
			for(int yCurr = 0; yCurr < tile.getHeight(); yCurr++){
				if(xPos + xCurr < 0 || yPos + yCurr < 0 || xPos + xCurr >= width || yPos + yCurr >= height)continue;
				if(mirrorX)xColor = tile.getWidth() - 1 - xCurr; else xColor = xCurr;
				if(mirrorY)yColor = tile.getHeight() - 1 - yCurr; else yColor = yCurr;
				pixelData[Math.abs(xPos + xCurr) + ((yPos + yCurr) * width)] = tile.getPixelData()[xColor + yColor * tile.getWidth()];
			}
		}
		
	}
```

Hier wurde ein Tile übergeben. Ein tile beinhaltet dann auch wie der Screen einen int[] Array, in dem die farbe des Pixels gespeichert wurde.

Dies ist auch schon alles, was gerade beim rendern gemacht wird, vielleich findet ja jemand möglichkeiten diese Methoden zu optimieren. 

mfg Major_Sauce


----------



## Foxei (16. Nov 2014)

Da will man dir Helfen und es geht nicht weil man an die Screen.java nicht ran kann da diese den selben inhalt hat wie die Main.java :/


----------



## Major_Sauce (16. Nov 2014)

Tschuldigung, habs geändert 

mfg Major_Sauce


----------



## Foxei (16. Nov 2014)

Du sorry der Code läuft offensichtlich nicht in einer Standard Java Umgebung sondern irgend einer API. Ich kann dir da nicht wirklich weiterhelfen :/ ich kann den Code ja nicht mal ausführen.


----------



## Major_Sauce (16. Nov 2014)

Benutze keine API, ist alles from scratch.

Es sind natürlich nicht alle klassen, die benutzt werden oben eingefügt, sondern nur die, die etwas mit dem rendern zu tun haben. Wenn du willst kann ich aber gerne mal das ganze Projekt hochladen, dann sollte es bei dir auch laufen.


----------



## Foxei (16. Nov 2014)

Gut ich kenne das jetzt persönlich nicht aber rein Logisch wenn du 60 mal in der Sekunde alle 1920 x 1080 Pixel eines Bildes neue auslesen lässt dann ist das wohl der Grund. 1920x1080x60=124.416.000 ist auch für einen Rechner nicht gerade wenig.


----------



## Major_Sauce (16. Nov 2014)

Mache ich nicht, ich lese beim programmstart ein mal die pixel des bildes aus, ist außerdem im mom nur 800x600. Die pixel werden in einem int[] array gespeichert, und durch das verändern dieses arrays, zum Beispiel : 


```
pixels[10] = 255000;
```

wird dem 10. pixel des BufferedImage die Farbe 255000 zugewiesen, was auch immer das für ne farbe ist.

Also wird nur ein mal ausgelesen, dann wird das bild ständig verändert, und dann wird es neu gezeichnet.

Es läuft im endeffekt so : 

init: Pixel auslesen.
update: pixel des BufferedImage dort wo nötig verändern
render: BufferedImage auf den bildschirm zeichnen


----------



## Thallius (16. Nov 2014)

Wiso speicherst du die Pixel des BufferedImages in einem int array? Warum nutzt du nicht direkt die Pixel des BufferedImages?


----------



## Major_Sauce (16. Nov 2014)

Oh, habs glaub falsch erklärt, ich lese die nicht aus sondern ich erstelle eine "Referenz" zu dem pixel-array, bearbeite also sogehen direkt das BufferedImage, im endeffekt ersetze ich also einfach die nativen funktionen zum zeichnen, also die Funktionen die Graphics mit sich bringt, um mir unzählige Instanzen von Images zu ersparen.

Ich benutze also keine images zum zeichnen, sondern lade meine tiles in einen int[] array und übertrage diesen dann wenn nötig auf den int[] array des BufferedImage


----------



## Foxei (16. Nov 2014)

Und warum tust du das denn überhaupt? Was willst du damit erreichen bzw wie soll das Bild danach aussehen? Vielleicht gibt es für das was du tuen willst eine einfachere Lösung die du vielleicht nicht kennst.


----------



## Major_Sauce (16. Nov 2014)

Ich habe ein SpriteSheet, also ein bild (png) auf dem die Ganzen Texturen drauf sind.
Die Texturen bestehen aus 4 Graustufen (weiß, hellgrau, dunkelgrau, schwarz). Nun möchte jede Texture einzeln laden, also im endeffekt ein SubImage erstellen und später beim Rendern soll die farbe der texture durch das Programm in eine Farbe meiner wahl geändert werden, also zum Beispiel wird hellgrau zu grün, weiß zu rot, dunkelgrau zu pink und schwarz zu blau.
Dies soll dann gezeichnen werden.
Das ändern der farben ist im bisherigen Code außerdem noch nicht vorhanden.


----------



## Foxei (16. Nov 2014)

Also für mich ist ein Sprite Sheet immer in Grid eingeteilt alsu Wenn du ein Grass Sprite mit 4 Grass Sorten hast das eine Auflösung von 32x32pixel hätte wären die 4 Graphiken immer 16x16 pixel groß und lägen auf (0/0) (0/16) (16/0) (16/16).
Also würde ich mir dann alle 4 Graphiken in 4 Betrennte Images Speichern bzw in ein Array.
Warum dann eine Farbraumanalysen? 

Zu dem zweiten Teil ich habe hier ne Methode die alle nicht weißen/transparente teile überschreibt mit einer RGB Farbe. Und dir immer ein gesamtes Bild zurück liefert. So musst du dann doch nur noch das gesamte Bild zeichnen oder?

Wenn ich dein Problem immer noch nicht richtig verstanden habe bitte daraufhinweisen;

```
public BufferedImage colorReset(BufferedImage img,int r,int g, int b){
		int width=img.getWidth();
		int height=img.getHeight();
		for(int y=0;y<height;y++){
			for(int x=0;x<width;x++){
				int rgb=img.getRGB(x, y);
				int alpha = (rgb >> 24) & 0xFF;
	            int red = (rgb >> 16) & 0xFF;
	            int green = (rgb >> 8) & 0xFF;
	            int blue = (rgb) & 0xFF;
	            if(red!=255&&green!=255&&blue!=255){
	            	img.setRGB(x, y, (int)(alpha<<24|r<<16|g<<8|b));
	            }
			}
		}
		return img;
	}
```


----------



## Major_Sauce (16. Nov 2014)

Die Farbumwandlung mag ich haben, weil ich die Farben dann während dem laufen ändern will, zum beispiel um nicht jedes mal eine neue Textur für eine Rote, eine Grüne und eine Gelbe Jacke haben will.
Oder um Texturen bei Tag oder Nacht eine andere Farbe zu geben, falls ich es noch nicht erwähnt habe, geht um ein kleines Spiel.
Das mit dem Transparent überschreiben habe ich schon in einem anderen Programm verwendet, dies kenne ich schon.

Ach ps : Ich möchte die Texturen nicht in einem BufferedImage speichern, da sie in einem einfachen Array weniges Speicher verbrauchen.


----------



## Foxei (16. Nov 2014)

Ich weiß nicht vielleicht liegt das Problem hier garnicht bei JAVA selber Packt deine Grafikkarte den sowas bzw hast du der Anwendung genug Ram zugewiesen?


----------



## Major_Sauce (16. Nov 2014)

Ich habe durchschnittlich 300 frames, wenn ich auf höchstleistung laufen lasse. Diese Ruckler kommen auch nicht die ganze Zeit, sondern alle 5 - 10 Sekunden mal.
Ich werde später mal die jar hochladen, kannst es dir ja mal anschauen wenn du willst.


----------



## Foxei (16. Nov 2014)

Gerne


----------



## Ruzmanz (16. Nov 2014)

> trotzdem habe ich hin und wieder kleine "laggs" oder auch größere Ruckler.



Ich hatte keine Lust deinen ganzen Quelltext durchzulesen. Dein Hauptproblem ist deine Game-Loop: Game loops! - Java-Gaming.org . Schneller ist nicht immer besser. Wann genau bekommt die JRE Zeit, um den Müll zu beseitigen? (== Rucker) Wann darf dein Betriebssystem die anderen Prozesse ausführen? (== Laggs) ...

Zumindest löst ein sleep in deiner while(true) das Hauptproblem:

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


----------



## Major_Sauce (16. Nov 2014)

Ich habe doch ein sleep ?


```
if(!DEBUGG){
				try {
					Thread.sleep(2L);
				} catch(InterruptedException e){
					e.printStackTrace();
				}
			}
```

ich habe nur einen boolean DEBUGG erstellt, damit ich mal testen kann wie viele frames is denn maximal haben kann, dient der performance verbesserung.


----------



## Ruzmanz (16. Nov 2014)

Dein DEBUG steht auf *true*, somit wird die Schleife momentan nicht ausgeführt. Wenn du normalerweise DEBUG auf false setzt, dann geht das trotzdem nicht in Ordnung. Die 2ms sind sehr sehr wenig. Versuchs mit 10 oder 20ms ... wenn das danach ruckelt, weil deine Frames zu niedrig sind, gibt es noch an anderen Stellen größere Probleme.


----------



## Major_Sauce (16. Nov 2014)

Hab die sleep-zeit mal auf 10 gesetzt und den boolean auf true gestellt, läuft immer noch auf konstant 60 fps, aber die Ruckler gibts immer noch.

Ich hab die jar jetzt mal angehängt, kannst dir ja mal kurz anschauen.
W, A, S, D ist bewegen.

Ach und die texturen sind relativ grell, ist nur zu testzwecken.


----------



## Major_Sauce (17. Nov 2014)

Habe jetzt nochmal alles überflogen und ein paar tests gemacht.
Mit meiner render funktion scheint alles zu passen, hat sonst jemand eine idee wo das "Flackern" herkommen könnte ?

mfg Major


----------



## Foxei (17. Nov 2014)

Sorry ich hatte gestern und heute wenig zeit ich werde mit das morgen angucken.


----------



## Major_Sauce (17. Nov 2014)

Alles klar, danke dir


----------



## Foxei (18. Nov 2014)

Ich habs  ohne Ruckeln und oder Laggs Ich muss Ruzmanz widersprechen das schlafen legen erzeugt nämlich deine Laggs und ein einfacher Datenstau dein Flackern.
Sprich das komplette Sleep Löschen.

```
if (shouldRender)
         {
          frames++;
          render();
         }
//      try
//     {
//        Thread.sleep(10L);
//     }
//     catch (InterruptedException e)
//    {
//         e.printStackTrace();
       }
       if (System.currentTimeMillis() - lastTimer > 1000L)
       {
         lastTimer += 1000L;
         System.out.println(frames + " | " + ticks);
         frames = 0;
         ticks = 0;
    }
```

Und dann noch die sich anstauenden Bilder Löschen in dem wir nach dem du die grafik anzeigen lässt alle laufenden Render Prozesse abbrechen. Ist einfacher als man Glaubt.

```
g.drawImage(this.image, 0, 0, null);
   g.dispose();     
   bs.show();
   Toolkit.getDefaultToolkit().sync();
```

Interessanterweise ist mir aber noch ein Bug aufgefallen :/ Du solltest niemals das spiel zweimal öffne dann kommt wieder das alte Bild. Ich nehme mal an dann gibt es wieder den Datenstau da wenn man die 2 Instanz schließt nach ca. 2 sec wieder alles Gut ist.

Wenn du noch Fragen hast gerne.
Lg Foxei


----------



## Major_Sauce (18. Nov 2014)

Hey, 

hab jetzt mal die änderungen vorgenommen und es läuft wirklich besser, habe zwar noch kleine ruckler aber ich hab keine Ahnung wo die herkommen.
Konnte deine Jar leider nicht öffnen, da du warscheinlich java8 hast ?

Ach ps: Dankeschön für die Tipps

mfg Major_Sauce


----------



## Foxei (18. Nov 2014)

Ja ich habe auch kein Java 7 mehr weil Java der Meinung war "Java 7 ist nicht Sicher" und hat das einfach gelöscht :/ also bei mir läuft es komplett ohne Ruckler. Ich bin in ca. 2 Stunden wieder zuhause dann kann ich es dir in Java 7 geben.


----------



## Major_Sauce (18. Nov 2014)

Das wäre super


----------



## Foxei (18. Nov 2014)

So müsste jetzt 7 sein.


----------



## Foxei (18. Nov 2014)

Also ich habe es nochmal getestet  auf meinem Rechner (i5 8gb ram und eine R9Dual-X270X) gibt es keine Ruckler aber gehe ich auf einen Laptop (i3 4gb ram und Inter OnBoard Graphics) sind die mini Ruckler noch da vielleicht solltest du die Renderhints für Render Qualitiy auf Fast und Antialising aus schalten wenn der Rechner zu langsame dafür ist D:


----------



## Major_Sauce (19. Nov 2014)

Hab nen Laptop, aber nen i7, und ne 2gb grafikkarte


----------



## Foxei (19. Nov 2014)

Hmm Sorry ich bin mit meinem Latein am Ende ich bin Software Entwickler ich habe mich nie auf Bild bearbeitung bzw rendering oder sowas Spezialisiert Sorry :/


----------



## Major_Sauce (19. Nov 2014)

Macht nichts, hab mein Projekt heute sowieso schon dem Lehrer gegeben, mal sehen was der dazu sagt.
Schlimmstenfalls gibts ein paar Punkte abzug.
Hätte mich jetzt nur noch persönlich interessiert.
Naja möchte trotzdem allen danken die versucht habe zu helfen.

mfg Major_Sauce


----------

