Performance Tipps für Spieleprogrammierung

  • Antworten:62
L3322
  • Forum-Beiträge: 467

30.01.2011, 12:13:55 via Website

Ich probiere zurzeit an Spielen herum!
mittlerweile fliegen auch schon mehrere Objekte über den Display, nur leider flackert es ab und zu ein bisschen, und ruckeln konnte ich auch gelegentlich feststellen es sind bis jetzt noch nicht soooo viele Objekte und deshalb wundert es mich dass derartiges auftritt!
Ich schreibe alles mit onDraw().

Habt ihr ein paar Tipps wie ich es anders machen könnte oder auf was ich achten sollte?!?

Danke

"Hard work beats talent, when talent fails to work hard"

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

30.01.2011, 12:59:10 via Website

Darüber wurden schon ganze Bücher verfasst, daher kann man ganz allgemein nicht viel sagen.

Vermeide das erzeigen neuer Objecte wo es geht, aber zuerst muss es funtzten, danach wird Optimiert!
Zeitbasiert ist besser als sich auf FPS zu verlassen.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Tobias Eckert
  • Forum-Beiträge: 155

30.01.2011, 14:18:14 via Website

Ein paar Sachen die mir geholfen haben:

  1. Verwende eine Surface View statt einer regulären view. Damit kannst Du Deine Zeichen-Methode recht elegant in einen anderen Thread auslagern und hast die Verarbeitung von Nutzereingaben getrennt von den Grafikoperationen.
  2. Achte darauf dass Du zur Laufzeit keine Grafik-Skalierungen machst da diese sehr rechenzeitintensiv sind. Am besten alles zu Programmstart entsprechend skalieren.
  3. Wenn Dein Spiel flackert kann das daran liegen dass genau dann eine Garbage Collection läuft. Die braucht immer ein paar Milli-Sekunden und legt in der Zeit Dein Spiel lahm. Das siehst Du sehr schön in der Log-Ausgabe. Das kannst Du verhindern indem Du drauf achtest in Deiner Haupt-Schleife (z.B. in onDraw) keine neuen Variablen zu allokieren, sondern immer wieder die gleichen zu verwenden. Du kannst umgekehrt eine Garbage Colection auch gezielt anstossen (z.B. nach den Resize Operationen für Schritt 2) durch System.gc()

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

30.01.2011, 17:26:54 via Website

Also eine generelle Methode um Flackern zu verhindern ist Double-Buffering.
Weiss leider nicht, ob man das auch bei Android mit vertretbarem Aufwand hinbekommt.

Dabei wird das Bild zunächst in eine Art Cache gemalt und erst wenn es dort vollständig aufgebaut wurde, wird es auf den tatsächlichen Canvas für den Bildschirm übertragen, was dann extrem schnell geht, weil einfach nur die Pixel kopiert werden müssen und dabei keine Berechnungen mehr erfolgen.

Dadurch gibt es dann kein Flackern mehr, denn das Flackern entsteht durch Pausen zwischen dem malen der einzelnen Objekte, wenn dies sequenziell geschieht.

Und mal ein Tipp, der dir das Leben deutlich einfacher machen sollte:
Nimm für Spiele die AndEngine.
Die kann das alles schon von sich aus und ist extrem performant.
Im Market gibt es eine App namens "AndEngine Examples" ... dort kriegst du mal eine Kostprobe, was die so alles kann.
UND: sie ist kostenlos !

Antworten
Dominic Bartl
  • Forum-Beiträge: 180

31.01.2011, 09:53:51 via Website

Meine Tipps:
  1. Verwende openGL dazu gibts ein weltklassen Tutorial, von dem auch ich es gelernt habe: hier
  2. Zeichne die FPS niemals auf den Bildschirm

Antworten
L3322
  • Forum-Beiträge: 467

01.02.2011, 15:53:42 via Website

Okay ich versuche nun alles mit einer SurfaceView!!! (Ich beachte natürlich auch die anderen Tipps und DANKE) ;)

Ich habe jetzt die folgende Frage wie soll ich bei folgendem Timer am schonensten auslesen wann ein Sekunde vergangen ist???
1public class Timer extends Thread {
2
3 private SurfaceHolder _surfaceHolder;
4 private GameView gv;
5 private boolean _run = false;
6
7 public Timer(SurfaceHolder surfaceHolder, GameView gav) {
8 _surfaceHolder = surfaceHolder;
9 gv = gav;
10 }
11
12 public void setRunning(boolean run) {
13 _run = run;
14 }
15
16 @Override
17 public void run() {
18 Canvas c;
19 while (_run) {
20
21 c = null;
22 try {
23 c = _surfaceHolder.lockCanvas(null);
24 synchronized (_surfaceHolder) {
25 gv.onDraw(c);
26 gv.frame();
27 }
28 } finally {
29 if (c != null) {
30 _surfaceHolder.unlockCanvasAndPost(c);
31 }
32 }
33 }
34 }

Ich habe im Internet gelesen dass Threads besser sind als z.b timertasks also habe ich es mal so probiert!

Wenn etwas nicht stimmt lasse ich mich gerne eines besseren belehren

"Hard work beats talent, when talent fails to work hard"

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

01.02.2011, 17:03:11 via Website

Du musst nicht wissen wann eine Sekunde vergangen ist sonder nur wie viel Zeit vergangen ist:

now = System.nanoTime
dif = now - last;
last = now;

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
L3322
  • Forum-Beiträge: 467

03.02.2011, 20:29:33 via Website

Bei dem Versuch ein "Missile" zu löschen bekomme ich immer folgenden Error:
102-03 20:23:33.097: ERROR/AndroidRuntime(9828): java.util.ConcurrentModificationException
202-03 20:23:33.097: ERROR/AndroidRuntime(9828): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:576)
302-03 20:23:33.097: ERROR/AndroidRuntime(9828): at de.tapps.rocketfighter.GameView.onDraw(GameView.java:87)
402-03 20:23:33.097: ERROR/AndroidRuntime(9828): at de.tapps.rocketfighter.Timer.run(Timer.java:31)

1for(Missile m : missile_list) {
2 c.drawBitmap(m.getBitmap(), m.getX(), m.getY(), null);
3 m.move();
4 if(m.getY() <= 0) missile_list.remove(m);
5 }

Kanns mir nicht erklären!
ohne das
1if(m.getY() <= 0) missile_list.remove(m);

Funktioniert alles wunderbar! aber ich denke es ist besser für die Performance die Schüsse zu löschen, ODER?????

"Hard work beats talent, when talent fails to work hard"

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

03.02.2011, 22:31:32 via Website

Das liegt daran das du in einem Thread die Liste durchläufst während ein anderer diese nutzt (add/remove).
Z.b der UI Thread und der der SurfaceView.

PS: Iteratoren sind mist für Performance ;)

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

03.02.2011, 22:58:52 via Website

Mac Systems
Das liegt daran das du in einem Thread die Liste durchläufst während ein anderer diese nutzt (add/remove).
Z.b der UI Thread und der der SurfaceView.
Das hat (in dem Fall) nix mit Threading zu tun.

Man kann schlicht und ergreifend nicht in einem for-each-loop über die remove() Methode der durchlaufenen Liste Elemente löschen.
Das geht NUR über den Iterator, der die Liste grade durchläuft und das darf maximal EINER sein.
Auf den hat man mit for-each aber leider keinen Zugriff, daher muss man hier anders vorgehen.

1for (Iterator iter = list.iterator(); iter.hasNext(); ) {
2 bla();
3 blub();
4
5 if (condition) {
6 iter.remove(); // remove() des Iterator
7 }
8}

— geändert am 03.02.2011, 23:00:10

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

04.02.2011, 09:26:17 via Website

Ups,da hab ich gepennt ;) War ja schon spät. Ich würde das dennoch anders lösen und mit Rockets merken und nach den durchlauf löschen!

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
L3322
  • Forum-Beiträge: 467

07.02.2011, 20:24:57 via Website

Mac Systems
Ups,da hab ich gepennt ;) War ja schon spät. Ich würde das dennoch anders lösen und mit Rockets merken und nach den durchlauf löschen!
wie würdest du es lösen??
ich habs jetzt folgendermaßen geregelt:
1for(int i = 0; i < missile_list.size(); i++) {
2 Missile m = (Missile) missile_list.get(i);
3 c.drawBitmap(m.getBitmap(), m.getX(), m.getY(), null);
4 m.move();
5 if(m.getY() <= -10) missile_list.remove(i);
6 }

"Hard work beats talent, when talent fails to work hard"

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

08.02.2011, 09:30:23 via Website

Wandere durch die liste, merke die die die du löschen möchstes folgendermaßen:


private final List<Rockets> rocketsToRemove = new ArrayList<Rockets>();



rocketsToRemove.clear();
for(int i = 0; i < missile_list.size(); i++) {
Missile m = (Missile) missile_list.get(i);
c.drawBitmap(m.getBitmap(), m.getX(), m.getY(), null);
m.move();
if(m.getY() <= -10)
rocketsToRemove.add(m);
}
//
missile_list.removeAll(rocketsToRemove); // entgültiges Löschen

Aus Performance Sicht würde Ich die liste rocketsToRemove vor dem Durchlauf einfach löschen anstatt neu anzulegen.


hth,
Mac

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

08.02.2011, 09:54:55 via Website

Und was hast du dadurch gewonnen?

Die Iteration machst du sowieso, aber statt n Remove, hast du jetzt n Add + 1 removeAll (was intern auch n remove sind).
Wobei zusätzlich das add() potentiell zu einer Erweiterung des Array in der ArrayList führen kann, wenn die Kapazität erweitert werden muss, also hast Du noch ein Array-Create und ein Array-Copy zusätzlich im worst-case.

Also mindestens doppelt so viele Operationen, größeren Speicher-Footprint...

[EDIT]
Hinzu kommt noch, dass removeAll zuerst das zu löschende Objekt in der Liste finden muss, was einen linearen Durchlauf durch die Liste zur Folge hat und einen equals() Vergleich pro Eintrag. Löscht man direkt über den Index, ist das nicht nötig.
Also nicht nur doppelt so viele Operationen, sondern Faktor 3, 4 oder mehr...
[/EDIT]

Ergo: das remove() in der Iteration durchzuführen ist DEUTLICH effizienter.

@L3322:
Lass es einfach so wie es ist...das passt scho :)

— geändert am 08.02.2011, 11:12:19

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

08.02.2011, 11:15:10 via Website

@Rafael K

So so, woher weißt du das alles ?
Performance Gemessen ? Speicherverbrauch ?

Der Code ist straight forward, das zählt. Ich kann die ArrayList entsprechend mit einer capacity belegen die einem internen copy/swap vorbeugt.
Der Code ist gegen multithreading/race conditions resistent (wenn man das removeAll entsprechend synchronisiert, wenn nötig), das war die Frage hinter der ConcurrentModificationException. Der Speicher Footprint ist minimal da hier Referenzen kopiert werden keine Objekte!

Und dennoch ist zu frühe Performance Optimierung nicht gut, ich schreibe lieber erstmal Code des tut was er soll, stelle ich fest das es ein Problem gibt löse ich das entsprechend. Man könnte das ganze bis zur Unkenntlichkeit optimieren, was ich hier aber nicht als zwangsläufig zwingend gegeben sehe.
Letztendlich kann man später mit Arrays arbeiten, schneller geht was fast nicht. Dennoch ein JIT Compiler optimiert die Collections klassen recht gut und der ArrayCopy wird intern mit einem System.arrayCopy durchgeführt was letztendlich ein memcopy darstellt, dies geschieht aber dennoch eher selten (wenn die Liste wächst). Vergebe ich der liste eine Initial Capacity von sagen wir mal 256*0.75 (0.75 ist der schwellwert ab wann eine Liste intern wächst) Einträgen sind das schon einige menge an Objekten die ich verwalten kann ohne das hier hier auch nur eine Mem Copy Operation durchgeführt werden muss.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

08.02.2011, 11:23:16 via Website

Mac Systems
@Rafael K

So so, woher weißt du das alles ?
Das ist elementares Wissen über Java und elementare Theorie der Informatik. Laufzeitanalyse von Algorithmen.

Mac Systems
Der Code ist straight forward, das zählt.
Straight forward ist es sicherlich nicht, Elemente zwischenzuspeichern, um sie 3 Zeilen später zu löschen.
Straight forward ist es sie direkt zu löschen.

Mac Systems
Ich kann die ArrayList entsprechend mit einer capacity belegen die einem internen copy/swap vorbeugt.
Der Code ist gegen multithreading/race conditions resistent (wenn man das removeAll entsprechend synchronisiert, wenn nötig), das war die Frage hinter der ConcurrentModificationException. Der Speicher Footprint ist minimal da hier Referenzen kopiert werden keine Objekte!
Es ist an dieser Stelle dennoch unnötiger Overhead.
Es sind mehr Zeilen Code und es ist langsamer. Das ist leider fakt.

Mac Systems
Und dennoch ist zu frühe Performance Optimierung nicht gut, ich schreibe lieber erstmal Code des tut was er soll, stelle ich fest das es ein Problem gibt löse ich das entsprechend. Man könnte das ganze bis zur Unkenntlichkeit optimieren, was ich hier aber nicht als zwangsläufig zwingend gegeben sehe.
Letztendlich kann man später mit Arrays arbeiten, schneller geht was fast nicht. Dennoch ein JIT Compiler optimiert die Collections klassen recht gut und der ArrayCopy wird intern mit einem System.arrayCopy durchgeführt was letztendlich ein memcopy darstellt, dies geschieht aber dennoch eher selten (wenn die Liste wächst). Vergebe ich der liste eine Initial Capacity von sagen wir mal 256*0.75 (0.75 ist der schwellwert ab wann eine Liste intern wächst) Einträgen sind das schon einige menge an Objekten die ich verwalten kann ohne das hier hier auch nur eine Mem Copy Operation durchgeführt werden muss.
Du kannst auch einfach von vornherein Code schreiben, der nicht mehr macht als nötig, kompakter ist und dennoch schneller läuft.

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

08.02.2011, 11:34:52 via Website

Gut das du so gut Bescheid weißt, ohne dein Wissen zu begründen.
Zumal immer noch der Iterator genutzt wird, und new ist ein Schlüsselwort das in dem Code zwar nicht zu sehen ist dennoch aber geschieht.

Durch eine Liste zu rennen und sich die Elemente zu merken die zu löschen sind ist dennoch sehr einfach. Gibt genug Literatur zu solch Themen.

Ich sehe die Frage dennoch als beantwortet an, ich habe geschrieben wie ich es machen würde und warum, damit ist das an sich abgeschlossen. Viele Wege führen nach Rom das gilt auch für Software.

Evtl meldet sich der Threadersteller ja nochmal dazu :lol:

— geändert am 08.02.2011, 11:35:46

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

08.02.2011, 11:48:20 via Website

Mac Systems
Gut das du so gut Bescheid weißt, ohne dein Wissen zu begründen.
Die Begründung kannst Du beispielsweise in einigen Büchern von Ingo Wegener (RIP) zur Effizienz von Algorithmen nachlesen...

Aber gerne hier nochmal als Gegenüberstellung (ich beschränke mich mal auf den wesentlichen Teil, die Löschoperationen):

Orginal Algorithmus:
n Iterationen mit m Aufrufen von remove (mit m <= n)
Da hier über den Index gelöscht wird ist kein find() nötig, also eine Operation pro Aufruf.
~ m Operationen

Dein Algorithmus:
n Iterationen mit m Aufrufen von add (ebenfalls m <=n)
1 Aufruf von removeAll mit einer Liste der Größe m, den man nochmal aufschlüsseln muss:
- Für jedes Element der übergebenen Liste wird die Quellliste (Größe n, wir erinnern uns) durchlaufen und mit equals() die Identität der Objekte geprüft, um das Objekt zu finden, das gelöscht werden soll. Also im worst-case m*n equals() + m remove() Aufrufe.
Insgesamt also: ~ m*n + 2*m Operationen (wobei die ArrayList Instanzierung und ggf. Erweiterung noch nichtmal berücksichtigt ist)

m*n + 2*m >> m

Noch Fragen? ;-)

— geändert am 08.02.2011, 11:55:57

Antworten
Gelöschter Account
  • Forum-Beiträge: 21

08.02.2011, 16:09:52 via Website

1/**
2 * Removes all elements from this {@code ArrayList}, leaving it empty.
3 *
4 * @see #isEmpty
5 * @see #size
6 */
7 @Override public void clear() {
8 if (size != 0) {
9 Arrays.fill(array, 0, size, null);
10 size = 0;
11 modCount++;
12 }
13 }

Ich geb auch noch meinen Senf dazu. :grin:
Oben ist die Methode ArrayList.clear() aus den Android-Quellen zu sehen. Stammt von hier: http://source.android.com/index.html

Je nachdem was L3322 noch in seinen Loop packen möchte finde ich die Lösung von Mac Systems auch sicherer.

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

08.02.2011, 16:20:14 via Website

clear() ist auch was ganz anderes !

Hier ist mal der Code von removeAll()

[code]
public boolean removeAll(Collection<?> c) {
boolean modified = false;
Iterator<?> e = iterator();
while (e.hasNext()) {
if (c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}


public boolean contains(Object o) {
return indexOf(o) >= 0;
}


public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
[/code]

Es ist einfach nur um den Faktor 3-4 langsamer, und synchronisiert ist da auch nichts, von daher ist es auch nicht "sicherer".
Eine Schleife in einem Spiel, die pro Sekunde mehrmals durchlaufen wird, muss effizient sein.
Warum soll man sie also mit unnötigen Operationen aufblähen, um am Ende zum gleichen Ergebnis zu kommen?

Wenn überhaupt reicht ein synchronized(missileList) um den ganzen Loop und gut ist.

1synchronized(missile_list) {
2
3for(int i = 0; i < missile_list.size(); i++) {
4 Missile m = (Missile) missile_list.get(i);
5 c.drawBitmap(m.getBitmap(), m.getX(), m.getY(), null);
6 m.move();
7 if(m.getY() <= -10) missile_list.remove(i);
8}
9
10}

— geändert am 08.02.2011, 16:21:37

Antworten
Gelöschter Account
  • Forum-Beiträge: 21

08.02.2011, 17:17:32 via Website

Hast natürlich recht.
:*)
Ich hab erst geschrieben, dann nachgedacht.

Antworten
L3322
  • Forum-Beiträge: 467

08.02.2011, 21:39:52 via Website

Dann zur nächsten Frage:


Hier habe ich versucht das Problem darzustellen:
und zwar den genauen weg zu ermittlen das dass Objekt über das TouchEvent fliegt!

Satz des Pythagoras???

Ich komm nicht drauf

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

08.02.2011, 21:53:32 via App

genau

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

08.02.2011, 22:42:48 via App

also ich habs jetzt, zugegeben nicht alleine, gelöst.
ich werds morgen mal posten.

zu den arraylists.

mit den meteor_list.remove(i);
bekomme ich bei den meteoren die noch am Spielfeld sind ein kurzes flackern! wenn ich aber gar nichts entferne läuft alles flüssig. ich werde morgen mal anderes probieren und dann berichten!

danke

— geändert am 08.02.2011, 22:44:47

"Hard work beats talent, when talent fails to work hard"

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

08.02.2011, 23:15:10 via Website

synchronisierst du die Liste für den Durchlauf?
Wieviele Threads nutzt du für das rendern und was machen die genau?

Hast du mal geschaut, ob DoubleBuffering realisierbar ist?
Also dass du deine Grafiken alle in ein Canvas schreibst und dann einfach nur noch dieses Canvas auf den Bildschirm kopierst?

Sonst kannst Du halt immer mal Flackern haben.
Stell dir halt mal vor was da passiert. Du malst erst den Hintergrund, dann die Objekte eins nach dem anderen.
Wenn das alles schnell genug geht, sieht es so aus, als würden sich die Objekte nur bewegen.
Hat aber dein Handy doch mal kurz was zu tun ... Speicher aufräumen o.ä. entsteht eine Pause in der noch nicht alle Objekte gemalt sind....und es flackert.

Also erst das Gesamtbild unsichtbar im Hintergrund aufbauen und dann in EINER ATOMAREN Operation auf den Bildschirm kopieren,
wäre mein Ansatz gegen jede Form von Flackern.

— geändert am 08.02.2011, 23:16:07

Antworten
L3322
  • Forum-Beiträge: 467

09.02.2011, 22:32:10 via App

L3322
Dann zur nächsten Frage:


Hier habe ich versucht das Problem darzustellen:
und zwar den genauen weg zu ermittlen das dass Objekt über das TouchEvent fliegt!

Ich komm nicht drauf
okay ich habe dochnicht geschafft!
wie würdet ihr das machen?

"Hard work beats talent, when talent fails to work hard"

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

09.02.2011, 23:53:40 via Website

Berechne dir den Abstand zwischen beiden Punkten. (euklid)
Rechne das Verhältnis aus zur Anzahl der Pixel, die du es pro Schritt bewegen willst.
Berechne mit Pythagoras die x und y Entfernung und skaliere sie mit dem o.g. Faktor.

Dann hast du die Anzahl der Pixel in x und y Richtung, die du bei jeden Schritt addieren musst.

Wäre so eine erste Idee.

Antworten
L3322
  • Forum-Beiträge: 467

10.02.2011, 19:37:41 via Website

1int startx = rocket.getX() + rocket.getBitmap().getWidth()/2;
2int starty = rocket.getY();
3int endx = (int) event.getX();
4int endy = (int) event.getY();
5
6int xlength = endx - startx;
7int ylength = endy - starty;
8double clength = Math.sqrt((xlength * xlength) + (ylength * ylength));
9
10double dx = xlength / (clength / 4);
11double dy = ylength / (clength / 4);

So hab ich jetzt gemacht.. danke für die Tipps

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

10.02.2011, 20:25:12 via Website

Mac Systems
Wandere durch die liste, merke die die die du löschen möchstes folgendermaßen:


private final List<Rockets> rocketsToRemove = new ArrayList<Rockets>();



rocketsToRemove.clear();
for(int i = 0; i < missile_list.size(); i++) {
Missile m = (Missile) missile_list.get(i);
c.drawBitmap(m.getBitmap(), m.getX(), m.getY(), null);
m.move();
if(m.getY() <= -10)
rocketsToRemove.add(m);
}
//
missile_list.removeAll(rocketsToRemove); // entgültiges Löschen

Aus Performance Sicht würde Ich die liste rocketsToRemove vor dem Durchlauf einfach löschen anstatt neu anzulegen.


hth,
Mac

Danke Mac hierfür!
Ich merke wirklich einen PerformanceSchub und es flackert nichtmehr kurzzeitig!

Danke nochmal an alle ich lerne in diesem Thread seeehr viel;

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

11.02.2011, 23:28:17 via Website

Jetzt sitze ich vor dem nächstem Problem!
Die Zusammenstöße!

Ich habe begonnen es mit Rect zu machen um dann:
1if(rect1.intersect(rect2))
Bei zwei, drei Objekten noch ganz okay aber wenn ich mehrere Objekte und damit 5 foreach schleifen habe wird es sehr ungenau!

Wie soll ich das am besten machen? ich habe bisher alle for schleifen ineinander geschrieben!

Danke

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

21.02.2011, 13:20:51 via App

okay dann noch eine frage:
wie könnte ich feste Objekte wie Background nur einmal zeichnen sodass sie nicht mehr jedes mal in der onDraw Methode gemalt werden?
ich denke auf Dauer wäre das sehr Performance schonend da somit jede aktuallisierung weniger obkljekte zeichnen müsste! gibts da was?

"Hard work beats talent, when talent fails to work hard"

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 13:27:13 via Website

Bei der AndEnginge gibts für genau sowas Scene.setBackground(Sprite s) :)

Ansonsten muss der Background aber immer neu gemalt werden...die Stellen wo die bewegten Objekte sind, werden ja von diesen Objekten "übermalt" und überschreiben die Pixel des BG. Die muss man dann wieder neu malen.

Evtl. gibts da ja ne Möglichkeit nur die Stellen neu zu malen, die "dirty" sind, also überlagert wurden, aber keine Ahnung.

— geändert am 21.02.2011, 13:28:15

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

21.02.2011, 13:27:28 via Website

Wenn der Background statisch ist diesen einfach zum löschen des Screens verwenden, viel schneller geht es nicht.
DoubleBuffering verwenden, ich denke das macht Android aber eh schon, da ich hier explizit nichts zu gelesen habe das was zu tun wäre.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 13:29:41 via Website

Mac Systems
DoubleBuffering verwenden, ich denke das macht Android aber eh schon, da ich hier explizit nichts zu gelesen habe das was zu tun wäre.
Ich denke eher das es das NICHT tut, sonst würde es nicht flackern, wenn man länger dauernde Operationen im redraw-loop hat.
Das wäre dann nämlich prinzipbedingt ausgeschlossen.

— geändert am 21.02.2011, 13:30:00

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

21.02.2011, 13:46:53 via Website

In keinem Buch habe ich dazu was gefunden, es würde drinstehen denke ich wenn android das nicht könnte bzw. man sich selbst drum kümmern müsste um den pageSwap durchzuführen denke ich mir zumindest... Die API Doc zu SurefaceHolder sagt dazu auch nix: http://developer.android.com/reference/android/view/SurfaceHolder.html

Mir scheint das alles weg gekapselt in der Methode lockCanvas zu sein. Meiner Meinung nach macht das auch Sinn (Denke gerade an die alte Java Fullscreen API) da es somit denkbar einfach zu benutzt ist.

Die Methode unlockCanvasAndPost deutet das evtl sogar an, ist aber Abstract, was das erhärtet da es unterschiedliche Strategien geben kann je nach Art des Buffers.

Finish editing pixels in the surface. After this call, the surface's current pixels will be shown on the screen, but its content is lost, in particular there is no guarantee that the content of the Surface will remain unchanged when lockCanvas() is called again.
Parameters

- Mac

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 13:54:27 via Website

Ich schließe das jetzt einfach mal aus dem Verhalten, dass es nicht so sein kann.
Mit DoubleBuffering ist Flackern ausgeschlossen. Es kann höchstens Tearing auftreten.

Wenn es quakt wie eine Ente und aussieht wie eine Ente...ist es wohl eine Ente ;-)

— geändert am 21.02.2011, 13:54:47

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

21.02.2011, 14:00:14 via Website

Wenn es quakt wie eine Ente und aussieht wie eine Ente...ist es wohl eine Ente ;-)

Gerade mal den LunarLander Quellcode angeschaut dazu:

@Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) updatePhysics();
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}

Deine Ente ist nicht zu erkennen.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

21.02.2011, 14:10:42 via Website

Evtl spielen hier noch andere Faktoren rein. Ein Buch von Reto Meier das mir neben liegt, würde dem wohl Aufmerksamkeit widmen.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 14:19:38 via Website

Also ich vertrau ja lieber auf das was ich selbst festelle, als dogmatisch an dem festzuhalten was andere schreiben.
Das kann nämlich sowohl falsch, als auch unvollständig, als auch veraltet, als auch ... sein.
Alles schon erlebt...sogar in SUN Zertifikatsprüfungen.

Ich sags gern nochmal :)
Bei korrekt implementiertem DoubleBuffer Algorithmus können einzelne Objekte nicht flackern. Das geht prinzipbedingt nicht.
Es kann nur Tearing auftreten, wenn zeilenweise geflusht wird.
Wenn es bei ihm geflackert hat, kann also seine App kein DoubleBuffering verwenden. Simple Logik.

Da brauchen wir jetzt garnicht weiter drüber zu diskutieren, das ist Fakt.

Lass uns lieber darauf konzentrieren dem Einsteiger zu helfen und sowas können wir von mir aus auch gerne privat ausdiskutieren ;-)

— geändert am 21.02.2011, 14:22:55

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

21.02.2011, 14:26:14 via Website

Gegenfrage an den Thread Ersteller: Flackert Lunar Lander bei dir ?

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
L3322
  • Forum-Beiträge: 467

21.02.2011, 16:21:52 via App

nein und auch mein bisheriges Spiel flackert nicht!!

ich wollte dies nur so als Frage stellen damit Objekte die sich weder verändern noch bewegen
nicht dauernd gemalt werden müssen... meine Performance ist bisher gut!

Ich habe bisher auch nichts über Doublebuffering in android gelesen!

"Hard work beats talent, when talent fails to work hard"

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 16:33:46 via Website

L3322
bekomme ich bei den meteoren die noch am Spielfeld sind ein kurzes flackern! wenn ich aber gar nichts entferne läuft alles flüssig.
Die Diskussion bezog sich darauf ... das würde nämlich gegen DoubleBuffering sprechen.

Ist aber echt nicht Gegenstand dieses Threads :-)

Die Frage mit dem BG wäre ja aber geklärt.

Antworten
Tobias Eckert
  • Forum-Beiträge: 155

21.02.2011, 20:28:32 via Website

Rafael K.
Die Diskussion bezog sich darauf ... das würde nämlich gegen DoubleBuffering sprechen.

Android macht bei SurfaceViews definitiv Double Buffering. Die eine Canvas wird dargestellt während Du auf die zweite zeichnest. Hab ich selbst beim Bug-Fixing festgestellt. Mit geschickter Programmierung flackert's auch bei Double Buffering... :D

Für eine sehr genaue Erklärung wie das funktioniert, ein Beitrag direkt aus der Android Grafikabteilung.


Rafael K.

Ist aber echt nicht Gegenstand dieses Threads :-)

Egal -_-

L3322

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

21.02.2011, 22:02:10 via Website

Tobias Eckert
Rafael K.
Die Diskussion bezog sich darauf ... das würde nämlich gegen DoubleBuffering sprechen.

Android macht bei SurfaceViews definitiv Double Buffering. Die eine Canvas wird dargestellt während Du auf die zweite zeichnest. Hab ich selbst beim Bug-Fixing festgestellt. Mit geschickter Programmierung flackert's auch bei Double Buffering... :D
Danke für den Link :)

Joa mit Buffer Flipping kriegt man das hin, mit traditionellem, kaskadiertem Buffer muss man das Flackern schon selbst programmieren, damit es flackert :)
Sollte mit dem hier geposteten Quellcode aber auch nicht passieren...denn partielle Updates macht er ja nicht.

Find ich aber lustig, dass die einen Triple Buffer als Lösung dieser "Schwäche" empfehlen :)

Antworten
L3322
  • Forum-Beiträge: 467

21.02.2011, 22:09:22 via App

wie gesagt es flackert nicht!
:)

danke für die antworten und Diskussionen!

— geändert am 21.02.2011, 22:10:05

"Hard work beats talent, when talent fails to work hard"

Antworten
L3322
  • Forum-Beiträge: 467

10.03.2011, 21:31:46 via Website

Es gehört nicht wirklich zur Performance aber egal:

Wie soll ich beim Beenden der Activity meines Spiels das derzeitige Spiel speichern???
Integer oder Strings etc. könnte ich ja leicht in eine Datenbank packen allerdings wüsste ich nicht dass es bei folgenden Dingen geht:
1ArrayList<Missile>

Ich es zwar mit onSaveInstanceState versucht allerdings löscht sich der/die/das Bundle Automatisch sobald die Activity geschlossen wird oder habe ich mich da verlesen??

Gibt es Alternativen??
danke

— geändert am 10.03.2011, 21:33:33

"Hard work beats talent, when talent fails to work hard"

Antworten
Andy N.
  • Forum-Beiträge: 3.112

11.03.2011, 08:46:04 via Website

Den kannst Du ja so wie er ist in eine Datei speichern und evtl. das ganze ein wenig verschlüsseln, so dass die Datei nicht verändert oder ausgetauscht werden kann.

Antworten
L3322
  • Forum-Beiträge: 467

11.03.2011, 15:56:48 via Website

Okay ich habe es vorerst ohne verschlüsseln gemacht !

Dass mit den ArrayLists klappt super:
1fos = mContext.openFileOutput("missile", Context.MODE_PRIVATE);
2 out = new ObjectOutputStream(fos);
3 out.writeObject(missile_list);
Ich musste meine Klasse Serializable machen und dann ging es!

jetzt klappt es allerdings nicht mit ints!
Speichern tu ich es so:
1fos = mContext.openFileOutput("score", Context.MODE_PRIVATE);
2 out = new ObjectOutputStream(fos);
3 out.writeObject(score);
auslesen so:
1is = mContext.openFileInput("score");
2 ois = new ObjectInputStream(is);
3 score = ois.read();

Doch Score ist beim auslesen immer -1!!!

"Hard work beats talent, when talent fails to work hard"

Antworten