Nota: Tengo que sondear, en lugar de hacer devoluciones de llamada debido a limitaciones de API (SFML). También me disculpo por la falta de un título 'decente'.
Creo que tengo dos preguntas aquí; cómo registrar la entrada que estoy recibiendo y qué hacer con ella.
Manejo de entrada
Me refiero después del hecho de que haya registrado que se ha presionado la tecla 'A', por ejemplo, y cómo hacerlo desde allí.
He visto una variedad de todo el teclado, algo así como:
bool keyboard[256]; //And each input loop check the state of every key on the keyboard
Pero esto parece ineficiente. Por ejemplo, no solo está acoplando la tecla 'A' al 'jugador que se mueve hacia la izquierda', sino que verifica cada tecla, 30-60 veces por segundo.
Luego probé otro sistema que solo buscaba las claves que quería.
std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.
Sin embargo, el problema con esto es que ahora no puedo escribir un nombre, por ejemplo, sin tener que vincular cada clave.
Entonces, tengo el segundo problema, que realmente no puedo pensar en una buena solución para:
Enviando entrada
Ahora sé que se ha presionado la tecla A o que el jugador Izquierdo es verdadero. ¿Pero cómo voy desde aquí?
Pensé en simplemente marcar
if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
Esto acopla la entrada a las entidades, y me parece bastante desordenado. Prefiero que el jugador maneje su propio movimiento cuando se actualiza. Pensé que algún tipo de sistema de eventos podría funcionar, pero no sé cómo hacerlo. (Escuché señales y las ranuras eran buenas para este tipo de trabajo, pero aparentemente es muy lento y no puedo ver cómo encajaría).
Gracias.
fuente
Creo que la discusión del OP está agrupando un montón de cosas, y que el problema puede simplificarse sustancialmente dividiéndolo un poco.
Mi sugerencia:
Mantenga su conjunto de estados de claves. ¿No hay una llamada API para obtener todo el estado del teclado a la vez? (La mayor parte de mi trabajo es en consolas, e incluso en Windows para un controlador conectado, obtienes todo el estado del controlador a la vez). Tus estados clave son un mapa "duro" en las teclas del teclado. Sin traducir es lo mejor, pero sin embargo, lo más fácil es sacarlo de las API.
Luego, mantenga unos pocos arreglos paralelos que indiquen si la clave subió en este marco, otro indicando que bajó y un tercero para indicar simplemente que la clave está "abajo". Quizás agregue un temporizador para que pueda realizar un seguimiento de cuánto tiempo ha estado la clave en su estado actual.
A continuación, cree un método para crear una asignación de teclas a acciones. Querrás hacer esto un par de veces. Una vez para las cosas de la interfaz de usuario (y tenga cuidado de consultar las asignaciones de Windows porque no puede asumir que el código de escaneo cuando presiona 'A' le dará una A en la computadora del usuario). Otro para cada "modo" en el juego. Estas son las asignaciones de códigos clave a acciones. Puede hacer esto de dos maneras, una sería mantener una enumeración que utiliza el sistema receptor, otra sería un puntero de función que indica la función que se llamará en un cambio de estado. Tal vez incluso un híbrido de los dos, dependiendo de sus objetivos y necesidades. Con estos "modos" puede empujarlos y desplegarlos en una pila de modo de controlador, con banderas que permiten que la entrada ignorada siga bajando por la pila o lo que sea.
Finalmente, maneje esas acciones clave de alguna manera. Para el movimiento es posible que desee hacer algo complicado, traduzca 'W' hacia abajo para que signifique "avanzar", pero no es necesario que sea una solución binaria; puede hacer que "W esté abajo" significa "aumentar la velocidad en X hasta un máximo de Y" y "W está arriba" para ser "disminuir la velocidad en Z hasta que llegue a cero". En términos generales, desea que su "interfaz de manejo del controlador en los sistemas de juego" sea bastante estrecha; haga todas las traducciones clave en un solo lugar y luego use los resultados de eso en cualquier otro lugar. Esto está en contraste con la comprobación directa para ver si la barra espaciadora se presiona en cualquier lugar al azar en el código, porque si está en algún lugar aleatorio, probablemente será golpeado en algún momento aleatorio cuando no lo desee, y simplemente no lo haga ' no quiero lidiar con eso ...
Realmente detesto el diseño de patrones y creo que los componentes aportan más costos de desarrollo que buenos, por eso no mencioné ninguno. Los patrones surgirán si están destinados a hacerlo, al igual que los componentes, pero establecerlo desde el principio solo complicará su vida.
fuente
En SFML, tiene las teclas en el orden en que se presionaron con el tipo de evento KeyPressed. Usted procesa cada clave en un momento (getNextEvent ()).
Entonces, si la tecla presionada está en su mapa de Teclas-> Acción, ejecute la acción correspondiente, y si no es así, reenvíela a cualquier widget / material que pueda necesitarla.
Con respecto a tu segunda pregunta, te recomiendo que la mantengas así porque hace que sea más fácil modificar tu juego. Si usa señales o algo así, tendrá que hacer una ranura para "RunKeyDown" y otra para "JumpKeySlot". Pero, ¿qué sucede si en su juego, se realiza una acción especial cuando se presionan ambos?
Si desea decorelacionar la entrada y las entidades, puede hacer que su entrada sea un Estado (RunKey = true, FireKey = false, ...) y enviarla al jugador como si enviara cualquier otro evento a sus AI.
fuente
La solución correcta es a menudo una combinación de los dos métodos que discute:
Para la funcionalidad del juego con un conjunto predefinido de teclas, sondear cada cuadro es completamente apropiado y solo debe sondear las teclas que están realmente vinculadas a algo. En realidad, esto es análogo a cómo consultaría la entrada del controlador en un juego de consola, va a ser un sondeo completo, especialmente cuando se trata de dispositivos de entrada analógica. Durante el juego general, probablemente quieras ignorar los eventos de pulsación de teclas y solo usar el sondeo.
Cuando se trata de escribir entradas para cosas como nombres, debes cambiar el juego a un modo de manejo de entrada diferente. Por ejemplo, tan pronto como aparezca el mensaje "ingrese su nombre", puede modificar lo que hace su código de entrada. Puede escuchar los eventos de pulsación de teclas a través de alguna interfaz de devolución de llamada, o puede comenzar a sondear cada tecla si es necesario. Resulta que, por lo general, durante los eventos de mecanografía no te importa tanto el rendimiento de todos modos, por lo que las encuestas no serán tan malas.
Por lo tanto, desea utilizar un sondeo selectivo para la entrada del juego y el manejo de eventos para las entradas de escritura de nombres (o todo el sondeo del teclado si el manejo de eventos no está disponible).
fuente
Me gusta mucho la respuesta de dash-tom-bang, realmente resalta algunos aspectos que debes tener en cuenta al diseñar un sistema de entrada.
Me gustaría agregar un pequeño tutorial con el que me topé que va en la misma dirección (incluidos los contextos de entrada, 3 capas, ...):
http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/
fuente