Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

ERROR

Alter Hase

  • »ERROR« ist der Autor dieses Themas

Beiträge: 417

Wohnort: Paderborn

Beruf: Informatik Student

  • Private Nachricht senden

1

25.01.2014, 23:10

Code Design Problem

Ich habe ein kleines Code Design Problem und zwar geht es um die Abfrage des Inputs.

1)
Ich programmiere es meistens so, dass an jeder Stelle an der es um bestimmten Input geht, dieser jedes Mal einzeln angefragt wird.
Zum Beispiel prüft das UI nach Mausklick und wo dieser war, dann prüft irgendetwas bewegliches ob die arrowkeys gedrückt wurden und so weiter.

2)
Die nächste Methode habe ich selber noch nie benutzt(bisher nicht benötigt), aber sie scheint verbreiteter zu sein. Damit meine ich: Man prüft den Input und wertet diesen anschliessend an den Stellen an denen er benötigt wird aus.
Es gibt irgendwo relativ am Anfang der Hauptschleife eine Abfrage nach sämtlichen Input, dieser wird gespeichert und an die Methoden die ihn brauchen weiter gegeben.



Auf den Punkt gebracht ist meine Frage nun: Welche der beiden (oder andere?)Methoden benutzt ihr, ist am meisten verbreitet usw. Ich hoffe ich konnte erklären was ich meine :)

2

26.01.2014, 01:49

#binfür2
Ich trickse ein bisschen. Ich lass alle Events in einen Container stecken und werte die dann in einer eigens dafür angefertigten Klasse aus, die dann als Referenz an die jeweiligen Gamestates gegeben wird, die das Ganze dann weiter 'verarbeiten'.
Das ist einfach schön modular, im Gegensatz zu ersterem. Des Weiteren kann ich so die Steuerung auch ganz leicht verändern, wenn ich wollen würde. Die Erfahrung habe ich bei Ersterem zu meinen Beginnertagen der Beginnertagen, denn ich halte mich noch immer nicht für einen Nicht-Beginner, nicht erlebt. Ich hatte nicht wenig Probleme mit dem Input, gerade was Design angeht.

MfG
Check

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

3

26.01.2014, 13:16

Die zweite Methode ist auch die einzig richtige.
Der Input muss nur die Nachrichten weiter leiten. Die Objekte, die diese Nachrichten erhalten, müssen selbst dafür verantwortlich sein was sie damit machen.
Wenn du das nicht so machst können deine Abhängigkeiten bis ins Unendliche steigen und irgendwann kannst du nichts mehr ändern ohne 10 Dateien zu bearbeiten.

Versuch alles so abstrakt wie möglich zu halten. Klassen sollten wenn möglich eine einzige! klar definierte Aufgabe haben, die sie geschlossen löst. Die Klasse die den Input verwaltet und weiter leitet muss und darf nicht wissen was sie damit auslöst. Der Vorteil ist nicht nur, dass der Code übersichtlicher ist und du Fehler schneller findest sondern auch, dass du dich danach nicht mehr um die Inputverwaltung kümmern musst und daher vergessen kannst was in ihrem inneren genau passiert. Das ist wiederum eine Voraussetzung dafür, dass andere Programmierer deine Klassen nutzen können.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

4

26.01.2014, 16:31

Wenn ich Option 2 richtig verstanden habe, dann rate ich dir auch zu dieser Option.

Bei mir unterscheide ich zwischen Low-level Input und High-level Input. Beispielsweise wäre ein Low-level Input "Taste X gedrückt" und ein High-level Input "Springen". Die Low-level Inputs werden von einem ActionMapper-Objekt abgefangen und auf High-level Inputs (Actions) gemappt: Leertaste gedrückt -> Springen. Die Actions werden anschließend von einem Controller-Objekt ausgewertet: if (actions.hasBecomeActive(Action::Jump)) ... Abhängig vom Ergebnis wird der Entity, die dem Controller zugewiesen ist, ein Befehl gesendet (in diesem Fall der Befehl zum Spingen).

So ungefähr habe ich die zweite Option verstanden.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

5

26.01.2014, 16:45

Bitte sag nicht, Jump eine Konstante eines Enums ist... Damit verdirbst du dir doch die ganze Flexibilität.

Eine "einfache" Möglichkeit ist, ein Objekt zu erstellen, dass beim Eventmanager eingetragen werden muss. Das Objekt teilt dem Eventmanager mit unter welchen Umständen es Aktiv ist und der Eventmanager teilt dem Objekt Änderungen an dem Zustand des Events mit.
Pseudocode:

C-/C++-Quelltext

1
2
Event event(Tastendruck(Taste::Leertaste), eventmanager); // Neues Event wird erstellt und es meldet sich Automatisch beim übergebenen Manager an.
if(event.aktiv()) // Prüfung ob das aktiv ist.

Das lässt sich mit Interfaces stark ausbauen. Mit etwas Arbeit könntest du sogar einen Tastendruck von einem entfernten Rechner angeben ohne viel zu ändern.

edit: Danke, für die Frage. Nun weiß ich wie ich meine NetzwerkEvents verwalte. Meinen Kollegen wird das gefallen. :whistling:

Hier wird erklärt wie es in Unity funktioniert: https://docs.unity3d.com/Documentation/Manual/Input.html
Lass dich ruhig inspirieren.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »NachoMan« (26.01.2014, 16:53)


ERROR

Alter Hase

  • »ERROR« ist der Autor dieses Themas

Beiträge: 417

Wohnort: Paderborn

Beruf: Informatik Student

  • Private Nachricht senden

6

26.01.2014, 16:52

Danke für eure ganzen Tipps, ich werde dann wohl die zeite Art wählen.

Ich dachte mir, dass ich es dann so aufbaue:

Es gibt eine zentrale Input Klasse. In dieser Klasse sind mehrere Container vorhanden, die für die relevanten Tasten angeben ob diese gedrückt sind oder nicht. Ich denke eine std::map wäre hier ganz hilfreich. Dann könnte ich die map mit den Tasten und einem jeweiligen bool befüllen. true = gedrückt und false != gedrückt. Diese Klasse könnte ich am Anfang der Hauptschleife Updaten und dann an alle, die die Informationen benötigen weitergeben.

Wäre das wohl so eine gute Methode oder eher nicht so? :)


Damit ich nicht eine std::map für den aktuellen und den letzten Durchgang machen musss, würde ich da auch eine eigene Klasse schreiben. Also eine Klasse für jeden Key mit Informationen wie Dauer, aktuell, letzer Durchganng usw. Die würde ich dann gerne in Container packen und sie aufrufbar machen per name der Taste, welchen Container sollte man dafür nehmen?
das sollte dann in etwa so aussehen:

C-/C++-Quelltext

1
2
Input.Keys('A'). IsPressed()
Input.Keys('A'). PressTime()//Ja der Name ist nicht der beste, aber es ist nur ein kleines Beispiel :D

ERROR

Alter Hase

  • »ERROR« ist der Autor dieses Themas

Beiträge: 417

Wohnort: Paderborn

Beruf: Informatik Student

  • Private Nachricht senden

7

26.01.2014, 17:42

Wieso? damit setze ich doch genau das um, was Nachoman sagte:

Zitat

Die Klasse die den Input verwaltet und weiter leitet muss und darf nicht wissen was sie damit auslöst.
So habe ich die eine Klasse, die den Input hat und anderen Klassen sagt, welcher Knopf gedrückt ist oder eben nicht. die jeweiligen klassen werten das ganze dann aus.

Ich übergebe dann die Input Klasse an die jeweiligen Klassen.
So wird beispielweise der Klasse Menü gesagt, dass Enter gedrückt wurde, aber die Menü Klasse muss selber sehen was sie damit macht.

Ist das nicht genau das Prinzip, welches ich verwenden soll, oder bin ich grade komplett auf dem falschen Wege?

Etwas Pseudocode:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
    GameLoop
    {
        Input.Update();
        If(Input.NewInput)
        {
            UpdateInputStuff(Input);
        }
        UpdateTimeBasedStuff() //Bewegungen usw die keinen Input vom Spieler (mehr) benötigen
        Draw()
    }

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

8

26.01.2014, 17:43

Ich habe meinen letzten Beitrag editiert während du gepostet hast. Unity macht das sehr gut.
Du brauchst auf jeden Fall ein Eventobjekt, weil dir das viele Vorteile bei kleinem Aufwand bietet.
War mein Beispiel zu klein?
Welche Bibliothek verwendest du?
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

ERROR

Alter Hase

  • »ERROR« ist der Autor dieses Themas

Beiträge: 417

Wohnort: Paderborn

Beruf: Informatik Student

  • Private Nachricht senden

9

26.01.2014, 18:16

Ich benutze nur SFML und halt C++.

Aber dann müsste der Eventhandler ja widerum wissen, was grade so alles passiert.
Nur weil grade "e" gedrückt wurde, heisst es ja nicht dass immer die gleiche Aktion ausgeführt wird.

Der Eventhandler müsste also wissen, was grade sonst noch anderes passiert, zum Beispiel, ob ich im Menü bin oder ob eine Figur angeklickt wurde oder ob grade ein QTE ist .... .Aber das widerspricht doch dem Prinzip. Wenn ich Allerdings den Input erstmal komplett einlese und ihn dann jede Klasse so auswerten lasse, wie sie es braucht, dann ist das doch genau das Prinzip, dass jede Klasse nur ihr eigenes Zeug macht.

Dann würde ich an verschiedenen Klassen den Input übergeben und dann würde das Menü zum Beispiel aus dem geklickten "e" nichts machen, der angeklickte Bauer würde wissen er soll ein Haus bauen, da grade ein Bauer ausgewählt wurde und er mit dem gedrückten "e" etwas anzufangen weiss, würde zB im GUI keine weitere Aktion ausgeführt werden (welche das auch immer wäre, mir fällt grade kein Beispiel ein).

Das ist doch genau die Art, der Programmierung, die immer empfohlen wird: Jede Klasse macht nur das was sie betrifft und weiss nur wass sie betrift. So weiss die Input Klasse, dass es Input gab und gibt diese information an andere Klassen ohne zu wissen was diese daraus machen.

EDIT:

Es wäre ja auch falsch einer Taste eine Aktion zuzuweisen, da diese
je nach Situation völlig anders sein kann. Habe ich ein QTE bei dem
Leetaste gedrückt wird, will ich ja nicht
if(Input.isPressed("Jump")) da stehen haben. sondern
if(Input.isPressed("Leer")).

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »ERROR« (26.01.2014, 18:21)


NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

10

26.01.2014, 18:58

Das erledigt die SFML schon für dich: http://sfml-dev.org/documentation/2.1/cl…1_1Keyboard.php

Es ist wichtig die "Tasten" als Events zu abstrahieren, damit das System flexibel wird. Sonst wird es dir nie möglich sein eine alternative Tastenbelegung im Spiel zu unterstützen.
Du kannst jedem Event eine Standardtaste geben und in dem Eventmanager mehreren Events die selben Tasten zuweisen. Wo liegt dann das Problem bei "Jump"? (abgesehen davon, dass die Identifierung über einen String auch nicht sooo schön ist)
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »NachoMan« (26.01.2014, 19:19)


Werbeanzeige