Trap mouse dans SDL

12

Comment piéger la souris de l'utilisateur dans mon jeu? Ce n'est pas un jeu en plein écran, mais je le veux pour que l'utilisateur ne puisse pas faire glisser la souris vers l'extérieur de l'écran.

Dois-je vérifier les coordonnées de la souris et de SDL_WarpCursor pour le faire dire à l'intérieur de la fenêtre (manuellement), ou existe-t-il un moyen automatique?

Je vous remercie.

David Gomes
la source
Avez-vous envisagé de cacher le curseur et de le déformer vers le centre? Ensuite, dessinez simplement votre réticule au centre de l'écran à la place du curseur du système d'exploitation.
Vaughan Hilts

Réponses:

24

Bien que vous puissiez implémenter cela à l'aide de SDL_WarpCursor (), j'ai rencontré des problèmes avec cette méthode sur certaines plates-formes. J'ai rencontré de réels problèmes avec certaines plateformes qui n'effectuaient pas de manière fiable l'action WarpCursor (), en particulier lorsque je l'appelais à chaque image.

N'oubliez pas également que sur de nombreuses plates-formes, le curseur est géré à une fréquence plus élevée que votre application. Cela est particulièrement vrai si vous utilisez moins de 60 images par seconde! Ainsi, même si la plate-forme déforme avec succès la souris sur chaque image de votre jeu, le curseur peut toujours s'éloigner de votre fenêtre s'il reçoit des mises à jour entre vos images rendues.

La bonne méthode pour piéger la souris sous SDL est:

SDL_WM_GrabInput( SDL_GRAB_ON );

Cela indique à SDL que votre intention est de prendre le contrôle total de la souris + du clavier (voir la documentation ) et donc de garder la souris à l'intérieur de la fenêtre, quoi qu'il arrive. À partir de ce moment, la souris ne se déplacera pas en dehors de la fenêtre, quelle que soit votre fréquence d'images, et vous ne devez pas appeler SDL_WarpCursor, sauf si vous avez vraiment l'intention de téléporter le curseur quelque part, plutôt que de le spammer en continu.

En mode "capture", vous continuerez de recevoir les événements de mouvement de la souris comme si la souris n'était pas contrainte à l'intérieur de la fenêtre. (Donc, si le curseur se trouve sur le bord droit de l'écran et que l'utilisateur déplace sa souris plus à droite, vous recevrez un événement de mouvement de la souris indiquant un mouvement vers la droite, bien que la position du curseur ne change pas). Ceci est vraiment utile pour (par exemple) tourner les commandes des jeux FPS, où vous ne vous souciez que du mouvement relatif du curseur, pas de sa position absolue.

Mise à jour pour SDL2 - 9 décembre 2013

Cette interface a changé pour SDL2. Si vous utilisez SDL1.2, la réponse ci-dessus est toujours correcte. Cependant, sous SDL2, la SDL_WM_GrabInput(SDL_GrabMode)fonction n'est plus disponible. La nouvelle façon de SDL2 de capturer la souris est:

SDL_SetRelativeMouseMode(SDL_TRUE);

Sinon, c'est identique à la fonction précédente - dans ce mode, vous continuerez à recevoir des SDL_MOUSEMOTIONévénements comme si la souris n'était pas contrainte à l'intérieur de la fenêtre.

Trevor Powell
la source
1
Avertissement: j'ai remarqué que sur certaines plates-formes, je reçois immédiatement un événement MouseMotion parasite avec un mouvement très important, immédiatement après avoir activé la saisie de la souris. Pour faire face à cela, mon code ignore le premier événement de mouvement de souris reçu après avoir activé ce mode.
Trevor Powell
Cela fonctionnait parfaitement et c'est beaucoup plus facile que la méthode manuelle. Je vous remercie!
David Gomes
3

Bien que la réponse mise à jour de Trevor reflète l'état actuel de SDL2, vous pouvez également piéger la souris en créant votre SDL_Windowavec l' SDL_WINDOW_INPUT_GRABBEDensemble. Sachez que j'ai rencontré des problèmes étranges sur Linux (probablement en raison d'une bizarrerie de fenêtrage X) où vous ne pouvez jamais quitter la fenêtre à moins que SDL_QUIT soit appelé (même si un autre événement du système d'exploitation dérobe le focus).

Justin Skiles
la source
Merci, SDL_WINDOW_INPUT_GRABBED fonctionne parfaitement sur mon code SDL2.
Adrian Maire
3

Pour SDL2, il semble également y avoir la fonction SDL_SetWindowGrab si vous souhaitez l'activer et la désactiver.

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

Vous pouvez utiliser l' événement de mouvement SDL pour détecter les mouvements de la souris. Ensuite, vous pouvez appeler WarpCursor à l'intérieur même après avoir déclenché un événement pour diriger les valeurs relX et relY. Vous pouvez également masquer le curseur de votre système d'exploitation et dessiner un réticule ou quelque chose de similaire au centre de l'écran. Cela garantit que la souris semble toujours être au milieu pour l'utilisateur et que vous pouvez toujours recevoir des valeurs de mouvement et similaires.

Vaughan Hilts
la source