Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug)



  • Hallo,
    da ich begeisterter Fan der Boeing 777 (Düsenflugzeug) bin, habe ich früher einen 2D-Cockpitsimulator mit Javascript/HTML gebaut. Hinweis: Javascript ist was anderes als Java! Das ging aber schnell an die Grenzen des Prozessors bzw. RAM des PCs. Dann habe ich mich für C++ (neu für mich) mit Visual Studio und Qt als GUI entschieden. Ein Joystick mit der SDL2-Library soll auch dazugehören. Letzters habe ich in einem Testprojekt von Visual Studio schon zum Laufen gebracht. Siehe dieses Thema. Das Programmieren ist nur ein Hobby von mir, daher muss nicht alles perfekt sein, Hauptsache es funktioniert.

    Der erste Weg sieht in etwa so aus, dass ich die Klasseninstanzen (current, engineL, engineR, fuel etc.) an andere Klassen, die die aktuellen Daten brauchen, über den Konstruktor übergeben habe. Ich wurde eines besseren belehrt, dass man gegenseitige Klassen nicht aufrufen sollte... Deshalb habe ich mein Konzept über den Haufen geschmissen.

    Kürzlich habe ich verschiedene Möglichkeiten gefunden, mit denen Singleton-Objekte definiert werden. Erste Möglichkeit:
    hier bei Github mit dem Code-Auszug

    QJoysticks *QJoysticks::getInstance()
    {
       static QJoysticks joysticks;
       return &joysticks;
    }
    

    Dann habe ich noch einen zweiten Ansatz gefunden:
    zweiter Ansatz
    und einen dritten mit einem Template. Mit einem Template (wie dort beschrieben als auch abgeändert) kann ich mir momentan am ehesten vorstellen, dass das für mich der bessere Lösungsweg ist. Denn: Klassen wie current, fuel, hydraulics etc. brauche ich nur eine Instanz, um die aktuellen Werte zu haben und diese müssen zum Weiterverarbeiten abgerufen werden können.

    Im sogenannten Overhead Panel (nachfolgend von mir OHP genannt) einer B777 sind einige Schalter und Taster (Electrics, Fuel, Hydraulics etc.) deren Schaltzustände den Ablauf zur "Runtime" des Programms wichtig sind. Es gibt zudem noch 5 Monitore (PFD, ND, EICAS, MFD und CDU) die unterschiedliche Werte/Grafiken anzeigen und als Widget, gezeichnet mit dem QPainter, deklariert werden.
    Mein erstes C++/Qt-Konzept sieht so aus:
    Ein großes Widget für das Overhead Panel mit PushButtons, die in die einzelnen Klassen wie Engine, Current (bzw. im OHP Electrics) den Schaltzustand weitergeben.
    Das zweite noch nicht Ausprobierte ist, jedem Teil des OHP als Widget UND den zugehörigen Eigenschaften des Systems zu vereinen.
    Noch eines vorneweg: Die Werte von Current (also z.B. Battery on/off, APU off/start/on/cooldown, Left/Right Main Current on/off) in den meisten anderen Klassen zwingend bereitzustellen. Weil sich damit das Verhalten ändern kann.

    Das ist jetzt erst einmal viel geschriebenes, aber ohne dieses Hintergrundwissen könnt ihr mir wahrscheinlich nicht konkret weiterhelfen. Ich wünsche mir zum aktuellen Stand folgendes:
    Die 4 Monitore sollen bestimmte verschiedene Inhalte anzeigen können. Wenn jetzt z.B. Monitor 0 das PFD anzeigt und ich per Schalter das PFD auf den Monitor 1 lege, muss das PFD-Objekt die aktuellen Ereignisse anzeigen bzw. besser gesagt nicht eine neue Instanz von PFD erzeugen. Vom PFD soll weiterhin nur eine Instanz, also abgeleitet vom Singleton-Template und vom QWidget sein. Dieses Umschalten einer Monitoranzeige habe ich momentan mit einer eigenen Funktion realisiert:

    void Monitor::SetMyChild(QWidget* mychild)
    {
    	mychild->setParent(this);
    	mychild->show();
    }
    

    this wäre hier bspw. die Instanz monitor[1] und mychild = die Instanz von PFD.
    Die Klasse Monitor muss also auf die Instanzen von ND, PFD, EICAS etc. zugreifen.

    Ich weiß nicht, ob dieser Weg für dieses Vorhaben der richtige ist:
    in main wird das StartWindow erzeugt mit einer Angabe im std::string Format und nach der Auswahl wird das MainWindow erzeugt und dort die Auswahl (Flughafenposition des Flugzeugs) ausgewertet wird und in dem alle anderen Widgets und Current-, Fuel-, Engine-Instanzen erzeugt werden. Bisher habe ich über ein QTimer-"Interval" eine Funktion aufgerufen (bisher alle 0.5 sec = 500 ms) die alles kontinuierlich berechnet und überwacht. Sollte diese Funktion in der MainWindow-Klasse oder besser über eine GameEngine-Klasse definiert sein? Falls im MainWindow, wäre es unter Umständen vielleicht besser, da dann die hier erzeugten Instanzen bekannt sind und nicht mehr weitergereicht werden müssen. Die GameEngine müsste sonst Zugriff auf Klassen wie Current, Fuel, Hydraulics etc. haben.

    Mein Problem ist nicht, wie das Flugzeugverhalten programmiert und innerhalb der Monitore angezeigt werden soll, sondern quasi der Aufbau des Programms und der Klassen. Ich hoffe, ihr könnt mir soweit folgen was ich vorhabe und was ich brauche... Ansonsten bin ich natürlich auch gerne bereit weiteres zu erklären. So das war jetzt der Einstieg und ich hoffe auch hilfreiche Antworten...
    Vielen Dank im Voraus.

    Edit: Eine Frage kommt nicht klar heraus: Kann ich eine Klasse mit einem Qwidget und dem QPainter im drawEvent zusammen mit den Eigenschaften und Methoden zusammenpacken? Also z.B. Current mit den Schaltzuständen der Taster und die OHP "Electrics"-Anzeigen auf den QPushButtons im OHP.

    Edit: Schreibfehler korrigiert



  • Ach so: Die Klassen die nur eine Instanz haben sollten NICHT static sein, da auch auf die beiden Instanzen von Engine (also engineL und engineR = den Triebwerken) ein Zugriff ermöglicht werden sollte. Statische Objekte können nicht auf nicht-statische Objekte zugreifen, wie man mir hier im Forum beigebracht hat.

    Des weiteren sollte das "richtige" Konzept mit dem Signal-Slot Prinzip von Qt arbeiten. Da fällt mir ein, dass es darum umso mehr besser wäre, alle QWidgets-Klassen und QPushButtons über das MainWindow zu erzeugen damit dieses eben genannte Prinzip auch gut läuft.



  • @stefanpc81 sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    Hinweis: Javascript ist was anderes als Java!

    Ich denke das weiss so ziemlich jeder der hier mitliest.

    Das ging aber schnell an die Grenzen des Prozessors bzw. RAM des PCs.

    Dann hast du vermutlich irgendwas falsch gemacht. JavaScript ist nicht so lahm wie viele meinen. (Es ist mMn. eine elendige Dreckssprache, aber langsam ist es nicht.)



  • @hustbaer Danke für deinen Beitrag.
    Darum geht es mir jetzt aber nicht. Mit C++ und Qt kann ich vieles besser und zusätzlich grafisches darstellen und mit dieser objektorientierten Programmiersprache kürzeren Code schreiben als mit Javascript.
    Meinen Simulator will ich mit C++ schreiben, die mit Javascript ist Vergangenheit bzw. da mache ich nichts mehr mit. Im Visual Studio habe ich zudem auch einen viel besseren Überblick. ☺



  • @stefanpc81 sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    Der erste Weg sieht in etwa so aus, dass ich die Klasseninstanzen (current, engineL, engineR, fuel etc.) an andere Klassen, die die aktuellen Daten brauchen, über den Konstruktor übergeben habe. Ich wurde eines besseren belehrt, dass man gegenseitige Klassen nicht aufrufen sollte... Deshalb habe ich mein Konzept über den Haufen geschmissen.

    Kürzlich habe ich verschiedene Möglichkeiten gefunden, mit denen Singleton-Objekte definiert werden.

    Wie kommst du auf die Idee, dass man gegenseitig keine Klassen aufrufen soll. Composition ist ein gängiges und übliches Mittel. Auch Abhängigkeiten über den Konstruktor weiterzugeben ist üblich, siehe dependency injection.

    Ich würde von Singletons abraten. Die machen es nur schwerer die einzelnen Komponenten mit Unittests zu testen.

    Ansonsten habe ich gerade keine Zeit/Lust mir ein Klassendesign für einen Flugsimulator aus dem Ärmel zu schütteln. Ich würde dir raten, hier konkrete Fragen zu stellen, dann gibt es i.d.R. auch konkrete Antworten 😉

    @stefanpc81 sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    Kann ich eine Klasse mit einem Qwidget und dem QPainter im drawEvent zusammen mit den Eigenschaften und Methoden zusammenpacken? Also z.B. Current mit den Schaltzuständen der Taster und die OHP "Electrics"-Anzeigen auf den QPushButtons im OHP.

    Prinzipiell "kann" man sehr viel. Eigentlich sollte jede Klasse für eine einzige Sache zuständig sein. (Single-responsibility principle)
    Wenn es um die konkrete Implementierung geht, dann bitte ein Beispiel mit Code, dass ist viel eindeutiger als jede Menge Text und Metaerklärungen.



  • @Schlangenmensch sagte:

    Wie kommst du auf die Idee, dass man gegenseitig keine Klassen aufrufen soll.

    Das schrieb Miglied Th69 bei https://www.c-plusplus.net/forum/topic/353112/problem-bei-zugriff-auf-eine-funktion-einer-anderen-klasseninstanz/2 Ich wusste nicht mehr genau den Kontext dazu, da habe ich etwas durcheinander gebracht...

    Composition ist ein gängiges und übliches Mittel. Auch Abhängigkeiten über den Konstruktor weiterzugeben ist üblich, siehe dependency injection.

    Ich würde von Singletons abraten. Die machen es nur schwerer die einzelnen Komponenten mit Unittests zu testen.

    Danke für die Ratschläge.

    Ansonsten habe ich gerade keine Zeit/Lust mir ein Klassendesign für einen Flugsimulator aus dem Ärmel zu schütteln.

    Das war auch gar nicht meine Absicht. Mit deinen Infos bin ich jetzt schlauer und sicherer wie ich vorgehen KANN. Mir ging es mehr darum, wo ich etwas Neues erzeuge, aufrufe usw.

    Ich würde dir raten, hier konkrete Fragen zu stellen, dann gibt es i.d.R. auch konkrete Antworten 😉

    Mach ich, sobald ich irgendwo nicht mehr weiterkomme.

    @stefanpc81 sagte:

    Kann ich eine Klasse mit einem Qwidget und dem QPainter im drawEvent zusammen mit den Eigenschaften und Methoden zusammenpacken? Also z.B. Current mit den Schaltzuständen der Taster und die OHP "Electrics"-Anzeigen auf den QPushButtons im OHP.

    Prinzipiell "kann" man sehr viel. Eigentlich sollte jede Klasse für eine einzige Sache zuständig sein. (Single-responsibility principle)
    Wenn es um die konkrete Implementierung geht, dann bitte ein Beispiel mit Code, dass ist viel eindeutiger als jede Menge Text und Metaerklärungen.

    Ok, danke!



  • @stefanpc81 sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    Das schrieb Miglied Th69 bei https://www.c-plusplus.net/forum/topic/353112/problem-bei-zugriff-auf-eine-funktion-einer-anderen-klasseninstanz/2 Ich wusste nicht mehr genau den Kontext dazu, da habe ich etwas durcheinander gebracht...

    In dem Beispiel wolltest du in A Sachen aus B aufrufen und aus B Sachen aus A. Das ist was anderes 😉



  • @Schlangenmensch sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    Wie kommst du auf die Idee, dass man gegenseitig keine Klassen aufrufen soll.
    ...
    In dem Beispiel wolltest du in A Sachen aus B aufrufen und aus B Sachen aus A. Das ist was anderes 😉

    Ja genau, es geht hierbei um das "gegenseitig".

    @stefanpc81: Ich würde außerdem auch dir raten, auf Singletons zu verzichten (neben der schlechteren Testbarkeit umgehen sie auch gutes Design, da sie - wie globale Variablen - von überall aufgerufen werden können).



  • @stefanpc81
    Bevor du dich an die Implementierung machst, würde ich dir empfehlen ein UML Klassendiagramm zu entwickeln. So kannst du die einzelnen Komponenten deiner Simulation und deren Beziehungen erkennen.

    Ein Beispiel: Ein B777 Overhead Panel (OHP) besteht aus dem ND Monitor, dem PFD Monitor, usw.

    Vom PFD soll weiterhin nur eine Instanz, also abgeleitet vom Singleton-Template und vom QWidget sein.

    Und genau deswegen ist ein PFD Monitor kein Singleton. Nur weil ein Objekt A aus exakt einem Objekt B besteht, bedeutet dies nicht dass das Objekt immer nur einmal instanziiert werden darf.



  • @Quiche-Lorraine sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    @stefanpc81
    Bevor du dich an die Implementierung machst, würde ich dir empfehlen ein UML Klassendiagramm zu entwickeln. So kannst du die einzelnen Komponenten deiner Simulation und deren Beziehungen erkennen.

    Das habe ich noch nie gemacht. Aber ich habe aus älteren Versionen viel Code zum Kopieren bzw. zum Nachsehen. Ich mache mir teilweise auf Papier Pläne, wie mit dem aktuellen Projekt was wie ablaufen soll usw.

    Ein Beispiel: Ein B777 Overhead Panel (OHP) besteht aus dem ND Monitor, dem PFD Monitor, usw.

    Da hast du was falsch verstanden 😉 Das OHP befindet sich an der Decke und hat mehrere Schalter und Drehregler (bzw. in Englisch switches, selectors). Die Monitore sind unterhalb des Cockpitfensters angeordnet und haben (fast) keine direkte Eingabefunktion.

    @all Vielen Dank nochmals! Das heutige aktuelle Projekt ist begonnen und bisher läuft es. Wenn ich Glück habe, bin ich auf dem richtigen Weg. Und vom Singleton habe ich mich persönlich auch verabschiedet!



  • @stefanpc81 sagte in Brauche Beratung/Hilfe zu einem Cockpitsimulator (Flugzeug):

    @hustbaer Danke für deinen Beitrag.
    Darum geht es mir jetzt aber nicht. Mit C++ und Qt kann ich vieles besser und zusätzlich grafisches darstellen und mit dieser objektorientierten Programmiersprache kürzeren Code schreiben als mit Javascript.

    Ich weiss dass es darum nicht ging. Ich wollte dir nur mitteilen dass du die Möglichkeiten und Performance von JavaScript vermutlich etwas falsch einschätzt. Auf die eigentliche Frage(n?) hab ich nicht geantwortet weil ich ehrlich gesagt zu faul war die ganze Wall-of-Text ausreichend aufmerksam zu lesen um die ne sinnvolle Antwort geben zu können.

    Meinen Simulator will ich mit C++ schreiben, die mit Javascript ist Vergangenheit bzw. da mache ich nichts mehr mit. Im Visual Studio habe ich zudem auch einen viel besseren Überblick. ☺

    Darfst du natürlich gerne! Wünsche viel Spass und guten Erfolg damit. Und wie schon geschrieben wurde: kürzere Fragen, vielleicht auch mit kleinem Code-Beispiel, bekommen schneller/bessere Antworten. Wenn die Frage ist wie man etwas in C++ macht, kannst du auch gerne ein Code-Beispiel bringen in dem du die Teile wo du nicht weisst wie man es macht mit Kommentaren beschreibst.



  • @hustbaer Vielen Dank für die nette Antwort!


  • Gesperrt

    Dieser Beitrag wurde gelöscht!

Anmelden zum Antworten