Verständnisfrage ID-System

  • Allgemein

Es gibt 39 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.

    Verständnisfrage ID-System

    Hallo Leute.

    Ich hätte mal eine Frage, die jetzt nicht direkt was mit einer bestimmten Programmiersprache zu tun hat, sondern eher mit dem Design einer Programmstruktur in OOP.
    Wenn ich ein Spiel programmiere, dann möchte ich das ja am liebsten so machen, dass es leicht um neue Elemente (Spielinhalte) erweiterbar ist (z.B. neue Einheiten, Rohstoffe etc.). Nach dem Prinzip von OOP lege ich mir also dafür jeweils Basisklassen an (z.B. Entity für alle Gegenstände im Spiel), von der ich dann alle Dinge ableite. Nun ist es ja aber so, dass ich auch dynamisch auf diese Objekte zugreifen können will, ohne sie alle in einer Steuerungs-Klasse einzeln einzutragen. Das betrifft das Speichern, das Laden, aber auch das dynamisch Erstellen von Instanzen. Hier scheinen alle Spiele, die ich kenne, auf ein ID-System zurückzugreifen. Im Prinzip habe ich sowas auch schon umgesetzt, und zwar indem ich alle verfügbaren Typen mit Reflection ausgelesen habe und sie mitsamt einer ID in ein Dictionary gepackt habe. Wenn dann z.B. durch einen Spielstand eine Instanz der Klasse erstellt werden musst, habe ich dafür Activator.CreateInstance() (also wieder Reflection) verwendet. Nun ist es ja aber so, dass ich Reflection eigentlich immer mit einem grundlegenden Designfehler verbinde, denn dadurch greift man auf Dinge zu, auf die man sonst keinen Zugriff hätte. Außerdem steht Reflection ja sowieso nur aufgrund des .Net-Frameworks zur Verfügung, in C++ o.ä. gibt es das nicht. Es muss also irgendwie anders und besser gehen, allerdings weiß ich nicht, wie. Kennt sich da jemand gut aus?
    Dafür kannst du das Minecraft Coder Package verwenden. Da Minecraft aber normalerweise keine Mods laden kann, musst du zuerst den Minecraft Modloader installieren, bevor du es dekompilierst.
    Ich kann mir nicht anners vorstellen, als dass ein professionelles Spiel immer auf einem relationalen Datenmodell aufbaut. Und wenn du sagst, dass dir da immer die IDs auffallen, dann spricht das sehr für meine Vermutung.
    Kann sehr gut sein, dass dabei eine annere Technologie verwendet wird als olle Dataset, aber in einem Spiel existieren eben m:n - Beziehungen, und daher muß halt relational modelliert werden.
    Du könntest ein auf Komponenten basierendes Game-Object-System nutzen und dir eine Serialisierung/Deserielisierung in z.B. XML schreiben. Also dass das dann am Ende so aussehen könnte:

    XML-Quellcode

    1. <Entity name="DiamondFarmer">
    2. <Image source="buildings/diamondfarmer.png" />
    3. <Components>
    4. <FarmerComponent Resource="Diamond" AmountPerMinute="10" />
    5. <LifepointsComponent Amount="100" />
    6. <!-- [...] -->
    7. </Components>
    8. </Entity>


    Nur so eine Idee.
    @Trudi
    Naja, aber dann wäre Vererbung nicht mehr möglich, ich hätte nur noch eine Klasse Entity, die die Funktionen für alle Spielobjekte übernimmt, je nach dem was in der XML-Date steht. Ich würde somit eigentlich nichts mehr wirklich im Programm machen, sondern alles nur noch in externen Dateien.
    Hmm, ok. Ich habe die Frage falsch verstanden.
    Wie Minecraft das macht, das ist schon gut, würde ich mir definitiv angucken :)

    Wenn ich das richtig im Kopf habe ist das ungefähr so wenn man ein Plugin programmiert (dürfte sich nicht vom internen Unterscheiden oder?):

    C-Quellcode

    1. Manager.RegisterBlock(MyBlockInstance);
    2. // -----
    3. class MyBlock : Block
    4. {
    5. public MyBlock()
    6. {
    7. this.Hardness = Hardness.Breakable;
    8. this.StackCount = 16;
    9. // ...
    10. }
    11. }
    Also ich erklär einfach mal anhand von TowerDefense, was ich meine.
    Ich habe dort z.B. eine Basisklasse "Tower". Für jeden vorhandenen Turmtyp gibt es eine Klasse, die von Tower erbt und Werte wie Schaden, Reichweite etc, aber auch Aussehen und Verhalten (also wie der Turm schießt) festlegt.
    In der Basisklasse Tower wird dann mit Reflection in der Assembly nach Klassen gesucht, die von Tower erben und diese werden in eine List(Of Type) gepackt, zusammen mit einer ID.
    Ich suche nun eine Möglichkeit, dass die abgeleiteten Turmklassen der Basisklasse sagen können "Hallo, ich bin hier", da Reflection nicht wirklich das wahre ist.
    und son Turm kannman nicht mit Eigenschaften ausrüsten, wie Höhe, Panzerung, Reichweite, Feuerrate, Durchschlagskraft und Zeugs?

    Dann hätte man nur eine Turm-Klasse, aber lauter verschiedene Türme.
    Also noch sehe ich nicht recht, warum du verschiedene Turm-Erben brauchst. Die von dir angesprochenen Dinge passen findich gut in die derzeitige Basisklasse, und die Gestaltung der Türme besteht im Festlegen der Werte derlei Properties.
    Die genannten sind auch alles Eigenschaften, aber die Türme verhalten sich unterschiedlich. Einige schießen mit Lasern, die kontinuierlich langsam Schaden machen, andere schießen mit Geschossen, die einmalig beim Aufprall Schaden machen und einer macht sogar gar keinen Schaden, sondern verlangsamt die Gegner nur. Das alles in eine Klasse unterzubringen wäre imo nicht besonders klug.
    Ich würde das einfach ins Entity reinschreiben, sodass es sich selbst um seine "Dinge" kümmert.

    Pseudocode

    C-Quellcode

    1. class Entity
    2. {
    3. public abstract void Draw(RenderTarget target);
    4. public abstract void Update(float elapsed);
    5. }
    6. class Tower : Entity
    7. {
    8. // Weitere allgemeine Eigenschaften von einem Tower
    9. }
    10. class AggressiveTower : Tower
    11. {
    12. public override void Draw(RenderTarget target)
    13. {
    14. foreach(Shot shot in this.Shots)
    15. shot.Render(target);
    16. }
    17. public override void Update(float elapsed)
    18. {
    19. Enemy[] enemies = this.findAllEntitiesInRadius(this.EntityManager.AllEntites);
    20. foreach(Enemy enemy in enemies)
    21. this.shots.Add(new Shot(enemy));
    22. foreach(Shot shot in this.Shots)
    23. shot.Update(elapsed);
    24. // ....
    25. }
    26. }
    27. class LaserTower : Tower
    28. {
    29. // ...
    30. public override void Draw(RenderTarget target)
    31. {
    32. foreach(Enemy enemy in this.targetedEnemies)
    33. target.DrawLine(this.Position, enemy.Position, Color.Blue);
    34. }
    35. public override void Update(float elapsed)
    36. {
    37. this.targetedEnemies = findEnemiesInRadius(this.EntityManager.AllEntities);
    38. }
    39. // ...
    40. }
    So hab ichs ja auch gemacht. ;)
    Das funktioniert auch, allerdings besteht eben das Problem, dass ich irgendwie alle verfügbaren abgeleiteten Klassen kennen möchte, ohne sie alle Manuell zu einer Auflistung hinzuzufügen, das sollen sie selber machen.
    Beispiel Baumenü: im Baumenü sollen alle Türme erscheinen, die es gibt, und wenn man dann einen baut soll auch eine Instanz des gewählten Turms erstellt werden. Das geht über Reflection, aber es muss doch auch schöner gehen. Und die Einträge im Baumenü sollen natürlich automatisch eingetragen werden, also ich möchte nicht für jede Turm-Klasse einen Eintrag manuell erstellen.
    Wurde oben ja schon vorgeschlagen. Wenn sich die Türme nur in ihren Eigenschaften unterscheiden würden, dann wäre das auch kein Problem, einfach ein DataSet benutzen und fertig. Aber wie ich schon geschrieben habe weisen die Türme große Unterschiede in ihrem Verhalten auf, das Spiel soll ja auch vielfältig sein.