Atrapar el mouse en SDL

12

¿Cómo puedo atrapar el mouse del usuario dentro de mi juego? No es un juego de pantalla completa, pero lo quiero para que el usuario no pueda arrastrar el mouse fuera de la pantalla.

¿Tengo que verificar las coordenadas del mouse y SDL_WarpCursor para que diga dentro de la ventana (manualmente), o hay una forma automática?

Gracias.

David Gomes
fuente
¿Has considerado ocultar el cursor y retorcerlo al centro? Luego, simplemente dibuje su punto de mira en el centro de la pantalla en lugar del cursor del sistema operativo.
Vaughan Hilts

Respuestas:

24

Si bien puede implementar esto usando SDL_WarpCursor (), he tenido problemas con ese método en algunas plataformas. He tenido problemas reales con algunas plataformas que no realizan de manera confiable la acción WarpCursor (), particularmente cuando lo he estado llamando a cada cuadro.

Además, recuerde que en muchas plataformas, el cursor se maneja a una frecuencia más alta que su aplicación. ¡Esto es particularmente cierto si estás corriendo por debajo de 60 fps! Entonces, incluso si la plataforma está deformando con éxito el mouse en cada cuadro de su juego, el cursor aún podría alejarse de su ventana si está recibiendo actualizaciones entre sus cuadros procesados.

El método correcto para atrapar el mouse bajo SDL es:

SDL_WM_GrabInput( SDL_GRAB_ON );

Esto le dice a SDL que su intención es tomar el control total del mouse + teclado (consulte la documentación ) y, por lo tanto, mantener el mouse dentro de la ventana sin importar qué. A partir de este momento, el mouse no se moverá fuera de la ventana, independientemente de su velocidad de fotogramas, y no debe llamar a SDL_WarpCursor, excepto si realmente tiene la intención de teletransportar el cursor en algún lugar, en lugar de enviarlo de manera continua.

Mientras esté en este modo de "captura", continuará recibiendo eventos de movimiento del mouse como si el mouse no estuviera restringido dentro de la ventana. (Entonces, si el cursor está en el borde derecho de la pantalla y el usuario mueve su mouse más a la derecha, recibirá un evento de movimiento del mouse que muestra el movimiento a la derecha, aunque la posición del cursor no cambiará). Esto es realmente útil para (por ejemplo) girar controles para juegos FPS, donde solo te importa el movimiento relativo del cursor, no su posición absoluta.

Actualización para SDL2 - 9 de diciembre de 2013

Esta interfaz ha cambiado para SDL2. Si está utilizando SDL1.2, la respuesta anterior sigue siendo correcta. Sin embargo, bajo SDL2 la SDL_WM_GrabInput(SDL_GrabMode)función ya no está disponible. La nueva forma de SDL2 de capturar el mouse es:

SDL_SetRelativeMouseMode(SDL_TRUE);

De lo contrario, esto es idéntico a la función anterior: en este modo continuará recibiendo SDL_MOUSEMOTIONeventos como si el mouse no estuviera restringido dentro de la ventana.

Trevor Powell
fuente
1
Advertencia: He notado que en algunas plataformas, inmediatamente recibo un evento espurio de MouseMotion con un movimiento muy grande, inmediatamente después de activar el agarre del mouse. Para hacer frente a eso, hago que mi código ignore el primer evento de movimiento del mouse recibido después de activar este modo.
Trevor Powell el
Eso funcionó perfectamente, y es mucho más fácil que la forma manual. ¡Gracias!
David Gomes el
3

Si bien la respuesta actualizada de Trevor refleja el estado actual de SDL2, también puede atrapar el mouse al crear su SDL_Windowcon el SDL_WINDOW_INPUT_GRABBEDconjunto. Tenga en cuenta que me he encontrado con algunos problemas extraños en Linux (presumiblemente debido a alguna peculiaridad de la ventana X) donde nunca puede salir de la ventana a menos que se llame a SDL_QUIT (incluso si otro evento del sistema operativo le quita el foco).

Justin Skiles
fuente
Gracias, SDL_WINDOW_INPUT_GRABBED funciona perfectamente en mi código SDL2.
Adrian Maire
3

Para SDL2 parece que también existe la función SDL_SetWindowGrab si desea habilitarla y deshabilitarla.

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

Puede usar el evento de movimiento SDL para detectar cuándo se mueve el mouse. Luego, puede llamar a WarpCursor dentro de eso incluso después de disparar un evento para canalizar los valores relX y relY. También puede ocultar el cursor del sistema operativo y dibujar una cruz o algo similar en el centro de la pantalla. Esto garantiza que el mouse parece estar siempre en el medio para el usuario y que aún puede recibir valores de movimiento y similares.

Vaughan Hilts
fuente