Tastatur-Abfrage in jedem Schleifendruchgang?

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

Guten Abend liebe ZFX'ler :)

Mir brennt wiedermal eine - ich vermute - Anfängerfrage unter den Nägeln.
Es geht um folgendes:

In meinem kleinen Spiel reagiert der Player offensichtlich nicht mehr immer auf die Tastatureingabe.
Seit ich den Simulationsteil nur ausführe, nachdem ein bestimmtes Zeitdelta erreicht ist, fallen die Ereignisse [PFEILTASTE] und zeitdelta > 2ms oftmals nicht mehr zusammen.
Nach genauerem Ausprobieren habe ich festgestellt, dass das Ereignis "event.key.keysym.sym" trotz gedrückter Taste, nur in jedem (ca.) 50-sten Schleifendruchlauf auf SDLK_UP gesetzt ist.

Die Tastatur frage ich zur Zeit mittels der SDL folgender Massen ab:

Code: Alles auswählen

while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) {
				running = false;
			}
			else if (event.type == SDL_KEYDOWN) {
				switch (event.key.keysym.sym) {
				case SDLK_UP:
					player.move = true;
					break;
			         }
                         }
}
Gibt es vielleicht eine Methode, mit der ich mit Sicherheit in jedem Schleifendurchgang den "wahren" Status der Tastatur ermitteln kann?
Oder gehe ich das ganze irgendwie verkehrt an?

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
joeydee
Establishment
Beiträge: 1039
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von joeydee »

SDL kann ein Keystate-Array liefern: https://wiki.libsdl.org/SDL_GetKeyboardState
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von xq »

Nach genauerem Ausprobieren habe ich festgestellt, dass das Ereignis "event.key.keysym.sym" trotz gedrückter Taste, nur in jedem (ca.) 50-sten Schleifendruchlauf auf SDLK_UP gesetzt ist.
Du bekommst für jeden Button Press ein Event. Wenn du die Taste initial drückst, bekommst du einmal ein Event, wenn du die Taste jetzt hältst, wird der Key Repeat deiner Tastatur ausgeführt (damit: die Taste wird regelmäßig gedrückt).

Wenn du (ohne SDL_GetKeyboardState) wissen willst, ob eine Taste gedrückt ist, sollte das ca. so aussehen:

Code: Alles auswählen

while (SDL_PollEvent(&event)) {
    if (event.type == SDL_QUIT) {
        running = false;
    }
    else if (event.type == SDL_KEYDOWN) {
        switch (event.key.keysym.sym) {
            case SDLK_UP:
                player.move = true;
                break;
        }
    }
    else if (event.type == SDL_KEYUP) {
        switch (event.key.keysym.sym) {
            case SDLK_UP:
                player.move = false;
                break;
        }
    }
}
Du darfst player.move natürlich nicht zurücksetzen in deinem Game Loop
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

Super, ich sehe jetzt was ich falsch gemacht hatte! :-)
Ich hatte tatsächlich player.move in jedem Schleifendurchgang auf "false" zurückgesetzt, da mir nicht klar war, dass sich mittels "event.type == SDL_KEYUP" ermitteln lässt, wann eine Taste nicht gedrück ist.

Zu welcher Methode würdet ihr mir denn raten, wenn es darum geht, eine Spielfigur zu steuern (laufen, drehen)?
Beim Drehen der Spielfigur fällt nämlich auf, dass sie sich beim Drücken der Taste zuerst um eine Einheit dreht, dann kurz pausiert und erst danach das kontinuierliche Drehen (quasi das "Dauerfeuer") einsetzt.

Ich vermute, mit einer Methode über SDL_GetKeyboardState wird dies anders sein, richtig?

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von xq »

starcow hat geschrieben:Ich vermute, mit einer Methode über SDL_GetKeyboardState wird dies anders sein, richtig?
Ja, mit SDL_GetKeyboardState bekommt man den Zustand der Tastatur beim letzten Aufruf von SDL_PollEvent. Damit kannst du dann gezielt jegliche Taste auf "gedrückt" oder "nicht gedrückt" abfragen und musst das nicht selbst tracken. Für ein Spielermovement interessiert dich ja normalerweise nicht das Event, abgesehen von so Sachen wie "Dash" oder "Hüpfen", dafür solltest du dann die Events nehmen
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

Ok, das klingt einleuchtend. Vielen Dank. :-)

In der SDL-Doku ist unter SDL_GetKeyboardState noch folgendes vermerkt:
Note: This function gives you the current state after all events have been processed, so if a key or button has been pressed and released before you process events, then the pressed state will never show up in the SDL_GetKeyboardState() calls.
Wenn ich das richtig verstehe, könnte es sein - vorausgesetzt der Schleifendurchgang dauert z. B. durch einen "Slowdown" eine gewisse Zeit -, dass wenn man schnell genug eine Taste drückt und wieder loslässt, das Spiel dies nicht "mitbekommt". Einfach weil das entsprechende Array-Feld bei der Abfrage bereits wieder auf 0 steht.

Ideal scheint mir, dass alle Tastatureingaben - unabhängig wann diese zeitlich stattfinden - einen Zyklus erhalten bleiben.
Lässt sich das irgendwie realisieren oder führt das jetzt zu weit?

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von Krishty »

Ich unterscheide grundsätzlich zwischen kontinuierlichen und diskreten Eingaben.

Eine kontinuierliche Eingabe ist z.B. „vorwärts laufen“. Eine diskrete Eingabe wäre „pausieren“.

Das, was du gerade abfragst, sind kontinuierliche Eingaben. Wenn W gedrückt ist, bewegst du den Spieler vorwärts. Jeden Frame das gleiche. Da ist es eigentlich nicht schlimm, wenn die Eingabe „verschluckt“ wird – sie wäre eh so kurz gewesen, dass es nicht viel ausmacht.

Diskrete Eingaben musst du über die Events abfragen, wie du es vorher getan hast – wenn ESC gedrückt wurde (egal wie lange), pausierst du. Nicht in jedem Frame, in dem ESC gedrückt ist. Nur beim ersten Drücken. Das wird aber auch nicht verschluckt, denn das Event kriegst du so oder so.

Stell dich also drauf ein, beide Systeme parallel zu verwalten und nicht ausschließlich bei SDL_GetKeyboardState() zu bleiben, weil es gerade dein Problem löst.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

Ok, verstehe - klingt auch sehr sinnvoll. Ich werde dein Prinzip gerne übernehmen. Danke fürs Teilen :daumen: :mrgreen:

In der SDL 2.0-Doku unter "SDL_PumpEvents" bin ich noch auf folgenden Hinweis gestossen:
WARNING: This should only be run in the thread that initialized the video subsystem, and for extra safety, you should consider only doing those things on the main thread in any case.
Ist mit "main thread" die main-Funktion gemeint? Also, man darf den Funktionsaufruf "SDL_PumpEvents" nicht in andere Funktionen auslagern?
Oder bezieht sich dieser "main thread" auf komplett was anderes.
Zur Zeit liegt der Funktionsaufruf "SDL_PumpEvents" bei mir noch in der main-Funktion - doch ich hatte eigentlich geplant eine separate Funktion für die Tastatur-Abfrage anzulegen...

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von xq »

Ich wüsste ehrlich gesagt nicht, wofür du SDL_PumpEvents brauchst, SDL_PollEvent fragt die Events auch schon ab.

SDL_PumpEvents brauchst du nur, wenn du ohne eigenes Verarbeiten der Events einen aktualisierten Tastatur-Zustand oder ähnliches brauchst
starcow hat geschrieben:Ist mit "main thread" die main-Funktion gemeint? Also, man darf den Funktionsaufruf "SDL_PumpEvents" nicht in andere Funktionen auslagern?
Nein, das ist so gemeint, wie es da steht: Die Main-Funktion wird im Main Thread gestartet und alle Funktionsaufrufe davon landen auch im Main Thread. Das ganze bezieht sich auf Multithreading, aber ich gehe mal davon aus, dass du das nicht nutzt ;)
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

MasterQ32 hat geschrieben:Ich wüsste ehrlich gesagt nicht, wofür du SDL_PumpEvents brauchst, SDL_PollEvent fragt die Events auch schon ab.

SDL_PumpEvents brauchst du nur, wenn du ohne eigenes Verarbeiten der Events einen aktualisierten Tastatur-Zustand oder ähnliches brauchst
starcow hat geschrieben:Ist mit "main thread" die main-Funktion gemeint? Also, man darf den Funktionsaufruf "SDL_PumpEvents" nicht in andere Funktionen auslagern?
Nein, das ist so gemeint, wie es da steht: Die Main-Funktion wird im Main Thread gestartet und alle Funktionsaufrufe davon landen auch im Main Thread. Das ganze bezieht sich auf Multithreading, aber ich gehe mal davon aus, dass du das nicht nutzt ;)
Ok, danke Master! Ja, du ahnst da schon richtig - ich wüsste jetzt auch gar nicht, wie man eine Multithreading-Solution aufsetzt :>

Bezüglich den SDL_PumpEvents: Ich bin durch den Wiki-Eintrag von SDL_GetKeyboardState auf diesen Trichter gekommen.
Da steht:
Remarks
Note: Use SDL_PumpEvents() to update the state array.
Ich bin jetzt davon ausgegangen, das SDL_GetKeyboardState (resp. zu dessen Aktualisierung) nur in Kombination mit SDL_PumpEvents richtig funktioniert.
Aber interessant zu wissen, das es auch mit SDL_PollEvent geht.

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von xq »

https://wiki.libsdl.org/SDL_PumpEvents hat geschrieben:SDL_PumpEvents() gathers all the pending input information from devices and places it in the event queue. Without calls to SDL_PumpEvents() no events would ever be placed on the queue. Often the need for calls to SDL_PumpEvents() is hidden from the user since SDL_PollEvent() and SDL_WaitEvent() implicitly call SDL_PumpEvents(). However, if you are not polling or waiting for events (e.g. you are filtering them), then you must call SDL_PumpEvents() to force an event queue update.
Steht doch direkt unter der Warning, dass SDL_PollEvent() und SDL_WaitEvent() auch aufrufen ;)

An was bastelst du eigentlich grade?
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von starcow »

MasterQ32 hat geschrieben: Steht doch direkt unter der Warning, dass SDL_PollEvent() und SDL_WaitEvent() auch aufrufen ;)
Tatsächlich... :oops:
MasterQ32 hat geschrieben: An was bastelst du eigentlich grade?
Eigentlich an meinem ersten richtigen "Mni-Spiel-Prototyp" wenn man so will (-:
Dabei geht es mir - neben dem eigentlichen Mini-Spiel natürlich - auch darum, die Techniken bisschen kennen zu lernen und zu Programmieren. :-)
Auch wenn ich nur im Schneckentempo vorwärts komme... Der Spass an der Freude ist trotzdem sehr gross :mrgreen:

Nachdem ihr mir ja schon reichlich gute Tipps gegeben habt, welche Stationen man wann anpeilen sollte, bin ich jetzt dabei, das ganze so vorzubereiten, damit ich mich danach der Kollisionsabfrage annehmen kann.
joeydee hat mir da ja freundlicherweise eine solide Anleitung erstellt, wie ein "sweep and prune" Algorithmus aufzugleisen ist.
Aber dazu muss sich ja erstmal die Spielfigur (Kreis) irgendwie übers Spielfeld bewegen können - um das ganze zu testen. ^^
Im Moment sieht das Projekt jetzt so aus:
Bild

Die roten Linien stellen dabei die Mauern dar, welche aus einem Array gelesen werden.

Das grosse Ziel dieses Projektes wäre dann, neben der Kollision, auch eine erste Art Gameplay zu entwickeln - so dass der Player an den Mauern entlang "sliden" kann.
Dabei begeistert mich ja schon, dass sich der Kreis smooth über den Bildschirm steuern lässt :mrgreen: - und dies nicht zuletzt durch eure kompetente Hilfe!
Eure Unterstützung bedeutet mir da echt sehr viel... (Ich hoffe euch mit meinen Anfängerfragen nicht zu sehr "zu löchern") (-:

Ist dein Avatar eigentlich eine Figur aus einem deiner Spiele?

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: Tastatur-Abfrage in jedem Schleifendruchgang?

Beitrag von xq »

Ist dein Avatar eigentlich eine Figur aus einem deiner Spiele?
Haha, nein, das ist ein Krieger-Meerschweinchen aus Sunless Sea

Viel Erfolg mit deinem Prototypen!
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Antworten