Remarque: je dois interroger plutôt que de faire des rappels en raison des limitations de l'API (SFML). Je m'excuse également pour l'absence d'un titre «décent».
Je pense que j'ai deux questions ici; comment enregistrer l'entrée que je reçois et quoi en faire.
Gestion de l'entrée
Je parle après le fait que vous avez enregistré que la touche «A» a été enfoncée, par exemple, et comment le faire à partir de là.
J'ai vu un tableau de l'ensemble du clavier, quelque chose comme:
bool keyboard[256]; //And each input loop check the state of every key on the keyboard
Mais cela semble inefficace. Non seulement vous couplez la clé «A» au «joueur se déplaçant vers la gauche», par exemple, mais il vérifie chaque clé, 30 à 60 fois par seconde.
J'ai ensuite essayé un autre système qui cherchait juste les clés qu'il voulait.
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.
Cependant, le problème avec ceci est que je ne peux pas maintenant taper un nom, par exemple, sans avoir à lier chaque clé.
Ensuite, j'ai le deuxième problème, que je ne peux pas vraiment penser à une bonne solution pour:
Envoi d'entrée
Je sais maintenant que la touche A a été enfoncée ou que playerLeft est vrai. Mais comment je vais partir d'ici?
J'ai pensé à vérifier simplement que
if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
ceci couple grandement l'entrée aux entités, et je la trouve plutôt désordonnée. Je préférerais que le joueur gère son propre mouvement lorsqu'il est mis à jour. Je pensais qu'une sorte de système d'événements pourrait fonctionner, mais je ne sais pas comment y aller. (J'ai entendu que les signaux et les créneaux horaires étaient bons pour ce genre de travail, mais c'est apparemment très lent et je ne vois pas comment cela irait).
Merci.
la source
Je pense que la discussion du PO rassemble un tas de choses ensemble, et que le problème peut être considérablement simplifié en le décomposant un peu.
Ma suggestion:
Conservez votre tableau d'états de clés. N'y a-t-il pas un appel d'API pour obtenir l'état du clavier entier à la fois? (La plupart de mon travail se fait sur des consoles, et même sur Windows pour un contrôleur connecté, vous obtenez tout l'état du contrôleur à la fois.) Vos états de touches sont une carte "dure" sur les touches du clavier. Non traduit est le meilleur, mais vous obtenez le plus facilement les API.
Gardez ensuite quelques tableaux parallèles qui indiquent si la clé a remonté cette trame, un autre indiquant qu'elle est descendue et un troisième pour indiquer simplement que la clé est "baissée". Ajoutez peut-être une minuterie pour que vous puissiez savoir depuis combien de temps la clé est dans son état actuel.
Créez ensuite une méthode pour créer un mappage des clés des actions. Vous voudrez le faire plusieurs fois. Une fois pour les choses de l'interface utilisateur (et veillez à interroger les mappages Windows car vous ne pouvez pas supposer que le scancode lorsque vous appuyez sur 'A' va donner un A sur l'ordinateur de l'utilisateur). Un autre pour chaque "mode" du jeu. Ce sont les mappages des codes clés aux actions. Vous pouvez le faire de plusieurs façons, l'une serait de conserver une énumération utilisée par le système récepteur, une autre serait un pointeur de fonction indiquant la fonction à appeler lors d'un changement d'état. Peut-être même un hybride des deux, selon vos objectifs et vos besoins. Avec ces "modes", vous pouvez les pousser et les faire apparaître sur une pile de mode contrôleur, avec des drapeaux qui permettent aux entrées ignorées de continuer à descendre dans la pile ou autre.
Enfin, gérez ces actions clés d'une manière ou d'une autre. Pour le mouvement, vous voudrez peut-être faire quelque chose de délicat, traduisez «W» vers le bas pour signifier «aller de l'avant», mais cela n'a pas besoin d'être une solution binaire; vous pouvez avoir "W est en baisse" signifie "augmenter la vitesse de X jusqu'à un maximum de Y" et "W est en hausse" pour être "diminuer la vitesse de Z jusqu'à ce qu'il atteigne zéro." De manière générale, vous voulez que votre "interface de gestion des contrôleurs dans les systèmes de jeu" soit assez étroite; effectuez toutes les traductions clés en un seul endroit, puis utilisez les résultats partout ailleurs. Cela contraste avec la vérification directe pour voir si la barre d'espace est pressée n'importe où au hasard dans le code, car si elle se trouve à un endroit aléatoire, elle sera probablement frappée à un moment aléatoire lorsque vous ne le voulez pas, et vous ne le faites pas '' Je ne veux pas y faire face ...
Je déteste vraiment concevoir des modèles et je pense que les composants apportent plus de coûts de développement que de bien, c'est pourquoi je n'ai mentionné ni l'un ni l'autre. Des schémas émergeront s'ils sont destinés à, comme le feront les composants, mais le fait de faire l'une ou l'autre dès le départ ne fera que compliquer votre vie.
la source
Dans SFML, vous avez les touches dans l'ordre dans lequel elles ont été enfoncées avec le type d'événement KeyPressed. Vous traitez chaque clé dans un certain temps (getNextEvent ()).
Donc, si la touche enfoncée se trouve dans votre carte Key-> Action, exécutez l'action correspondante, et si ce n'est pas le cas, transférez-la à n'importe quel widget / élément qui pourrait en avoir besoin.
En ce qui concerne votre deuxième question, je vous recommande de le garder comme ça car il est plus facile de modifier votre gameplay. Si vous utilisez des signaux ou autres, vous devrez créer un emplacement pour le "RunKeyDown" et un autre pour le "JumpKeySlot". Mais que se passe-t-il si dans votre jeu, une action spéciale est exécutée lorsque les deux sont pressés?
Si vous souhaitez décorréler l'entrée et les entités, vous pouvez faire de votre entrée un état (RunKey = true, FireKey = false, ...) et l'envoyer au joueur comme vous envoyez tout autre événement à vos IA.
la source
La bonne solution est souvent une combinaison des deux méthodes dont vous discutez:
Pour la fonctionnalité de jeu avec un jeu de clés prédéfini, l'interrogation de chaque image est tout à fait appropriée et vous ne devez interroger que les clés qui sont réellement liées à quelque chose. Ceci est en fait analogue à la façon dont vous interrogeriez les entrées de contrôleur dans un jeu de console, cela va être entièrement polluant, en particulier en ce qui concerne les périphériques d'entrée analogiques. Pendant le jeu général, vous voudrez probablement ignorer les événements de pression de touche et utiliser uniquement l'interrogation.
Quand il s'agit de taper des entrées comme des noms, vous devez basculer le jeu dans un mode de gestion des entrées différent. Par exemple, dès qu'une invite "entrez votre nom" apparaît, vous pouvez modifier ce que fait votre code d'entrée. Il peut écouter les événements de pression de touche via une interface de rappel, ou vous pouvez commencer à interroger chaque touche si nécessaire. Il s'avère que généralement lors de la frappe d'événements, vous ne vous souciez pas autant des performances de toute façon, donc l'interrogation ne sera pas si mauvaise.
Par conséquent, vous souhaitez utiliser l'interrogation sélective pour l'entrée de gameplay et la gestion des événements pour les entrées de saisie de nom (ou toutes les interrogations au clavier si la gestion des événements n'est pas disponible).
la source
J'aime beaucoup la réponse de dash-tom-bang, elle met vraiment en évidence certains aspects que vous devez garder à l'esprit lors de la conception d'un système d'entrée.
Je voudrais ajouter un petit tutoriel sur lequel je suis tombé qui va dans le même sens (y compris les contextes de saisie, 3 couches, ...):
http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/
la source