Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Käsekönig

1x Contest-Sieger

  • »Käsekönig« ist der Autor dieses Themas
  • Private Nachricht senden

1

31.10.2012, 22:29

Einheitenhandling in Strategiespiel

Ich hab vor einem halben Jahr mal angefangen, ein Strategiespiel zu programmieren - zumindest sollte es irgendwann mal eins werden. :D
Es sollte also ein Echtzeit-Strategiespiel in 2D werden. Umgesetzt wird das ganze mit SFML 2.0 und C++. Nachdem jetzt doch eine ziemlich lange Zeit vergangen ist, wollte ich das alte Projekt wieder aufgreifen und ein wenig weiter programmieren.

Was ich bisher habe:
  • Die Map, sowie eine Übersichtsmap - man kann die Ansicht also bewegen und somit die ganze Map "abfahren", der aktuelle Sichtbereich wird in der Übersichtsmap dargestellt
  • Einheiten - die Einheiten lassen sich anklicken und von A nach B schicken (sie "fahren" also einfach entlang einer Gerade zu dem Punkt hin und bleiben dann dort stehen)
  • Gebäude - ich hab bisher nur ein Gebäude eingefügt, aber man kann es anklicken, wo sich dann ein kleines "Menü" öffnet, wo vorerst mal nur ein paar Informationen zum Gebäude drinnen stehen

Nun zu meinem "Problem", dem Handling der Einheiten. Ich hab eine Basisklasse "CEinheit", von der ich die verschiedenen Einheiten ableite, z.B. "CFlugzeug", "CFahrzeug", etc. In der Basisklasse sind eben ein paar grundlegende Dinge drinnen, wie "bewege von A nach B", die Koordinaten, Maße der Einheit, Gewicht, etc. Und in "CFahrzeug" hab ich noch nicht viel drinnen, bis auf eine Variable mit "Fahrzeugtyp".

Ich hab nun also per Hand ein paar Einheiten erzeugt:

C-/C++-Quelltext

1
2
3
4
CFlugzeug Flugzeug (EUROFIGHTER_TYPHOON);
    Flugzeug.SetPosition (200.0f, 100.0f);
    Flugzeug.SetZiel (200.0f, 100.0f);
    MainClass.NeueEinheit (Flugzeug);


In der letzte Zeile übergeb ich "Flugzeug" einer Funktion, die das "Flugzeug" in eine Liste vom Typ "CEinheit" schiebt. Und danach hab ich einfach wieder dieses Flugzeug genommen, eine neue Position gesetzt und wieder in die Liste gegeben.
Mir stellt sich jetzt die Frage, ob das so sinnvoll ist. So wie ich das mache, muss ja eine komplette Kopie der Klasse in der Liste stehen. Das kopieren und vielleicht auch das Durchlaufen durch die Liste ist dann eventuell ziemlich langsam? Eventuell wär es sinnvoller, die Einheiten mittels new zu erzeugen und dann eine Liste mit Zeigern zu haben? Wenn ich dann die Einheit in der Liste hab, kann ich aber ja auch nur Funktionen von "CEinheit" aufrufen und nicht von "CFlugzeug" oder "CFahrzeug", wie könnt ich das irgendwie umgehen?
Vielleicht hat jemand auch einen anderen Ansatz zu dem Ganzen. Ich hoffe, ich hab mich halbwegs verständlich ausgedrückt. ;)

2

15.11.2012, 21:26

Vererbung

Eine Sache, die Du suchst, ist glaube ich die Vererbung, engl. inheritance:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CEinheit{
public:
CEinheit();
    bool setPosition(float x, float y);
};

class CFlugzeug : public CEinheit{
public:
    CFlugzeug();
};

CFlugzeug::CFlugzeug():CEinheit(){
}

class CEurofighter : public CFlugzeug{
public:
CEurofighter();
};

CEurofighter::CEurofighter():CFlugzeug(){
}


Diese Vererbungshierarchie bedeutet, dass ein CEurofighter ein CFlugzeug ist und ein CFlugzeug ist auch eine CEinheit.
Du kannst also den CEurofighter auch in eine Liste von CEinheiten aufnehmen.
Ich sehe gerade, das weißt Du schon.

Deine Frage ist eher, "was mache ich mit den Sonderfähigkeiten der Einheiten?".
Nun ja, Du könntest diese entweder alle in der CEinheit-Klasse abhandeln mit Funktionspaaren canThis(); doThis(); wobei This die Aktion beschreibt wie This=Move This=Shoot This=Bomb.

Alternativ würde ich Dir - erweiterbar und modbar - vorschlagen eine Klasse, ein Enum, oder ein Integer für jede mögliche Art von Aktion festzulegen und eine canDo(int) - Funktion zu schreiben und dazu eine canDo(int, x, y)-Funktion und dann schließlich do(int, x, y)

Die Alternative dazu ist es, die Einheiten der Liste darauf zu prüfen, welche Klasse sie sind und abhängig davon sie dann auf diese Klasse zu casten dh. aus dem Zeiger auf die CEinheit wieder einen Zeiger auf den CEurofighter zu machen. Ich finde das aber grauenhaft.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

3

15.11.2012, 22:16

:dash:
Vergiss alles was Adder nach dem ersten Absatz geschrieben hat.

Es ist blödsinn eine Einheit zu fragen was sie kann bevor sie es tut. Sag ihr einfach "mach was du kannst" und fertig.
Lass sie die Spezialfähigkeiten selbst in die Oberfläche zeichnen und lass sie sich selbst auf die Karte zeichnen, falls es da unterschiedliche Darstellungen gibt.

Um sowas richtig zu machen brauch man viel Erfahrung. Lass dich also nicht entmutigen wenn du nicht gleich eine Lösung findest. Notlösungen sind erlaubt, wenn du dir aufschreibst, dass du sie später behebst.

Schau dir mal die Pattern Command, Abstract Factory und Strategy an.

Achja, ich würde dir empfehlen das C vor den Klassen weg zu lassen, Variablen klein zu schreiben(unter anderem damit es keine Konflikte wie "Flugzeug Flugzeug(...);" gibt) und deutsche Bezeichner sind einfach schrecklich. dict.leo.org ;)
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »NachoMan« (15.11.2012, 22:21)


Käsekönig

1x Contest-Sieger

  • »Käsekönig« ist der Autor dieses Themas
  • Private Nachricht senden

4

15.11.2012, 22:40

Super, dass sich noch jemand hier melden in diesem Thread! :)
Und du hast es genau erfasst - die Vererbung hatte ich schon, nur was mach ich eben, wenn ich eine Sonderfunktion aufrufen will, die ich nicht in CEinheit habe. Ich hab jetzt nicht für jeden Einheitentyp eine eigene Klasse, da alle Flugzeuge ja einigermaßen das selbe können. Die Basiswerte (z.B. Radarquerschnitt, Tankgröße, Geschwindigkeit, etc.) sind halt eben nur anders, je nachdem, welches Flugzeug, und das entscheide ich dann eben, wenn ich eine Instanz von CFlugzeug erzeuge (da übergeb ich einfach den Flugzeugtyp).
Ich mag jetzt aber nicht in CEinheit alle Funktionen haben, die z.B. mit Flugzeugen zusammenhängen, wie "werfe Bombe ab", etc. Oder Funktionen, die nur Fahrzeuge betreffen wie "drehe Turm" oder so. Diese Funktionen sollen eben in CFahrzeug oder CFlugzeug stehen. Wenn ich aber eine Liste mit Zeigern auf CEinheit Instanzen habe (hab das jetzt so gemacht, dass ich in der Liste die Zeiger speicher), dann kann ich diese Funktionen eben nicht aufrufen.
Das was du zum Schluss erwähnt hast, wär eine Idee gewesen, kommt mir auch etwas unschön vor - aber hab ich denn eine andere Möglichkeit? Vielleicht hat noch jemand einen Ansatz dazu. Oder ich hab das von Grund auf falsch gemacht?

EDIT: Jetzt hab ich wohl zu lange gebraucht, um das hier zu schreiben. :D
Nein, ich frag die Einheit ja nicht, zumindest weiß ich jetzt nicht genau, was du damit meinst. Ich mag einfach eine Funktion aufrufen können, die in CFlugzeug definiert ist, obwohl ich eine Liste mit Zeigern auf Instanze von CEinheit habe (wobei das eben entweder CFlugzeug oder CFahrzeug ist). Genau hier liegt eben mein Problem - eventuell mit mehreren Liste?

Ich weiß, dass es am Ende meist im Chaos endet - aber man lernt doch immer dazu, bessert es womöglich dann aus, oder fängt einfach ein neues Projekt an, wo man das nicht mehr so macht. Und auch wenns eine schlechte Lösung ist - mein Ziel ist es einfach, eine Lösung zu finden, die funktioniert. ;)

Dieses C vor den Klassen hab ich aus "C++ für Spieleprogrammierer" und fand das eigentlich ganz sinnvoll. :) Und zu den deutschen Bezeichnern - ja ich weiß, wie (fast) alle darüber denken, doch ich arbeite allein an dem Projekt und ich mach das rein als Hobby - aber du hast schon recht, ich sollte es mir vielleicht angewöhnen, Deutsch und Englisch nicht zu mischen, sondern nur Englisch zu verwenden.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Käsekönig« (15.11.2012, 22:49)


NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

5

15.11.2012, 23:07

Ich mag einfach eine Funktion aufrufen können, die in CFlugzeug definiert ist, obwohl ich eine Liste mit Zeigern auf Instanze von CEinheit habe

Nenn mal ein Beispiel für eine solche Funktion.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Käsekönig

1x Contest-Sieger

  • »Käsekönig« ist der Autor dieses Themas
  • Private Nachricht senden

6

15.11.2012, 23:17

Ich mag einfach eine Funktion aufrufen können, die in CFlugzeug definiert ist, obwohl ich eine Liste mit Zeigern auf Instanze von CEinheit habe

Nenn mal ein Beispiel für eine solche Funktion.

Zum Beispiel Bombe_abwerfen () für ein Flugzeug, oder Hauptkanone_schießen () für einen Panzer oder solche Funktionen halt. Die sind halt für jede Einheit, bzw. zumindest für jeden Typ (Flugzeug, Hubschrauber, Fahrzeug, etc.) unterschiedlich.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

7

15.11.2012, 23:27

Wer entscheidet denn wann eine Bombe abgeworfen werden soll. Sollte das nicht das Flugzeug selbst entscheiden?
Was spricht dann dagegen, die Methode innerhalb einer virtuellen Updatemethode aufzurufen?
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Käsekönig

1x Contest-Sieger

  • »Käsekönig« ist der Autor dieses Themas
  • Private Nachricht senden

8

15.11.2012, 23:34

Naja, wenn ich als Spieler z.B. auf die Einheit klicke, ist sie mal markiert. Wenn ich dann beispielsweise mit der anderen Maustaste auf eine gegnerische Einheit klicke, will ich, dass die Einheit angreift. Und du willst drauf hinaus, dass die Einheit immer das macht, was sie kann? Also sollte ich in CEinheit eine Funktion Angriff () haben, die dann von den einzelnen Einheiten überladen werden und dann eben das ausführen, was sie können!? Meinst du das so in etwa?
Wie meinst du das mit einer virtuellen Updatemethode? Sorry, ich glaub, ich bin da etwas überfordert. :S

Renegade123

Alter Hase

Beiträge: 494

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

9

15.11.2012, 23:42

Mein Rat:

Versuche nicht, dir eine Basisklasse CEinheit zu erstellen, und in dieser viele Funktion aufzuwahren die womöglich erbende Klassen realisieren oder überschreiben. (unflexibel und führt zu einer "Blob-Klasse")
Einfach Beispiel: Basisklasse CEinheit, abgeleitete Klassen CFlugzeug und CPanzer. Was geschieht, wenn du nun versuchen möchtest, eine Einheit zu kreieren die fliegen kann und Ketten besitzt?
Versuche lieber, dir eine Klasse CAkteur zu erstellen, die eine Liste mit Komponenten besitzt. Die Klasse CKomponente könntest du z.B. mit Funktionen wie Update, oder Render ausstatten. So ermöglichst du dir selbst, zur Laufzeit Komponenten zu erstellen oder hinzuzufügen / zu löschen.
Desweiteren könntest du die Akteure über eine Fabrik erstellen lassen, die eine XML Datei ausliest, welche Komponenten nun der jeweilige Akteur besitzt - Stichwort: Data Driven Design.
Abschließend kann ich dir raten, schau dir mal an wie Unity seine Akteure verwaltet. Da wirst du eine ähnliche Herangehensweise feststellen.

PS: Wegen dem Iterieren über eine Liste von Akteuren kannst du der Klasse CAkteur einfach eine einzigartige ID vergeben, so müsstest du nur über eine Liste von Integers iterieren!

lg René
Liebe Grüße,
René

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

10

15.11.2012, 23:46

Also sollte ich in CEinheit eine Funktion Angriff () haben, die dann von den einzelnen Einheiten überladen werden und dann eben das ausführen, was sie können!? Meinst du das so in etwa?

Klingt sinnvoll.
Wie meinst du das mit einer virtuellen Updatemethode? Sorry, ich glaub, ich bin da etwas überfordert. :S

Was eine virtuelle Methode ist weißt du?

Bei mir hat jedes Objekt eine virtuelle Methode mit dem Namen Update. Diese Methode wird in jedem Frame genau einmal aufgerufen. Darin können sich Einheiten z.B. bewegen oder die Entscheidung treffen stehen zu bleiben und zu schießen.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Werbeanzeige