Öffentliches RPG Projekt



  • Dragon4411 schrieb:

    Hmmm, das verwirrt mich jetzt, destruktoren kann man aber virtual machen oder?

    Sicher, das macht ja auch Sinn.
    Warum macht ein virtueller Konstruktor keinen Sinn? Ganz einfach, wenn du eine Instanz einer Klasse erstellst, sollte dir der genaue Typ ja bekannt sein. Aber wenn du sie wieder aufräumst, ist eventuell nur der statische Typ bekannt. (Nicht der dynamische.)



  • Dragon4411 schrieb:

    Fragen:
    - Du beachtest viele Anmerkungen nicht, die du bereits bekommen hat (u.a. Mischung Groß-/Kleinschreibung...).
    - Ist ein Charakter wirklich ein Monster?
    - Wenn eine Klasse bereits Monster heißt, warum die Member nochmals mit "Monster" beginnen.

    Damti wenn ich später noch weitere Klassen machen die Variablen unterscheiden kann.

    Ich verstehe den Sinn dahinter nicht.

    Wenn ich ein Objekt der Klasse Monster habe, ist es klar das die Member auch zu einem Monster gehören. Zudem verbaust du dir Möglichkeiten wie generische Funktionen (Templatefunktionen).

    Dragon4411 schrieb:

    - Grundsätzlich sollte man sehr vorsichtig sein, Member öffentlich zu machen.

    Dies ist mir bekannt jedoch wäre es mühsam hier alles abzutrennen, nicht?

    Faulheit war noch nie ein Garant für saubere Software. Ich verwende öffentliche Member ausschließlich in reinen Datenklassen (oder Strukturen), sobald du alles öffentlich machst erlaubst du einen Benutzer deiner Klasse auch Mechanismen zu umgehen.

    Was ist z.B. wenn du willst das Bezeichnungen maximal 50 Zeichen lang sind (vielleicht verwendest du eine Datenbank etc. die dies erzwingt), oder das eine Variable nur bestimmte Wertebereiche aufnehmen kann? Und wie mühsam ist es, wenn sich nachträglich die Anforderungen ändern?

    Du solltest dir zumindest über diese Aspekte Gedanken machen. Sobald du von außen einen Wert beliebig ändern kannst, wirst du niemals sicher stellen können, ob der Wert etwas erwartetes darstellt.

    Ja, auch in der Praxis kommen durchaus öffentliche Member vor, je nach Programmieransatz. Aber in der Regel nur bei "dummen" Datenklassen ohne (oder mit wenig) Funktionalität. Andere Ansätze verbergen alles, und erlauben auch nur begrenzt Setter/Getter, sondern besagen das alle Werte nur in vollständigen Kontext geändert und abgerufen werden können.

    Der Zwischenschritt ist das Arbeiten mit Gettern und Settern, auch wenn dies ebenso von einigen nicht unbedingt als "sauber" empfunden wird. Es gibt aber dennoch einen unterschied zu öffentlichen Membern:
    1. Du kannst (auch nachträglich) noch Bereichsprüfungen hinzufügen.
    2. Du kannst bestimmte Zugriffe verhindern (z.B. hast du Werte die aus anderen Berechnet werden, und zwar gelesen aber nicht geschrieben werden sollen).
    3. Du kannst auch leichter Codeteile verschieben, wenn ein Objekt zu komplex wird, und die Getter dann im ersten Schritt umleiten, bevor du sie entfernst (Änderungen in kleinen Schritten sind meist einfacher zu testen).

    Dragon4411 schrieb:

    - Ich würde in der Regel eine Header-/Sourcedatei pro Klasse machen, und nicht mehrere Klassen zusammen in eine Datei einfügen.

    Sprich auch die anderen "Unterklassen"?

    Ich hantiere es so, und vor allem finde ich so Klassen auch leichter. Wenn die Anzahl wirklich groß wird, verteile ich die Klassen halt auf Unterverzeichnisse (Manche IDEs lassen auch virtuelle Verzeichnisse zu).

    Dragon4411 schrieb:

    - Basisklassen sollten entweder ein nicht-öffentlichen oder virtuellen Destruktor haben.

    Werde ich mri duchlesen, was die Vorteile sind und es heir auflisten damit es die anderen auch sehen.

    Kurz zusammen gefasst: Wenn du eine Klassenhirachie hast, die über Zeiger auf Basisklassen zugreift, kann es zu nicht freigegebenen Speicher führen, sofern der Destruktor nicht virtuell ist.



  • out schrieb:

    In C++ versteht man unter Objekt alles, ...

    Jajaja... Tut mir leid, ich programmiere nun einmal nicht komplett nur in C++ und verwende auch Begriffe aus der Objektorientierung.



  • asc schrieb:

    out schrieb:

    In C++ versteht man unter Objekt alles, ...

    Jajaja... Tut mir leid, ich programmiere nun einmal nicht komplett nur in C++ und verwende auch Begriffe aus der Objektorientierung.

    :p Du hast doch nichts falsches gesagt, ich wollte deinen Gedanken, für den TE, nur noch weiterführen. 🙂



  • asc schrieb:

    Dragon4411 schrieb:

    Ich hoffe ich hab das jetzt richtig verstanden:

    Konstruktoren und Destruktoren sind zuständig für erzeugen und die auflösung von Objekten.

    Ich würde es etwas anders formulieren: Der Konstruktor dient dazu ein Objekt mit einem konsistenten Zustand zu initialisieren, der Destruktor dient der Freigabe von Ressourcen (Neben Konstruktor und Destruktor kennt C++ noch mindestens zwei weitere Methoden: Zuweisungsoperator und Kopierkonstruktor, du solltest hier mal nach Regel der Drei bzw. Dreierregel schauen).

    Dragon4411 schrieb:

    Ein Konstruktor kann Werte definieren(Werte können in der Klasse selbst nochmals redefiniert werden).

    Wie von cooky451 schon geschrieben ist definieren hier ein sehr unpassendes Wort (Initialisieren / Zuweisen bzw. Überschreiben).

    Dragon4411 schrieb:

    Ein Destruktor löst das Objekt auf.

    Eher umgekehrt: Ein Destruktor wird aufgerufen wenn ein Objekt zerstört wird.

    Dragon4411 schrieb:

    Diest ist dem Scope einer Variable sehr ähndlich.

    Eine Variable umfasst auch Objekte. Wenn ich eine Klasse A habe ist "A a;" eine Variablendefinition, auch wenn hier ein Objekt einer Klasse gemeint ist. Der unterschied zu den Datentypen wie int ist nur das eine Klasse ein Konstruktor und Destruktor etc. besitzt. Für die Lebenszeit gibt es keine Unterschiede.

    Wie wird dann das Objekt aufgelöst?
    Das verwirrt mich einwenig :S

    Nächsten Montag oder Dienstag sollte ich meine 3 Bücher weider haben, dann kann ich endlich anfangen zu lesen 😃



  • Dragon4411 schrieb:

    Wie wird dann das Objekt aufgelöst?

    Die Instanz (oder im OO-Sinne das Objekt) wird am Ende des Scopes zerstört. Der Unterschied zu anderen Typen ist der, das mit der Erzeugung der Konstruktur oder Kopierkonstruktur, bei der Zuweisung der Zuweisungsoperator und bei der Zerstörung der Destruktor aufgerufen wird.

    Dies geschieht hinter den Kulissen, du kannst dies aber bei der dynamischen Allokation und Freigabe bemerken:

    Wenn du mit den C++ Funktionen new/delete arbeitest wird Konstruktor und Destruktor entsprechend behandelt. Wenn du mit den C Funktionen malloc/free arbeitest wird dies nicht gemacht, die C-Funktionen kennen keine Konstruktoren etc. (dies ist der Grund warum man diese Funktionen unter C++ tendenziell meiden, oder nur mit großer Sorgfalt verwenden sollte).

    Du selbst wirst wohl niemals direkt einen Destruktor aufrufen (es gibt einen Sonderfall, der ist aber so selten das ich dies hier nicht erläutern will).

    Wie dies genau im Hintergrund abläuft wirst du in nahezu keinen Buch finden. Dies ist auch eher theoretisches Wissen. Ich könnte mir denken, das das bereits recht alte Buch "The Design and Evolution of C++" vielleicht etwas dazu sagen könnte.



  • asc schrieb:

    generische Funktionen (Templatefunktionen)

    *Funktionstemplates



  • Du lernst es nie



  • out schrieb:

    Du lernst es nie

    Welcher Spaten klaut sich hier meinen - nicht registrierten - Benutzernamen. Shame on you. 🙄



  • out schrieb:

    out schrieb:

    Du lernst es nie

    Welcher Spaten klaut sich hier meinen - nicht registrierten - Benutzernamen. Shame on you. 🙄

    dann registriere dich doch.

    OT: irgendwie gehen mir die ganzen nicht registrierten Deppen so langsam auf den Keks. Ich habe das Gefühl, das das meistens "richtige" User sind, die da irgendeinen Mist hinrotzen wollen, ohne dass das unter ihrem Namen geschieht.



  • daddy_felix schrieb:

    out schrieb:

    out schrieb:

    Du lernst es nie

    Welcher Spaten klaut sich hier meinen - nicht registrierten - Benutzernamen. Shame on you. 🙄

    dann registriere dich doch.

    OT: irgendwie gehen mir die ganzen nicht registrierten Deppen so langsam auf den Keks. Ich habe das Gefühl, das das meistens "richtige" User sind, die da irgendeinen Mist hinrotzen wollen, ohne dass das unter ihrem Namen geschieht.

    *applaus*



  • registriert schrieb:

    *applaus*

    qed



  • Ich habe mal ein Teil eurer Vorschläge umgesetzt:

    stdafx.h

    #pragma once
    
    #include "targetver.h"
    #include <stdio.h>
    #include <tchar.h>
    #include <string>
    #include "Charakter.h"
    #include "Haendler.h"
    #include "Item.h"
    #include "Item.h"
    #include "Monsters.h"
    #include "NPC.h"
    #include "Quest.h"
    #include "QuestNPC.h"
    #include "Ruestungsteil.h"
    #include "Trank.h"
    #include "Waffe.h"
    

    Charakter.h

    #pragma once
    class Charakter : public Monster
    {
    public:
    	public:
    	int HelmWert;
    	int BrustWert;
    	int HandWert;
    	int ArmWert;
    	int HoseWert;
    	int GurtWert;
    	int SchuheWert;
    	int Schildwert; 
    	std::string HelmName;
    	std::string BrustName;
    	std::string HandName;
    	std::string ArmName;
    	std::string HoseName;
    	std::string GurtName;
    	std::string SchuheName;
    	std::string SchildName;
    	Charakter()
    	: 	HelmWert(0), 
    		BrustWert(0), 
    		HandWert(0), 
    		ArmWert(0), 
    		HoseWert(0), 
    		GurtWert(0), 
    		SchuheWert(0), 
    		Schildwert(0), 
    		HelmName(""), 
    		BrustName(""), 
    		HandName(""), 
    		ArmName(""), 
    		HoseName(""), 
    		GurtName(""), 
    		SchuheName(""), 
    		SchildName("")
    
    	{
    		//Konstruktorrumpf
    	}
    
    	Charakter( //Konstruktor mit Parametern
    	std::string HelmName, 
    	std::string BrustName,
    	std::string HandName,
    	std::string ArmName,
    	std::string HoseName,
    	std::string GurtName,
    	std::string SchuheName,
    	std::string SchildName,
    	int HelmWert, 
    	int BrustWert, 
    	int HandWert, 
    	int ArmWert, 
    	int HoseWert, 
    	int GurtWert, 
    	int SchuheWert, 
    	int Schildwert)
    	:	HelmName(HelmName),	//Zuweisung Parameter zur Membervariablen
    		BrustName(BrustName),
    		HandName(HandName), 
    		ArmName(ArmName), 
    		HoseName(HoseName), 
    		GurtName(GurtName), 
    		SchuheName(SchuheName), 
    		SchildName(SchildName), 
    		HelmWert(HelmWert), 
    		BrustWert(BrustWert),
    		HandWert(HandWert),
    		HoseWert(HoseWert),
    		GurtWert(GurtWert),
    		SchuheWert(SchuheWert),
    		Schildwert(Schildwert)
    	{
    
    	}
    	virtual ~Charakter(void);
    };
    

    Haendler.h

    #pragma once
    class Haendler : public Monster
    {
    public:
    	Haendler(void);
    
    	//Inventar
    
    	void Verkaufen()
    	{
    		//Gegenstände des Händlers anzeigen und verkaufen.
    	}
    
    	void Einkauf()
    	{
    		//Gegenstände des Charakters anzeigen und kaufen.
    	}
    	virtual ~Haendler(void);
    };
    

    Item.h

    #pragma once
    class Item
    {
    public:
    	Item(void);
    	std::string Name;
    	int Preis;
    	virtual ~Item(void);
    };
    

    Monster.h

    #pragma once
    class Monster 
    { 
    	public: 
    	int Leben;
    	int Mana;
    	int Geld;
    	int EXP;
    	int Level;
    	int Angriff;
    	int Verteidigung;
    	int Schaden;
    	int RuestungsWert; 
    	std::string WaffeName;
    	std::string Name;
    	Monster()
    	:	Name(""),
    		WaffeName(""),
    		Leben(0), 
    		Mana(0), 
    		Geld(0), 
    		EXP(0), 
    		Level(0), 
    		Angriff(0), 
    		Verteidigung(0), 
    		Schaden(0), 
    		RuestungsWert(0)
    
    	{
    		//Konstruktorrumpf
    	}
    
    	Monster( //Konstruktor mit Parametern
    	std::string const & MonsterName, 
    	std::string const & MonsterWaffeName,
    	int Leben, 
    	int Mana, 
    	int Geld, 
    	int EXP, 
    	int Level, 
    	int Angriff, 
    	int Verteidigung, 
    	int Schaden, 
    	int RuestungsWert)
    	:  Name(MonsterName),	//Zuweisung Parameter zur Membervariablen
    		WaffeName(MonsterWaffeName),
    		Leben(Leben), 
    		Mana(Mana), 
    		Geld(Geld), 
    		EXP(EXP), 
    		Level(Level), 
    		Angriff(Angriff), 
    		Verteidigung(Verteidigung), 
    		Schaden(Schaden), 
    		RuestungsWert(RuestungsWert)
    	{
    	}
    
    	void MonsterKampf()
    	{
    		//Kampfhandlung
    	}
    
    	virtual ~Monster(void) //Destruktor
    
    };
    

    NPC.h

    #pragma once
    class NPC : public Monster
    {
    public:
    	NPC(void);
        // Interaktionen
    
    	void Unterhalten()
    	{
    		//Smalltalk.
    	}
    	virtual ~NPC(void);
    };
    

    Quest.h

    #pragma once
    class Quest
    {
    	public:
    	Quest(void);
    	std::string Name;
    	std::string Beschreibung;
    	std::string Ziel;
    	std::string Geber;
    	std::string Abgaber;
    	std::string Status; 
    	int IDStatus;
    	enum  {Angenommen=1,Annehmbar=2,Abgebrochen=3,Abgeschlossen=4} ID;
    	~Quest(void);
    };
    

    QuestNPC.h

    #pragma once
    class QuestNPC : public Monster
    {
    public:
    	QuestNPC(void);
    	//Quest
    	void QuestGeben()
    	{
    		//Quest anzeigen, annehmen.
    	}
    
    	void QuestAbschliessen()
    	{
    		//Quest abschliessen, Belohnung geben.
    	}
    	virtual ~QuestNPC(void);
    };
    

    Ruestungsteil.h

    #pragma once
    class Ruestungsteil : public Item
    {
    public:
    	Ruestungsteil(void);
    	int Wert;
    	virtual ~Ruestungsteil(void);
    };
    

    Trank.h

    #pragma once
    
    class Trank : public Item
    {
    public:
    	Trank(void);
    	enum {HP=1,Mana=2} Typ;
    	int Wert;
    	virtual ~Trank(void);
    };
    

    Waffe.h

    #pragma once
    class waffe : public Item
    {
    public:
    	waffe(void);
    	int Angriff;
    	int WaffeVerteidigung;
    	int Schaden;
    	virtual ~waffe(void);
    };
    

    Des weiteren habe ich mir GEdanke gemacht über die Fortführung des Projektes.
    Ich möchte einige Änderungen vornehmen:

    - ICQ Gruppenchat erstellen.
    - Einen oder merhere Mentoren ernnen.

    Habt ihr noch änderungs Vorschläge oder Verbesserungen.

    Gruss,

    Dragon4411



  • Ich hoffe dir ist bewusst, dass das ganze Konzept was mit der stdafx.h einher geht kein Standard-C++ ist? (Da du ja eh #pragma once nutzt.. na ja, kann man auch später noch ändern wenn man will.)

    Dragon4411 schrieb:

    Ich habe mal ein Teil eurer Vorschläge umgesetzt:

    Nä, eher nicht. Immer noch einfach int genommen bei Dingen die float, unsigned oder u/intX_t sein sollten. Zudem keine Klasse für Rüstungen. std::string musst du nicht manuell initialisieren, das macht der schon selbst. Ein Parameterloser Konstruktor macht hier keinen Sinn, auch das wurde schon besprochen. Wenn keine Parameter erwartet werden reicht (), (void) ist in C++ unnötig. Zudem du das inkonsistent gemacht hast. In Zeile 13 steht übrigens Schildwert statt SchildWert, liest du deinen Code eigentlich noch mal durch, nachdem du ihn schreibst? Und seit wann ist ein Händler ein Monster? Und der Charakter? Und warum ist der Händler kein NPC? Und wozu hast du überhaupt eine Klasse NPC, wenn du QuestNPC dann wieder nur von Monster erben lässt? Und oh, du hast ja eine Klasse für Rüstungen. Warum zum Geier benutzt du sie dann nicht auch? Und bei der Quest Klasse erstellst du ein enum ID, aber anstatt das zu nutzen hast du noch 2 separate Variablen die den Queststatus speicher, ein string und ein int. Was denn jetzt. Argh. Dazu noch ein lehrer, nicht virtueller Destruktor - warte, der ist ja doch virtuell. Warum steht das dann nicht sofort da? Und deine Klasse "waffe" schreibst du jetzt plötzlich klein statt wie sonst alle Klassennamen groß, entscheide dich. (Was irgendwie den Verdacht verstärkt, dass du dir den Code nicht noch mal durchgelesen hast, das springt doch sofort ins Auge.)

    Bleibt also zusammenzufassen: Sieht aus wie verständnislos zusammenkopiert, und dabei haste noch nicht mal deinen Compiler drüber schauen lassen, der sollte an ein paar Stellen nämlich meckern. Lies deinen Code noch mal ganz genau durch, und frag dich bei jeder Zeile warum sie da steht, was sie macht, etc.



  • cooky451 schrieb:

    Ich hoffe dir ist bewusst, dass das ganze Konzept was mit der stdafx.h einher geht kein Standard-C++ ist? (Da du ja eh #pragma once nutzt.. na ja, kann man auch später noch ändern wenn man will.)

    Dragon4411 schrieb:

    Ich habe mal ein Teil eurer Vorschläge umgesetzt:

    Nä, eher nicht. Immer noch einfach int genommen bei Dingen die float, unsigned oder u/intX_t sein sollten. Zudem keine Klasse für Rüstungen. std::string musst du nicht manuell initialisieren, das macht der schon selbst. Ein Parameterloser Konstruktor macht hier keinen Sinn, auch das wurde schon besprochen. Wenn keine Parameter erwartet werden reicht (), (void) ist in C++ unnötig. Zudem du das inkonsistent gemacht hast. In Zeile 13 steht übrigens Schildwert statt SchildWert, liest du deinen Code eigentlich noch mal durch, nachdem du ihn schreibst? Und seit wann ist ein Händler ein Monster? Und der Charakter? Und warum ist der Händler kein NPC? Und wozu hast du überhaupt eine Klasse NPC, wenn du QuestNPC dann wieder nur von Monster erben lässt? Und oh, du hast ja eine Klasse für Rüstungen. Warum zum Geier benutzt du sie dann nicht auch? Und bei der Quest Klasse erstellst du ein enum ID, aber anstatt das zu nutzen hast du noch 2 separate Variablen die den Queststatus speicher, ein string und ein int. Was denn jetzt. Argh. Dazu noch ein lehrer, nicht virtueller Destruktor - warte, der ist ja doch virtuell. Warum steht das dann nicht sofort da? Und deine Klasse "waffe" schreibst du jetzt plötzlich klein statt wie sonst alle Klassennamen groß, entscheide dich. (Was irgendwie den Verdacht verstärkt, dass du dir den Code nicht noch mal durchgelesen hast, das springt doch sofort ins Auge.)

    Bleibt also zusammenzufassen: Sieht aus wie verständnislos zusammenkopiert, und dabei haste noch nicht mal deinen Compiler drüber schauen lassen, der sollte an ein paar Stellen nämlich meckern. Lies deinen Code noch mal ganz genau durch, und frag dich bei jeder Zeile warum sie da steht, was sie macht, etc.

    Das mit (void) macht mein MVS 2008 automatisch, daher dachte ich das es richtig ist.

    Was meinst du mit: "Warum steht das dann nicht sofort da"?
    Und wo ist das: "std::string musst du nicht manuell initialisieren, das macht der schon selbst. Ein Parameterloser Konstruktor macht hier keinen Sinn"?

    Waffe gross/klein hab ich bereits geändert, aber vergessen im Post zu ändern :S

    Einige Klassen werden nicht benutzt (zur Zeit) das ist richtig.
    Die werden noch benutzt 😉

    Ich hab mich Entschiden Gegner als Monster zu erstellen, Charakter als ein Monster mit "Zusatzwerten" und einen NPC ebenfals als Monster da diese dann nur sprechen müssen.

    Ich hab ein paar Sachen angepasst und der Compeiler gibt keinen Error aus.

    Bitte nicht vergessen ich bin Anfänger und bin gern offen für Ratschläge und Hilfestellungen.
    Das ich die Typen alle als int oder String deklariert habe, ist schlicht und einfach das ich es simpel halten möchte.

    Gruss,
    Dragon



  • Darf ich noch schnell Fragen ob ich das richtig sehe, ich könnte fast immer unsigned int nehmen?
    Da die Werte nie im - Bereich?

    Gruss&Danke,

    Dragon



  • Dragon4411 schrieb:

    Darf ich noch schnell Fragen ob ich das richtig sehe, ich könnte fast immer unsigned int nehmen?
    Da die Werte nie im - Bereich?

    Bin selber noch Anfänger, hatte dir auch ne Mail geschrieben. 😉
    MMn kannst du unsigned int für alles nehmen, außer Werte, wie wenn z.b. ein Rüstungsteil zwar +5 auf Stärke, aber -2 auf Konstitution gibt. (grade gesehen, dass solche Attribute nicht vorkommen, sry :))
    Geld kannst du auch int lassen, wenns nen Dispo geben soll, wär auch mal was 😃

    berichtigt mich, wenn ich was falsches gesagt habe 🙂



  • Ich schreib dir mal ein kleines Beispiel:

    struct primary_attributes
    {
      float strength;
      float dexterity;
      float stamina;
      // ...  
      primary_attributes(float strength, float dexterity, float stamina)
        : strength(strength)
        , dexterity(dexterity)
        , stamina(stamina)
        // ...
      {}
    };
    
    struct attributes // Diese Attribute folgen aus primary_attributes + Rüstung und müssen dementsprechend neu berechnet werden, wenn z.B. etwas anderes angelegt wird.
    {
      float health;
      float mana;
      // ...
      attributes(float health, float mana)
        : health(health)
        , mana(mana)
      {}
    };
    

    Warum float? Weil diese Dinge durch eventuelle Modifier etc. (z.B. 1.5% mehr Lebenspunkte) verändert werden. Das sind keine diskreten Werte, könnte man auch sagen.

    struct equipment : public item
    {
      enum equip_type
      {
        helm, 
        pants, 
        // ..
      };
      equip_type type; // SO nutzt man enum
      std::string name; // Wenn man extra Namen möchte "Todeshose der Zerstörung", oder was da so üblich ist.
      std::uint16_t value; // Basis-Rüstungswert / Schaden bei Waffen
    
      equipment(equip_type type, const std::string& name, std::uint16_t value)
        : type(type)
        , name(name)
        , value(value)
      {}
    };
    
    // Hier könnte man uU auch Vererbung einsetzen, aber das muss man an den Rest anpassen und ist wohl teilweise auch Geschmackssache.
    
    // Aber wichtig ist:
    
    class character
    {
      std::unique_ptr<equipment> helm_slot_; // Nutze deine Klassen! Wozu hast du sie denn sonst?
      std::unique_ptr<equipment> pants_slot_; // Die Idee hier ist, wenn der Pointer 0 ist, ist der slot nicht besetzt
      // ..
      // Da würde man bei Vererbung natürlich den richtigen Typ angeben.
    
      std::uint64_t experience_;
      std::uint64_t gold_; // Von mir aus auch std::int64_t, 
      // aber "int" kann auch 2 byte groß sein, das läuft dann über wenn man mehr als 32767 gold hat.
    
      primary_attributes primary_attributes_;
      attributes attributes_;
    
      // ...
    
      character(std::uint64_t xp, std::uint64_t gold, primary_attributes pa, attributes a, /* ... */)
        : // ...
      {}
    };
    

    So, das nur mal als kleines Beispiel, wie man so etwas aufbauen kann. Was bringt dir eine Rüstungsklasse, wenn du sie nicht benutzt?

    berichtigt mich, wenn ich was falsches gesagt habe 🙂

    Siehe mein Kommentar zu int. 😉



  • cooky451 schrieb:

    Ich schreib dir mal ein kleines Beispiel:

    struct primary_attributes
    {
      float strength;
      float dexterity;
      float stamina;
      // ...  
      primary_attributes(float strength, float dexterity, float stamina)
        : strength(strength)
        , dexterity(dexterity)
        , stamina(stamina)
        // ...
      {}
    };
    
    struct attributes // Diese Attribute folgen aus primary_attributes + Rüstung und müssen dementsprechend neu berechnet werden, wenn z.B. etwas anderes angelegt wird.
    {
      float health;
      float mana;
      // ...
      attributes(float health, float mana)
        : health(health)
        , mana(mana)
      {}
    };
    

    Warum float? Weil diese Dinge durch eventuelle Modifier etc. (z.B. 1.5% mehr Lebenspunkte) verändert werden. Das sind keine diskreten Werte, könnte man auch sagen.

    struct equipment : public item
    {
      enum equip_type
      {
        helm, 
        pants, 
        // ..
      };
      equip_type type; // SO nutzt man enum
      std::string name; // Wenn man extra Namen möchte "Todeshose der Zerstörung", oder was da so üblich ist.
      std::uint16_t value; // Basis-Rüstungswert / Schaden bei Waffen
    
      equipment(equip_type type, const std::string& name, std::uint16_t value)
        : type(type)
        , name(name)
        , value(value)
      {}
    };
    
    // Hier könnte man uU auch Vererbung einsetzen, aber das muss man an den Rest anpassen und ist wohl teilweise auch Geschmackssache.
    
    // Aber wichtig ist:
    
    class character
    {
      std::unique_ptr<equipment> helm_slot_; // Nutze deine Klassen! Wozu hast du sie denn sonst?
      std::unique_ptr<equipment> pants_slot_; // Die Idee hier ist, wenn der Pointer 0 ist, ist der slot nicht besetzt
      // ..
      // Da würde man bei Vererbung natürlich den richtigen Typ angeben.
    
      std::uint64_t experience_;
      std::uint64_t gold_; // Von mir aus auch std::int64_t, 
      // aber "int" kann auch 2 byte groß sein, das läuft dann über wenn man mehr als 32767 gold hat.
    
      primary_attributes primary_attributes_;
      attributes attributes_;
    
      // ...
    
      character(std::uint64_t xp, std::uint64_t gold, primary_attributes pa, attributes a, /* ... */)
        : // ...
      {}
    };
    

    So, das nur mal als kleines Beispiel, wie man so etwas aufbauen kann. Was bringt dir eine Rüstungsklasse, wenn du sie nicht benutzt?

    berichtigt mich, wenn ich was falsches gesagt habe 🙂

    Siehe mein Kommentar zu int. 😉

    Danke schön 😃
    Schau mir das ganze sofort an und versuche es zu verstehen.

    Das mit den 1.5% (als beispiel) wollte ich ja nicht machen daher hab ich das Leben als int definiert.
    Eine Rüstung hat bei mir zur Zeit nur einen Rüstungswert.
    Später evtl. Leben+40.



  • xStrykex schrieb:

    Dragon4411 schrieb:

    Darf ich noch schnell Fragen ob ich das richtig sehe, ich könnte fast immer unsigned int nehmen?
    Da die Werte nie im - Bereich?

    Bin selber noch Anfänger, hatte dir auch ne Mail geschrieben. 😉
    MMn kannst du unsigned int für alles nehmen, außer Werte, wie wenn z.b. ein Rüstungsteil zwar +5 auf Stärke, aber -2 auf Konstitution gibt. (grade gesehen, dass solche Attribute nicht vorkommen, sry :))
    Geld kannst du auch int lassen, wenns nen Dispo geben soll, wär auch mal was 😃

    berichtigt mich, wenn ich was falsches gesagt habe 🙂

    Danke dir das du dir die Mühe machst mir zu Antworten.
    Du hast recht, werde die Datentypen nun anpassen.


Anmelden zum Antworten