Zeiger auf Objekt in Vektor speichern



  • Grüße! Ich bin neu hier, zunächst einmal jedem ein frohes Fest! :xmas1:

    Beschäftige mich seit einiger Zeit mit C++, und möchte mich an einem Text-RPG versuchen. Dazu habe ich mir ein "Item-Handling"-System überlegt.
    Jedes Item soll eine Klasse sein. Weiters soll es eine Slot-Klasse geben, daher der Rucksack, in den man Items packen kann 😋
    Habe mir das etwa so vorgestellt:

    class CHealpotion
    {
    public:
    	void use()
    	{
    	}
    }; CHealpotion oHealpotion; CHealpotion *ptrCHealpotion = &oHealpotion;
    
    class CSlots
    {
    }; CSlots* oSlots[5];
    

    "ptrCHealpotion" ist dann sozusagen der Zeiger auf das Item. Diesen möchte ich nun in der CSlots-Klasse in einen Vektor speichern. Allerdings funktioniert das nicht, da man anscheinend in diesen Klassen-Vektor nur Objekte der eigenen Klasse speichern kann.

    (oSlots[0] = ptrCHealpotion funktioniert nicht)

    Mein Ziel ist es, ein dynamisches Inventar zu schreiben. Items werden in einen Slot geschoben, wieder entfernt, usw.
    Man soll dann zB. nicht

    oHealpotion.use();

    schreiben müssen, sondern eher:

    slot[0].use();

    oder so ähnlich.
    Dann wird das Item in Slot 1 benutzt.

    Ich hoffe, man kann so etwas realisieren. Aber ich denke schon.
    MfG,
    Aedyn



  • ja, das stimmt. z.b. in einem string vector kann man nur strings speichern.

    du kannst aber ein int vector definieren, dann kannst du die zeiger die auf unterschiedliche klasenobjekte zeigen, speichern.

    Ich weiss, aber nicht ob es so sinnvoll ist, zu jedem objekt, dann einen ptr zu erzeugen denn du dann speicherst. sinnvoller wäre es gleich den this zeiger zu speichern. hmmm vielleicht so in der art

    class Test{
    
    .....
    int GetObject(){ return this;}
    
    }
    

    frohe xmas :xmas1: :xmas1: :xmas2: :xmas1: :xmas1:



  • Wenn ich dich richtig verstanden habe, könntest du eine Basisklasse "item" machen,
    und davon die richtigen Items ableiten.

    class item
    {
    public:
        item() {}
        virtual ~item() {}
    
        virtual void use() = 0;
    };
    
    class healpotion : public item
    {
    public:
        healpotion() : item() {}
        ~healpotion() {}
    
        void use() { // bla }
    };
    
    std::vector<item*> slots;
    
    slots.push_back(new healpotion());
    
    slots.back().use();
    


  • Für nen kleines Spiel ist die Variante von leo_ super, aber wenn du mal was größeres machst, solltest du dir ne allgemeine item-Klasse schreiben und die einzelnen items in einer Metasprache (kannst zB xml nehmen).
    So kannst du sauber Daten und Code trennen und jeder hat die Möglichkeit neue Gegenstände hinzuzufügen. Soll nur nen kleiner Hinweis am Rande sein, den du dir im Hinterkopf behalten solltest 🙂



  • Wie ich mit XML Items definiere, ist mir ein Rätsel. Sollte das nicht eine Klasse sein? Ich gehe jetzt von einem großen Softwareprojekt aus.

    Wie könnte ich das mit den Items + Inventar nun am besten hinbekommen?
    Wichtig ist wiegesagt nur:

    Items sollen sich in Slots schieben lassen, dann soll slot.use(); ausgeführt werden können.



  • So wie ich es dir gezeigt habe? o_O



  • <?xml version="1.0"?>
    
    <item id="health_potion">
        <type>Potion</type>
        <usedSlots>1</slots>
        <onUse>player.health + 10</onUse>
    </item>
    

    oder (mit eigener Syntax) z.B.

    item health_potion:
        type : potion
        usedSlots : 1
        onUse : player.health \
                + 10
    

    Sowas in der Art (die genauen Elemente solltest du dir dann selbst überlegen). Das parst du dann (vor allem den onUse Teil, z.B. mit Lambda-Ausdrücken) und feddich.

    Die Idee ist, dass die existierenden und machbaren Items nicht von deiner Klassenstruktur abhängig sind. Das macht das Itemsystem deutlich flexibler, beispielsweise wenn du zufällige Items willst.

    BTW, im Moment ist da ein Speicherleck, du solltest, wenn ein vector die Zeiger selbst verwaltet und nicht nur benutzt sowas verwenden.



  • @leo_

    Ob das Ableiten so gut ist? Ich weiß nicht so recht. Wenn ich dann mit XML arbeite, geht das dann überhaupt noch



  • Aedyn schrieb:

    @leo_

    Ob das Ableiten so gut ist? Ich weiß nicht so recht. Wenn ich dann mit XML arbeite, geht das dann überhaupt noch

    Nein, das geht dann natürlich nicht. Aber wie "User--" schon gesagt hat,
    solltest du meine Methode nur bei kleineren Projekten verwenden.



  • Eben, ich möchte aber gleich eine Methode, die man bei großen Projekten verwenden kann.



  • @ajax

    #include <iostream> 
    
    class CHealpotion 
    { 
    public: 
    	int GetObject()
    	{ 
    		return this;
    	}
        void use() 
        { 
        } 
    }; CHealpotion oHealpotion;
    
    void main()
    {
    	int slot[5];
    	slot[0] = oHealpotion.GetObject();
    }
    

    Das funktioniert nicht!
    Weil:

    Error C2440: 'return' : 'class CHealpotion *const ' kann nicht in 'int' konvertiert werden

    MfG,
    Aedyn



  • Ich glaub die Meta-Metode solltest du noch etwas aufschieben, komm erstmal mit C++ klar (und da ist leo_s System wirklich ne super Übung) und dann kann man sowas immernoch machen.

    Ich würde im Übrigen das Verhalten in XML einfach als embedded LUA machen (so wie es auch in world of warcraft der Fall ist).



  • Zu früh abgeschickt.

    #include <iostream>
    
    class CHealpotion
    {
    public:
        int GetObject()
        {
            return this;
        }
        void use()
        {
        }
    }; CHealpotion oHealpotion;
    
    void main()
    {
        int slot[5];
        slot[0] = oHealpotion.GetObject();
    }
    

    Mach das mal so:

    #include <iostream>
    
    class Item
    {
      public:
        virtual void use() = 0;
    };
    
    class Healthpotion : public Item
    {
      public:
       virtual void use()
       {
          std::cout << "Player restores 50 hitpoints";
       }
    };
    
    int main()
    {
      Item* slots[ 15 ];
      slots[ 0 ] = new Healthpotion;
    
      slots[ 0 ]->use();
    
      delete slots[ 0 ];
    }
    


  • Jo danke hat mir um einiges weitergeholfen. Stimmt, ich werde mich zunächst weiter in der Sprache üben.

    Nun, eine Frage noch, was ist "embedded LUA" ?

    Tatsächlich denke ich beim programmieren an World of Warcraft, solche Systeme zu entwickeln finde ich sehr interessant.



  • LUA ist einfach eine Skriptsprache, dazu findest bei google tonnenweise Infos und mit embedded meinte ich einfach, statt einem separaten lua-file den lua-code direkt in die XML-Datei zu schreiben.



  • Okay ich möchte es mal mit deinem Beispiel probieren.
    Habe aber schon das Problem mit Zugriffen. Die Item und Healthpotion-Klasse sind in einem Header, die Player Klasse auch.

    main.cpp

    #include <iostream> 
    #include "main.h"
    
    void main() 
    { 
      Item* slots[15]; 
    
      slots[0] = new Healthpotion;
    
      slots[0]->use(); 
      delete slots[0]; 
    }
    

    items.h

    #ifndef _ITEMS_H_
    #define _ITEMS_H_
    
    class Item 
    { 
    public: 
    	virtual void use() = 0; 
    }; 
    
    class Healthpotion : public Item 
    { 
    public: 
    	virtual void use() 
    	{ 
    		std::cout << "Player restores 50 hitpoints"; 
        } 
    }; 
    
    #endif
    

    main.h

    #ifndef _MAIN_H_
    #define _MAIN_H_
    
    #include "items.h"
    
    class PLAYER
    {
    public:
    	signed health;
    };
    
    #endif
    

    Wie kann ich von der use()-Funktion auf player.health zugreifen?



  • Du könntest der use-Funktion noch nen Parameter spendieren:

    #ifndef _MAIN_H_
    #define _MAIN_H_
    
    #include "items.h"
    
    class PLAYER
    {
    public:
        signed health;
    };
    
    #endif
    
    #ifndef _ITEMS_H_
    #define _ITEMS_H_
    
    class Item
    {
    public:
        virtual void use( PLAYER& entity ) = 0;
    };
    
    class Healthpotion : public Item
    {
    public:
        virtual void use( PLAYER& entity )
        {
            std::cout << "Player restores 50 hitpoints";
            entity.health += 50;
        }
    };
    
    #endif
    
    #include <iostream>
    #include "main.h"
    
    int main()
    {
      Item* slots[15];
    
      slots[0] = new Healthpotion;
    
      PLAYER player;
      player.health = 30;
    
      slots[0]->use( player );
    
      delete slots[0];
    }
    

    Statt PLAYER könntest du auch ne Basisklasse machen die für alle Charaktere im Spiel gültig ist, dann können NPCs auch Gegenstände verwenden/besitzen.



  • d:\c++\rpgtest\items.h(7) : error C2061: Syntaxfehler : Bezeichner 'PLAYER'
    d:\c++\rpgtest\items.h(13) : error C2061: Syntaxfehler : Bezeichner 'PLAYER'
    d:\c++\rpgtest\main.cpp(13) : error C2660: 'use' : Funktion akzeptiert keine 1 Parameter



  • Du musst im Item-Header die PLAYER-Klasse sichtbar machen, dazu musst den entsprechenden Header inkludieren.


Anmelden zum Antworten