NAS

Java JPanel oder Canvas

XHotSniperX

Lt. Junior Grade
Registriert
Jan. 2008
Beiträge
474
Hi

ich bin an einem 2D Game dran. Deibei werden quadratförmige Bilchen gezeichnet (Tiled Map). Es funktioniert alles aber das Problem ist, es ist sehr langsam.

Immer wenn die Karte geupdatet wird, vergeht ne Sekunde. Ich habe JPanels paintComponent(Graphics g) überschrieben und benutzt.

Denkt ihr, Canvas wäre besser? Oder habt ihr irgendwelche Tipps?

Was eignet sich am besten um eine Map aus Bildchen zu malen?
 
Hast Du das JPanel.paintComponent(Graphics g) vielleicht so überschrieben, daß jetzt immer alle Unterkomponenten neu gezeichnet werden, auch wenn das nicht nötig wäre (und ein Region Update gereicht hätte)?
 
Poste mal den Inhalt deiner paintComponent() und sämtliche Stellen wo repaint() calls sind (also vermutlich deinen game loop).
 
Code:
    @Override
    public void paintComponent(Graphics g) {
    	super.paintComponent(g);
    	// Clear the board
    	g.clearRect(0, 0, 625, 625);
    	// Draw the grid
    	map.draw(g, 0, 0);
    	for(int i = 0; i<=4; i++){
    		if(InThread.pGetPlayer(i)!=null && InThread.pGetPlayer(i).coords!=null){
    			if(!InThread.pGetPlayer(i).coords.equals("-1,-1") && InThread.pGetPlayer(i).coords.length()!=0){
    				characters.get(i).position.x = InThread.getXCoord(i)*TILE_SIZE + 3;
    				characters.get(i).position.y = InThread.getYCoord(i)*TILE_SIZE + 3;
    				characters.get(i).draw(g);
    			}
    		}
    	}
    }
    
    public void updateMap(final String[] mapArray){
    	map = map.load(spriteLoader, mapArray, NUM_ROWS);
    	paintComponent(getGraphics());
    	repaint();
    }

hab noch an anderen Stellen repaint. aber nicht in dieser klasse. und ja, irgendwie hab ich das gefühl, alles wird neu gezeichnet im ganzen Panel oder sogar Frame. Weil auch buttons immer flackern.
 
Zuletzt bearbeitet:
Schwer zu sagen, anhand dieses Ausschnitts. Allerdings fällt auf, dass du die Zeichenlogik mit dem Rest des Programms vermischst, was ich eher ungünstig finde und das macht es auch schwerer nachvollziehbar, weil der Fehler jetzt überall liegen kann, sowohl in deiner map, als auch in den characters.

updateMap() sieht schon verdächtig aus. Wie oft und wo wird denn das gecalled? Zu jedem gerenderten Frame? Dann hat es zumindest den Anschein als würden da ständig sprites geladen, aber das kann ich wie gesagt ohne den Rest zu kennen nicht beurteilen, aber forsche da mal nach.

Wie oft ruft denn dein game loop überhaupt repaint auf, also wie sind deine frames per second?


Allgemein kann ich dir jedenfalls versichern, dass es nicht an der Verwendung von JPanel liegt, dass es nicht schneller geht. Ich weiß zwar nicht, wie groß deine map ist und was für ein System du verwendest, allerdings ist es eher unwahrscheinlich, dass es daran hapert. Du machst irgendwo irgendwas Komisches.

Zur Not - Brechstangenmethode und benchen (z.B. innerhalb der paintComponent()), bis du weißt, wo die Performance flöten geht. Alternativ auch Profiler anwerfen, falls du damit Erfahrung hast. Damit geht es wesentlich schneller.

Edit: Was mir auch gerade noch aufgefallen ist - der direkte Aufruf von paintComponent() in updateMap(). Repaint calls sollten mit repaint() geschehen, nicht anders. Seltsamerweise folgt ja sogar ein repaint() danach. Doppelt gemoppelt. Vermutlich rufst du updateMap() auch nicht im EDT auf. repaint() hingegen findet immer im EDT statt, daher ist das sicher zu verwenden.
 
Zuletzt bearbeitet:
Der Aufruf von repaint() aus dem EDT wäre nicht sicherer, da sie zu den Thread-Safe-Methoden gehört:
The following JComponent methods are safe to call from any thread: repaint(), revalidate(), and invalidate(). The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate(), respectively. The invalidate() method just marks a component and all of its direct ancestors as requiring validation.
(Quelle)
 
Genau das dachte ich geschrieben zu haben. :D
Vielleicht habe ich mich da auch missverständlich ausgedrückt. Wie gesagt - die repaint() ist sicher zu verwenden, d.h. man muss sich keine Mühe machen den call in den EDT zu verfrachten, weil repaint() selbst nur ein PaintEvent zur EventQueue hinzufügt und nicht selbst wild drauf loszeichnet. Das ist schon deshalb wichtig, weil dabei redundante events abgefangen werden und die Queue nicht unnötig zugepflastert wird.
 
Naja das mit repaint spielt keine Rolle. Bleibt genau gleich langsam. Habs trotzdem rausgenommen aus dem invokelater.

Hab mal Profiler installiert. Aber ich kann mein Programm damit nicht starten. Kommt immer "A Java Exception has occurred". Weiss nicht warum. Muss man für Profiler irgendwas machen, um starten zu können?
 
Kommt drauf an, welchen Profiler du benutzt. Bei visualvm startest du z.B. erst den Profiler, dann die Anwendung und dann siehst du im Profiler schon die laufende Java-Anwendung angezeigt und kannst dich da einklinken.
 
Das Performance-Problem ist jetzt behoben :) lag am debug-Modus vom Server. Der Server ist nicht eine Konsole sondern ein Fenster mit GUI. Alles von der Konsole wird dabei ins GUI geschrieben... Wenn der Debug-Modus an ist, verlangsamt das anscheinend extrem.

Jetzt gehts super schnell.. :)

Danke euch allen
 
mal ne andere Frage. Wie verwendet man repaint am besten?

wenn ich zum Beispiel repaint() nur auf ein Textfeld anwende und eine andere Rechtecksfläche repainte(), dann fehlen einfach plötzlich sachen... ich möchte aber auch kein flickering. wieso verschwindet manchmal einfach ein Teil, wenn ich nicht alles immer repainte?
 
Zurück
Oben