Konzeptfrage "Event-Handling"
Übersicht

Gray FoxBetreff: Konzeptfrage "Event-Handling" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Guten Morgen,
ich arbeite aktuell an einem kleinen Framework, das als Basissystem für meine zukünftigen Spiele dienen soll. Momentan beschäftige ich mich mit dem Thema "Event Handling" bzw. damit, wie meine Objekte (Interface-Elemente, ImageContainer, etc) auf die Mauseingaben reagieren können (onMouseover, onClick usw). Geplant war, dass ich meine Objekte in einer Event-Handling-Klasse registriere (Eine Referenz des Objektes in einer TMap speichere). Ich liege doch richtig, dass (komplexe) Objekte nur als Referenz übergeben? In der Grundversion soll vorerst nur geprüft werden, ob sich die Maus über einem registrierten Objekt befindet. Das wollte ich wie folgt realisieren: Zu Anfang habe ich eine Grundklasse entworfen, die über die Basisattribute und Basismethoden verfügt. Die weiteren Objektklassen werden davon abgeleitet(?). Ich weiß nicht genau, wie man das Vorgehen nennt, aber ich meine "klasse B extends Klasse A". Beim Aufruf der Update-Methode der Event-Handling-Klasse werden die Koordinaten der Maus ermittelt. Anschließend wird die TMap, in der die Referenzen der registrierten Objekte gespeichert sind, durchlaufen und die Mauskoordinaten werden mit den Objekt-Attributen X,Y, Width und Height verglichen und sollte sich die Maus innerhalb der Fläche des Objektes befinden, wird beispielsweise dessen interne "onMouseover" -Methode aufgerufen. (Event-Bubbling / Event-Order mal außen vorgelassen) Jetzt kommt der Knackpunkt, Werte werden in einer TMap nur als Typ "Object" gespeichert. Somit müssten die Werte, in dem Fall die unterschiedlichen Klassen, erst wieder in die korrekte Klasse umgewandelt (umgecastet??) werden oder irre ich mich da? Da ich gerade nicht an meinem Rechner sitze, kann ich auch leider keinen Sourcecode posten, außer einem kleinen Konzeptbeispiel, deshalb hoffe ich, dass meine Erläuterungen verständlich sind. Meine Hauptfrage ist, ob der Ansatz durchführbar ist oder ob ich nicht lieber das Thema aus einem anderen Blickwinkel betrachten sollte? So sieht mein Code im Kern bisher aus: Innerhalb der "main.bmx" BlitzMax: [AUSKLAPPEN]
'Innerhalb der systemCore-Klasse: BlitzMax: [AUSKLAPPEN]
|
||
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Grüße!
- Objekte werden als Referenz übergeben, das ist richtig. - Abgeleitet oder Vererbte Klassen, richtig. - Du solltest vielleicht kein Object speichern, sondern als eine Klasse, die die richtigen Methoden besitzt. In eine unbekannte Klasse zu casten könnte kompliziert werden. und ein letzter Hinweis: Code: [AUSKLAPPEN] system.eventHandler.update(system.mouse.getEvent()) Wenn getEvent Klammern besitzt, wird die Funktion/Methode aufgerufen und das Ergebnis übergeben, ohne wird die Referenz übergeben.
|
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Guten Morgen,
danke für den Hinweis, aber hast du auch eine Idee, wie ich die Klassen speichern könnte? Immerhin könnten ja verschiedene Klassen als Referenz übergeben werden. Wobei alle Klassen von einer Basisklasse abgeleitet werden. Wäre es alternativ möglich, den Code so anzupassen, dass, statt des Objektes selbst, "nur" die "Update-Methode des Objektes als Referenz übergeben wird? Würde das Sinn machen? |
||
![]() |
Lobby |
![]() Antworten mit Zitat ![]() |
---|---|---|
Nun, wäre doch toll, wenn die Basisklasse alle Methoden die du im EventHandler aufrufen können würdest wollen, schon festlegt. Dann brauchst du in den Klassen, die von dieser Hauptklasse erben, diese Methoden nur noch (neu) definieren und der EventHandler muss immer nur Objekte in die Basisklasse casten um die entsprechenden Methoden aufrufen zu können.
Leider kann man in BlitzMax keine Methoden übergeben. Häufig wird das damit umgangen, dass man eine Funktion übergibt, sowie ein Objekt, das als Parameter für diese Funktion dient. Innerhalb der Funktion wird dann das Parameterobjekt wieder in die gewünschte Klasse umgecasted und kann so verwendet werden. Allerdings ist diese Vorgehensweise eben recht aufwändig und verfehlt damit ihren eigentlichen Zweck. |
||
TheoTown - Eine Stadtaufbausimulation für Android, iOS, Windows, Mac OS und Linux |
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich bin mir ziemlich sicher, dass es keinen Sinn macht, die Methode zu übergeben; Was soll denn aufgerufen werden, wenn das Objekt die Methode nicht besitzt oder es kein Objekt gibt, auf das die Methode angewandt werden kann?
Wenn die Basis-klasse die Methoden besitzt, sollte es keine Probleme geben. Die Kind Klassen werden dann ihre eigenen Methoden aufrufen: BlitzMax: [AUSKLAPPEN] SuperStrict |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Vielen Dank erstmal für eure Hinweise. Ich werde das mit der Basisklasse gleich einmal ausprobieren, aber gehen nicht die Attribute (Fields), die in den Kindklassen definiert wurden, verloren, wenn ich das übergebene Objekt in die Basisklasse umcaste? | ||
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Die wären dann nicht Sichtbar, dass Stimmt.
Wenn du den direkten Zugriff brauchst, solltest du eine ID vergeben, damit du weißt, in welchen Typ du zurück casten musst. |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
![]() |
Lobby |
![]() Antworten mit Zitat ![]() |
---|---|---|
Mag sein, dass du bei einer Referenz einer von der Basisklasse vererbten Klasse nicht auf die Felder zugreifen kannst, wenn du es zur Basisklasse castest, aber das brauchst du ja auch gar nicht. Dafür sind die Methoden da, und da automatisch immer die Methode aufgrufen wird, die in der Klasse steckt von der du ursprüngich die Instanz erstellt hast, sind in dieser auch alle von dir für diese Klasse definierten Felder vorhanden.
Verloren geht nichts, es wird nur für dich unsichtbar ![]() |
||
TheoTown - Eine Stadtaufbausimulation für Android, iOS, Windows, Mac OS und Linux |
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Ich muss sagen, das ergibt alles Sinn ![]() Xeres Vorschlag hört sich gut an, man definiert in der Basisklasse ein Field / Attribute "cType oder controlType", castet das Objekt erstmal in die Basisklasse und macht dann eine select case-Abfrage und castet das Objekt entsprechend um. EDIT: Ich habe es mal ausprobiert, es scheint sogar zu funktionieren ![]() Jetzt muss ich mir mal um das "Naming" meiner Klassen Gedanken machen. Gegen eine Beschriftung im Stile von "obj_typ_name" ist doch nichts einzuwenden, oder? Beispiel: obj_control_imageList BlitzMax: [AUSKLAPPEN] Local obj_imageList = New obj_control_imageList Wobei ich eigentlich das Folgende bevorzuge: BlitzMax: [AUSKLAPPEN] Local obj_imageList = New objControlImageList |
||
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
So, ich muss mich leider nochmal melden. ![]() Ich habe noch kleinere Probleme, bei denen ich einen Denkanstoß gebrauchen könnte. Gibt es in BlitzMax anonyme Funktionen, ähnlich denen in Javascript? Code: [AUSKLAPPEN] element.onEvent = function() { //do something } --------- Wie könnte ich folgendes Problem am geschicktesten lösen? Ich habe meinen EventHandler soweit fertiggestellt, dass es möglich ist, bei jedem registrierten Objekt ein "onMouseOver"- und "onClick"-Event auszulösen. Im Moment besitzt jedes Objekt ein "onMouseOver"- und ein "onClick"- Feld (Field). Diesen Feldern werden dann individuelle Funktionen zugewiesen (Nennt sich dann doch Funktionspointer?) Das Problem ist nun, dass ich innerhalb von Funktionen nicht mit "self" arbeiten kann, weil es ja keine Methoden sind. Mein Ansatz war, dass ich eine Referenz des Objektes, bei dem ein Event ausgelöst wurde, an die Funktion übergebe. Da ich aber vermeiden will, dass ich in jeder Funktion vorher den Typ des Objektes umcasten muss, wollte ich es so regeln, dass es nur einen allgemeingültigen Objekttyp gibt, der je nach Bedarf angepasst wird und ein anderes "Steuerelement / Control" darstellt. So würde das dann beispielsweise aussehen: BlitzMax: [AUSKLAPPEN]
Kann man den Ansatz so lassen oder sieht das "unschön" oder unprofessionell aus? Ich versuche das Hintergrundsystem auf diese Art so universell wie möglich zu gestalten, damit ich es später relativ einfach für andere (Spiele)Projekte einsetzen kann. |
||
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Der inoffizielle Standard ist "T"<name> für Types/Klassen um sie von Objekten/Instanzen zu unterscheiden.
Anonyme Funktionen gibt es nicht. So mit Strings zu arbeiten halte ich für etwas unschön, weil langsam und sieht sehr hardcoded aus. Da man kein Attribut/Field on the fly deklarieren kann wie in Javascript, müsste dein Universal-Type auch alle Fields besitzen die man irgendwann mal gebrauchen wollte. Und die kann man auch nicht als String ansprechen. BlitzMax ist kein Javascript und ich würde nicht so tun, als wäre es so. |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Xeres hat Folgendes geschrieben: Der inoffizielle Standard ist "T"<name> für Types/Klassen um sie von Objekten/Instanzen zu unterscheiden.
Das finde ich wiederum unschön, aber nun gut, vielleicht sollte man sich den Konventionen der eingesetzten Programmiersprache einfach unterwerfen ![]() Zitat: Anonyme Funktionen gibt es nicht.
Schade.. Zitat: So mit Strings zu arbeiten halte ich für etwas unschön, weil langsam und sieht sehr hardcoded aus.
Da man kein Attribut/Field on the fly deklarieren kann wie in Javascript, müsste dein Universal-Type auch alle Fields besitzen die man irgendwann mal gebrauchen wollte. Und die kann man auch nicht als String ansprechen. In einer TMap kann ich doch verschiedene Dateitypen speichern, somit kann ich doch theoretisch alle Attribute / Fields "on the fly" generieren? Wie sehe denn ein besserer Ansatz aus? |
||
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ah, die TMap habe ich leicht übersehen... kann natürlich klappen, aber alles über Strings an zu sprechen halte ich trotzdem nicht für das wahre. Statt des cType Strings würde ich aber vom Universalobjekt ableiten. Ein riesiges Select Case Konstrukt ist nicht besonders schick oder praktisch.
Aber lass dich nicht von mir von etwas abbringen, am besten merkt man nach dem 3. Anlauf, was man hätte machen sollen. :p |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Gray Fox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Xeres hat Folgendes geschrieben: ich aber vom Universalobjekt ableiten. Ein riesiges Select Case Konstrukt ist nicht besonders schick oder praktisch.
Das habe ich anfangs gemacht, aber ich habe dann trotzdem noch das beschriebene Problem, welches ich weiter oben beschrieben habe, und das ich mit dem jetzigen Konstrukt lösen wollte. |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group