Aktuelle Zeit: 12.05.2025, 23:18

Alle Zeiten sind UTC + 1 Stunde




Ein neues Thema erstellen Auf das Thema antworten  [ 15 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
BeitragVerfasst: 18.04.2009, 20:21 
Offline
Benutzeravatar

Registriert: 23.03.2009, 18:52
Beiträge: 23
Wohnort: Bremen
Hallo zusammen,

ich bin relativ neu hier im Forum und habe gerade erst meine ersten Gehversuche
mit Irrlicht gemacht. Ich habe allerdings schon einige Erfahrungen mit Python, C++, (und wx),
Java und der A6-Engine gemacht und möchte nun ein Spiel mit Irrlicht in C++ programmieren.
Ich habe mir nun, nachdem ich einige Tests mit Irrlicht gemacht habe und mich etwas über
OpenAl und ODE schlau gemacht habe, einige Vorüberlegungen zur Struktur gemacht.

Ich habe mir vorgestellt, das Spiel modular über verschiedene Manager aufzubauen, so dass
es einen Gamemanager gibt, der das gesamte Spiel steuert und andere Manager für Entities
usw. benutzt, um den Spielfluss zu regeln. Meine Frage ist jetzt, ob der Ansatz so sinnvoll ist,
oder ob sich da ein erfahrener Entwickler die Haare rauft. Gibt es Dinge, die geändert werden sollten,
oder gibt es bessere Methoden? Ich habe hier einmal die wesentlichen
Eigenschaften zusammengefasst (einiges ist auch schon implementiert):


GameManager
  • fängt Events ab und bietet anderen Managern eine Schnittstelle,
    um diese Abzufragen (z.B. isKeyDown(TASTE_SPRINGEN))
  • steuert GameStates (STATE_MAIN_MENU, STATE_GAME usw.)
  • hat eine Methode MainLoop, welche die Hauptschleife beinhaltet,
    die Hauptschleife ruft dabei verschiedene Funktionen wie
    "smgr->drawAll" oder "physicsmanager->doPhysics" auf

SoundManager
  • nutzt OpenAl
  • hat eine eigene virtuelle Welt
  • spielt 3D-Sounds, die permanent abgespielt werden, wie z.B.
    das Rauschen eines Wasserfalls
  • spielt 3D-Sounds, die einmalig abgespielt werden, wie z.B.
    den Schuss eines Gegners
  • spielt nicht-räumliche Sounds, wie z.B. Hintergrundmusik
    oder im Menü beim Klick auf einen Button

PhysicsManager
  • nutzt ODE
  • hat eine eigene virtuelle Welt
  • führt eine Liste mit Körpern (Gegenstücke zu den Meshes
    im SceneManager von Irrlicht)
  • hat eine Methode "doPhysics", die einen Berechnungsschritt
    für die Physikwelt macht und in der Hauptschleife aufgerufen wird

EntityManager
  • Entities
    - laden
    - verändern
    - löschen
  • Entities werden beim Laden in SceneManager, PhysicsManager
    und ggf. SoundManager (falls ein permanenter 3D-Sound abgespielt werden soll)
    eingefügt

LevelManager
  • liest Dateien, in denen Entities mit Position, Mesh, Eigenschaften, Skript usw.
    gespeichert sind.
  • die Entities werden mittels des EntityManagers geladen


Und dann noch eine Frage zur Verwendung von ODE:
ist es sinnvoll, die Kollisionserkennung komplett von ODE berechnen zu lassen,
ohne Irrlicht damit zu konfrontieren?
Und ist es dann besser, in jedem Hauptschleifendurchlauf durch die Liste
mit Entities zu iterieren und die Positionen aktualisieren,
oder lieber eigene SceneNodes schreiben, die sich automatisch mit ihrer
ODE-Position synchronisieren?


Ich wäre sehr dankbar für Hinweise und Vorschläge

_________________
Bit Happens!


Nach oben
 Profil  
 
BeitragVerfasst: 20.04.2009, 20:00 
Offline

Registriert: 12.09.2008, 21:41
Beiträge: 187
Wohnort: Deutschland
Hi,

ich bin leider kein Experte, aber es fällt mir sofort auf, dass du den Manager für die IDE oder GUI vergessen hast, die solltest du auf jedenfall mit aufführen, da sie vor allem für den Spieler später wichtig ist, ohne sie läuft das ganze Spiel nicht...

Ansonsten sieht das sehr wasserfest aus, also es könnte durchaus funktionieren, vielleicht findest du auch den ein oder anderen der dir hilft einen dieser Manager zu schreiben...

Gruß
Scarabol

_________________
My Toolbox:
- Irrlicht 1.7.1
- Blender 2.49a
- Microsoft Visual C++ Express Edition 2008
- Newton Game Dynamics 2.xx
Regeln zur Programmierung:
Regel 1: Die Programmiersprache hat keine Fehler.
Regel 2: Solltest du doch einen Fehler finden, tritt automatisch Regel 1 in Kraft.


Nach oben
 Profil  
 
BeitragVerfasst: 21.04.2009, 06:45 
Offline
Benutzeravatar

Registriert: 16.10.2007, 07:56
Beiträge: 229
Wohnort: Regensburg
Guten Morgen,

zur ODE-Frage: ich würde alle Animationen, die auf das Verhalten der Welt Einfluss haben (also z.B. Kollisionen, Bewegung von Körpern usw) von der ODE berechnen lassen und Irrlicht dabei komplett aussen vor lassen. Bei Sachen, die nur so als "Dekoration" laufen (was weiß ich ... Wolken oder so) würde ich hingegen (wegen der Performance) von Irrlicht rechnen lassen. Kannst ja mal meinen ODE-Wrapper anschauen (Schleichwerbung, ich weiss ... trotzdem: http://www.irrlicht3d.de/forum/viewtopic.php?f=15&t=992), bei dem "IrrOdeCar" Demo gibt Schilder über den Sprungschanzen, die sind nicht in der ODE (OK, die sind auch nicht animiert). Bis jetzt hab ich es noch nicht geschafft, mit diesen Schildern zu kollidieren, also sind die auch nicht als Physik-Objekte vorhanden ... man würde einfach durchspringen.

_________________
Bild


Nach oben
 Profil  
 
BeitragVerfasst: 21.04.2009, 20:25 
Offline
Benutzeravatar

Registriert: 23.03.2009, 18:52
Beiträge: 23
Wohnort: Bremen
danke erstmal für die Antworten.
Für das Benutzerinterface habe ich schon angefangen eine Klasse MainMenu zu schreiben, die kann
Buttons darstellen, macht Hovereffekte und reagiert auf Klicks. Für ein HUD- oder
Inventar habe ich allerdings noch nichts vorgesehen, also danke auf jeden Fall für den Hinweis.

Zur Physik, also ich hatte mir so etwas schon gedacht, das heißt also Terrain, bsp-Maps und alle
NPCs, Baumstämme und so weiter werden von ODE verwaltet (zumindest die Kollision), alles andere
darf ja ruhig durchlässig sein. Wahrscheinlich ist es dann auch sinnvoll, allem außer Terrain und BSP
nur Boundingboxen zur Kollision zu erteilen, oder? Der Player muss ja nicht polygongenau kollidieren.

@Brainsaw: Deinen ODE-Wrapper wollte ich mir schon ansehen, habe ihn auch schon heruntergeladen,
bin aber noch nicht dazu gekommen, mir mehr als die Demo anzusehen, weil ich im Moment noch das
Handbuch von ODE lese...
(nur so am Rande finde ich Schleichwerbung in diesem Rahmen durchaus hilfreich ;-P)

Aber ist es jetzt sinnvoller, eine Methode in der Hauptschleife aufzurufen, die in einer Schleife die
Positionen aller Physik-Entities aktualisiert, oder den SceneNodes selbst die Fähigkeit zu geben?

_________________
Bit Happens!


Nach oben
 Profil  
 
BeitragVerfasst: 22.04.2009, 06:40 
Offline
Benutzeravatar

Registriert: 16.10.2007, 07:56
Beiträge: 229
Wohnort: Regensburg
Also in ODE gibts ja die "step" Funktionen, die ruft man einmal für die Welt auf. Es wäre (glaub ich) möglich, das Ganze in einem Animator zu machen, aber ich habe mich dafür entschieden, den Aufruf in die Hauptschleife einzubauen. Ich benutz Irrlicht wirklich nur zum Darstellen des Ganzen, alle Bewegungen werden von ODE gerechnet.

Zu den Kollisionen: es kommt halt ganz drauf an. Ich denke, es macht Sinn, aus Performancegründen die Kollisionen von Objekten (so weit möglich) mit einfachen Formen zu erledigen (Box, Sphere, Capsule ... Cylinder ist nicht so der Hit). Für Terrain und BSP sollte man dann schon Trimeshes nehmen, aber der Rest kann auch angenähert werden (muss in IrrODE allerdings noch die Funktionalität einbauen, dass man an einen Body mehr als ein Geom dranhängen kann, damit man z.B. mit 3 oder 4 Boxes ein Flugzeug hinkriegt). Im ODE Wiki ist ein Artikel darüber, wie man eine "Upright Capsule" für FPS Spiele macht, das ist dafür wohl normal (allerdings sollte man aufpassen ... bei meinem Alltime-Favorite-Game (Battlefield 1942) schauen öfters mal Gewehre oder Füße durch die Wände durch und das ist nicht gut, wenn man sich verstecken will).

_________________
Bild


Nach oben
 Profil  
 
BeitragVerfasst: 22.04.2009, 19:21 
Offline
Benutzeravatar

Registriert: 23.03.2009, 18:52
Beiträge: 23
Wohnort: Bremen
Okay, das klingt gut^^

danke auf jeden Fall für die Hilfe! 8)

_________________
Bit Happens!


Nach oben
 Profil  
 
BeitragVerfasst: 25.04.2009, 21:36 
Offline

Registriert: 16.01.2008, 12:31
Beiträge: 79
Also was die GameStates angeht, das würde ich anders machen.
Eher so:

Code:
class IGameState {

private:

protected:
  IrrlichtDevice *deviceValue;
  IGameState();

public:
  ~IGameState(void);
  virtual void OnEnter(IrrlichtDevice *device)=0;
  virtual void OnUpdate(irr::f32 timeElapsed) = 0;
  virtual void OnDraw() = 0;
  virtual void OnLeave() = 0;
};

class GSRunning : IGameState {

public:
  virtual void OnEnter() {
  }

  virtual void OnUpdate(irr::f32 timeElapsed) {
  }

  // etc.
};

class CGameStateManager {
private:
  IrrlichtDevice *deviceValue;
  IGameState *currentGameStateValue;

public:
  CGameStateManager(IrrlichtDevice *device) {
    deviceValue = device;
    currentGameStateValue = 0;
  }

  void ChangeState(IGameState *newState) {
    if (currentState) {
      currentState->OnLeave();
    }
    currentState = newState;
    currentState->OnEnter();
  }

  void OnUpdate(irr::f32 timeElapsed) {
    if (currentGameStateValue) {
      currentGameStateValue->OnUpdate(timeElapsed);
    }
  }

  void OnDraw() {
    if (currentGameStateValue) {
      currentGameStateValue->OnDraw();
    }
  }
}

Dann gibts nen GS für Intro, Pause, läuft etc.

Ob ich nen Sound-Manager basteln würde weiss ich nicht, vermutlich würd ich eher ne Klasse bauen, die weiss welche Datei sie abspielen soll und bei Aufruf einer Start-Methode nen Thread startet und das macht und bei Aufruf einer Stop-Methode eben aufhört.


Nach oben
 Profil  
 
BeitragVerfasst: 28.04.2009, 09:46 
Offline
Benutzeravatar

Registriert: 24.04.2009, 11:25
Beiträge: 14
Und gib bloß nicht jeder Klasse den IrrlichtDevice Pointer. Das wird irgendwann soviel extra Code, dass Du ins Zweifeln gerätst! Ich habe dafür auch noch keine perfekt Lösung gefunden, aber inzwischen spare ich mir 'ne Menge Schreiberei (Erste Zuweisung im Ctor; Deklaration d. Pointers als Member; Beim Aufruf des Ctor im Parameter; Im Ctor Parameter bei Deklaration sowie Definition) und sehe immernoch (z.B. via Doxygen), welche Klassen ihn benutzen indem ich eine getDevice() Funktion protected Erbe, von einer Klasse, die eine statische Kopie des IrrlichtDevice pointer enthält. Ich denke, das ist der beste Weg.

Code:
#define CRASH_BECAUSE(X) assert(false && X)


Code:
class accessDevice
{
public:
        //! Constructor
        accessDevice() {
                // Check
                if (!accessDevice::s_pDevice)
                        CRASH_BECAUSE("Device not yet initialized!");
        }

        //! Destructor
        virtual ~accessDevice() {}

protected:
        static inline IrrlichtDevice* getDevice() {
                return s_pDevice;
        }

        static inline ISceneManager* getSceneManager() {
                return s_pDevice->getSceneManager();
        }

        static inline IVideoDriver* getVideoDriver() {
                return s_pDevice->getVideoDriver();
        }

private:
        //! Access for Client class which fills s_pDevice
        friend class Client;

        //! Access for Server class which fills s_pDevice
        friend class Server;

        //! The Irrlicht Device Pointer
        static IrrlichtDevice* s_pDevice;
};


Dann (Pseudocode):

Code:
class Bla : private accessDevice
{
        void Func();
};

void Bla::Func()
{
        getDevice()->getLogger()->log(L"Tada!");
        getSceneManager()->addCubeSceneNode(...);
        // etc.
}


Nach oben
 Profil  
 
BeitragVerfasst: 28.04.2009, 17:18 
Offline

Registriert: 16.01.2008, 12:31
Beiträge: 79
Das war/ist bisher auch immer mein Problem gewesen, das man das IrrlichtDevice praktisch überall benötigt.

Eine Lösung die ich richtig schick finde habe ich allerdings auch noch nicht gefunden.

Alternativ könnte man, wenn man sich eine CApp-Klasse baut, was ich praktisch immer mache, dort eine Statische-methode unterbringen die den Pointer zurück gibt.


Nach oben
 Profil  
 
BeitragVerfasst: 28.04.2009, 17:23 
Offline

Registriert: 20.03.2009, 10:02
Beiträge: 50
In simpleIrr habe ich es so gelöst dass alle Klassen von TIrrlicht abgeleitet werden. Das war aber nur nötig weil BlitzMax keine friendly Classes kennt. Also habe ich eine Basis-Klasse TIrrlicht die mittels Init() und Graphics3D() das Interface etabliert und alle anderen Klassen erben von TIrrlicht.

Eine GameEngine die auf simpleIrr aufsetzt kann dann seine Strukturierung behandeln wie sie möchte.


Nach oben
 Profil  
 
BeitragVerfasst: 30.04.2009, 15:23 
Offline
Benutzeravatar

Registriert: 23.03.2009, 18:52
Beiträge: 23
Wohnort: Bremen
Ich habe das so gelöst, dass mein GameManager einen Pointer auf das Device hat.
Der GameManager wird als globale Variable erzeugt und der Pointer ist ein public
Attribut. Also können alle anderen Manager auf gamemanager->device zugreifen

_________________
Bit Happens!


Nach oben
 Profil  
 
BeitragVerfasst: 30.04.2009, 15:28 
Offline
Benutzeravatar

Registriert: 24.04.2009, 11:25
Beiträge: 14
Hm, super. Da habt ihr aber alle drei keinerlei Zugriffskontrolle.
Dann könnt ihr den IrrlichtDevice Pointer ja gleich global machen.


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 15 Beiträge ]  Gehe zu Seite 1, 2  Nächste

Alle Zeiten sind UTC + 1 Stunde


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 18 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de