mmofacts.com

Nebel des Krieges

gepostet vor 16 Jahre, 4 Monate von cherry

Hi,

ich will meine Gedanken zur Planung und Umsetzung vom Nebel des Krieges in einem Weltraum 4X Spiel aufschreiben und zur Diskussion stellen. Das Spiel setzt folgende Gegebenheiten voraus:

  1. es gibt eine 2D Karte
  2. auf der 2D Karte befinden sich Sternensysteme (repraesentiert durch Sterne)
  3. auf der 2D Karte befinden sich Schiffsflotten

Es gibt folgende Regeln zur Berechnung des Nebel des Krieges:

  1. Scanradius der Sternensysteme: gegnerische Schiffe im Scanradius der Sternensysteme werden fuer den Spieler auf der Karte sichtbar; unerforschte oder gegnerische Sternensysteme im Scanradius der Sternensysteme werden fuer den Spieler sichtbar wobei sichtbar bedeutet, dass Details ueber die Sternensysteme erfahren werden koennen - sichtbar sind sie immer - ausserhalb des Scanradius tauchen sie jedoch als "unerforscht" auf
  2. Scanradius der Schiffe: gegnerische Schiffe im Scanradius der eigenen Schiffe werden sichtbar
  3. Schiffe im Orbit unerforschter Sternensysteme: Details ueber die Sternensysteme in denen sich eigene Schiffe befinden werden sichtbar

So weit so gut. Ich denke nun seit einigen Tagen ueber die Implementierung so eines Systems nach. Es faellt mir schwer eine effiziente Loesung dafuer zu finden. Folgende Probleme habe ich mir ueberlegt:

  1. Ich muss die Sichtbarkeit auf der Serverseite berechnen - wenn ich dem Client alles schicke und ihn rechnen lasse kann der Spieler die Daten auslesen und cheaten. Folge: Je mehr Spieler desto mehr Berechnungen.
  2. Ein Spieler kann in Runde X das Sternensystem Orion sehen weil es im Scanradius eines eigenen Planeten liegt. In Runde X 1 wird das Sternensystem das Orion scant erobert. Der Spieler hat keine aktuellen Detailinformationen mehr ueber Orion. Allerdings macht es keinen Sinn zu sagen Orion ist unerforscht. Der Spieler wusste ja schon, dass es dort einen Planeten der Klasse M gibt der sehr viele Rohstoffe hat. Also muss ich quasi den "letzten Stand" immer abspeichern. Folge: Je mehr Spieler desto mehr Speicherplatz.

Man kann jetzt argumentieren, dass das ja ganz normal ist, dass man mehr Speicher und mehr Rechenkapazitaet braucht je mehr Spieler man hat. Ich finde den Gedanken speziell in diesem Fall trotzdem unangenehm und frage mich ob es bessere Moeglichkeiten gibt - entweder das Konzept zu vereinfachen oder eine gute Idee zur Implementierung.

Fuer die Berechnung des Nebel des Krieges selbst oder Besser der Sichtbarkeit der einzelnen Spielelemente kann man sich glaub ich eine relativ effizienten Algorithmus ueberlegen, so dass man nicht die Distanz jedes Planeten zu jedem Planeten und jedes Schiffs zu jedem Schiff und jedes Planeten zu jedem Schiff berechnen muss.

Ich denke das Hauptproblem ist im Grunde die Tatsache, dass der Client es nicht berechnen soll. Der Client waere logischerweise Ideal dafuer, da es dem Server dann relativ egal ist ob 100 oder 1000 Spieler den Nebel des Kriegs berechnen.

Wuerde mich ueber Gedanken, Erfahrungen und Ideen zum Thema freuen!

cherry

gepostet vor 16 Jahre, 4 Monate von n26

Ich finde deine Punkte der theoretischen Umsetzung so passend. Bloss das ich bei mir diese Art des Merkens, wenn ein Feld oder was auch immer mal bekannt war vorerst weggelassen habe.

Ich hatte mit den ersten Alpha Runden meines Spiels starke Probleme mit der Performance und ein Punkt wo ich u.a. etwas geändert hatte, war die Umsetzung des FoWs (Fog of Wars). Ich hatte Anfangs die Sichtbarkeit aller Felder mit einmal ausgelesen. Dabei hatte ich Anfangs nur die sichtbaren Felder einbezogen, was logischer Weise zu Fehlern führte. Z.B. hat ein Radar bei mir einen Sichtradius von 10 Feldern und wenn ich nun oben links ein Feld habe, was gerade das 10. Feld ist, wurde dies dadurch nicht sichtbar gemacht, weil ich das ganze beim Auslesen zu stark eingegrenzt hatte.

Darauf hin hatte ich provisorisch alle sichtbaren Felder ausgelesen, was aber eben sehr viel Performance gefressen hatte.

Aktuell habe ich den Fog of War wiefolgt umgesetzt:

Bei jedem Feld wird einzeln geprüft, ob es sichtbar ist. Dafür gehe ich folgende Punkte durch, und sobald einer true ist, werden die anderen übersprungen. Ist kein Punkt davon true, ist das Feld nicht sichtbar:

  • Wenn das aktuelle einem selbst oder einem Verbündeten gehört (eine Liste der Verbündeten wird vorher aus der Datenbank gelesen)
  • Wenn ein eigenes Feld oder eins von einem Verbündeten 1 Feld entfernt ist
  • Wenn das Feld in Reichweite eines Gebäudes mit erhöhtem Sichtradius ist (z.B. Radar)
  • Wenn das Feld in Sichtradius einer eigenen oder verbündeten Armee ist

Dabei steht hinter jedem Punkt ein Query. Der sieht jeweils ähnlich dem aus:

PHP:

$this->DatabaseHandler->query( '
SELECT
...
FROM gebaeude
JOIN daten_bauplaene ON( bauplan_Funktion = "Radar" AND gebaeude_Bauplan = bauplan_Id )
WHERE
( gebaeude_Besitzer = '.implode( ' OR gebaeude_Besitzer = ', $participants ).' ) AND
( ABS( gebaeude_X - '.$X.' ) ABS( gebaeude_Y - '.$Y.' ) ) <= bauplan_Sichtradius AND
gebaeude_Aktiv = 1 );
?>

Beim laden der Karte incl. Rest des Interfaces (außer Minikarte, die wird nur aller 10min mitgezeichnet) braucht das ganze so ca. 0.7 Sekunden.

Bei der Minimap nehme ich aber einen anderen Weg. Ich habe ein Template für die Minimap, wie sie aussehen würde, wenn nichts sichtbar wäre und über das zeichne ich die Felder.

Dabei hole ich mir zuerst alle Felder, welche besetzt sind und welche an ein besetztes angrenzen.

PHP:

$this->DatabaseHandler->query( '
SELECT
a.feld_X,
a.feld_Y,
a.feld_Typ,
a.feld_Besitzer
FROM mkarte AS a
INNER JOIN mkarte AS b ON (
( ABS( a.feld_X - b.feld_X ) ABS( a.feld_Y - b.feld_Y ) ) = 1 AND
( b.feld_Besitzer = '.implode( ' OR b.feld_Besitzer = ', $participants ).' ) )
WHERE
a.feld_Besitzer IS NULL OR
( a.feld_Besitzer <> '.implode( ' AND a.feld_Besitzer <> ', $participants ).' )' );

(mkarte ist übrigens ein live Klon der original Karte, bloss das diese Datenbank im Ram gehalten wird)

Und dann noch die Felder, welche durch Armeen und Gebäude sichtbar gemacht werden.
Queries sehen ca so aus:

PHP:

$this->DatabaseHandler->query( '
SELECT
gebaeude_X,
gebaeude_Y,
bauplan_Erweitert
FROM gebaeude
JOIN daten_bauplaene ON gebaeude_Bauplan = bauplan_Id
WHERE
( gebaeude_Besitzer = '.implode( ' OR gebaeude_Besitzer = ', $participants ).' ) AND
bauplan_Funktion = "Radar" AND
gebaeude_Aktiv = 1' );

Der einzige Nachteil ist hier, dass ich manche Felder doppelt zeichne. Aber eine bessere und "einigermasen leicht" umsetzbare Variante ist mir hier noch nicht eingefallen.

Mal schauen vllt bau ich meine Varianten im Verlaufe des Threads nochmal von Grund auf um :)

gepostet vor 16 Jahre, 3 Monate von Drezil

Naja .. ich frage alles in 1 Query ab. Da kann die Datenbank optimieren, jedes Feld wird max 1x geprüft und durch indizes und bereichs-einschränkungen hab ich so nur noch eine gerine anzahl an potentiellen vergleichen ;)

Mal ein Beispiel, wie ich das umgesetzt hab - ist mittlerweile schon optimiert und fragt in echtzeit ab, welches von ca. 30.000 Objekten sich gerade in reichweite eines planeten (flotten haben das atm nicht, die künnte man auch noch hinzufügen - am besten ohne union ;) ) befindet.

PHP:

static function getObjectsRectangle($uid,$x_from,$y_from,$x_to,$y_to) {
/*
* where
* (sundiff² < range² 400 and (sundiff² < range² -400) or [exact calc])) or stationrange and [...]
*/
$pdo =& api::getPDO();
$objekte = array();
$qry = $pdo->query(
'select DISTINCT o.oid, ' .
'o.x,' .
'o.y,' .
'obr.name_'.$_SESSION['lang'].' as typ,' .
'o.met, ' .
'o.sil, ' .
'o.verb, ' .
'o.krist, ' .
'o.kristverb, ' .
'o.energ, ' .
'o.zit' .
' from ' .
'objekte o join objektreferenz obr on (o.otyp = obr.otyp), ' .
'gebaeude g join gebaeudereferenz gr on (g.gid = gr.gid) left outer join stationen st on (st.stationid=g.stationid and st.uid='.$uid.') left outer join planeten p on (g.pid=p.pid and p.uid='.$uid.') left outer join sonnen s on (s.sid=p.sid)' .
' where ' .
'('.
'(pow(o.x-s.x,2) pow(o.y-s.y,2) ' .
'< case g.gid ' .
'when 50 then pow(500 - 500*pow(0.75,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 51 then pow(1000 - 1000*pow(0.8,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 52 then pow(750 - 750*pow(0.90,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 53 then pow(1250 - 1250*pow(0.95,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'ELSE 0 end 400 AND ' .
'(pow(o.x-s.x,2) pow(o.y-s.y,2) ' .
'< case g.gid ' .
'when 50 then pow(500 - 500*pow(0.75,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 51 then pow(1000 - 1000*pow(0.8,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 52 then pow(750 - 750*pow(0.90,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 53 then pow(1250 - 1250*pow(0.95,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'ELSE 0 end - 400 ' .
'or ' .
'pow(o.x-s.x-(p.pnr*cos(unix_timestamp()*p.bahnfaktor/(p.pnr*13750.987083139757010431557155385))),2) pow(o.y-s.y-(p.pnr*sin(unix_timestamp()*p.bahnfaktor/(p.pnr*13750.987083139757010431557155385))),2) ' .
'< case g.gid ' .
'when 50 then pow(500 - 500*pow(0.75,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 51 then pow(1000 - 1000*pow(0.8,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 52 then pow(750 - 750*pow(0.90,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 53 then pow(1250 - 1250*pow(0.95,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'ELSE 0 end ))' .
'or pow(o.x-st.x,2) pow(o.y-st.y,2) ' .
'< case g.gid ' .
'when 56 then pow(500 - 500*pow(0.75,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 57 then pow(1000 - 1000*pow(0.8,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 58 then pow(1500 - 1500*pow(0.90,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) ' .
'when 59 then pow(2000 - 2000*pow(0.85,g.stufe),2)*g.prodfaktor*g.arbeiter/(gr.arbeiter*g.stufe) '.
'ELSE 0 end) AND ' .
'g.gid in (50,51,52,53,56,57,58,59) AND ' .
'g.uid = '.$uid.' AND ' .
'o.x between '.($x_from).' and '.($x_to).' AND ' .
'o.y between '.($y_from).' and '.($y_to));
while ($row = $qry->fetch(PDO::FETCH_ASSOC)) {
array_push($objekte,$row);
}
$qry->closeCursor();
return $objekte;
}

 Die Berechnung sieht etwas eklig aus, da während der qry die positionen der Planeten erst noch errechnet werden (sonnenposition radius*umlaufgeschwindigkeit).

Vom Prinzip her baut das ding 2 temporäre Tabellen. Zum einen die Objekte-Tabelle eingeschränkt auf die koordinaten (xfrom, xto, yfrom, yto). Zum anderen eine Tabelle aller Dinge die sehen können mit prinzipiell folgenden angaben: xpos, ypos, reichweite.

Und dann kommt nur noch nen bissl pythagoras im where und das wars. Um das ganze zu optimieren (insbesondere bei den planeten, weil ich da sin/cos-berechnungen drin hab, die teuer sind) werden bei den bewegenden planeten noch 2 zusätzliche bereichsprüfungen fällig. Zum einen das "definitiv drin", sprich wenn der planet selbst in ungünstigster stellung noch das objekt sehen kann (unabhängig, wie er grad steht; kann man mit 2 pyth. abschätzen) und zum anderen das "definitiv draußen", halt wenn man ihn nicht sehen kann.

Durch die anordnung (CheckDraussen AND (CheckDrin OR RechneGenau)) wird das where an der frühestmöglichen stelle abgewürgt. Ist CheckDraussen false, ist der ausdruck false und wird nicht weiter ausgewertet; ist es true und CheckDrin true ist der ausdruck auch true und ich hab die sin/cos-krams nicht. Und wenn alles fehlschägt (also selten), dann rechnet er genau.

Das ganze ding läuft mit 100 einträgen in der theoretischen "sichbarkeitstabelle" (die mit x,y,radius) und 30k objekten in der "zu überprüfen"-tabelle ganz zackig durch... insbesondere, wenn man die gelesenen Tabellen im Ram hält, weil sie ohnehin fast nur read-only sind.

Das sind meine erfahrungen dazu.. und ich weiss - es ist übertrieben alles sooo haarklein live zu berechnen .. mit caching und allem drum und dran könnte man tonnen von performance sparen ... ;)

 Für andere einsatzzwecke gibt es sicher auch noch andere herangehensweisen.

Man kann z.b. für jeden Spielen eine "hat er schon gesehen"-Map erzeugen, die auf Rechteckrasterung basiert und sich in einem Quadtree sowohl im Ram, wie auch serialisiert auf der Platte halten kann. In der DB würd ich das nicht ablegen, da die Daten ohnehin meist statisch sind (bzw. man die Momente in denen sich was z.b. durch einen gebbau ändert abfangen kann und dann "manuell" den Eintrag updatet) und keine hohen anforderungen an durchsuchbarkeit etc haben.

Edit: BTW: Die Query losgelassen auf alle 30k Objekte (und nicht nur die Sektoren, die angefragt wurden) dauert um die 800ms. Da kann man mit bereichssuchen auch noch einschränken, ist für meinen Fall aber nicht notwendig, da ich immer nur ein paar sektoren per ajax nachliefer ;)

Ein konkreter Ausschnitt (Sektoren sind bei mir 500x500 einheiten gross, können aber aneinander gehängt werden und so größere "kästen" bilden) von 2000x1500 Einheiten dauert nur um die 50ms. Mein Spieluniversum hat lediglich die Ausdehnung von 10k x 10k Einheiten, also sind noch größere anfragen eher selten.

Wie sich die performance aber weiter auswirkt (wenn man mehr als 10-20 planeten/stationen hat oder wenn ich die Flotten etc. noch mit in dieselbe qry nehme), hab ich noch nicht getestet.

gepostet vor 16 Jahre, 3 Monate von n26

Ich hatte bei mir auch schon testweise alles in einem Query. Jedoch war da die Ausführungszeit extrem hoch. Nutzt du MySQL od. eine andere Datenbank (@Drezil)?

gepostet vor 16 Jahre, 3 Monate von Kallisti

Ich wuerde einfach fuer alle Objekte mit Sichtradius ein Quadrat mit Schiffen und Planeten aus der DB auslesen, allso bei x/y 50/50 mit 25 Einheiten Sicht waere das dann von 25 bis 75 x und y, was mit indizierten x/y Spalten recht flott sein sollte.

Bei der Ergebnismenge wuerde ich dann im eigentlichen Programmcode per Pythagoras abgleichen ob die Entfernung zwischen gefundenem Objekt und Objekt mit Sichtradius < 25 ist, um den Kreisradius abzubilden. Kann man auch direkt in der Datenbank machen, aber Business Logic dermassen in die DB auszulagern ist so eine Sache und kann an einigen Stellen zu Problemen mit Indizes fuehren.

Denke das ist die bei weitem einfachste, am besten zu wartende, am besten zu erweiternde (z.B. um Lautstaerkeerkennung, dynamische Reichweiten, usw.) und performanteste Loesung.

Der "Pseudo" fog of war, der bereits verlorene Planeten weiterhin anzeigt, laesst sich nun einmal nicht anders loesen, als wenn du das speicherst.

Allerdings brauchst du da doch nur eine ganz simple Tabelle, die die Relation user <> zur Haelfte sichtbare Planeten speichert. Wenn der User einen Planeten einnimmt, kannst du die entsprechenden Eintraege ja wieder entfernen. Die Datenmenge duerfte dir wirklich nicht weh tun.

userid | planetid....

gepostet vor 16 Jahre, 3 Monate von Drezil

Ich nutz postgres.

Die Ausführungszeit häng extrem von der Schreibweise der Query ab. Weil wenn der Query-Planner da was verhaut, dann geht das ganz schnell in die zeit. Oder wenn ein Index nicht genutzt werden kann oder nicht existiert etc.

Ich logge bei mir alle querys mit > 500 ms mit und nehme mir die dann vor.

Die qry von oben schaut im konkreten beispiel so aus: http://mission-unknown.de/stuff/query-plan.png

Dieselbe Qry auf dem Server: http://mission-unknown.de/stuff/query-plan2.png

(Die Zeiten unten rechts geben an, wann das Ergebnis vollständig vorlag. Da man aber meist unbuffered liest, kann man die ersten Zeilen schon nach 60ms verarbeiten)

Die Unterschiede kommen dadurch zu stande, dass es auf dem Server viel mehr gebäude gibt (gibt ja auch mehr spieler), viel mehr bewohnte planeten etc. und er da nen anderen weg nimmt um die mit den anderen tabellen zu verknüpfen.

Optimierungen sind simpel: Man muss die Zahl der Zeilen so früh wie möglich reduzieren. Da bei mir die Gebäude "sehen", hab ich in der Gebäudetabelle die user-id redundant gespeichert (redundant, da ich die auch über den besitzer der Planeten etc. ermitteln kann) und kann darüber schonmal 95% der Zeilen reduzieren. Der rest wird dann noch auf die genaue id geprüft (minen und forschungsgebs etc. können ja nicht sehen). Dann noch nen paar verknüpfungen über pks/fks mit der referenz (weil ich da daten zum rechen her brauche - könnte man auch noch cachen)  und den planeten, sonnen etc.

Wie man sieht, kosten diese verknüpfungen quasi nichts (Hash Join und Merge Join sind fix; für nen Merge join muss die Ausgangsmenge aber sortiert sein, was durch die reduzierung der Zeilen in erster linie auch ganz fix geht).

Was auch noch zur minimierung beiträgt ist schon innerhalb der joins (also in dem on-clause) konstanten anzugeben (konkret hier: die uid bei den planeten). Dann greift er sich nämlich IMMER den index und startet gleich mit einer stark reduzierten Tabelle (10 statt 3000 Einträgen) den Join.

Die eigentliche Zeit geht da drauf, wo die beiden dicken Pfeile in einem langsamen nested loop zusammenkommen. Ein Nested Loop ist folgendes:

Code:

for (i=0;i	for (j=0;j
if (cond)
put_in_result()
}
}

 Und wie man sieht, mit wachsender Datenmenge auf einer der beiden seiten vervielfacht sich die ausführungszeit.

Um da zu optimieren sollte man die cond so effektiv wie möglich schreiben. Am besten sind AND-only odor OR-only-konstrukte. Beispiel:

Code:

1. foo and bar and baz
2. foo or bar or baz

 da das ding serialisiert abgearbeitet wird kann man im ersten fall schon sagen: ist eins false, ist alles false. Analog beim zweiten Fall: ist eins true ist alles true. Da braucht man sich im idealfall nur die erste Bedingung anschauen und kann dann gleich abbrechen. Das ganze hab ich oben schon versucht zu erläutern - wenn man mal genau hinsieht besteht meine Bedingung immer nur aus ANDs.

Was auch noch viel hilft: Ausprobieren. EXPLAIN nutzen. Dieselbe Query kann entweder 300sec dauern (wenn man z.b. ungünstig nen Nested-Loop-Join hat, der 2 dicke Tabellen verbindet und danach erst aussortiert) oder in 0.x durchrennen (wenn man statt 300k einträge auf 20k gejoined nur noch 1.5k auf 20k indiziert joined (hash join)).

Irgendwo wird es auch für mysql ein tool geben, dass den aufbau einer qry so visualisiert - dann kann man gleich sehen, wo die änderungen am effektivsten sind.

gepostet vor 16 Jahre, 3 Monate von cherry

Vielen Dank fuer die Meinungen, Ratschlaege und Beispiele. Ich interpretiere es mal als: Keine Angst vor komplizierten Abfragen bzw. etwas komplexeren Algorithmen. Manchmal fuehrt kein Weg drum herum. Ich habe lange keine solchen SQL queries gesehen Drezil, danke fuers posten. Was ich auch ueberhaupt nicht kannte ist dieser PostgreSQL Query Planer - der sieht ja sehr hilfreich aus mit den huebschen Icons unten.

Die Pseudo Fog of War Sache laesst sich wohl tatsaechlich nicht anders loesen. Ich muss die Sachen zwischenspeichern. Wieviel ich zwischenspeichern muss haengt wohl von meinem Design ab. Im Prinzip hast Du recht Kallisti, es ist nur eine Tabelle die die Relation User <> Planeten abbildet. Wenn es aber etwas komplexer wird ist es nicht mehr so einfach. Ein Gegner koennte z.B. den einst gesehenen Planeten terraformen - dann weiss ich als Spieler nicht den aktuellsten Zustand des Planeten sondern einen Alten welchen ich dann speichern muesste.

Die Frage was man wo berechnet ist auch interessant. Laesst man es von der Datenbank machen holt man die Daten und berechnet es selber. Frage mich obs dazu Benchmarks gibt.

Die Methode von n26 das ganze in mehrere Abfragen aufzusplitten ist meiner Meinung nach intuitiver, leichter zu handhabend und zu pflegen. Welche Methode schneller ist kann man wohl durch draufschauen nicht sagen. Muss man ausprobieren!

Einen Vorteil sehe ich noch darin zumindest einen Teil der Berechnung datenbankseitig durchzufuehren. Man kriegt einen gewissen Grad an skalierbarkeit - wenn es eine Maschine nicht mehr packt kann man den DB Server auf einen zweiten Rechner auslagern und damit die Rechenlast verteilen.

gepostet vor 16 Jahre, 3 Monate von abuzeus

Soso, ein 4X-Game, wo es einen Planeten mit Namen Orion gibt.

Ich hab jetzt die Datenbankabfragen nicht so genau durchgelesen, weil ich mich damit eh nicht so auskenne. Wollte nur einwerfen, dass du die Strukturierung deiner Daten eventuell davon abhängen lassen solltest, wie viele unterschiedliche Zustände so ein Planet annehmen kann. Wenn es sowieso nur wenige unterschiedliche Zustände gibt (Planet rot, blau, grün, gelb) und die sich eh selten ändern, kannst du ja für jeden Spieler einfach seinen aktuellen Kenntnisstand abspeichern. Bei vielen Systemen und Spielern kann das aber problematisch werden, wenn die Zustände des Planeten (das ganze gilt übrigens genauso für jede beliebige Anwendung des FoW) über eine sehr große Bandbreite verfügen.

Ein anderer Ansatz wäre dann IMHO, für jeden Planeten eine "Versionsgeschichte" anzulegen, also zu speichern, wie er wann ausgesehen hat (nur die Änderungen, versteht sich). Es würde dann reichen, für jeden Spieler nur abzuspeichern, wann er diesen Planeten das letzte Mal gesehen hat. Kannst dir ja merken, wer den Planeten als letzter gesehen hat, und nicht mehr benötigten Zustände löschen.

Wie man das jetzt in eine Datenbank umsetzt, bleibt dem Leser als einfache Übung überlassen.

gepostet vor 16 Jahre, 3 Monate von cherry

Soso, ein 4X-Game, wo es einen Planeten mit Namen Orion gibt.

Was dagegen? Hier ist der Karten-Prototyp http://soa-world.de/dev/release3/game/map2.html

Ich hab jetzt die Datenbankabfragen nicht so genau durchgelesen, weil ich mich damit eh nicht so auskenne. Wollte nur einwerfen, dass du die Strukturierung deiner Daten eventuell davon abhängen lassen solltest, wie viele unterschiedliche Zustände so ein Planet annehmen kann. Wenn es sowieso nur wenige unterschiedliche Zustände gibt (Planet rot, blau, grün, gelb) und die sich eh selten ändern, kannst du ja für jeden Spieler einfach seinen aktuellen Kenntnisstand abspeichern. Bei vielen Systemen und Spielern kann das aber problematisch werden, wenn die Zustände des Planeten (das ganze gilt übrigens genauso für jede beliebige Anwendung des FoW) über eine sehr große Bandbreite verfügen.

Ich sehe sowohl die Zustaende des Planeten als auch die Anzahl der Spieler als Problem. Irgendwann skaliert es einfach nicht mehr.

Ein anderer Ansatz wäre dann IMHO, für jeden Planeten eine "Versionsgeschichte" anzulegen, also zu speichern, wie er wann ausgesehen hat (nur die Änderungen, versteht sich). Es würde dann reichen, für jeden Spieler nur abzuspeichern, wann er diesen Planeten das letzte Mal gesehen hat. Kannst dir ja merken, wer den Planeten als letzter gesehen hat, und nicht mehr benötigten Zustände löschen.

Das habe ich mir auch ueberlegt. Ich faende es gut, wenn ich noch einen zweiten Grund haette eine "Versionsgeschichte" mitzuschreiben. Aber da es abgesehen vom FOW sehr uninteressant ist wie ein Planet vor 10 Turns aussah habe ich den Gedanken verworfen.

gepostet vor 16 Jahre, 3 Monate von MrMaxx

@cherry ... ich weiss es ist nur ein Prototyp, aber du renderst da sehr sehr sehr viele divs, nur um sie dann wieder durch ein kleines "Overlay"-Div mit overflow:hidden zu verdecken. Auf meinem Laptop, der nur 1GHz und 512MB Ram hat wurde auf einmal alles sehr sehr laangsam.

gepostet vor 16 Jahre, 3 Monate von cherry

Original von MrMaxx

@cherry ... ich weiss es ist nur ein Prototyp, aber du renderst da sehr sehr sehr viele divs, nur um sie dann wieder durch ein kleines "Overlay"-Div mit overflow:hidden zu verdecken. Auf meinem Laptop, der nur 1GHz und 512MB Ram hat wurde auf einmal alles sehr sehr laangsam.

Jo, kein Wunder. Sind 400 divs. In meiner dev Version wird nun ein grosses gif erzeugt - das sollte es etwas verbessern. Gibts leider noch nicht zu sehen. Aber back to topic

Auf diese Diskussion antworten