Verständnisfrage
-
Hallo,
ich hatte mir kürzlich eine Frage gestellt:
Nehmen wir als Beispiel ein Strategie oder eine Bausimulation. Dort habe ich die Möglichkeit Gebäude zu bauen. Wie sieht das programmiertechnisch aus?
- Sind die einzelnen Gebäude als Klassen vorhanden und erben z.B. von einer "allgemeinen Gebäudeklasse" (welche sagt, dass es sich hierbei um ein Gebäude handelt; die individuelle Klasse sagt dann nur, welche Möglichkeiten dieses Gebäude bietet (Bau von Fahrzeugen, Bauzeit, ...))?
- Gleiches für Einheiten
- Wird beim Erstellen von Gebäuden / Einheiten jedes mal ein neues Objekt dieser Klassen erzeugt?
- Wenn die bisherigen Gedanken stimmen / annährend der Wahrheit entsprechen: wie kann man sich das ohne OOP vorstellen?Falls das ganze einfach Mist ist - bitte erhängt mich nicht, ich interessiere mich nur für die Materie - ich beherrsche aber nicht im Ansatz die Programmierung von Spielen. Mich interessiert es lediglich.
Danke schonmal
-
Hendriks schrieb:
- Sind die einzelnen Gebäude als Klassen vorhanden und erben z.B. von einer "allgemeinen Gebäudeklasse" (welche sagt, dass es sich hierbei um ein Gebäude handelt; die individuelle Klasse sagt dann nur, welche Möglichkeiten dieses Gebäude bietet (Bau von Fahrzeugen, Bauzeit, ...))?
- Gleiches für Einheiten
- Wird beim Erstellen von Gebäuden / Einheiten jedes mal ein neues Objekt dieser Klassen erzeugt?Ja, im Prinzip wird man das in der Regel genau so machen...
Hendriks schrieb:
- Wenn die bisherigen Gedanken stimmen / annährend der Wahrheit entsprechen: wie kann man sich das ohne OOP vorstellen?
Naja, du wirst deine Einheiten trotzdem irgendwie repräsentieren müssen. Ist jetzt schwer da irgendwas konkretes drauf zu sagen...
-
Hendriks schrieb:
- Sind die einzelnen Gebäude als Klassen vorhanden und erben z.B. von einer "allgemeinen Gebäudeklasse" (welche sagt, dass es sich hierbei um ein Gebäude handelt; die individuelle Klasse sagt dann nur, welche Möglichkeiten dieses Gebäude bietet (Bau von Fahrzeugen, Bauzeit, ...))?
- Gleiches für Einheitennaja, das ist die idealisierte welt von OOP programming tutorials/buechern. in der realen welt macht man aber keine neue klasse fuer alles,
1. macht es keinen sinn zwei klassen zu machen die dasselbe machen (z.b. 'leichter panzer', 'schwerer panzer')
2. wird es schnell komplex mit mehrfachvererbung wenn du das voll durchziehst, z.b. kannst du eine basis klasse "einheit" haben, davon "gebaeude" und "fahrzeug" ableiten, dann willst du noch dass beide auf events reagieren, also musst du bei beiden von dem "event interface" ableiten, jetzt baust du einen bauhof der wie bei manchen spielen beweglich ist, also mal "gebaeude" und mal "fahrzeug" ist, also leistest du das von "Gebaeude" und "fahrzeug" ab, dann ist aber "event interface" zweimal drinnen, jetzt faengst du mit virtueller ableitung an und musst dafuer sorgen dass die events richtig delegiert werden an das bastard objekt und wenn du davon ableitest etc etc etc.Hendriks schrieb:
- Wird beim Erstellen von Gebäuden / Einheiten jedes mal ein neues Objekt dieser Klassen erzeugt?
irgendwo wirst du irgendwie einen datenbereich brauchen der die einheit representiert.
Hendriks schrieb:
- Wenn die bisherigen Gedanken stimmen / annährend der Wahrheit entsprechen: wie kann man sich das ohne OOP vorstellen?
heutzutage will man dinge eher "data driven" machen, das bedeutet, dass man daten von funktionen trennt. naiv koennte man eine klasse/struct machen, die alle eigenschaften hat die je ein objekt haben koennte, aber garkeine funktionen.
Irgendwo hast du dann die konfigurationen (z.b. als xml, ini oder txt) fuer alle einheiten. ein kraftwerk wird dann durch die selben member representiert wie ein panzer wie ein soldat wie ein farmer wie ein baum.
kraftwerk: max-geschwindigkeit:0 panzerung:100 3dobjekt:kraftwerk.obj textur:kraftwerk.png
panzer: max-geschwindigkeit:100 panzerung:10 3dobjekt:panzer.obj textur:panzer.png
soldat: max-geschwindigkeit:10 panzerung:2 3dobjekt:soldat.obj textur:soldat.png
farmer: max-geschwindigkeit:5 panzerung:0 3dobjekt:farmer.obj textur:farmer.pngauf diese weise kann ein spiel algorithmen auf objekte anwenden, ohne sonderfaelle pro objekt machen zu muessen. man kann auch neue typen einbauen oder existierende aendern, ohne seiteneffekte im code zu befuehrten, denn dieser kennt die typen nicht, sie sind nur einstellungen. man kann auch flexibel die daten bearbeiten, weil z.B. 'speed' nichts irgendwo im code von 'panzer' festgelegtes ist, sondern nur eine variabel, kann man auch einfach so einbauen, dass wegen eines sandsturms alle einheiten -30% max speed haben.
ich hoffe das gibt dir den gewuenschten ueberblick
:schland:
-
Naja, da gibt es keine Musterlösung, aber ich persönlich finde es schöner wenn es eine allgemeine "Object" oder "Entity" Klasse gibt die dann gemeinsame Aspekte von Einheiten und Gebäuden unterbringt (z.B. Behandlung von Signalen bei einem ereignisbasiertem Ansatz) oder evtl. AI (falls deine Gebäuden nicht einfach nur rumstehen sondern z.B. auch schießen). Dann würde ich von der Klasse eine allgemeine Gebäudeklasse ableiten, die nur Gebäudenspezifisches definiert und davon werden dann alle anderen Gebäuden abgeleitet.
Falls man viele Arten von Gebäuden hat, die sich in ihrer Funktion nicht wirklich unterscheiden, kann man auch eine Art "Gebäudendefinition" schreiben statt für jeden Typ eine neue Klasse zu schreiben. Das könnte dann so aussehen.BuildingDescription bd; bd.name = "Farm"; bd.hp = 100; bd.faction = Factions::Humans; bd.model = farm_model; // mithilfe von definitionen kann man unterschiedliche Gebäuden // mit der selben Klasse erstellen. Building* farm = new Building(bd);
Gleiches könnte auch für Einheiten, Items, etc. gelten.
Und ja, für jedes Gebäude muss selbstverständlich eine Instanz erstellt werden.Edit:
rapso war schneller
-
c0ff33.alex schrieb:
Naja, da gibt es keine Musterlösung, aber ich persönlich finde es schöner wenn es eine allgemeine "Object" oder "Entity" Klasse gibt die dann gemeinsame Aspekte von Einheiten und Gebäuden unterbringt (z.B. Behandlung von Signalen bei einem ereignisbasiertem Ansatz) oder evtl. AI (falls deine Gebäuden nicht einfach nur rumstehen sondern z.B. auch schießen). Dann würde ich von der Klasse eine allgemeine Gebäudeklasse ableiten, die nur Gebäudenspezifisches definiert und davon werden dann alle anderen Gebäuden abgeleitet.
Schau was Rapso geschrieben hat. Vererbung wird überstrapaziert und funktioniert meistens nur in Büchern gut. Das Beispiel mit dem Bauhof, der mal Gebäude und mal Fahrzeug ist, macht jede Hierarchie platt.
-
könnte man das nicht auch über "abilities" machen? also ich füge nem basistyp während der laufzeit beliebige fähigkeiten hinzu? das mit den conf - dateien find ich ja ganz lusig, aber oop ist das imo nicht mehr?
-
Ich denk das Grundproblem hier ist, dass die Leute immer zu denken scheinen, dass es nur entweder oder gibt. Data Driven Design ist kein Ersatz für OOP ist kein Ersatz für generische Programmierung ist kein Ersatz für funktionale Programmierung ist kein Ersatz für Data Oriented Design ist kein Ersatz für <your favourite buzzword here> ist kein Ersatz für ...
Diese Dinge arbeiten alle zusammen und ergänzen sich. Die Kunst ist, Probleme richtig zu identifizieren, abhängig vom Kontext die richtigen Werkzeuge auszuwählen und diese am Ende auch noch richtig zu benutzen, um Lösungen zu implementieren.
-
Das Beispiel mit dem Bauhof, der mal Gebäude und mal Fahrzeug ist, macht jede Hierarchie platt.
Dann plane deine Hierarchien bevor du sie implementierst damit sowas nicht vorkommt. Ich meine, wenn man weiss, dass man später von mehreren Klassen mit der gleichen Basis ableitet, soll man halt sein Design überdenken.
Es mag ja sein, dass *Mehrfach*vererbung einem Probleme bereiten kann, aber das ist kein Grund, auf OOP zu verzichten.
Und das problem mit event interfaces lässt sich dadurch lösen, dass man sowas wie ein "Event interface" gar nicht erst implementiert und stattdessen Containment von Singalen benutzt (wie das die GUI libs machen) :p .
-
Vielen Dank für die Antworten. Genau auf solche Antworten hatte ich gehofft :)...
-
c0ff33.alex schrieb:
Dann plane deine Hierarchien bevor du sie implementierst damit sowas nicht vorkommt.
Sehr naiver Ansatz!
rapso schrieb:
naja, das ist die idealisierte welt von OOP programming tutorials/buechern.
-
árn[y]ék schrieb:
c0ff33.alex schrieb:
Dann plane deine Hierarchien bevor du sie implementierst damit sowas nicht vorkommt.
Sehr naiver Ansatz!
Wenn er aufhört bei mir zu funktionieren suche ich mir einen neuen .
Ich will ja nicht sagen dass OOP gut für alles ist. Aber wenn man sich dafür entscheidet, soll man halt vorausplanen.
-
Da ich zur Zeit Teilzeit an einem Casual Game arbeite, stelle ich immer häufiger fest, das ein rein Objektorientierter Ansatz irgendwie immer in einer Sackgasse endet.
Man ist sich nicht über Verantwortlichkeiten im Klaren, "Kommunikation" zwischen Objekten wird letztendlich über Delegates o.ä. Prinzipien abgefackelt und da du i.d.R. später bestimmten Klassen mehr Funktionalitäten einräumst als jemals geplant waren, endet das Ganze bei uns momentan in einer recht monolitischen Sprite Klasse und einem Rahmensystem (Screens etc.), welche untereinander per Delegates Kommunizieren.
Ich stelle immer wieder fest, das OOP toll ist, wenn man theoretische Beispiele mal schön veranschaulichen will. In der Praxis wird der Ansatz eigentlich meistens dazu benutzt, gemeinsame EIGENSCHAFTEN zu gruppieren, aber wie im Beispiel von Rapso schön zu sehen ist, ändert sich ständig der Kontext.
Du müsstest also dein OOP Modell ständig anpassen, mal abgesehen von der statischen Verhaltensweise.
In Spielen möchtest du im Idealfall dynamisch sagen können, welche Eigenschaften und Verhaltensweisen ein Objekt hat. Du willst Rotation? Füge Sie dynamisch hinzu, leite aber nicht von einem Rotationssprite ab.
Zugegeben, für die Standard World Transformationsmember hinkt der Vergleich vielleicht ein wenig, aber alles darüber kannst du statisch eigentlich kaum mehr kontrollieren.Ich kenne allerdings auch leider keine 99% Lösung, wie man diesbzgl. am besten vorgeht. In den einschlägigen Magazinen zur Spieleentwicklung scheint man aber immer mehr in Richtung dynamischer Modelle zu wandern, wie immer das im Kern aussehen mag.
-
xaoC schrieb:
Man ist sich nicht über Verantwortlichkeiten im Klaren, "Kommunikation" zwischen Objekten wird letztendlich über Delegates o.ä. Prinzipien abgefackelt und da du i.d.R. später bestimmten Klassen mehr Funktionalitäten einräumst als jemals geplant waren, endet das Ganze bei uns momentan in einer recht monolitischen Sprite Klasse und einem Rahmensystem (Screens etc.), welche untereinander per Delegates Kommunizieren.
Klingt mir so, als wär das Design kaputt und ein Refactoring dringend notwendig.
-
c0ff33.alex schrieb:
Das Beispiel mit dem Bauhof, der mal Gebäude und mal Fahrzeug ist, macht jede Hierarchie platt.
Dann plane deine Hierarchien bevor du sie implementierst damit sowas nicht vorkommt. Ich meine, wenn man weiss, dass man später von mehreren Klassen mit der gleichen Basis ableitet, soll man halt sein Design überdenken.
Es mag ja sein, dass *Mehrfach*vererbung einem Probleme bereiten kann, aber das ist kein Grund, auf OOP zu verzichten.Naiv ist, OO mit Vererbung gleichzusetzen.
Vererbung ist oft ein gutes Mittel in Bibliotheken. Bei der Modellierung von Objekten aus der realen Welt ist es eben meistens keine simple "ist ein" Beziehung mehr.
-
dot schrieb:
Klingt mir so, als wär das Design kaputt und ein Refactoring dringend notwendig.
"Kaputtes Design" ist in 99% der Fälle ein Totschlargument.
-
lolalter schrieb:
dot schrieb:
Klingt mir so, als wär das Design kaputt und ein Refactoring dringend notwendig.
"Kaputtes Design" ist in 99% der Fälle ein Totschlargument.
Na schau dir doch mal an was er schreibt:
xaoC schrieb:
Man ist sich nicht über Verantwortlichkeiten im Klaren, "Kommunikation" zwischen Objekten wird letztendlich über Delegates o.ä. Prinzipien abgefackelt und da du i.d.R. später bestimmten Klassen mehr Funktionalitäten einräumst als jemals geplant waren, endet das Ganze bei uns momentan in einer recht monolitischen Sprite Klasse und einem Rahmensystem (Screens etc.), welche untereinander per Delegates Kommunizieren.
Wenn das für dich nicht nach kaputtem Design klingt, dann kann ich auch nicht helfen...
-
dot schrieb:
Klingt mir so, als wär das Design kaputt und ein Refactoring dringend notwendig.
Es gibt kein Design. Es ist unser erstes Projekt. Natürlich gibt es Überlegungen und Ideen, wie man etwas umsetzt, basierend auf Erfahrungen, aber es ist meiner Erfahrung nach so gut wie nie Praktikabel, etwas "Durchzudesignen".
Speziell im Game-Design muss man erstmal ein Gefühl dafür entwickeln, wie man ein einfaches Framework aufzieht, wie sich Objekte unterhalten, und zwar an konkreten Anforderungen. Ich will keine Engine schreiben, die in der Theorie toll aussieht, mit der man aber praktisch nichts anfangen kann.
Die Anforderungen ergeben sich durch das Spielekonzept. Genau dieses muss so klar wie möglich sein. Dann fängst du an, dir Gedanken zu machen wie du anhand dieses Konzept ein primitives Framework aufziehen musst.
Und hier passiert nun mal die Drecksarbeit. Du stellst schnell fest, dass das Design des Frameworks sich dynamisch an Anforderungen anpassen muss und sich dadurch teils erheblich ändert. Du hast noch keine "Foundation". Du musst erst in die Fehler rennen, um sie zu verstehen. Dann kannst du dir Gedanken darüber machen, wie du dein OOP Konzept aufsetzt (oder ob überhaupt ;-)).
Anders herum programmierst du einen theoretischen, unbrauchbaren Wasserkopf ohne Praxisrelevanz.
-
xaoC schrieb:
Natürlich gibt es Überlegungen und Ideen, wie man etwas umsetzt, basierend auf Erfahrungen, aber es ist meiner Erfahrung nach so gut wie nie Praktikabel, etwas "Durchzudesignen".
Exakt, darum ist es auch so wichtig, ständig zu refactoren...
xaoC schrieb:
Speziell im Game-Design muss man erstmal ein Gefühl dafür entwickeln, wie man ein einfaches Framework aufzieht, wie sich Objekte unterhalten, und zwar an konkreten Anforderungen.
Richtig, daher fängt man ungefähr mal grob irgendwo an und passt das Design iterativ entlang des Weges an. Ein Prozess bekannt als "Refactoring".
xaoC schrieb:
Und hier passiert nun mal die Drecksarbeit. Du stellst schnell fest, dass das Design des Frameworks sich dynamisch an Anforderungen anpassen muss und sich dadurch teils erheblich ändert.
Mit anderen Worten: Du musst ständig refactoren.
xaoC schrieb:
Du musst erst in die Fehler rennen, um sie zu verstehen.
Und wenn du die Fehler verstanden hast, besserst du sie aus -> Refactoring.
-
dot schrieb:
Wenn das für dich nicht nach kaputtem Design klingt, dann kann ich auch nicht helfen...
Nochmal kurz:
Schnapp dir deinen Gamma, kritzel dir Kombinationen aus 10 Design Patterns zusammen und sei glücklich, wenn am Ende alles aufgeht.
Hab ich auch schon oft probiert. Und mindestens genau so oft verworfen.
Grundlagenforschung ohne tiefere Relevanz, eigentlich nur dann sinnvoll, wenn du abgesteckte, relativ statische Anforderungen hast. Dann kann dir so ein Entwurfsmuster weiterhelfen.Vielleicht verstehe ich dich ja falsch, aber bei dem Wort "Design" denke ich an stundenlanges Grübeln über abstrakte Anwendungsfälle, um den "perfekten" Entwurf zu basteln.
Wenn ich 5 Interfaces implementieren muss, um einem Sprite neue Funktionalität hinzuzufügen, ist das IMO der falsche Ansatz, darum geht es mir.
-
Dann verstehst du mich falsch. Unter Design versteh ich den Entwurf von Software. Das ist in meinem Augen ein sehr organischer Prozess, Design ist einer ständigen Evolution unterworfen. Stundenlanges Grübeln und malen irgendwelcher Diagramme hilft vielleicht beim wählen der Anfangswerte der Iteration, aber das eigentliche Design ist nicht statisch, sondern entwickelt sich während die Software entwickelt wird.