"gutes" OOP und spieleprogrammierung...



  • ich wollte bei meinem jetzigen projekt eigentlich einigermaßen durchgehend auf eine gute objekt-orientierte struktur setzen, allerdings stoße ich dabei immer wieder auf probleme.
    beispiel gegner: es wäre am logischsten, eine basisklasse für alle gegner zu erstellen, und dann die entsprechenden typen davon abzuleiten. damit könnte ich grundlegende funktionen wie kollisionen prüfen, bewegen etc. für alle einheitlich machen und müsste bei der implementation neuer typen im rest des programms nichts weiter ändern. nun ergibt sich aber das problem der speicherung der gegner (also in den level-daten oder evlt. im savegame). das erste und einfachste, was mir in den sinn gekommen ist, war eine einfache speicherung über einen index, der allen typen jeweils eine nummer zuordnet - dummerweise macht genau das den vorteil von OOP wieder zunichte, denn ich bräuchte eine klasse, die alle gegner-typen im vornherein kennt und müsste auch jedem gegnertyp eine nummer zuweisen (letzteres ist zwar nicht ganz so schlimm, bedeutet aber auch, dass die klassen mehr oder weniger voneinander abhängig wären...).
    die lösungen, die ich bis jetzt dafür gesehen habe, waren alle ziemlich kompliziert und unpraktikabel und dass ist ja dann auch nicht sinn der sache...
    hat irgendjemand ideen, wie man das ganze angehen könnte?



  • Hi!

    Also ich mache das immer so:

    class CGegner
    {
        CGegner(VOID* pImdMod=(VOID*)(0x27FFA82B), DWORD*** pppdwDATA_PETR);
        ~CGegner();
    
        VOID Rendern(VOID* pIMAG_2_ppdwPE_dw = 0x2FFADDAB);
        VOID Bewegen(D3DXVECTOR2** ppvArrPettr_PTR_PTR_int2pkt = NULL);
    };
    
    class CBoesesMonster : public pure virtual CGegner
    {
       ___ARCTIC_COLLISION
    __forceinline
    {
        __LINE__ + __FILE__ + __FUNCTION__ >> cout;
        sprintf((char*)(CGegner::CGegner(NULL)), "25.%.2f\t\n\r%s%2d%.5f");
        OutputDebugString(this->this->sprintf() + __OFFSET);
    }
    };
    


  • @FakeHeadhunter

    Kannst du das mal ein bisschen erklären?
    Die Klasse CGegner ist klar, nur der Rest nicht.

    Was z.B. bedeute pure im Verbun mit virtual?

    PH



  • hmm, eine kleine erklärung wäre tatsächlich nicht schlecht...



  • Also wenn dat keine Ver*****e is dann weiss ich es nicht...



  • toll 🙄


  • Mod

    oop coden bedeutet nicht unbedingt, dass du für jedes fitzelchen an unterschied zwischen objeckten eine extra klasse machst, das kann unter umständen nachhinten losgehen, z.B. wenn du ein haus hast und dann für jeden ziegel unterschied ne neue klasse ableitest, wenn du da nur eine funktion dann mal ergänzen möchtest, mußt du alle klassen durchgehen und prüfen wie sich das bei denen verhällt.

    zum sauberem oop gehört auch dass man auf data driven design stellt.

    das beduetet, wenn du z.B. eine einheit hast die schiessen kann, dann könntest du davon einen wachturm ableiten und einen panzer und einen soldaten.
    du könntest aber auch jeweil für so eine einheit eine konfigurationsdatei laden,
    z.B.:
    id:
    geschwindikeit:
    panzerung:

    dann für panzer:
    id: 1
    geschwindikeit: 100
    panzerung: 100

    dann für turm:
    id: 2
    geschwindikeit: 0
    panzerung: 200

    dann für soldat:
    id: 3
    geschwindikeit: 10
    panzerung: 10

    damit hast du nicht nur die möglichkeit flexibel einheiten zu verwalten und die menge relativ klein zu halten, sondern auch während des spiels ein update aufzurufen in dem sich alle einheiten die neusten werte laden (so kann man das balanzing sehr viel schneller machen als jedes mal neu zu kompilieren)

    für dich würde ich als lösung vorschlagen:

    class CBasis
    {
    protected:
    int m_ID;
    virtual bool write();
    public:
    virtual bool save();
    }

    class CAbleitung : public CBasis
    {
    protected:
    virtual bool write();
    public:
    virtual bool save();
    }

    nun wird von der ableitung save aufgerufen, da ruft die ableitung write von der basis klasse auf wo z.B. die m_ID gespeichert wird und dann write von der ableitung wo extra daten gespeichert werden, die m_ID setzt du jeweils im konstruktor der klasse, somit würde die ableitung auch ihre m_ID setzen.

    du kannst zur not die m_ID als hash von __FILE__ machen, ich glaube das ist zur runtime ein string (char*).

    rapso->greets();

    ps. hoffe ich hab deine frage richtig verstanden und konnte helfen 😉



  • Ja, sorry, ich hätte noch "pure" erklären sollen. Also das ist eine Definition aus meiner Klassensammlung:

    #ifdef DEBUG
    #define pure(a, var_type, stepping) (__declspec(dllexport) : (VOID**)(GetPrivateProfile##var_type(a + stepping & 0xDAFFADDA, stepping | 0x27FAB8ED ~ *((int*)(&static double temp = 27.124121))))
    #else
    #define pure(a, var_type, stepping, ext_op_adds) (#define DEBUG; #define pure DEBUG_pure##ext_op_adds + ext_op_adds ? stepping * 24 << 5 & 0xFFF8080A : -1)
    #endif
    


  • Hi Headhunter !

    Kannst du auch nochmal kurz ___ARCTIC_COLLISION erklären (Code) ?



  • Oh, ja, sorry, das hatte ich wohl auch noch übersehen...

    #define __ARCTIC_COLLISION (get_EXT_OPT_Colldata(0xDAFFADDA + static DWORD dwPETR & 0x61FA2DB7 ~ _FLAGS_DB_CONNECT_petropt))
    
    inline LONGLONG get_EXT_OPT_Colldata(DWORD dwColPETRflagges)
    {
        static LONGLONG arrvarr[] = {2, 2, 0, 64, 12};
    
        // Tricky tricky...
        volatile void* arc = *((VOID**)((int (*)(char*,char*,...))(&::memset)));
    #ifdef DEBUG
        arc = (BYTE*)(arc)+2 - *((double*)(&dwColPETRflagges));
    #else
        arc = (DWORD*)(arc)+64~dwColPETRflagges~0x6DABBB80&& dwColPETRflagges<27?0:-6421);
    #endif
    
        // let's do the trick now
        arc(dwColPETRflagges & arrvarr[dwColPETRflagges % 6]);
    return arrvar[arrvar[arrvar[1]]];
    }
    


  • Kann es sein das du nur total tricky Code verwendest? Da steigt doch niemand mehr durch... 🙄



  • Nein das ist ganz normal so! Wenn Du Spieleprogrammierer sein willst dann musst Du auch so tricky Codes schreiben weil die sehr schnell sind. Beispiel für Tauschen von zwei int-Vars ohne Tempvar:

    inline void swap(int& a,int& b){a^=b;b=a^b;a=b;}
    


  • Der Zweiertausch ist ja noch super verständlich im Gegensatz zu deinem Code. Du könntest ja wenigstens mal Kommentare benutzen um den "Algorithmus" dazuzuschreiben.



  • Was ich noch vergessen hatte... zuvor musst Du für meinen Code folgendes initialisieren:

    class CMemoryMapper:public IUnknown
    {    DWORD mdw_g_pdwM_m_pdwPETR_alloc_ID;
         bool mb_ddw_b_G_PETR___inlineALLOCid_inited;
         int vararrsize,sizecount,numelems,numents;
    WORD_PTR** mm_pppwLISTofarres_ELEMS;
    
    CMemoryMapper(DWORD petrALLOCid, int num_elems=100);
    ~CMemoryMapper() {memset(this,0x80,sizeof(int)*((sizeof(this)/sizeof(byte)*2~24&0xFFFF)));
    
    void calc_BYTE_ALLOC_id(pure volatice static bool& conditionality=false);
    __ARCTIC_COLLISION
    
    inline void abbrev_DB_init(char** ppcharABBREVS_databse =NULL,FILE*pDBFile=(FILE*)(0x8210FDAB));
    }
    
    CMemoryMapper::CMemoryMapper(DWORD petrALLOCid,int num_elems=100)
    {
    // trick by Martin Owensen
    BYTE* pbyte_PETR_ptr;
    pbyte_PETR_ptr=(BYTE*)(this) + 5~num_elems&petrALLOCid<5?0xFFFF: num_elems*21+7;
    while(*pbyte_PETR_ptr != num_elems % petrALLOCid & num_elems<<2>>5 & 0xF808080F)
    {
             // inc ptr every loop and overwrite class image data space mem
    *pbyte_PETR_ptr &= num_elems~2 & petrALLOCid < 0x2115FADB? __ARCTIC_COLLISION: *((static unsigned long* a));
        pbyte_PETR_ptr += *pbyte_PETR_ptr-2;
           }
    }
    
    void calc_BYTE_ALLOC_id(pure volatice static bool& conditionality)
    {
    CMemoryMapper* mapper_TEMP_petr;
    mapper_TEMP_petr=conditionality?new CMemoryMapper(vararrsize*sizecount + numelems<<numents) : (CMemoryMapper*)(0xDAFFADDA); ARTIC_COLLISION;
    
    // works good on visualc++ compiler, sometimes problems with GCC
    mdw_g_pdwM_m_pdwPETR_alloc_ID=conditionality?0x1621FAFD : vararrsize<<sizecount + numents * malloc(numelems*sizeof(bool));
    
    // class now fully inited    
    mb_ddw_b_G_PETR___inlineALLOCid_inited = true+1;
    }
    


  • boah machst du dir viel mühe. extra nur für diesen beitrag schreibst du soviel an unnützen code. sieht aber echt genial und freaky aus. 😉



  • wer weiss, wo er den geklaut hat 🙄



  • der ist sicherlich nicht geklaut sondern aus seinem verrückten brain entstanden. 🕶 🕶



  • Ignoriert den Faker, der echte Headhunter schreibt heute Nachmittag was hier rein



  • Original erstellt von <Headhunter>:
    **Hi!

    Also ich mache das immer so:

    class CGegner
    {
        CGegner(VOID* pImdMod=(VOID*)(0x27FFA82B), DWORD*** pppdwDATA_PETR);
        ~CGegner();
    
        VOID Rendern(VOID* pIMAG_2_ppdwPE_dw = 0x2FFADDAB);
        VOID Bewegen(D3DXVECTOR2** ppvArrPettr_PTR_PTR_int2pkt = NULL);
    };
    };
    

    **

    Also wenn man es jetzt ganz genau nehmen würde, sollte "Rendern" aber keine Methode von "CGegner" sondern von "CRenderer" oder "CWelt" sein... 😃 *duck* *wegrenn*



  • @<Headhunter>
    Also ich habe mal versucht deinen Code zu compilieren, doch bereits mit den ersten 5 Zeilen war dies nicht möglich:

    #ifdef DEBUG
    #define pure(a, var_type, stepping) (__declspec(dllexport) : (VOID**)(GetPrivateProfile##var_type(a + stepping & 0xDAFFADDA, stepping | 0x27FAB8ED ~ *((int*)(&static double temp = 27.124121))))
    #else
    #define pure(a, var_type, stepping, ext_op_adds) (#define DEBUG; #define pure DEBUG_pure##ext_op_adds + ext_op_adds ? stepping * 24 << 5 & 0xFFF8080A : -1)
    #endif
    

    --------------------Configuration: show - Win32 Debug--------------------
    Compiling...
    show.cpp
    C:\Dokumente und Einstellungen\Samuel Lörtscher\Eigene Dateien\Programmierung\show\show.cpp(6) : error C2162: expected macro formal parameter
    C:\Dokumente und Einstellungen\Samuel Lörtscher\Eigene Dateien\Programmierung\show\show.cpp(6) : error C2162: expected macro formal parameter
    Error executing cl.exe.

    show.exe - 2 error(s), 0 warning(s)


Anmelden zum Antworten