Une partie très importante de la création d'un jeu vidéo est l'interface avec le joueur, ou IHM (Interface Homme Machine). Définir comment le joueur va interagir avec notre jeu, c'est penser une ergonomie : si le joueur a l'impression que le jeu ne réagit pas à ses commandes ou au contraire si le jeu réagit trop vite, il risque de ne pas arriver à jouer ou bien de se désintéresser du jeu. Nous devrons probablement passer du temps à tester et à affiner nos réglages pour que le jeu donne un bon "feeling" au joueur, qui est là pour s'amuser !
Expliquer au joueur comment jouer lors du premier niveau, faire des niveaux avec une difficulté progressive, sont également des principes à garder en tête : nous avons conçu notre jeu, donc nous savons comment y jouer... mais le futur joueur lui ne le sait pas, ce n'est pas évident pour lui. La première chose à considérer est donc quel matériel votre joueur va utiliser pour jouer. En fonction des périphériques du joueur, nous ne ferons pas les mêmes types de jeux : concevoir un jeu jouable au clavier et à la souris n'a rien à voir avec un jeu tactile sur un smartphone, ou un jeu qui suppose que le joueur fasse de grands gestes devant un détecteur de mouvements.
Dans le BGE, on récupère les informations envoyées par les périphériques via les briques logiques de type sensor (Keyboard, Mouse, ou Joystick) ou bien via des scripts Python, grâce aux objets logic.keyboard
, logic.mouse
ou logic.joysticks
, ou encore par le protocole OSC (voir plus loin).
En Python, nous devrons donc importer en début de code les modules logic
et events
. Ce dernier contient les constantes correspondant à toutes les entrées possibles du clavier et de la souris. Pour toutes les touches et boutons, qu'il s'agisse du clavier ou de la souris, il existe 3 statuts différents :
logic.KX_INPUT_NONE
: le statut par défaut, bouton au repos, non actif ;logic.KX_INPUT_JUST_ACTIVATED
: si une touche ou un bouton vient juste d'être pressé ;logic.KX_INPUT_ACTIVE
: si une touche ou un bouton est actuellement pressé.Le clavier est le périphérique qui contient le plus d'entrées. Si votre jeu nécessite un grand nombre de commandes différentes, comme souvent dans les jeux de stratégie ou les jeux à la première personne avec de multiples actions possibles du héros, vous aurez certainement besoin du clavier.
Dans la première section de ce manuel, pour déplacer notre personnage, nous avons vu comment récupérer les frappes clavier avec le sensorKeyboard. Référez-vous à cette partie si vous avez des doutes : section Créer son premier jeu, chapitre Déplacer le personnage.
Pour écrire un script Python qui récupère les frappes au clavier, voici comment procéder:
from bge import logic, events clavier = logic.keyboard if clavier.events[ events.UPARROWKEY ] == logic.KX_INPUT_ACTIVE : print("La touche up active")
Etudions ce code ligne par ligne.
from bge import logic, events
L'import des modules Python est l'entête obligé de tout script Python dans le BGE. Nous aurons besoin de logic
pour accéder au clavier et events
pour les constantes du clavier.
clavier = logic.keyboard
Cette technique classique en programmation Python consiste à assigner la référence d'un objet accessible par une expression complexe à variable locale pour plus de clarté et d'efficacité.
if clavier.events[ events.UPARROWKEY ] == logic.KX_INPUT_ACTIVE :
L'objet clavier a un attribut events
qui est un dictionnaire qui répertorie le statut courant de toutes les touches (actif, tout juste activé ou inactif). Le test vérifie si le statut de la touche flèche vers le haut (
) est active (statut events.UPARROWKEY
logic.KX_INPUT_ACTIVE
).
print("La touche up active")
Et si c'est le cas, le test imprime ce message en console.
Notons que pour que ce simple script fonctionne, il faut au minimum l'attacher à un sensorAlways dont le pulse mode TRUE level triggering est actif. Autrement dit, il faut que ce script soit exécuté à chaque frame.La souris est l'extension la plus importante et la plus courante après le clavier. Qu'elle se pende ou non au bout d'un fil, qu'on l'appelle trackpad ou mulot1. Qu'elle possède un, deux ou trois boutons, c'est l'outil de base du joueur pour pointer des éléments sur un écran. C'est précis, sensible et encore bien ancré dans des pratiques de jeu.
La brique logique permettant de récupérer les événements liés à la souris est la bien nommée sensor Mouse. Elle est assez simple à configurer puisqu'il n'y a qu'une seule option : c'est l'action de la souris qui active ce sensor. Ce sont bien sûr les clics de boutons mais aussi le simple fait de déplacer la souris (Movement).
L'autre type d'action intéressant est l'événement Mouse Over qui correspond au passage de la souris au dessus de l'objet 3D auquel ce sensor est attaché. Cette option peut se révéler très utile pour créer un menu ou sélectionner des éléments dans une scène.
Voici comment procéder en Python :
from bge import logic, events souris = logic.mouse if souris.events[events.LEFTMOUSE] == logic.KX_INPUT_JUST_ACTIVATED : print("Clic gauche") # Affiche en console la position de la souris print( souris.position ) # Afficher le curseur pendant le jeu souris.visible = True
Comme pour le clavier, nous assignons l'objet logic.mouse
à une variable "souris" pour plus de clarté.
L'objet souris possède également un attribut events
qui répertorie le statut de toutes les actions souris. Cette fois, nous détectons si le bouton de gauche (events.LEFTMOUSE)
est "tout juste activé" (logic.KX_INPUT_JUST_ACTIVATED
). Cette condition sera vérifiée lorsque le joueur aura tout juste appuyé sur le bouton gauche de sa souris. S'il maintient le bouton appuyé, cette condition ne sera plus vérifiée.
La manette, le joystick, le volant, le gamepad, etc., sont autant d'accessoires bien connus des joueurs. Ils ont la particularité de renvoyer davantage d'informations que le simple fait de cliquer sur tel ou tel bouton. Ces accessoires ont des formes multiples, parfois en lien étroit avec le type de jeu auxquels ils sont apparentés (les volants pour les courses de voiture par exemple). En revanche, ils partagent tous la caractéristique d'envoyer des informations précises de direction, parfois variables en intensité et souvent représentées sur des axes x et y.
Dans la suite de ce chapitre, nous utiliserons le terme manette pour désigner la manette de jeu dans son ensemble et joystick pour désigner un manche en particulier. Les joysticks peuvent être à axe simple (par exemple avant-arrière) ou multiple (par exemple avant-arrière, gauche-droit). Contrairement à la souris qui renvoie une position dans un rectangle (la fenêtre de jeu). Ici, il s'agit plutôt de déterminer ici l'angle du joystick par rapport à sa position au repos.
Nous pouvons utiliser ce .blend pour tester si notre manette préféré est supportée par le BGE: [référence vers blends/SCA_PythonJoystick/joystick_test.blend + 8bitoperator.ttf]
Pour utiliser une manette, nous nous servirons de la brique logique sensor Joystick.
Plusieurs manettes peuvent être connectées à l'ordinateur. Le BGE numérote automatiquement les manettes en partant de 0. C'est ce numéro que nous indiquons dans le champ Indexpour spécifier quelle manette nous intéresse. Lorsqu'il n'y a qu'une seule manette connectée, elle aura d'office l'index 0. Mais dans le cas de plusieurs manettes, nous ne pouvons malheureusement pas savoir à l'avance quel seront leurs numéros.
Cette question est importante lorsque nous publions un jeu : quel index choisir dans les sensors et comment permettre à l'utilisateur de choisir la manette qui sera utilisée dans le jeu ? La solution de facilité est de fixer l'index à 0 dans tous les sensors, ce qui force l'utilisateur à prendre une manette en particulier, ou l'oblige à débrancher ses autres manettes pour utiliser sa manette préférée. La solution complexe consiste à proposer un choix par menu à l'utilisateur et à modifier par Python le champs index des sensors, voire de se passer complètement des sensors, car tous les événements manette sont récupérables par Python (voir plus bas).
L'option event Typedétermine le type d’événement que nous allons récupérer : simple bouton pressé (Button), action sur une croix directionnelle (Hat), déplacement d'un joystick à axe simple ou multiples (Axis). Malheureusement le même problème se pose pour les boutons et les joysticks des manettes: ils sont numérotés automatiquement et l'ordre peut varier fortement d'un fabriquant de manette à l'autre.
Voici un extrait de script permettant de récupérer facilement les indices des manettes connectées.
from bge import logic # Affichons les manettes connectées et leur indice indice = 0 for manette in logic.joystick : if manette != None : print( manette.name, " a l'indice ", indice ) indice += 1
L'objet logic.joystick
contient la liste de manettes connectées à l'ordinateur dans l'ordre où elles ont été numérotées par le BGE. La boucle for
passe en revue les éléments de cette liste. Si un élément n'est pas vide (None
), il représente une manette actuellement connectée. Nous pouvons accéder à ses propriétés, comme par exemple son nom (ici par l'affichage en console de manette.name
). La variable indice
sert à connaître l'index de chaque manette car elle est incrémentée à partir de 0. En affichant le nom de la manette et son index, nous savons maintenant quelle valeur nous devons mettre dans le champ Index des sensors Joystick.
Voici les propriétés d'une manette accessible par Python :
name
: le nom de la manette.activeButtons
: une liste d'entiers représentant les boutons actuellement pressés.axisValues
: une liste contenant les valeurs des axes du joystick.hatValue
: statut de la croix directionnelle (0:None, 1:Up, 2:Right, 4:Down, 8:Left, 3:Up-Right, 6: Down-Right, 12: Down-Left, 9:Up-left).En modifiant notre code précédent; nous affichons les données envoyées par les joysticks lorsqu'on appuie sur leurs boutons :
from bge import logic for manette in logic.joysticks : if manette != None : # Affichons les boutons actifs for bouton in manette.activeButtons : print( bouton )
En plus de la boucle sur les joysticks, nous bouclons sur la liste active Buttons
de chaque joystick et nous imprimons son contenu. Les éléments de cette liste sont de simples nombres entiers qui représentent le numéro des boutons actuellement pressés. Ce sont ces numéros que nous utiliserons dans le champ Button Number des sensors pour détecter tel ou tel bouton. La liste est vide si aucun bouton n'est pressé.
Pour les autres propriétés, la démarche sera similaire.
AxisValue
: retourne une liste de nombres décimaux compris entre -1 et +1 qui représentent l'inclinaison d'un axe de joystick (0 est la position de repos). A noter qu'un joystick double axe prend deux positions successives dans cette liste.HatValues
: retourne une liste de nombres entiers qui représentent la valeur de chaque croix directionnelle.Il est tout à fait possible d'utiliser d'autres périphériques avec Blender que ceux cités plus haut. Seulement, il n'existe pas de brique logique pour cela. C'est grâce à l'utilisation de scripts Python et du protocole OSC que nous pourrons étendre à l'infini ces possibilités d'interface. Par exemple, la télécommande Wiimote, le senseur Kinect, des capteurs sur Arduino, des contrôleurs provenant d'autres logiciels comme Pure-Data, un clavier MIDI, etc. peuvent tous servir comme interface de contrôle.
Pour la Kinect360, l'usage de OSCeleton permet de facilement récupérer les données des squelettes des utilisateurs détectés par le senseur. Ces données pourront ensuite être traitées dans le BGE. Il existe plusieurs méthodes pour utiliser le protocole OSC dans le Game Engine :
Étant donné la diversité des possibilités à ce niveau, nous nous contenterons d'un exemple simple avec pyOSC. Pour les besoins de l'exemple, nous utiliserons 2 instances du Blenderplayer plutôt qu'un contrôleur physique externe, de sorte que n'importe qui puisse comprendre le fonctionnement, sans dépendre d'un matériel spécifique. Le principe est de contrôler le mouvement d'un cube dans un player à partir d'un autre player.
<OSC_send.blend>
Dans ce premier fichier, on se contente de récupérer les événements du clavier, et d'assigner des commandes à certaines touches. Ces commandes sont envoyées par le script en OSC sur le réseau. Ici en envoyant les infos vers l'ordinateur lui-même, en utilisant l'adresse interne ou localhost (127.0.0.1). On peut également spécifier une autre adresse réseau pour envoyer les messages OSC vers une machine distante.
<OSC_receive.blend>
Dans ce fichier, le script Python appelle le module pyOSC et écoute les messages qu'il reçoit pour ensuite utiliser ces données pour ajuster la position du cube en xyz. Une subtilité importante est la fonction quit()
qui éteint le serveur à la sortie du jeux (sinon, à la prochaine relance, il risque d'y avoir une erreur de port réseau resté ouvert). La touche clavier Echap est ici également reliée explicitement à une action Game > Quit, de sorte à quitter le Game Engine (sinon, la touche est réassignée à l'action du script et le jeu ne quitte plus...).
Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.
Vous devriez rafraîchir la page.