Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Kentnisse über Klassen mittels Übung festigen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
17.01.2016, 18:55 Uhr
Dexter19971



Hallo ihr Lieben, ich komme gleich zur Sache:

Ich habe mir kürzlich erste Kentnisse über die objektorientierte Programmierung angeeignet. Um gelerntes anzuwenden und dadurch zu verinnerlichen, habe ich mir eine kleine Projektidee ausgedacht. Es handelt sich um ein Rollenspiel, welches ich gleich noch näher beschreiben werde.

Ich stoße leider auf einige Probleme, wenn ich versuche darüber nachzudenken, wie man den Quellcode möglichst sauber gestalten kann.

Kurz zu den Rahmenbedingen:
Ich bin in der Lage eine Klasse mit (überladenen Konstruktoren) zu schreiben, die Begriffe public, private und protected korrekt anzuwenden und kann Klassen ableiten.
Ich packe den gesamten Code in eine Datei, nix Modularisierung.

Ein Problem was sich noch nebenbei ergibt: In Python beispielsweise gibt es Listen (Arrays), in denen man Daten völlig unterschiedlicher Datentypen hineinpacken kann. Etwas vergleichbares brauche ich für die Erstellung von Gegenständen auch in C++, da diese Werte haben, dessen Datentyp nicht immer übereinstimmt.

Ich wollte nun alle Erfahrenen unter euch fragen, wie ihr mein Projekt strukturieren würdet, dazu stelle ich einmal den Grundriß vor:

Es handelt sich um ein Rollenspiel, in dem man einen Magier spielt und gegen Monster kämpft. Es gibt hierbei zwei zentrale Phänomene bzw. Objekte, die existieren: Der Spieler und das Monster.

### SPIELER

## Der Spieler hat:

# Werte:

Stufe (int)
Erfahrung (int)
Leben (int)
Schaden (Array; bestehend aus zwei Werten, Zufallsprinzip, wieviel Schaden gemacht wird)
Mana (int; brauch man um Fähigkeiten zu wirken)

# Gegenstaende

Waffe (Name; Schadwert1, Schadwert2; z.B.: Zauberstab des Grauens, 10, 20)
Rüstung (Name; Leben)
Amulett (Name, Mana)

# Fähigkeiten

Feuerball (Verursacht Schaden * Stufe der Fähigkeit)
Heilung (Der Spieler heilt sich im Kampf)

## Der Spieler tut:

Stufen aufsteigen
Faehigkeiten nutzen (z.B Feuerball zaubern)

### Monster

## Das Monster hat:

Name (z.B. Wolf)
Leben
Schaden

## Das Monster tut:

Im Kampf Faehigkeiten anwenden
Beim Sterben Gegenstaende fallen lassen

Das wär's soweit. Wie würdet ihr an die Sache rangehen? Welche Klassen sollten ungefähr wie erstellt werden? Ich bin froh über alle klugen Richtungsweisungen, die ich bekommen kann.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.01.2016, 00:08 Uhr
Hans
Library Walker
(Operator)


Hi,


Zitat:
In Python beispielsweise gibt es Listen (Arrays), in denen man Daten völlig unterschiedlicher Datentypen hineinpacken kann. Etwas vergleichbares brauche ich für die Erstellung von Gegenständen auch in C++, da diese Werte haben, dessen Datentyp nicht immer übereinstimmt.

Sowas gibt es in C++ nicht. Da musst Du Dir schon was anderes einfallen lassen. Etwa eine Struktur, in der die Namen der Gegenstände als Strings gespeichert sind. Oder allgemeiner: Du definierst mit struct eine Datenstruktur, in der Du die Typen unterbringst, die Du brauchst und packst die in einer Liste. Anders geht es in C++ nicht, weil es sonst gegen die strengere Typisierung verstossen würde. Aber die ist in C++ ja gerade gewollt, eben damit man Daten nicht beliebig als den Typ deuten kann, den man gerade gern hätte.


Zitat:
Wie würdet ihr an die Sache rangehen? Welche Klassen sollten ungefähr wie erstellt werden? Ich bin froh über alle klugen Richtungsweisungen, die ich bekommen kann.

Hm... - ohne Gewähr, ob sich das später auch als sinnvoll erweist, würde ich zuerst einmal über die Eigenschaften nachdenken, die Spieler und Gegner immer haben sollen, also schon zu Spielbeginn. Das wären Kandidaten für (Basis?)klassen. Weitere Klassen definieren alle Gegenstände, mit denen hantiert werden kann und deren Eigenschaften. Das Hauptprogramm müsste dann die Spiellogik enthalten die festlegt, ab wann man was machen kann, wie man weitere Fähigkeiten erhält und all das auch verwalten. Und natürlich käme auch die Steuerung der Ausgabe dahin, wobei man die Details einer fertigen Grafik- bzw. Spieleengine überlassen kann.
Dazu wäre es interessant zu wissen, auf welchem Betriebssystem Du arbeitest und welches Deine Lernquellen zu C++ sind. Evtl. wäre dann dieses Buch eine nützliche Empfehlung...

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
18.01.2016, 09:39 Uhr
ao

(Operator)



Zitat:
In Python beispielsweise gibt es Listen (Arrays), in denen man Daten völlig unterschiedlicher Datentypen hineinpacken kann. Etwas vergleichbares brauche ich für die Erstellung von Gegenständen auch in C++, da diese Werte haben, dessen Datentyp nicht immer übereinstimmt.

Du solltest überlegen, ob wirklich alle Gegenstände (Waffen, Rüstungen, Amulette) in einer einzigen Liste verwaltet werden sollen oder ob hier nicht drei Listen passender sind. Was fängst du in der Praxis mit einer allgemeinen "Gegenstand"-Liste an? Jeden einzelnen Gegenstand untersuchen: Bist du eine Waffe? Ach nein, ein Amulett, also weg damit ...

Wenn eine Spielaktion beginnt, weißt du doch, dass du jetzt eine Waffe brauchst oder ein Amulett, oder? Also kannst du auch gleich in der passenden Liste nachsehen.

Als ersten Ansatz kann man wohl verwenden, dass Stufe, Erfahrung, Leben, Schaden und Mana Member der Klasse Spieler sind. Wobei die nicht Spieler heißen sollte, sondern Magier oder Charakter (das sind Elemente des Spiels). Eine Klasse Spieler kann es natürlich auch geben, aber nicht innerhalb der Spielhandlung, sondern eher zur Verwaltung, für deinen Namen, deinen Highscore und zur Speicherung deiner Spielcharaktere.

Monster ist eine andere Klasse, mit den Eigenschaften Name, Leben, Schaden.

Vielleicht haben beide (Magier und Monster) auch eine gemeinsame Basis (z.B. "Wesen"), die Eigenschaften wie Name, Leben und Methoden wie Bewegen oder Essen enthält.

Wie die Methoden der Klassen definiert werden, das hängt von der Architektur der Spiel-Engine ab und davon, wie sie mit den Spielfiguren interagiert.

Dieser Post wurde am 18.01.2016 um 09:45 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
19.01.2016, 22:14 Uhr
Dexter19971



Vielen Dank für die Antworten! Das sind interessante Ansätze!

Ich lese das Buch "Der C++ Programmierer von Ulrich Breymann, aber erst seit neuem. Habe davor Die kurze Einführung von Jürgen Wolf gelesen, wovon mir jedoch abgeraten wurde.

Mein Problem wäre nur noch zu wissen, wie die Klassen miteinander interagieren sollen...

Ich habe Klassen als Gebilde kennengelernt, die sich, man könnte fast schon sagen, gegenseitig nicht leiden können.

Das heißt, daß, da man ja auf gar keinen Fall Elementvariablen public setzen soll, beispielsweise fremde Elementmethoden aus fremden Klassen nicht auf diese zugreifen können.

Ich nenne mal ein Beispiel:

Ich hätte eine Klasse Mensch und eine Klasse Monster erstellt:
Nun kann der Mensch beispielsweise das Monster angreifen, weswegen man eine Elementmethode Angreifen() schreibe. Diese Methode soll den Lebenswert des Monsters reduzieren. Da aber von der Programmiererkaste einschlägig davon abgeraten wird, Elementvariablen public zu setzen, weiß ich nicht wie ich unter dieser Einschränkung auf eine Elementvariable der Klasse Monster mit einer fremden Methode einer fremden Klasse zugreifen soll... Es gäbe Möglichkeiten, die Dinge anders zu strukturieren. Dann würden sie aber unlogisch und verworren werden. Und das soll ja nicht passieren...

Dieser Post wurde am 19.01.2016 um 22:16 Uhr von Dexter19971 editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
20.01.2016, 00:18 Uhr
Hans
Library Walker
(Operator)


Hi,


Zitat:
Ich lese das Buch "Der C++ Programmierer von Ulrich Breymann,

das Buch ist gut, damit machst du nichts falsch. Das hab ich auch.

Was die Sache mit den Klassen angeht:
Es ist so, dass die Klassen als Hilfsmittel dienen sollen, um von bestimmten Gegenständen zu abstrahieren. Aber Du brauchst immer noch ein Hauptprogramm, das diese Klassen verwendet, also damit arbeitet. In Deinem Beispiel, Mensch und Monster, ist es dann die Aufgabe Deines Hauptprogramms, die Elementfunktionen (oder Methoden) der Klassen nacheinander aufzurufen.
Nehmen wir mal an, Du steuerst Dein Spiel über die Tastatur, wobei damit der Mensch gesteuert wird, der gegen das Monster kämpft. Dazu definierst Du z.B., dass bestimmte Tasten mit bestimmten Aktionen verbunden sind. Zum Beispiel "t" für "treten" und "s" für "schlagen". Dann muss das Hauptprogramm die Tastatur abfragen und auswerten. Wenn also etwa die Taste "t" gedrückt wurde, dann ruft das Hauptprogramm eine Funktion der Klasse Mensch auf, die für die Aktion "treten" zuständig ist. Die Funktion innerhalb der Klasse überprüft dann beispielsweise, ob der Mensch Kampfstiefel mit Stahlkappen trägt oder nicht, und führt den Tritt aus, indem sie einen Statuswert zurück gibt, der aussagt, wieviel Schaden der Tritt verursacht, wenn er trift. Mit diesem Wert ruft das Hauptprogramm anschliessend eine Funktion der Klasse Monster auf, die überprüft, ob der Tritt tatsächlich soviel Schaden angerichtet hat. Evtl. stand der Mensch ja nicht nah genug dran oder das Monster ist ausgewichen. Jenachdem, was Du da definiert hast, gibt die Funktion einen Wert zurück, der dem Hauptprogramm mitteilt, ob tatsächlich soviel Schaden angerichtet wurde, wie erwartet, oder weniger. Mit dieser Information berechnet das Hauptprogramm dann die Anzeige für die Lebenskraft des Monsters neu und aktualisiert sie. Dann ist das Monster am Zug, um auf den Tritt zu reagieren. Das passiert, indem das Hauptprogramm eine Elementfunktion der Klasse Monster aufruft, die für die Steuerung des Selben zuständig ist. Die liefert einen Wert zurück, der angibt, was das Monster gemacht hat. Diesen Wert reicht es an eine Funktion der Klasse Mensch weiter, die auswertet, was die Aktion bei ihm bewirkt hat. Diese gibt dann wiederum einen Wert an das Hauptprogramm zurück, das damit die Lebenskraft des Menschen neu berechnet und anzeigt. Dann ist wieder der Spieler am Zug, d.h. die Tastatur wird erneut ausgewertet, um festzustellen, was der Spieler als nächstes tun will.

So ungefähr könnte ein System bzw. eine Logik aussehen, die hinter dem ganzen sitzt, bzw. eigentlich darüber steht, weil die Klassen ja nur "Dienstleister" innerhalb des Spiels sind, die die jeweilige Figur und ihre Eigenschaften (Fähigkeiten) repräsentieren. Weitere Klassen können dann weitere, neue Figuren darstellen. Die haben dann alle ihre eigenen Elementfuktionen, mit denen sie Auskunft über ihre internen Zustände geben, bzw. womit die internen Zustände verändert werden. (Die können auch von einer Basisklasse abgeleitet sein, die alle Eigenschaften definiert, die jedes Monster immer hat. Davon abgeleitete Klassen spezifizieren ein Monster dann genauer.) Die internen Zustände der Klassen sind jedoch in den private-Variablen abgelegt. Die können deshalb für jedes Monster anders sein. Das ist dann wichtig, wenn mehrere Monster in Aktion treten sollen. Wichtig ist dabei, dass das Interface, mit dem das Hauptprogramm die einzelnen Elementfunktionen aufruft, so gestaltet ist, das die Aufrufe weitgehend ähnlich sind, und es lediglich von den Parametern abhängt, was passiert, bzw. passieren soll.

Ich glaube für den Anfang ist es am einfachsten, wenn Du nur festlegst, das ein Monster soundsoviele Treffer einstecken kann, etwa durch einen Zähler der auf Null herunter zählt. Wenn der Zähler bei Null angekommen ist, ist das Monster tot. Die Elementfunktion prüft dann lediglich, ob das Monster getroffen wurde oder nicht. Wenn ja zählt sie den Zähler runter, wenn nicht, dann behält er seinen aktuellen Stand.

Soweit mal das, wobei ich hoffe, dass ich ich jetzt nicht zu sehr verwirrt habe.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
20.01.2016, 00:31 Uhr
ao

(Operator)


Das geht zum Beispiel so (sollte übersetzbar und lauffähig sein):

C++:
#include <iostream>

class Monster
{
    float leben;
    
public:

    //    frisches Monster beginnt mit 1.0 Leben
    Monster() : leben (1.0) {}
    
    void Treffer ()
    {
        //    Jeder Treffer kostet Lebenspunkte.
        if (leben > 0)
        {
            std::cout << "Monster: Aua!" << std::endl;
            leben -= 0.1;
        }
            
        std::cout << "Monster.leben: " << leben << std::endl;
    }
    
    bool Lebendig () const
    {
        //    wenn leben 0 oder kleiner wird,
        //    ist das Monster tot.
        return (leben > 0);
    }
};

class Mensch;
float Abstand (const Mensch & mensch, const Monster & monster);

class Mensch
{
    
public:

    void Angreifen (Monster & monster)
    {
        std::cout << "Zack!" << std::endl;
        //    Wenn der Abstand kleiner ist als 1 Meter,
        //    wird das Monster getroffen.
        if (Abstand (*this, monster) < 1.0)        
            monster.Treffer ();                
    }
};

float Abstand (const Mensch & mensch, const Monster & monster)
{
    //    Hier müssten irgendwie die Ortskoordinaten
    //    von Mensch und Monster ausgewertet und
    //    der Abstand berechnet werden.
    return 0.9;
}

int main ()
{
    Monster monster;
    Mensch mensch;
    
    while (monster.Lebendig ())
    {
        std::cout << "Monster lebt noch. Draufhauen!" << std::endl;
        mensch.Angreifen (monster);
        
        std::cout << std::endl;
    }
    std::cout << "Monster ist tot." << std::endl;
    
    return 0;
}
        




Zitat:
Das heißt, daß, da man ja auf gar keinen Fall Elementvariablen public setzen soll, beispielsweise fremde Elementmethoden aus fremden Klassen nicht auf diese zugreifen können.

Richtig. Und das geht noch weiter: Die fremde Klasse soll noch nicht mal wissen, dass hinter der Elementmethode eine Variable steckt oder von welchem Typ sie ist. Das geht sie nämlich nichts an.

Verabschiede dich mal ein bisschen von der Elementvariablen und stell dir stattdessen vor, dass das Objekt einen Zustand hat. Das muss keine explizite Variable sein. Der Zustand kann auch ein Berechnungsergebnis sein. Beispiel:


C++:
#include <time.h>
#include <string>

class Mensch
{
    time_t geburtsdatum;
    std::string name;
    
public:

    Mensch (const std::string & name_) : geburtsdatum (time(0)), name (name_) {}

    time_t Alter () const { return time(0) - geburtsdatum; }
};

#include <iostream>
int main ()
{
    Mensch willi ("Willi"); // Willi wird geboren
    
    std::cout << "Bitte warten und dann 0 und ENTER drücken" << std::endl;
    int x;
    std::cin >> x;
    
    std::cout << "Willi ist jetzt " << willi.Alter () << " Sekunden alt" << std::endl;
    return 0;
}


Die Klasse Mensch hat eine Methode Alter(), die das Alter in Sekunden liefert. Dass sie das tut, ist öffentlich. Wie sie es macht, geht keinen Außenstehenden etwas an. Hier ist es so gelöst, dass in dem Moment, in dem nach dem Alter gefragt wird, die Systemzeit abgeholt und das Geburtsdatum davon abgezogen wird.

Eine andere denkbar Möglichkeit wäre, dass Mensch einen Sekundenzähler hat, der von irgendeinem Betriebssystem-Dienst jede Sekunde um 1 erhöht wird. Die Methode Alter() muss dann nur den Zählerstand ablesen und zurückgeben.

Beides hat Vor- und Nachteile, und welche Implementierung man wählt, das hängt von den Anforderungen ab.

Das ist ein wichtiges Prinzip der Objektorientierung: Die Schnittstelle ist öffentlich, die Implementierung (also das Wie) ist privat. Das ermöglicht lokale Änderungen an einem Objekt (Bugfixes, Verbesserungen), ohne dass der Rest der Welt angepasst werden muss.

Dieser Post wurde am 20.01.2016 um 00:52 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
20.01.2016, 11:51 Uhr
Dexter19971



Danke für diese sehr ausführliche Antwort! Deine Sicht auf Klassen ist wesentlich klarer als meine, genau sowas habe ich gesucht, da ich mich ein wenig in falschen Vorstellungen verrannt habe.

Jetzt kann ich mich rannsetzen und an einer Umsetzung arbeiten, ich hoffe, dass es gelingt...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: