Irrlicht - from Noob to Pro: Grafische Benutzeroberfläche

Aus Wikibooks
Zur Navigation springen Zur Suche springen
Wikibooks buchseite.svg Zurück zu "Licht, Menüs und ein Sonnensystem in Echtzeit" | One wikibook.svg Hoch zu "Inhaltsverzeichnis" | Wikibooks buchseite.svg Vor zu "irrEdit"


Allgemeines[Bearbeiten]

Die GUI (graphical user interface) oder auch Graphische Benutzeroberfläche ist der Teil einer Softwareanwendung, die den Anwender mit dem Rechner kommunizieren lässt. Dabei stellt das Programm einfache graphische Symbole wie Buttons oder Checkboxen, sowie komplexe Symbole wie Kalender oder TreeViews bereit, die der Anwender entweder mit der Maus oder der Tastatur bedienen kann. Dabei löst der Anwender Events aus, die das Programm abfangen und interpretieren kann.

GUI in Irrlicht[Bearbeiten]

GUIEnvironment[Bearbeiten]

Irrlicht stellt einen GUI-Manager, der die Erstellung, Löschung und Verwaltung von GUI-Elementen übernimmt, bereit. Voraussetzung dafür ist eine valide Instanz des Irrlicht-Device. Wenn diese vorhanden ist, kann eine Instanz des GUI-Managers über eine get-Methode zurückgeliefert werden.

#include <irrlicht.h>

using namespace irr;

int main(int argc, const char* argv[])
{
    IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640,480));
    
    if(device != 0)
        IGUIEnvironment* guidev = device->getGUIEnvorinment();

    return 0;
}

GUI-Elemente[Bearbeiten]

Alle weiteren GUI-Elemente werden über den GUI-Manager erstellt und verwaltet. Irrlicht bietet eine Menge GUI-Elemente an, die einen Großteil der Standardanwendungen abdecken dürften. Man kann auch eine Klasse überladen um so ein neues GUI-Element zu erzeugen bzw. das Verhalten eines vorherigen Elementes neu zu definieren.

Irrlichts GUI-Manager hat eine klare Struktur und man erkennt eine Methode, die ein GUI-Element erzeugt stets am Methodennamen add*(paramlist). Zur Verdeutlichung zwei Beispiele am Code:

#include <irrlicht.h>

using namespace irr;
using namespace gui;

int main(int argc, const char* argv[])
{
        IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640,480));

	if(device != 0)
	{
		IGUIEnvironment* guidev = device->getGUIEnvironment();

		guidev->addButton(core::rect<s32>(0,0,128,32), 0, -1, L"PushButton", L"Just click me");
		guidev->addStaticText(L"Seriously - just click him", core::rect<s32>(0,32,128,64), false);
	
	
		while(device->run())
		{
			device->getVideoDriver()->beginScene(true, true, video::SColor(255,255,255,255));
				guidev->drawAll();
			device->getVideoDriver()->endScene();
		}
	}

	device->drop();

	return 0;
}


Dieser Code erzeugt einen Button und ein Label, welches man zur Ausgabe von Informationen nutzen kann. Man erkennt sehr gut die Konvonetion, dass zur Erzeugung eines GUI-Elementes eine add-Methode aufgerufen wird. Nun sind wir bereit zum nächsten Schritt zu gehen. Die Anwendung soll auf den Mensch reagieren. Dazu schauen wir uns Events in Irrlicht an.

Events[Bearbeiten]

Events oder Ereignisse sind Methoden um asynchrone Benutzereingabe zu ermöglichen. So wird nicht kontinuierlich eine Schleife durchlaufen um ein Objekt auf Veränderung zu testen, sondern viel mehr bei einer Änderung ein Ereignis ausgelöst, was von einem anderen Objekt wahregnommen wird, sodass das Programm darauf reagieren kann. Dieses Objekt ist bei Irrlicht der EventReceiver. Diese Klasse fängt nicht nur GUI-Events ab, sondern auch alle andere Arten von Benutzereingabe, wie Maus und Tastatur oder auch Joysticks.

Bevor wir aber Events abfangen können, müssen wir einen EventReceiver erstellen und an den IrrlichtDevice binden. Um möglichst flexibel zu sein leitet man sich ein Objekt vom Typ IEventReceiver ab und überlädt diesen nach seinen Wünschen. Folgender Code soll dies illustrieren:


#include <irrlicht.h>

using namespace irr;
using namespace gui;
using namespace core;
using namespace video;

class InputDevice : public IEventReceiver
{
private:
	IrrlichtDevice* internalDevice;

public:
	InputDevice(IrrlichtDevice* device) : internalDevice(device)
	{
                //bindet das Device an diese Instanz
                //Wichtig, da sonst nicht auf die Benutzereingabe reagiert werden kann!
		device->setEventReceiver(this);
	}

	virtual bool OnEvent(const SEvent& event)
	{
		//...
		return false;
	}
};

int main(int argc, const char* argv[])
{
        IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640,480));

	if(device != 0)
	{
		InputDevice input(device);

		IGUIEnvironment* guidev = device->getGUIEnvironment();

		guidev->addButton(core::rect<s32>(0,0,128,32), 0, 1000, L"PushButton", L"Just click me");
		guidev->addStaticText(L"Seriously - just click him", core::rect<s32>(0,32,128,64), false);
	
	
		while(device->run())
		{
			device->getVideoDriver()->beginScene(true, true, video::SColor(255,255,255,255));
				guidev->drawAll();
			device->getVideoDriver()->endScene();
		}
	}

	device->drop();

	return 0;
}

Der InputManager ist nun bereit auf die Benutzereingabe zu reagieren. Wie das ganze funktionieren soll wird in der OnEvent()-Methode beschrieben. In dieser werden alle Events abgefangen, die der Anwender produzieren kann. In unserem Fall soll ein neuer Text angezeigt werden, wenn der Benutzer auf den Button klickt. Folglich filtern wir die Events. Wir untersuchen alle GUI-Events und dann auch nur diese, die erzeugt werden, wenn ein Button gedrückt wurde. Um dann herauszufinden, welcher von möglicherweise vielen Buttons gedrückt wurden untersuchen wir die ID, dass das Event mitliefert. Sofern diese die gleiche wie die unseres Buttons ist, ist er der Sender des Events und wir führen unsere Schritte aus.

virtual bool OnEvent(const SEvent& event)
{
	//Nur die GUI-Events
	if(event.EventType == EET_GUI_EVENT)
	{
		//ID vom Sender abfragen
		u32 ID = event.GUIEvent.Caller->getID();
                IGUIEnvironment *internalEnv=internalDevice->getGUIEnvironment();
                IVideoDriver *internalDriver=internalDevice->getVideoDriver();

		//EGET_BUTTON_CLICKED - wurde ein Button gedrückt?
		switch(event.GUIEvent.EventType)
		{
			case EGET_BUTTON_CLICKED:
                        //ID unseres Buttons ist 1000
			if(ID == 1000)
			{
				internalEnv->addStaticText(L"Oiii you clicked it...", core::rect<s32>(0,64,256,96), false);
				return true;
			}
		}
	}

	return false;
}

Neue Schriftarten erstellen und nutzen[Bearbeiten]

Wenn wir (wie oben beschrieben) einen Text in Irrlicht darstellen wollen, erscheint dieser in der Standardschrift von Irrlicht. Diese ist leider sehr klein und deswegen nur zu experimentellen Zwecken nutzbar. Dieses Kapitel soll zeigen, wie man mit einem Irrlicht-Tool eine neue Schriftart (im Folgenden nur noch "Font" genannt) erstellt und diese in Irrlicht integriert.

Eine neue Font erstellen[Bearbeiten]

Zuerst müssen wir eine Font erstellen, dabei hilft uns das Tool "FontTool". Dieses Tool wird mit dem Irrlicht-SDK mitgeliefert und befindet sich im Beispielordner, also lautet der vollständige Pfad \bin\Win32-VisualStudio\FontTool.exe.
Starten Sie die .exe-Datei mit Doppelklick. Das FontTool besteht aus einem kleinen Irrlicht-Window, in dem einige Auswahlen getroffen werden können.

  • Charset: stellt den verwendeten Schriftsatz ein
  • Font: Hier können Sie alle Schriftarten, die sich auf Ihrem PC befinden, auswählen.
  • Size: stellt die Schriftgröße (in Pixel) ein
  • Bold, Italic, AA, Alpha: verschiedene Modifikationen können eingestellt werden
  • Max Width:
  • Max Height:
  • Filename: Stellen Sie hier den Dateinamen ein, unter dem später ihre Font gespeichert wird.
  • File Format: legt das Format fest, in dem Ihre Font gespeichert wird



Nun könne Sie eine Schriftart erstellen, wie folgendes Beispiel zeigt:

  • Charset: ANSI
  • Font: Arial
  • Size: 16px
  • Alpha: true (Häkchen bei "Alpha" setzen)
  • Max Width: 512 wide
  • Max Height: 512 tall
  • Filename: myfont
  • File Format: png

Klicken Sie nun den "Create" Button. Jetzt sehen Sie im Hintergrund die Font. Klicken Sie jetzt auf "Save". Damit wird die Font im selben Ordner der FontTool.exe gespeichert (also im Beispielordner von Irrlicht).
Jetzt müssten sich im Beispielordner mehrere neue Dateien befinden: myfont.xml, myfont0.png, myfont1.png. Natürlich heißen die Dateien anders, wenn Sie unter "Filename" etwas anderes eingestellt haben!

Achtung.svg

Je nach Schriftart werden weniger oder mehr .png-Dateien erstellt. Löschen Sie keine dieser Dateien, da sie sonst von Irrlicht nicht geladen werden können! Auch die .xml-Datei sollten Sie auf keinen Fall löschen.

Die Font laden[Bearbeiten]

Nun wollen wir einen Code schreiben und die eben erstellte Font nutzen.

#include <irrlicht.h>

using namespace irr;
using namespace video;
using namespace core;
using namespace gui;

int main()
{
    IrrlichtDevice *device=
       createDevice(EDT_OPENGL, dimension2d<u32>(640,480),0,false,false,false,0);
    if(!device)
        return 0;
    device->setWindowCaption(L"Neue Schriftart");
    IVideoDriver *driver=device->getVideoDriver();
    IGUIEnvironment *guidev=device->getGUIEnvironment();
    guidev->addStaticText(L"Neue Schriftart", rect<s32>(0,0,200,200), false);
    //Bis hier ist alles bekannt. Jetzt laden wir myfont.xml . Die .png-Dateien müssen nicht extra geladen werden, müssen sich aber im selben Verzeichnis (Ordner) befinden .

    IGUISkin* skin = guidev->getSkin();
    IGUIFont* font = guidev->getFont("C:/myfont.xml"); //Geben Sie zwischen den Apostrophen den genauen Pfad an.
    if(font)
        skin->setFont(font);

    while(device->run())
    {
        driver->beginScene(true, true, SColor(3,150,203,255));
        guidev->drawAll();
        driver->endScene();
    }
    device->drop();
    return 0;
}