Maus in SDL einschließen

12

Wie kann ich die Maus des Benutzers in meinem Spiel fangen? Es ist kein Vollbild-Spiel, aber ich möchte, dass der Benutzer die Maus nicht außerhalb des Bildschirms ziehen kann.

Muss ich die Koordinaten der Maus und von SDL_WarpCursor überprüfen, damit sie (manuell) im Fenster angezeigt werden, oder gibt es eine automatische Möglichkeit?

Vielen Dank.

David Gomes
quelle
Haben Sie darüber nachgedacht, den Cursor auszublenden und ihn wieder in die Mitte zu verschieben? Zeichnen Sie dann anstelle des OS-Cursors einfach Ihr Fadenkreuz in die Mitte des Bildschirms.
Vaughan Hilts

Antworten:

24

Während Sie dies mit SDL_WarpCursor () implementieren können, sind auf einigen Plattformen Probleme mit dieser Methode aufgetreten. Ich hatte echte Probleme mit einigen Plattformen, die die WarpCursor () - Aktion nicht zuverlässig ausführten, insbesondere, wenn ich sie für jeden Frame aufgerufen habe.

Denken Sie auch daran, dass der Cursor auf vielen Plattformen mit einer höheren Häufigkeit als Ihre App behandelt wird. Dies gilt insbesondere, wenn Sie unter 60 fps laufen! Selbst wenn die Plattform die Maus in jedem Frame Ihres Spiels erfolgreich verzieht, kann der Cursor dennoch von Ihrem Fenster entfernt werden, wenn Aktualisierungen zwischen Ihren gerenderten Frames empfangen werden.

Die korrekte Methode zum Einfangen der Maus unter SDL lautet:

SDL_WM_GrabInput( SDL_GRAB_ON );

Dies teilt SDL mit, dass Sie beabsichtigen, die vollständige Kontrolle über Maus und Tastatur zu erlangen (siehe Dokumentation ) und die Maus daher unabhängig von der jeweiligen Situation im Fenster zu lassen. Ab diesem Zeitpunkt bewegt sich die Maus unabhängig von Ihrer Framerate nicht mehr außerhalb des Fensters, und Sie sollten SDL_WarpCursor nicht mehr aufrufen, es sei denn, Sie möchten den Cursor tatsächlich irgendwohin teleportieren, anstatt ihn ständig zu spammen.

In diesem "Grabbing" -Modus empfangen Sie weiterhin Mausbewegungsereignisse, als wäre die Maus im Fenster nicht eingeschränkt. (Wenn sich der Cursor also am rechten Bildschirmrand befindet und der Benutzer die Maus weiter nach rechts bewegt, wird ein Mausbewegungsereignis angezeigt, das die Bewegung nach rechts anzeigt, die Cursorposition ändert sich jedoch nicht.) Dies ist sehr nützlich, wenn Sie beispielsweise die Steuerelemente für FPS-Spiele drehen, bei denen Sie sich nur um die relative Bewegung des Cursors und nicht um seine absolute Position kümmern.

Update für SDL2 - 9. Dezember 2013

Diese Schnittstelle wurde für SDL2 geändert. Wenn Sie SDL1.2 verwenden, ist die obige Antwort immer noch korrekt. Unter SDL2 ist die SDL_WM_GrabInput(SDL_GrabMode)Funktion jedoch nicht mehr verfügbar. SDL2 bietet die folgenden neuen Möglichkeiten zum Erfassen der Maus:

SDL_SetRelativeMouseMode(SDL_TRUE);

Ansonsten ist dies identisch mit der vorherigen Funktion - in diesem Modus werden weiterhin SDL_MOUSEMOTIONEreignisse empfangen , als ob die Maus nicht innerhalb des Fensters eingeschränkt wäre.

Trevor Powell
quelle
1
Vorsichtsmaßnahme: Ich habe festgestellt, dass ich auf einigen Plattformen sofort nach dem Einschalten des Mausgreifens ein falsches MouseMotion-Ereignis mit einer sehr großen Bewegung erhalte. Um damit umzugehen, habe ich meinen Code das erste Mausbewegungsereignis ignoriert, das nach dem Einschalten dieses Modus empfangen wurde.
Trevor Powell
Das hat perfekt funktioniert, und es ist viel einfacher als der manuelle Weg. Vielen Dank!
David Gomes
3

Die aktualisierte Antwort von Trevor gibt zwar den aktuellen Status von SDL2 wieder, Sie können jedoch auch die Maus fangen, indem Sie Ihre SDL_Windowmit dem SDL_WINDOW_INPUT_GRABBEDSet erstellen . Beachten Sie, dass ich unter Linux auf einige seltsame Probleme gestoßen bin (vermutlich aufgrund von X-Fenstern), bei denen Sie das Fenster erst verlassen können, wenn SDL_QUIT aufgerufen wird (auch wenn ein anderes OS-Ereignis den Fokus verliert).

Justin Skiles
quelle
Vielen Dank, SDL_WINDOW_INPUT_GRABBED funktioniert perfekt mit meinem SDL2-Code.
Adrian Maire
3

Für SDL2 scheint es auch die Funktion SDL_SetWindowGrab zu geben, wenn Sie sie aktivieren und deaktivieren möchten.

SDL_SetWindowGrab(SDL_Window* window, SDL_bool grabbed)
Michael Shaffer
quelle
2

Du kannst den ... benutzen SDL-Bewegungsereignis erkennen, wann sich die Maus bewegt. Anschließend können Sie WarpCursor innerhalb dieses Befehls aufrufen, auch nachdem Sie ein Ereignis ausgelöst haben, um die relX- und relY-Werte weiterzuleiten. Sie können den OS-Cursor auch ausblenden und ein Fadenkreuz oder ähnliches in die Mitte des Bildschirms zeichnen. Dies stellt sicher, dass die Maus für den Benutzer immer in der Mitte zu sein scheint und Sie weiterhin Werte für Bewegung und dergleichen erhalten können.

Vaughan Hilts
quelle