Table des matières
IntroductionPréliminairesLe système de propriétés que met en avant FlightGear peut paraître complexe au premier abord mais en creusant un peu plus, on se rend compte qu'il s'agit d'un mécanisme très complet et très riche qui permet de modifier très finement le comportement du simulateur. C'est peut-être sa richesse qui donne une impression de complexité mais on se rend compte que cette complexité n'est qu'apparente. Une bonne compréhension de l'arbre des propriétés permet d'avoir une bonne visibilité de ce qu'il est possible de faire sous FlightGear, de comprendre une grande partie de son fonctionnement. Une bonne façon de voir les propriétés est de les considérer comme des variables globales 1):
L'arborescence: la notions de noeudsLes propriétés sont organisées et hiérarchisées afin d'améliorer la lisibilité du code qui les exploite, et aussi permettre à l'utilisateur de retrouver le plus facilement possible la propriété recherchée. Cette organisation prend la forme d'un arbre, comme un arbre généalogique, ou une arborescence de fichiers et de répertoires (également appelés “dossiers” chez les windowsiens). Il y a donc une racine, nommée ”/” (slash ou barre de division) et des “branches”, qui se terminent par des “feuilles”. Chaque élément de l'arborescence est appelé un noeud (node in English).
non-objects have no members at ... Le nommage des noeuds et propriétésChaque noeud est identifié par un nom qui lui permet d'être reconnu et de savoir (normalement ) à quoi il correspond. Mais alors comment faire pour avoir autant de noms différents? Pas de panique, il est tout à fait possible de donner à plusieurs propriétés et noeuds d'un même niveau des noms identiques, FlightGear 2) ajoutera alors automatiquement un numéro d'index qui les séparera. Ce numéro est alors écrit entre crochets, à la fin du nom. Il existe une règle implicite dans FlightGear pour le nommage des propriétés et des noeuds:
Accéder aux propriétésLes propriétés sont classées selon leur appartenance à des catégories. Couramment, les plus intéressantes sont:
Chaque catégorie se rapporte à un équipement ou une fonctionnalité et contient toute une arborescence qui se termine par des feuilles (variables) contenant des valeurs que l'on peut éventuellement venir modifier de plusieurs manières. le navigateur de propriétésLorsque vous lancez FlightGear, vous avez la possibilité d'afficher une fenêtre présentant une arborescence des propriétés pour vous permettre d'y naviguer. Pour celà, sélectionnez Files→Browse Internal Properties. Un clic sur une des propriétés la sélectionne et il est alors possible d'en modifier la valeur. Un clic en appuyant simultanément sur la touche Ctrl permet d'afficher la valeur de manière continue sur l'écran. Notez que certaines propriétés ne sont pas modifiables manuellement car elles sont mise à jour automatiquement par le modèle de vol (JSBSim par exemple). Si vous essayez de modifier une telle propriété, vous constaterez que FlightGear semble ne pas vouloir prendre en compte la valeur que vous spécifiez. Pas de panique, il s'agit d'un comportement normal. la méthode des vrais hommes :-)Notez qu'il existe également (en version CVS) la possibilité de chercher et afficher simplement une ou plusieurs propriétés avec le raccourcis-clavier ”/” (barre de division), il existe ensuite tout un tas d'autres raccourcis pour rechercher la bonne propriété et en faire ce qu'on veut. Pour activer cette fonctionnalité il faut aller dans Debug→Development Keys et cocher la case “Enable '/'-key property handler” (ce choix est automatiquement sauvegardé à la fermeture de FlightGear).
Le système propose également un code de couleur
quelques fonctions Nasal bien pratiques
affiche l'arborescence depuis propriété (ou le répertoire la contenant), par défaut propriété est la racine de l'arbre. La valeur “1” indique d'afficher l'arbre en utilisant l'indentation, si elle n'est pas spécifiée (ou égale à 0) l'affichage est “à plat”.
indique chaque changement/création/suppression de la propriété propriété Les types de propriétésLes propriétés sont typées, et il existe types différents:
Il existe également un type particulier: ALIAS. Ce type indique que la propriété est un deuxième nom pour une autre propriété (comme sous *NIX, un fichier peut avoir plusieurs noms), donc la propriété possède exactement les mêmes attributs (valeur, type) que “l'original”. Il existe en Nasal deux fonctions permettant de lier/délier des propriétés: alias() et unalias(). Cette gestion des alias peut être très utile pour par exemple la gestion des pannes: un instrument est lié à l'alias de la propriété contenant la valeur à afficher, en cas de panne de l'instrument il suffit de délier l'alias pour faire afficher une valeur différente de celle que l'instrument est sensé afficher. Manipuler l'arbre des propriétésNativement, FlightGear supporte deux langages: le XML (qui structure les données comme des nombres ou des phrases), et le Nasal (qui permet de créer de vrais “sous-programmes” de manière très souple). Ils sont intimement liés à l'arbre des propriétés Propriétés et XMLQuasiment l'intégralité des fichiers de configuration de FlightGear sont écrit en XML. Une attention profonde montrera que chaque balise contenue dans chaque fichier ”.xml” correspond à un noeud dans l'arbre des propriétés. Ce sont donc les valeurs qui seront passées à FlightGear lors de son lancement, et qui pourront être modifiées plus tard. Quand FlightGear 3) lit le fichier xml, il modifie (ou éventuellement crée) l'arborescence correspondante dans l'arbre des propriétés. Propriétés et NasalLe Nasal embarqué de FlightGear propose plusieurs possibilités pour créer, modifier, surveiller ou supprimer les propriétés.
Quelques cas pratiquesIl n'est pas raisonnable de détailler toutes les propriétés présentes sous FlightGear et de toutes façons cela n'aurait pas beaucoup de sens. Il vaut mieux en analyser quelques unes et voir comment on peut les utiliser pour réaliser diverses choses. L'exemple des interrupteursNous allons nous baser sur un avion que j'affectionne tout particulièrement, le fameux Lightning qui est un excellent jet d'interception des années 70. Les fichiers constituant ce modèle sont particulièrement complets et leur analyse permet d'apprendre beaucoup de choses sur la manière dont les propriétés fonctionnent. Dans le cockpit de cet avion est situé un commutateur 3 positions sur la console à droite du pilote. Ce commutateur contrôle l'allumage et l'extinction des feux de navigation. Ces feux sont situés aux extrémités des ailes. Un feu de couleur verte pour l'aile droite et un feu de couleur rouge pour l'aile gauche. Si, avec la souris, vous actionnez ce commutateur, vous allez effectivement allumer ou éteindre les feux de position, ce qui, à priori, est tout à fait souhaitable. Vous pouvez le constater en observant l'avion de l'extérieur. Maintenant, ouvrez la fenêtre des propriétés en allant dans Files→Browse Internal Properties, puis déplacez-vous dans controls/switches. Faites défiler le contenu de la fenêtre vers le bas de façon à afficher la propriété nav_lights. Actionnez de nouveau le bouton poussoir (avec la souris) et observez le changement immédiat de la valeur de la propriété (sa valeur passe de 0 à 1, puis revient à 0, puis -1, etc). Cliquez sur la propriété nav_lights, puis dans la zone de saisie, effacez l'ancienne valeur et entrez une nouvelle valeur, par exemple 1 à la place de 0. Lorsque vous validez en cliquant sur le bouton SET, vous pouvez observer dans le cockpit de l'avion que le bouton poussoir change également d'état dynamiquement. Maintenant, on va s'intéresser à une autre propriété. Dans la fenêtre des propriétés, déplacez-vous dans sim/model/lightning/lights/. Regardez la propriété nav_lights qui est à 0 (valeur par défaut). Si vous observez votre avion de l'extérieur, vous pouvez constater que les feux de navigation ne sont pas allumés. Maintenant, cliquez sur la propriété nav_lights, effacez la valeur 0 et entrez la valeur 1, puis validez. Observez de nouveau les feux de navigation. Ils sont allumés. En agissant sur cette propriété, vous avez en fait agi sur un état du modèle ce qui vous permet d'en observer un phénomène direct, l'allumage des feux. Vous savez maintenant agir directement sur quelques propriétés. Notez cependant que toutes les propriétés ne sont pas aussi triviales que les deux que nous prenons en exemple. Maintenant, comment se fait-il que lorsque vous actionnez le commutateur Allumage des feux dans le cockpit, les feux s'allument bien à l'extérieur ? Il doit y avoir quelque chose qui lie les deux propriétés que nous venons de voir, à savoir état du commutateur du cockpit et état des feux de position. Dans le monde réel, si on simplifie, on pourrait dire qu'il y a un cable électrique qui relie les deux. Qu'en est-il dans le monde virtuel de FlightGear ? Quelques explications… FlightGear intègre la possibilité d'exécuter des scripts externes écrits en langage NASaL (Not Another Scripting Language, voir l'excellent tutoriel http://fr.flightgear.tuxfamily.org/doku.php?id=devel:nasal_pour_les_nuls). Grâce à des fichiers .nas contenant du code en nasal, vous allez pouvoir modifier les propriétés, en particulier celles que nous venons de voir. Dans le cas du Lightning, il existe le fichier $FG_ROOT/Aircraft/Lightning/Systems/lightning-lights.nas. Ce fichier est référencé par le fichier $FG_ROOT/Aircraft/Lightning/lightning-set.xml qui chapeaute tous les autres via une directive <nasal>…</nasal>. Bref, passons sur ce détail mais sachez qu'un fichier .nas doit être référencé quelque part pour pouvoir être pris en compte. Dans ce fichier lightning-lights.nas, on trouve en particulier les lignes suivantes qui permettent de déclarer la fonction NavLights: var NavLights = func { var switch = getprop("controls/switches/nav_lights"); var light = getprop("sim/model/lightning/lights/nav_lights"); ... Ces deux lignes permettent de lire les valeurs des propriétés (appel à la fonction getprop) qui nous servent d'exemple ici. Les valeurs sont stockées dans les variables locales (mot clé var) switch et light. Pour l'instant, aucun lien n'est fait entre ces deux propriétés mais il est facile de le faire en écrivant le code suivant, toujours dans le même fichier .nas: if (switch == "0" or switch == "nil") { setprop ("sim/model/lightning/lights/nav_lights", 0); } Cette ligne indique clairement que si le commutateur (switch) vaut 0, alors on positionne la propriété sim/model/lightning/lights/nav_lights à 0, ce qui équivaut à éteindre les feux de navigation. L'écriture de la valeur d'une propriété est réalisée grâce à la fonction setprop. Remarquez le test particulier: switch == "nil" Il permet de tester l'existence de la variable switch. Si elle vaut nil (Not In List, réminiscence du langage Lisp), alors la variable n'existe pas (elle n'a pas été définie). On considère alors que les feux de navigation sont éteints. Notez également que dans ces quelques lignes de code, vous retrouvez l'arborescence des propriétés que nous avons prise en exemple. Maintenant, que se passe-t'il si vous voulez allumer les feux de navigation. Vous devez donc traiter le cas où la propriété controls/switches/nav_lights vaut 1, grâce au code suivant: ... elsif (switch > "0") { if (light == nil or light == "0") { light = "1"; # Allumage des feux (effectif à l'appel de **setprop()**) lightsec = 1; # Temporisation de 1 seconde } else { light = "0"; # Extinction des feux lightsec = 6; # Temporisation de 6 secondes } setprop("sim/model/lightning/lights/nav_lights", value); settimer(Lightning.NavLights, lightsec); } Dans ce code, si le commutateur switch est en position “1”, on fait clignoter les feux de position. Pour celà, si la valeur des feux de position light est à “0” (feux éteints), alors on les allume. S'ils étaient allumés, on les éteint. De plus, on les fait clignoter avec un rapport cyclique de 1 pour 6. Celà signifie que les feux restent allumés 1 seconde et éteints pendant 6 secondes, approximativement. La fonction settimer permet d'indiquer qu'il faut appeler la fonction NavLights au bout de lightsec secondes, c'est-à-dire dans notre exemple soit au bout de 1 secondes si les feux sont allumés, soit au bout de 6 secondes si les feux sont éteints. Dernière chose très importante ! Vous constatez que tout le code a été écrit dans une fonction qui s'appelle NavLights. Si vous voulez que cette fonction soit appelée dès que le commutateur situé dans le cockpit est actionné, il faut explicitement l'indiquer. Ceci est réalisé grâce à la dernière ligne de code suivante: setlistener ("controls/switches/nav_lights", NavLights); Cette ligne permet de “connecter” la propriété controls/switches/nav_lights vers notre fonction. Tout changement qui interviendrait dans la propriété (changement de valeur) résulterait automatiquement en l'appel de la fonction NavLights. Voilà pour ce premier exemple. Je vous engage à explorer l'arbre des propriété et voir l'influence des changements de certaines valeurs. Je vous engage également à regarder dans les différents fichiers qui constituent les modèles et qui peuvent vous apprendre beaucoup de choses. |