JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=0aec11ffca917b4bff6e21ac9adfd3b9Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

performanceprobleme: dynamisches array
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
manu
Super JLI'ler


Alter: 35
Anmeldedatum: 09.03.2006
Beiträge: 327
Wohnort: allgäu (DE)
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 10:42    Titel: performanceprobleme: dynamisches array Antworten mit Zitat

Hi, ich feile am Mapeditor eines 2d spiels.. Bis jetzt arbeite ich so, dass die ganze Karte in einem Array liegt und dann vom Benutzer die entsprechenden Tiles ausgewählt und bearbeitet werden können.

Eine Karte ist beliebig groß und die Größe dynamisch veränderbar, die einzige Grenze ist jetzt halt der Ram..

scroll ich im editor weiter und weiter.. hab ich z.B. bei einer Kartengröße von 800x800 ca.. 250MB ramauslastung.. ich mein die Karten werden wohl nie so groß. aber auch 60MB bei 200x200 sind schon irgendwie viel.


Jetzt wollt ich mal fragen wie ihr des angehen würdet.. also wie ich die Karte performanter verwalten kann.. Sollte ich immer nur einen kleinen Bereich in einem nicht dynamischen array geladen haben und den rest beim wegscrollen usw. gleich in die Mapdatei schreiben und bei weidergebrauch wieder auslesen.. Das wäre schon machbar, ich müsste halt einiges umstellen. Würde das was bringen?

mein Maparray sieht intern übrigens so aus:

CPP:
std::vector< std::vector<sTile> > m_Tileset;
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 12:48    Titel: Antworten mit Zitat

Im Prinzip schon, 800x800 sind ja immerhin satte 640.000 Tiles, je nach Größe der Tilestruktur kommt da schon einiges zusammen. Ich würde das System so umstellen, dass du keine kompletten Maps mehr verwaltest, sondern diese in viele kleinere "Maps" aufteilst. Da müsstest du dann eine vernünftige Größe ermitteln, vielleicht so, dass eine der kleineren Maps reichlich einen Bildschirm ausfüllt. Deine "große" Map teilst du nun entsprechend auf und musst eben deine Verwaltung so umstellen, dass du immer nur eine handvoll von den Kleineren im Speicher hälst. Man könnte das z.B. so machen, dass man ein 3x3 Array von diesen anlegt und der aktuelle Bildausschnitt ist ca. über die Mittlere gescrollt (2, 2). Scrollt man nun z.B. nach links und rutscht Quasi auf die Map (1, 2), löscht man die komplette rechte Spalte, verschiebt die verbleibenden beiden jeweils eins nach rechts (natürlich nicht mit memcpy, sondern einfach nur ein paar Zeiger umbiegen) und läd links parallel eine neue Spalte von der Festplatte. Idealerweise könntest du das in einem Thread machen. Das Problem wird eben sein, rauszukriegen, wie groß man diese kleinen Maps am besten dimensioniert. Wenn du sie zu klein machst, musst du dauernd nachladen, wenn du sie zu groß machst, dauert das Laden ansich wahrscheinlich zu lang. Man könnte das ganze natürlich auch etwas feiner skalieren und sagt eben, man hält sich nicht 3x3 Maps im Speicher, sondern vielleicht 10x10 oder so... Müsste man alles mal ausprobieren, ich kann dir da keine Erfahrungswerte mitteilen, aber würde mich auch mal interessieren... Der Vorteil von dem System ist, dass man sich quasi unendlich große Maps erschaffen und die Ladevorgänge unbemerkt im Hintergrund erledigen kann.

Naja, wenn das jetzt nicht so ganz klar geworden ist, kann ich auch nochmal ein paar Skizzen machen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 13:14    Titel: Antworten mit Zitat

Wie ist bei dir sTile definiert? Vielleicht kann man da was optimieren.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 15:26    Titel: Antworten mit Zitat

Sicher, wenn du es auf 60MB bei 40.000 (200x200) Tiles bringst, dann umfasst ein Tile ja ~1,5KB. Das erscheint mir in der Tat auch recht viel, selbst wenn man da Platz im RAM für andern Kram wie Texturen mit berücksichtig. Ein Tile dürfte doch schlimmsten Falls kaum 50 Byte groß sein.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
manu
Super JLI'ler


Alter: 35
Anmeldedatum: 09.03.2006
Beiträge: 327
Wohnort: allgäu (DE)
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 18:22    Titel: Antworten mit Zitat

also die zahlenwerte waren nur grob überschlagen..

grundsätzlich speichere ich keine texturen in der map, sondern nur identifier anhand derer ich sie aus dem grafikverwaltungssystem geliefert bekomme.. beim zeichnen der map.

CPP:
struct sTile
{
   std::wstring image;
   std::wstring deco1;
   std::wstring deco2;
   std::wstring message;
   std::wstring savepointname;
   std::wstring TargetMap;
   int TargetX;
   int TargetY;
   int effekt;
   bool walkable;
   bool ladder;
   bool teleporter;
   bool savepoint;
};
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 18:55    Titel: Antworten mit Zitat

Die Strukur belegt zumindest bei mir genau 40 Byte (4 Byte Alignment), könnte man noch komprimieren, ist aber auch nicht weltbewegend gigantisch. Dazu kommen noch die eigentlichen Stringdaten (wobei wstring für IDs ungünstig gewählt ist), die aber vernachlässigbar gering ausfallen sollten.

Was hälst du denn noch so im Speicher? Hast du eventuell irgendwo mit new und delete geschlampt und erzeugst non-stop irgendwelche dicken Objekte?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 05.10.2007, 18:58    Titel: Antworten mit Zitat

Wäre es nicht effektiver da etwas mehr aufzuteilen je nach nutzen? ala

CPP:
class k_BaseTile : public k_Transformable
{
public:
  std::wstring image;
  bool walkable;

  virtual void* TransformTo(...);
};

class k_SaveTile: public k_BaseTile
{
public:
  std::wstring savepointname;

  virtual void* TransformTo(...);
}


CPP:
std::vector< std::vector<k_BaseTile*> > m_Tileset;


CPP:
k_BaseTile* lk_Base_ = m_Tileset[x][y];
k_SaveTile* lk_Save_ = transform_object<k_SaveTile>(lk_Base_);
if (lk_Save_ != NULL)
  ...


(näheres dazu im Tutorial SubForum)

Das allein würde schon einiges an Speicher sparen, dann solltest du dir evtl überlegen ob du nicht evtl auf einige der recht grossen std Sachen verzichten kannst.
_________________
"I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse."
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 05.10.2007, 19:16    Titel: Antworten mit Zitat

Naja, ich find die Lösung so oder so etwas eigenwillig, da ich die verschiedenen Aspekte wie grafische Darstellung, Kollisionserkennung, Spiellogik usw. sowieso eher trennen würde. Eine Klasse, eine Aufgabe. Vererbungshierarchien sind in dem Fall sicher auch nicht das Mittel der Wahl, da Vererbung im Prinzip performancetechnisch zwar nicht dramatisch kritisch, aber bei der Menge an Tiles und damit verbundener Operationen doch eventuell bedenklich ist. Außerdem macht das Aufteilen des Tileverhaltens in verschiedene Kindklassen spätestens dann Probleme, wenn man Tiles mit mehreren Eigenschaften braucht, da würde ich eine andere Lösung vorziehen, frag mich jetzt nicht welche, ich würde wahrscheinlich versuchen, dass irgendwie über Komposition hinzubiegen, hab mir da aber jetzt keine Gedanken gemacht.

Toll ist die Struktur in dieser Form sicher nicht, aber wenn abzusehen ist, dass man später niemals auf den Gedanken kommen wird zusätzliche Features usw. hinzuzufügen, sicher im Groben erstmal akzeptabel.

Aber...:
CPP:
struct sTile
{
    /* Sind das IDs? Die "kleineren" integralen Typen wie short integer und char sind da eventuell ausreichend...*/
    unsigned char image, deco1, deco2;
   
    /* Müssen diese beiden Dinge wirklich im Tile gespeichert werden? Kann man "savepointname" z.B. nicht in Abhängigkeit davon, ob an dem Tile überhaupt gespeichert werden kann irgendwo herholen? */
    std::wstring message, savepointname;
   
    /* Ist das eine ID? Wenn ja, s. o. */
    unsigned char TargetMap;
   
    /* Die Position des Tiles? Kann man doch aus der Map heraus errechnen! */
    //int TargetX;
    //int TargetY;

    /* 4x Bool muss nicht sein, 1 Bit pro Flag reicht. */
    bool walkable : 1,
         ladder : 1,
         teleporter : 1,
         savepoint : 1;
};


Macht bei mir 13 Byte, durch das 4-Byte-Alignment also 16.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
manu
Super JLI'ler


Alter: 35
Anmeldedatum: 09.03.2006
Beiträge: 327
Wohnort: allgäu (DE)
Medaillen: Keine

BeitragVerfasst am: 06.10.2007, 08:19    Titel: Antworten mit Zitat

ich werd jetzt schon bei den wstrings bleiben, sonst müsst ich grad alles umstellen.. auch die schnittstellen der anderen Klassen.

ich werd aber mal versuchen ein paar vorschläge bzgl. der verwaltung umzusetzten..

frage 2: ich hab eine speicherleckverursachende Funktion, weiss aber nicht das Problem zu lösen, die wird in jedem gameloopdurchlauf aufgerufen und frisst den speicher voller und voller.

CPP:
inline std::wstring IntToString(int figure)
{
   std::wstringstream sstr;
   sstr << figure;
   std::wstring temp = sstr.str();
   return temp;
}
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 07.10.2007, 21:34    Titel: Antworten mit Zitat

CPP:
template<typename T, typename char_type=wchar_t>
inline std::basic_string<char_type> stream_in_string(T const& data)
{
    std::basic_ostringstream ss;
    ss << data;
    return ss.str();
}
...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Hazel
JLI MVP
JLI MVP


Alter: 39
Anmeldedatum: 19.07.2002
Beiträge: 1761

Medaillen: Keine

BeitragVerfasst am: 08.10.2007, 11:54    Titel: Re: performanceprobleme: dynamisches array Antworten mit Zitat

manu hat Folgendes geschrieben:
Hi, ich feile am Mapeditor eines 2d spiels.. Bis jetzt arbeite ich so, dass die ganze Karte in einem Array liegt und dann vom Benutzer die entsprechenden Tiles ausgewählt und bearbeitet werden können.

Eine Karte ist beliebig groß und die Größe dynamisch veränderbar, die einzige Grenze ist jetzt halt der Ram..

scroll ich im editor weiter und weiter.. hab ich z.B. bei einer Kartengröße von 800x800 ca.. 250MB ramauslastung.. ich mein die Karten werden wohl nie so groß. aber auch 60MB bei 200x200 sind schon irgendwie viel.


Jetzt wollt ich mal fragen wie ihr des angehen würdet.. also wie ich die Karte performanter verwalten kann.. Sollte ich immer nur einen kleinen Bereich in einem nicht dynamischen array geladen haben und den rest beim wegscrollen usw. gleich in die Mapdatei schreiben und bei weidergebrauch wieder auslesen.. Das wäre schon machbar, ich müsste halt einiges umstellen. Würde das was bringen?

mein Maparray sieht intern übrigens so aus:

CPP:
std::vector< std::vector<sTile> > m_Tileset;


Ist zwar schon älter aber trotzdem mal ein effizienter Lösungsansatz von mir:

Im Editor die Tiles in einer dynamischen Liste aufbewahren. So kannst du auch falsch gesetzte Tiles leicht entfernen oder sogar verschieben. Für das Rendering hashst du die Tiles in ein Grid. Das ist performant, da dies in konstanter Laufzeit durchführtbar ist, z.b. mittels folgender Hashfunktion:

f(x) = (ypos / cellsize) * gridwidth + (xpos / cellsize)

Wenn du Renderst schaust du welche Grid-Zellen sichtbar sind und malst halt nur die Tiles, die sich in den sichtbaren Grid-Behältern befinden.

Zum Grid an sich: Das Grid kannst du zum Beispiel als statisches Array von verketteten Listen realisieren. Jede Grid-Zelle ist also ebenfalls eine verkettete Liste in die du Zeiger auf deine Tiles/Objekte schieben kannst. Wenn du etwas am Level änderst dann löschst du einfach alle Grid-Zellen und hashst die Objekte neu(lineare Laufzeit).

Die Überprüfung, welche Gridzellen sichtbar sind und welche nicht ist ebenfalls in konstanter Zeit möglich:

xcell = camerax / cellsize
ycell = cameray / cellsize
first_visible_cell = xcell + ycell * gridwidth

Gutes gelingen.

[Nachtrag]

Achja: Wenn du dein Level als m * n Array speichern willst dann gehst du einfach durch deine Hauptliste aller Tiles und notierst die die höchste und die niedrigste Position. Die Differenz davon ist die Array-Größe die du benötigst. Den Speicher reservieren, durch die Liste gehen und die Tiles einzleln in das Array schreiben. Presto...
_________________
*click* Dabuu!?
Twitter: http://twitter.com/Ollie_R
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
fast hawk
Senior JLI'ler



Anmeldedatum: 15.07.2005
Beiträge: 237
Wohnort: Freiburg
Medaillen: Keine

BeitragVerfasst am: 09.10.2007, 18:53    Titel: Antworten mit Zitat

Hi
Ich würde dir empfehlen nicht für jedes Tile in der Map eine eigene Klasse anzulegen sonder eine eigene list oder ein vector..Wo du dann jewals deine Tiles angibt weil es unterscheidet sich nicht jedes Tile in der Map und in dem "MapTile" ist dann nurnoch die für jedes tile individuellen Variablen und ein Zeiger auf das Tile Element in der list(bzw. vecotr).

CPP:
struct sTile
{
   std::wstring image;
   std::wstring deco1;
   std::wstring deco2;
   std::wstring message;
   std::wstring savepointname;
   std::wstring TargetMap;
   int TargetX;
   int TargetY;
   int effekt;
   bool walkable;
   bool ladder;
   bool teleporter;
   bool savepoint;
};

std::vector<sTile> m_Tileset;

struct sMapTile //kein ahnung wie mans nenen soll^^
{
   sTile* psTile;
};

std::vector< std::vector<sMapTile> > m_MapTileset;



oder in dem Fall auch:

CPP:
/* Weglassen!!
struct sMapTile //kein ahnung wie mans nenen soll^^
{
   sTile* psTile;
};
*/


std::vector< std::vector<sTile*> > m_MapTileset;



Da sparst du schon bei 40 identischen Tiles, was du sicher hinbekommst,
40*40=1600 | 40+4*40 = 200 das wären 1400 Bytes(vorausgesetzt du hast keine individuellen variablen in den "MapTile"
_________________
Jetziges Projekt: The Ring War
Status: 40%
-----------------------------------
Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.
--
Lucius Annaeus Seneca (4)
röm. Philosoph, Dramatiker und Staatsmann
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
manu
Super JLI'ler


Alter: 35
Anmeldedatum: 09.03.2006
Beiträge: 327
Wohnort: allgäu (DE)
Medaillen: Keine

BeitragVerfasst am: 11.10.2007, 13:43    Titel: Re: performanceprobleme: dynamisches array Antworten mit Zitat

Hey, danke für die vielen Antworten, wenn ich mal wieder en ruhiges Wochenende hab werd ich mal versuchen das ganze System entsprechend
umzubauen.


Deviloper hat Folgendes geschrieben:
CPP:
template<typename T, typename char_type=wchar_t>
inline std::basic_string<char_type> stream_in_string(T const& data)
{
    std::basic_ostringstream ss;
    ss << data;
    return ss.str();
}
...


danke. du hast mich auf den richtigen Weg geleitet..
Aber deine Lösung war nicht so ganz korrekt, zumindest hat sie bei mir nur für einige Compileerrors gesorgt.

so hab ichs jetzt und es geht wunderprächtig.

CPP:
template<typename T, typename char_type>
inline std::basic_string<char_type> stream_in_string(T const& data)
{
    std::basic_ostringstream<char_type> ss;
    ss << data;
    return ss.str();
}


unteranderem darf man dem char_type net schon standardmäßig einen wert zuweisen und der basic_ostringstream erwartet noch den char_type.


Hazel hat Folgendes geschrieben:

f(x) = (ypos / cellsize) * gridwidth + (xpos / cellsize)


sollte da net irgendwo ein x im funktionsterm sein. rein theoretisch?
(da: Funktion f in Abhängikeit von x)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 11.10.2007, 17:59    Titel: Antworten mit Zitat

Ich glaube Hazel meinte nicht f(x) sondern f(xpos,ypos).
_________________
"I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse."
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 12.10.2007, 21:33    Titel: Antworten mit Zitat

@manu: Ja stimmt std::basic_ostringstream muss spezifiziert werden ... sorry ... ich tipps nur hier ins Eingabe Feld ... da kann schon mal was schief gehen Razz Allerdings kannst du schon einen Default-Type für Templates angeben ... aber nur bei class/struct ... ebenfalls sorry ... war wohl etwas durchn wind Razz
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum