Ich bin momentan dabei eine eigene (kleine) Engine zu schreiben, nur um zu verstehen wie so etwas im Detail funktioniert und um noch besser die Sprache C++ zu lernen.
Momentan häng ich daran, eigene Buttons und Eingabefelder im Spiel zu entwerfen. Felder & Buttons kann ich erstellen, sind erstellt, funktionieren auch gut. Das Problem ist, sie sind nicht sehr objektorientiert.
Mein Problem ist, wie soll eine Klasse aussehen, die für die Felder und Buttons zuständig ist, ohne für jedes Feld/jeden Button eine neue Klasse zu erstelln und diese am Ende des Spieles wieder zu löschen.
Ich hoffe, ihr könnt mir da weiter helfen, welche Idee dahinter steckt, um es so umzusetzen.
Frage zum eigenen GUI in DirectX9
Re: Frage zum eigenen GUI in DirectX9
Nun, es gibt natürlich einige GUI-Bibliotheken, aber für mein Spiel habe ich mir neulich auch ein paar GUI-Elemente selber programmiert.
Meine Buttonklasse hat im Wesentlichen ein Spriteobjekt und eine Position. Darüber hinaus gibt es ein Input-Handler und einen "Callback-Mechanismus", der die Buttonaktion umsetzt. Das ganze kann man sich dann in etwa so vorstellen: Das Sprite des Buttons wird an der entsprechenden Position gezeichnet. Der Inputhandler wird regelmäßig aufgerufen und bekommt z.B. die Mausposition und die Zustände der Maustasten übergeben. Merkt der Inputhandler jetzt, dass die Linke Maustaste unten ist, während der Mauszeiger über dem Button ist, wird die eigentliche Aktion ausgelöst.
Für die Aktion hat man natürlich mehrere Möglichkeiten. Man kann für jeden Knopf eine Klasse ableiten, die dann die entsprechende Aktion auslöst. Oder man übergibt dem Buttonobjekt einen Funktionszeiger, der aufgerufen werden soll. Ich habe die neuen C++11 Lambdas benutzt, in Kombination mit boost::signals. Das sieht dann bei mir so aus:
Der Button wird also angelegt, indem man das Sprite und die Position angibt. Dann wird dem boost::signal ein Lambda übergeben, das den entsprechenden Code ausführt. Dank boost signals könnte ich einem Button sogar mehrere Aktionen zuordnen. Man könnte auch boost::bind benutzen, um den Knopf eine Methode irgendeines Objektes aufrufen zu lassen.
Die letzte Zeile registriert den Button einfach in einem WidgetManager, der sich darum kümmert, dass alle Knöpfe gezeichnet werden und alle Eingaben weitergeleitet werden. Ich wollte halt, dass ein Button auch ohne irgendeinen Manager benutzbar ist, ansonsten würde man vielleicht die "angegklickt" Abfrage nicht erst im Button sondern schon im Manager machen.
Das alles ist relativ rudimentär, aber dank Lambdas echt nett zu benutzen. Ob ich das weiter ausbaue, oder zu einer anderen Bibliothek wechsle, wird sich zeigen, aber für den Anfang kann man das durchaus schonmal benutzen.
Meine Buttonklasse hat im Wesentlichen ein Spriteobjekt und eine Position. Darüber hinaus gibt es ein Input-Handler und einen "Callback-Mechanismus", der die Buttonaktion umsetzt. Das ganze kann man sich dann in etwa so vorstellen: Das Sprite des Buttons wird an der entsprechenden Position gezeichnet. Der Inputhandler wird regelmäßig aufgerufen und bekommt z.B. die Mausposition und die Zustände der Maustasten übergeben. Merkt der Inputhandler jetzt, dass die Linke Maustaste unten ist, während der Mauszeiger über dem Button ist, wird die eigentliche Aktion ausgelöst.
Für die Aktion hat man natürlich mehrere Möglichkeiten. Man kann für jeden Knopf eine Klasse ableiten, die dann die entsprechende Aktion auslöst. Oder man übergibt dem Buttonobjekt einen Funktionszeiger, der aufgerufen werden soll. Ich habe die neuen C++11 Lambdas benutzt, in Kombination mit boost::signals. Das sieht dann bei mir so aus:
Code: Alles auswählen
m_NewGameButton=new Button(DataPath("Game_Menu/spiel_starten.png"), vec2(PosX, 220));
m_NewGameButton->ConnectPressed([this]()
{
m_Game.m_Menu=false;
m_Game.Load("Start.xml");
});
m_WidgetManager.AddWidget(m_NewGameButton); //das hier erkläre ich später
Die letzte Zeile registriert den Button einfach in einem WidgetManager, der sich darum kümmert, dass alle Knöpfe gezeichnet werden und alle Eingaben weitergeleitet werden. Ich wollte halt, dass ein Button auch ohne irgendeinen Manager benutzbar ist, ansonsten würde man vielleicht die "angegklickt" Abfrage nicht erst im Button sondern schon im Manager machen.
Das alles ist relativ rudimentär, aber dank Lambdas echt nett zu benutzen. Ob ich das weiter ausbaue, oder zu einer anderen Bibliothek wechsle, wird sich zeigen, aber für den Anfang kann man das durchaus schonmal benutzen.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
Re: Frage zum eigenen GUI in DirectX9
Also sollte ich am besten für jeden Button/jedes Eingabefeld eine Klasse machen? Wie diese funktionieren, hab ich ja, ich möchte nur das etwas ordentlicher und einfach (sowie am besten-laufend) geschrieben haben.
Re: Frage zum eigenen GUI in DirectX9
Nein eigentlich nicht. Höchsten für jeden Button eine Klasse ableiten, die dann auch die Aktion implementiert. Aber ich finde die Variante mit Lambdas, bzw. Functors ansich schöner, allerdings kriegt man das nicht unbedingt mit C++ Grundlagen hin, muss sich also erst noch ein wenig in das Thema reinlesen. Zeig doch mal ein wenig Code.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
Re: Frage zum eigenen GUI in DirectX9
Mach doch einfach eine Basisklasse für alle GUI-Elemente (z.B. Widget), die grundlegende Dinge wie Name, Text, Position, Größe und eventuell virtuelle Funktionen zum Zeichnen usw enthält. Die Button-Klasse enthält dann nur noch Dinge, die spezifisch für Buttons sind (z.B. einen Press-Event-Handler oder andere Erscheinungsformen beim Status 'hover' und/oder 'pressed').PuRe hat geschrieben:Also sollte ich am besten für jeden Button/jedes Eingabefeld eine Klasse machen? Wie diese funktionieren, hab ich ja, ich möchte nur das etwas ordentlicher und einfach (sowie am besten-laufend) geschrieben haben.
Das Entscheidende ist das Event-System. Ich hatte damals einfach eine GUI-Klasse, die alle GUI-Elemente verwaltet hat. Die Event wurden im GameLoop zusammengebaut und an das GUI gesendet. Dieses hat es an alle GUI-Elemente weitergeleitet, die dann festgestellt haben, ob sie damit was anfangen konnten. Falls ja, wurde das GUI benachrichtigt und ein anderes Event generierte. Z.B. LeftClick-Event -> GUI -> Button -> Benachrichtigung an GUI -> ButtonClick-Event -> aktuelles Spielmenü -> beliebige Aktion.
Das GUI generiert also auf Basis von Mouse- und Tastaturevents GUI-Events, die dann im Programm ausgewertet werden können. Kann man natürlich auch anders machen, aber das ging ganz gut.
Ohne Input kein Output.
Re: Frage zum eigenen GUI in DirectX9
Ich hatte mir sowas mal in c# mit der SDL gebaut, im grunde so wie Berserker es auch beschrieben hat.
Eine Basisklasse für die Elemente und dann davon erbende.
Und dann einen "Handler" über den auch die Controls "addStaticText(..), addPushButton(..)" erzeugt werden. In der Hauptschleife werden die Events (Click und Koordinaten) an den Handler übergeben, er prüft dann ob der Klick auf einem Ihm bekannten Control durchgeführt wurde (bei mehreren Fenstern muss dann natürlich geprüft werden welches oben liegt etc.) und ruft eine Methode und teilt mit welche Widget ID betroffen war.
Dann ein switch case über die ID's und dann Deine Programmlogik aufrufen.
Wenn ich heute sowas nochmal machen würde, hatte das damals nur gemacht um es mal gemacht zu haben, würde ich sigc++ für das behandeln der Events verwenden.
EDIT: Oder in C# halt richtige EventHandler.
Du kannst Dir auch die Sourcen von Irrlicht runterladen, und dort mal angucken wie die das gemacht haben.
Eine Basisklasse für die Elemente und dann davon erbende.
Code: Alles auswählen
Widget
--> Window
--> StaticText
--> Pushbutton
--> Textbox
--> Scrollbar
--> ListBox
--> etc.
Dann ein switch case über die ID's und dann Deine Programmlogik aufrufen.
Wenn ich heute sowas nochmal machen würde, hatte das damals nur gemacht um es mal gemacht zu haben, würde ich sigc++ für das behandeln der Events verwenden.
EDIT: Oder in C# halt richtige EventHandler.
Du kannst Dir auch die Sourcen von Irrlicht runterladen, und dort mal angucken wie die das gemacht haben.