Unity Jeux 3D
Unity Jeux 3D
Développez des
Unity
avec
http://www.free-livres.com/
Codes
sources
Will Goldstone
LE P R O G RAM M E U R
Les exemples ou les programmes présents dans cet ouvrage sont fournis pour illustrer les descrip-
tions théoriques. Ils ne sont en aucun cas destinés à une utilisation commerciale ou professionnelle.
Pearson Education France ne pourra en aucun cas être tenu pour responsable des préjudices
ou dommages de quelque nature que ce soit pouvant résulter de l’utilisation de ces exemples ou
programmes.
Tous les noms de produits ou marques cités dans ce livre sont des marques déposées par leurs
propriétaires respectifs.
Aucune représentation ou reproduction, même partielle, autre que celles prévues à l’article L. 122-5 2˚ et 3˚ a) du code de la
propriété intellectuelle ne peut être faite sans l’autorisation expresse de Pearson Education France ou, le cas échéant, sans le
respect des modalités prévues à l’article L. 122-10 dudit code.
No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical,
photocopying, recording, or otherwise, without written permission from the publisher.
Table des matières
La détection de collision a priori...................... 103 Présentation des corps rigides ........................ 158
Créer l’objet GUI Texture ................................ 136 Ajouter le tas de bois........................................ 196
Positionner l’objet GUI Texture ....................... 137 Créer les systèmes de particules pour le feu .... 197
8. Conception de menus .................................... 213 Animer le texte avec l’interpolation linéaire.... 252
Les interfaces et les menus ............................ 214 Revenir au menu............................................... 255
Créer le menu principal ................................... 215 L’apparition en fondu
La création du menu – méthode 1 .................. 220 de la scène Island Level ................................. 258
Ajouter le bouton Play/Jouer ........................... 220 Le rendu de la texture UnityGUI ..................... 259
Ajouter le bouton des instructions ................... 224 Notiier la in du jeu ....................................... 260
Ajouter le bouton Quit/Quitter ......................... 224 En résumé....................................................... 261
Utiliser les commandes de débogage
10. Compilation et partage ............................... 263
pour vériier les scripts .................................... 226
Les paramètres Build Settings ....................... 264
La création du menu – méthode 2 .................. 227
Désactiver les Game Objects ........................... 227 L’option Web Player......................................... 265
graphique (GUI, Graphical User Interface) ain que les membres de l’équipe de déve-
loppement du jeu puissent plus facilement manipuler les éléments du moteur. Ces outils
facilitent non seulement le processus de création du jeu mais rendent également le moteur
accessible aux acheteurs potentiels et aux équipes de postproduction. Cela est également
vrai pour Unity, et une très importante communauté d’utilisateurs partage ses outils sous
forme de plugins. Pour en savoir plus, visitez le wiki de la communauté Unify à l’adresse :
http://www.unifycommunity.com/wiki.
Beaucoup de personnes tentées par le développement se heurtent à la dificulté d’apprendre
les langages de programmation comme C++ et les moteurs qui l’utilisent. Si on n’a pas
suivi des études de programmation ou d’animation par ordinateur, il est en effet dificile de
se lancer dans l’apprentissage des concepts, des méthodes et des principes de conception
nécessaires à la production de jeux vidéo. Unity Technologies est une des entreprises qui
a décidé de rectiier cette situation. Après avoir créé son propre moteur de jeu en 2001,
cette société de développement de jeux danoise a cherché à rendre ses outils abordables en
offrant une solution simple axée sur l’utilisateur que tout le monde puisse utiliser. L’équipe
a choisi de conserver le code source qui alimente le moteur dans les coulisses et de fournir
une interface graphique complète ain que l’utilisateur puisse contrôler le code source de
ce puissant moteur sans jamais avoir à créer lui-même de nouveaux éléments dans celui-ci.
Ce facteur a rendu Unity très populaire auprès des nouveaux développeurs et explique
probablement pourquoi vous lisez cet ouvrage. En déinissant des concepts logiques et en
regroupant par catégorie les méthodes communes utilisées pour produire des jeux, Unity
met la puissance de son moteur au service de l’utilisateur, lui permettant d’obtenir un maxi-
mum de résultats avec un minimum d’efforts, ain qu’il se concentre sur le facteur le plus
crucial de tous : le gameplay (la jouabilité).
En attirant de nombreux développeurs de jeux, Unity a comblé un vide sur le marché du
développement des jeux vidéo, ce que peu d’éditeurs peuvent prétendre. Unity est en effet
l’un des moteurs de jeux les plus dynamiques de son secteur car il permet de produire des
jeux 3D professionnels aussi bien sur Mac, sur PC ou sur le Web. Comme le moteur existe
également dans des versions destinées à la Nintendo Wii et à l’iPhone d’Apple, il offre un
accès au marché des ordinateurs mais aussi à celui des consoles et des mobiles une fois que
vous maîtrisez les bases.
L’évolution rapide de l’industrie du divertissement et du marketing nécessite que les jeux
soient produits rapidement. Aussi, de nombreuses entreprises se tournent vers des solutions
intégrées comme Unity pour que leurs créateurs sortent de meilleurs produits le plus facile-
ment possible. Depuis la sortie en 2009 de la version 2.5 et ses premiers pas sous Windows,
Unity est de plus en plus utilisé. Mais qu’est-ce que Unity ? Comment fonctionne-t-il ? Que
peut-il réaliser ? Et surtout, comment ce programme permet-il de développer des jeux 3D
en seulement quelques semaines ?
Préface 3
∑ Chapitre 6. Instanciation et corps rigides. Presque tous les scénarios de jeu que vous
pouvez imaginer imposent de créer ou de "reproduire" des objets dans l’environnement.
Il est essentiel pour tous les développeurs débutants de connaître et de savoir utiliser
cette notion, appelée instanciation en programmation, qui consiste à créer des objets
lors de l’exécution du jeu.
Vous verrez comment améliorer l’interactivité de votre jeu en créant un jeu de tir simple ;
en lançant des objets sur des cibles, le joueur pourra débloquer une partie de l’envi-
ronnement. Vous découvrirez ainsi non seulement l’instanciation, mais aussi comment
utiliser les corps rigides.
∑ Chapitre 7. Systèmes de particules. De nos jours, un jeu en 3D doit impérativement
proposer quelques effets visuels intéressants pour attirer le joueur. Dans ce dessein,
vous créerez un feu de bois pour que le personnage du jeu se réchauffe. Pour cela, vous
utiliserez deux systèmes de particules, l’un pour les lammes et l’autre pour la fumée.
Vous verrez comment les systèmes de particules permettent d’imiter le comportement
d’un feu et comment rendre chaque particule réaliste en utilisant des images. Enin,
vous éteindrez ce feu ain de donner un objectif au joueur : l’allumer pour ne pas périr
de froid !
∑ Chapitre 8. Conception de menus. Pour qu’un jeu soit agréable, ses menus doivent
avoir un aspect professionnel et être faciles à utiliser. Qui voudrait d’un jeu dont le
bouton Démarrer est impossible à trouver ? Ce chapitre abordera les différentes façons
de créer des menus et d’autres interfaces utilisateur avec lesquelles le joueur pourra
interagir.
Vous élaborerez des menus en utilisant à la fois les textures GUI et la classe GUI ain
de créer des interfaces redimensionnables qui puissent être utilisées aussi bien dans les
jeux destinés au Web que dans les applications autonomes.
∑ Chapitre 9. Dernières retouches. Lorsque vous réalisez un jeu, en particulier dans
Unity, il arrive un moment où vous créez un élément interactif dont vous êtes si ier que
vous souhaitez lui ajouter une touche supplémentaire pour le mettre en valeur.
Au il de ce chapitre, nous détaillerons l’utilisation du son, les effets de lumière, le rendu
des traînées lumineuses et d’autres effets dynamiques simples à implémenter, ain de
transformer votre simple jeu fonctionnel en produit ini.
∑ Chapitre 10. Compilation et partage. Vous verrez comment exporter votre jeu pour le
Web et en tant que projet autonome. Nous étudierons les différents réglages dont vous
devez tenir compte lorsque vous préparez le produit ini, comme la qualité graphique,
les commandes de contrôles, et plus encore.
Préface 5
Conventions typographiques
Cet ouvrage utilise plusieurs styles de texte ain d’établir une distinction entre les diffé-
rents types d’informations. En voici quelques exemples ainsi qu’une explication de leur
signiication.
Le code qui apparaît dans le corps du texte est présenté de la manière suivante : "Nous
pouvons inclure d’autres contextes, par l’utilisation de la directive include".
Voici un exemple de bloc de code :
if(collisionInfo.gameObject.name == "matchbox"){
Destroy(collisionInfo.gameObject);
haveMatches=true;
audio.PlayOneShot(batteryCollect);
Les nouveaux termes et les mots importants sont en italiques. Les mots afichés à l’écran,
dans les menus ou les boîtes de dialogue, par exemple, seront en petites capitales comme
ceci : "Cliquez sur le bouton Suivant pour passer à l’écran suivant."
Dans la notation des raccourcis clavier, la première variante est toujours pour Mac OS, la
seconde pour Windows. Appuyez sur Entrée/F2 signiie donc Entrée sur Mac OS et F2 sur
Windows.
Comprendre la 3D
Étudions les principaux éléments des mondes 3D et la façon dont Unity permet de développer
des jeux en trois dimensions.
8 Développez des jeux 3D avec Unity
Les coordonnées
Si vous avez déjà travaillé avec un programme d’illustration 3D auparavant, la notion
d’axe Z vous est probablement familière. L’axe Z représente la profondeur et s’ajoute aux
axes X, pour le plan horizontal, et Y, pour le plan vertical. Dans les applications 3D, les
informations sur les objets sont indiquées selon un système de coordonnées cartésiennes,
autrement dit au format X, Y, Z. Les dimensions, les valeurs de rotation et les positions
dans le monde 3D peuvent toutes être décrites de cette façon. Dans ce livre, comme dans
d’autres documents concernant la 3D, ces informations sont écrites entre parenthèses, de
la manière suivante :
(10, 15, 10)
Cette écriture s’explique principalement pour des raisons de clarté, mais aussi parce que ces
valeurs doivent être écrites de cette façon dans le code. Indépendamment de leur présen-
tation, vous pouvez partir du principe que tout ensemble de trois valeurs séparées par des
virgules est présenté dans l’ordre X, Y, Z.
Figure 1.1 Y
Y Z
L'espace local
(de l'objet)
Z
L'espace global X
Les vecteurs
Vous verrez également des vecteurs 3D décrits en coordonnées cartésiennes. Comme leurs
homologues 2D, ce sont simplement des lignes tracées dans le monde en 3D qui possèdent
une direction et une longueur. Les vecteurs peuvent être déplacés dans l’espace global
mais restent inchangés. Ils sont utiles dans le contexte d’un moteur de jeu, car ils permet-
tent de calculer la direction des objets ainsi que les distances et les angles relatifs entre les
objets.
Les caméras
Les caméras sont essentielles dans le monde 3D, car elles offrent un point de vue sur ce qui
s’afiche à l’écran. Leur champ de vision ayant une forme de pyramide, elles peuvent être
disposées à n’importe quel point dans le monde, être animées ou attachées à des person-
nages ou des objets comme éléments du scénario d’un jeu.
Les caméras 3D ont un champ de vision (FOV, Field of Vision) réglable et offrent un point
de vue sur le monde 3D. Dans les moteurs de jeu, vous remarquerez que les effets de
lumière, les lous de mouvement et les autres effets sont appliqués à la caméra pour simuler
la vision de l’œil humain sur le monde du jeu – vous pouvez même ajouter quelques effets
cinématographiques, comme les effets de rélexion du soleil sur l’objectif.
La plupart des jeux 3D modernes utilisent plusieurs caméras pour montrer certaines parties
du monde du jeu que la caméra attachée au personnage n’est pas en train d’examiner –
comme un "cut", pour reprendre un terme cinématographique. Dans Unity, il est possible
d’utiliser plusieurs caméras dans une seule scène et de les contrôler à l’aide du code, pour
que chacune d’elles devienne à tout moment la caméra principale lors de l’exécution du jeu.
10 Développez des jeux 3D avec Unity
Plusieurs caméras peuvent aussi être utilisées dans un jeu pour contrôler séparément le
rendu de certains éléments 2D et 3D lors du processus d’optimisation. Vous pouvez, par
exemple, regrouper des objets sur des calques puis paramétrer les caméras ain qu’elles
procèdent uniquement au rendu des objets sur certains calques. Vous contrôlez mieux ainsi
les rendus individuels de certains éléments dans le jeu.
un script chargé du style de rendu. Avec un shader de rélexion, par exemple, le rendu du
matériau réléchira les objets environnants tout en conservant sa couleur ou l’apparence de
l’image qui lui est appliquée comme texture.
Dans Unity, les matériaux sont simples à utiliser. Tous les matériaux créés dans votre logi-
ciel de modélisation 3D seront importés et recréés automatiquement par le moteur de Unity,
en tant que ressources que vous pouvez ensuite utiliser. Vous pouvez également créer vos
propres matériaux à partir de zéro, en déinissant des images comme ichiers de texture
et en sélectionnant un shader dans une grande bibliothèque intégrée. Vous pouvez aussi
rédiger vos propres scripts de shader ou implémenter ceux écrits par des membres de la
communauté Unity, ce qui vous offre une plus grande liberté par rapport aux éléments
fournis.
Fondamentalement, lors de la création de textures pour un jeu dans un logiciel graphique
comme Photoshop, vous devez être conscient de la résolution. Les textures d’un jeu doivent
être de forme carrée et leurs dimensions des puissances de 2. Autrement dit, elles
doivent avoir les dimensions suivantes :
∑ 128 × 128
∑ 256 × 256
∑ 512 × 512
∑ 1 024 × 1 024
Le moteur du jeu pourra utiliser des textures de ces dimensions comme tiles – les juxta-
poser pour former une surface. Vous devez également tenir compte de la taille du ichier de
texture, car ses dimensions ont un impact direct sur la puissance de traitement exigée par
l’ordinateur du joueur. Par conséquent, pensez toujours à donner à vos illustrations la plus
petite taille 2D possible, sans trop sacriier à la qualité.
RigidBody (corps rigide) à chaque objet que le moteur physique doit contrôler lors de la
création du jeu.
Les moteurs physiques des jeux utilisent le système dynamique des corps rigides pour créer
un mouvement réaliste. Ainsi, au lieu d’être de simples objets statiques dans le monde en
3D, ils peuvent posséder les propriétés suivantes :
∑ Masse
∑ Gravité
∑ Vélocité
∑ Friction
Comme la puissance du matériel et des logiciels augmente, la physique des corps rigides,
qui permet des simulations variées et réalistes, est de plus en plus largement utilisée dans
les jeux (voir Chapitre 6, "L’instanciation et les corps rigides").
La détection de collision
Plus cruciale dans les moteurs de jeu que dans l’animation 3D, la détection de collision est
la façon d’analyser le monde 3D pour les collisions entre objets. En donnant un composant
Collider (composant de collision) à un objet, on place effectivement un ilet invisible
autour de ce dernier. Ce ilet imite la forme de l’objet et il est chargé de signaler toute
collision avec d’autres colliders ain que le moteur de jeu réagisse en conséquence. Dans
un jeu de bowling, par exemple, un simple collider sphérique entoure la boule, tandis que
les quilles ont soit un collider simple en forme de capsule, soit un Mesh Collider (un
composant de collision respectant le maillage de l’objet) pour une collision plus réaliste.
Au moment de l’impact, les colliders de tous les objets touchés envoient un rapport au
moteur physique qui leur dicte leur réaction en fonction de l’orientation de l’impact, de la
vitesse et d’autres facteurs.
Dans cet exemple, si on emploie un Mesh Collider qui suit exactement à la forme de la
quille, le résultat est plus précis mais aussi plus coûteux en termes de calcul. Autrement dit,
la puissance de calcul demandée à l’ordinateur est plus importante, ce qui se traduit par une
baisse des performances – d’où le terme coûteux.
de procédures cohérentes ain que votre imagination soit la seule limite à votre créativité.
Grâce au concept de Game Object (GO), vous pouvez scinder les éléments du jeu en objets
faciles à gérer, constitués de nombreux composants individuels. En individualisant chaque
objet dans le jeu, puis en lui ajoutant des composants pour le rendre fonctionnel, vous êtes
en mesure d’étendre votre jeu à l’inini d’une manière progressive et logique. Les compo-
sants possèdent des variables – pour l’essentiel des paramètres permettant de les contrôler.
En ajustant ces variables, vous contrôlez totalement l’effet que ce composant a sur votre
objet. Prenons un exemple simple.
Le fonctionnement de Unity
Pour intégrer une balle qui rebondit dans le cadre d’un jeu, par exemple, on commence
par créer une sphère, ce qui peut rapidement être réalisé à partir des menus de Unity. On
obtient alors un nouveau Game Object possédant un maillage en forme de sphère (un ilet
de forme 3D) et un composant Renderer (de rendu) pour qu’il soit visible. On peut ensuite
ajouter un corps rigide (composant Rigidbody) pour indiquer à Unity que l’objet doit utiliser
le moteur physique. Ce composant intègre les propriétés physiques de masse et de gravité
ainsi que la capacité d’appliquer des forces à l’objet, soit lorsque le joueur agit dessus, soit
lorsqu’il entre en collision avec un autre objet. La sphère va maintenant tomber sur le sol
lors de l’exécution du jeu, mais comment la faire rebondir ? C’est simple ! Le composant
Collider possède une variable Physic Material – un paramètre du composant Rigidbody
qui déinit la réaction de celui-ci au contact des surfaces des autres objets. Il sufit donc de
sélectionner le paramètre prédéini Bouncy pour obtenir une balle qui rebondit en seulement
quelques clics.
Cette approche simpliiée pour les tâches les plus élémentaires, comme dans l’exemple
précédent, semble prosaïque au premier abord. Toutefois, vous découvrirez bientôt qu’elle
permet de réaliser très simplement des tâches plus complexes. Étudions rapidement les
concepts clés de Unity.
Les ressources
Ce sont les composants de base de tous les projets Unity. Des éléments graphiques sous
forme de ichiers image, aux modèles 3D en passant par les ichiers son, Unity désigne
tous les ichiers utilisés pour créer un jeu comme des ressources (assets). C’est pourquoi tous
les ichiers utilisés dans le dossier d’un projet Unity sont stockés dans un dossier enfant
nommé Assets.
14 Développez des jeux 3D avec Unity
Les scènes
Considérez les scènes comme des niveaux de jeu individuels ou des zones de contenu (les
menus, par exemple). En construisant votre jeu avec de nombreuses scènes, vous pourrez
répartir les temps de chargement et tester les différentes parties une par une.
Les composants
Les composants se présentent de différentes manières. Ils peuvent être utilisés pour créer un
comportement, déinir l’apparence ou exercer une inluence sur la fonction d’un objet dans
le jeu. En "attachant" les composants à un objet, vous pouvez appliquer immédiatement de
nouveaux éléments du moteur de jeu à votre objet. Les composants les plus courants pour
créer des jeux sont fournis avec Unity, depuis le composant Rigidbody, mentionné plus
tôt, jusqu’aux éléments plus simples comme les lumières, les caméras, les émetteurs de
particules, etc. Pour créer des éléments plus interactifs dans le jeu, vous écrirez des scripts,
qui sont considérés comme des composants dans Unity.
Les scripts
Tout en étant considérés comme des composants par Unity, les scripts sont un élément
essentiel de la création de jeux et méritent, à ce titre, d’être vus comme une notion clé. Dans
ce livre, vous écrirez vos scripts en JavaScript, mais Unity offre également la possibilité
Chapitre 1 Bienvenue dans la troisième dimension 15
d’utiliser les langages C# et Boo (un dérivé du langage Python). Nous avons choisi de
présenter Unity avec du code JavaScript car il s’agit d’un langage de programmation
fonctionnel dont la syntaxe est simple. En outre, certains d’entre vous ont peut-être déjà
rencontré JavaScript dans d’autres logiciels, comme son dérivé ActionScript dans Adobe
Flash, ou l’ont utilisé pour le développement web.
Unity ne nécessite pas d’apprendre le fonctionnement du code de son propre moteur ni de
savoir comment le modiier, mais vous utiliserez des scripts dans presque tous les scénarios
de jeu que vous développerez. Ces scripts sont assez simples et aisément compréhensibles
après quelques exemples, car Unity possède sa propre classe prédéinie de comportement
– un ensemble d’instructions auxquelles vous ferez appel. Les scripts peuvent être intimi-
dants, en particulier pour les nouveaux utilisateurs de Unity qui ne connaissent que la phase
de conception et découvrent le développement. Nous allons les présenter étape par étape,
ain de vous en montrer l’importance et les possibilités qu’ils offrent.
Pour écrire des scripts, vous pourrez utiliser l’éditeur de script autonome de Unity. Sous
Mac OS, cette application s’appelle Unitron, et sous Windows, Uniscite. Ces applications
distinctes se trouvent dans le dossier de Unity sur votre ordinateur. Elles s’ouvrent chaque
fois que vous créez ou modiiez un script. Lorsque vous modiiez les scripts et que vous les
enregistrez dans l’éditeur de script, celui-ci est immédiatement mis à jour dans Unity. Vous
pouvez également choisir votre propre éditeur de script dans les Préférences de Unity si
vous le souhaitez.
L’interface
Les différents panneaux qui composent l’interface de Unity peuvent être ancrés et déplacés.
Comme dans de nombreux autres environnements de travail, vous pouvez donc personna-
liser l’apparence de l’interface. Étudions la disposition par défaut :
Figure 1.2
Figure 1.3
Le panneau Scene s’accompagne de quatre boutons de contrôle très utiles (voir Figure 1.3).
Ces contrôles, accessibles à l’aide des raccourcis clavier Q, W, E et R, permettent d’exécuter
les opérations suivantes :
∑ Hand (Main) [Q]. Permet de naviguer dans le panneau Scene ain de visualiser diffé-
rentes parties du monde ou depuis différents angles. Maintenez la touche Alt enfoncée
pour faire pivoter la vue et la touche Cmd (Mac OS) ou Ctrl (Windows) pour zoomer.
Appuyez également sur la touche Maj pour effectuer ces changements de perspective
plus rapidement.
∑ Translate (Translation) [W]. C’est l’outil de sélection. Vous pouvez totalement interagir
avec le panneau Scene et repositionner un objet à l’aide de ses poignées d’axe dans ce
panneau après l’avoir sélectionné dans les panneaux Hierarchy ou Scene.
∑ Rotate (Rotation) [E]. Il fonctionne de la même manière que l’outil Translate, les
poignées d’axe permettant de faire tourner l’objet sélectionné autour de chacun de ses
axes.
∑ Scale (Échelle) [R]. Là encore, le fonctionnement est identique à celui des outils
Translate et Rotate. Cet outil permet d’ajuster la taille ou l’échelle d’un objet à
l’aide de ses poignées.
Lorsque vous sélectionnez un objet dans le panneau Scene ou Hierarchy, il est immé-
diatement sélectionné dans les deux panneaux et ses propriétés s’afichent dans le panneau
Inspector. Toutefois il peut arriver que vous ne voyiez pas dans le panneau Scene un objet
sélectionné dans le panneau Hierarchy : la touche F vous permet alors de centrer la vue
sur l’objet en question. Il sufit de le sélectionner dans le panneau Hierarchy, de placer le
curseur sur le panneau Scene et d’appuyer sur la touche F.
18 Développez des jeux 3D avec Unity
Le panneau Inspector
Le panneau Inspector est le principal outil pour ajuster chaque élément des objets de jeu
et des ressources de votre projet. Tout comme l’Inspecteur de propriétés dans Adobe Flash
et Dreamweaver, le contenu de ce panneau est sensible au contexte. Autrement dit, il afiche
les propriétés correspondant à l’objet sélectionné – il est donc sensible au contexte dans
lequel vous travaillez.
Le panneau Inspector afiche tous les composants de l’élément sélectionné ce qui permet
d’en ajuster les variables à l’aide d’éléments simples comme des zones de saisie de texte,
des curseurs, des boutons et des menus déroulants. Beaucoup de ces variables utilisent
également le système de glisser-déposer de Unity, ce qui signiie qu’avec cette méthode
vous pouvez déinir des paramètres plutôt que de sélectionner une valeur dans un menu
déroulant, si cela est plus pratique.
Ce panneau n’a pas uniquement pour rôle d’aficher les éléments qui composent les objets.
Il peut également aficher les préférences de votre projet selon l’option que vous sélection-
nez dans le menu Edit (Édition). Les propriétés des composants s’afichent dès que vous
sélectionnez de nouveau un objet ou une ressource.
Figure 1.4
À la Figure 1.4, le panneau Inspector afiche les propriétés d’un objet cible dans le jeu.
L’objet lui-même possède deux composants – Transform et Animation –, dont vous
pouvez modiier les paramètres dans le panneau Inspector. Notez également que vous pouvez
désactiver temporairement un composant à tout moment, ce qui est très utile pour effectuer
Chapitre 1 Bienvenue dans la troisième dimension 19
des tests et expérimenter différentes possibilités. Pour cela, il sufit de décocher la case
située à gauche du nom du composant. De même, pour désactiver un objet entier, décochez
la case en regard de son nom en haut du panneau Inspector.
Le panneau Project
Le panneau Project (projet) offre une vue directe du dossier Assets (ressources) du projet.
Chaque projet de Unity se compose d’un dossier parent, qui contient trois sous-dossiers :
Assets, Library (bibliothèque) et Temp lorsque l’Éditeur de Unity est ouvert. Les ressources
placées dans le dossier Assets sont immédiatement visibles dans le panneau Project et sont
importées automatiquement dans le projet Unity. De même, si vous modiiez et enregistrez
une ressource du dossier Assets dans une application tierce comme Photoshop, Unity la
réimportera, si bien que les modiications effectuées s’aficheront immédiatement dans le
projet et dans toutes les scènes qui utilisent cette ressource en particulier.
Le panneau Project s’accompagne d’un bouton Create (créer). Celui-ci permet la créa-
tion de tous les types de ressources disponibles dans Unity – scripts, éléments préfabriqués
et matériaux, par exemple.
Le panneau Game
Le panneau Game (jeu), qui s’afiche lorsqu’on clique sur Play, propose un aperçu réaliste
du jeu. Il dispose également de paramètres de résolution de l’écran, ce qui est utile pour
visualiser le point de vue du joueur dans certains ratios, comme le 4:3 (par opposition à un
écran large). Avant de cliquer sur Play, rappelez-vous ceci :
En mode Lecture, les ajustements que vous apportez à tous les éléments de la
ntion scène de jeu ne sont que temporaires. Ce mode est uniquement un mode de test,
Atte
si bien que, lorsque vous cliquez de nouveau sur Play pour arrêter le jeu, toutes
les modiications apportées en cours de lecture seront annulées. C’est souvent
très déroutant pour les nouveaux utilisateurs, alors n’oubliez pas !
20 Développez des jeux 3D avec Unity
Le panneau Game peut également être paramétré à l’aide de l’option Maximize. On obtient
alors un aperçu proche du plein écran en mode de lecture – la taille du panneau recouvre la
totalité de l’interface. Notez que vous pouvez également agrandir n’importe quel panneau
de l’interface. Il sufit pour cela de placer le curseur sur le panneau à agrandir puis d’appuyer
sur la barre d’espacement.
En résumé
Nous avons découvert au cours de ce chapitre les concepts clés que vous avez besoin de
comprendre pour compléter les exercices de ce livre. En raison de contraintes d’espace, nous
ne pouvons pas tout présenter en détail, car le développement 3D est un domaine d’étude
très vaste. C’est pourquoi nous vous conseillons de chercher des informations supplémen-
taires sur les sujets abordés, ain de compléter vos connaissances. Chaque logiciel dispose
de ses propres didacticiels et ressources consacrés à son apprentissage. Si vous désirez
apprendre à créer des modèles 3D pour les utiliser dans Unity, nous vous recommandons
de choisir et de vous familiariser avec le programme qui vous convient le mieux. Vous trou-
verez une liste des programmes compatibles avec Unity au Chapitre 2, "Environnements".
À présent que nous avons vu rapidement les concepts 3D et les processus utilisés par Unity
pour créer des jeux, vous allez commencer à utiliser le logiciel pour créer l’environnement
de votre jeu.
Au chapitre suivant, nous aborderons l’éditeur de terrain, un outil simple à utiliser pour
commencer la création d’un jeu situé dans un environnement extérieur. Avec lui, vous
construirez une île à laquelle vous ajouterez des fonctionnalités au il des chapitres suivants
ain de créer un mini-jeu dans lequel le joueur devra allumer un feu de camp après avoir
récupéré des allumettes dans un avant-poste dont la porte est verrouillée.
2
Environnements
Pour construire votre monde en 3D, vous utiliserez deux types différents d’environnement :
les bâtiments et les éléments de décor créés dans une application de modélisation 3D tierce
mais aussi des terrains créés à l’aide de l’éditeur de terrain de Unity.
Vous verrez rapidement ici comment déinir les paramètres nécessaires à l’importation des
modèles créés en dehors de Unity, mais vous utiliserez principalement les outils propres à
Unity pour créer des terrains. Vous verrez en particulier comment :
∑ créer votre premier projet Unity ;
∑ créer et conigurer des terrains ;
∑ utiliser les outils de terrain pour construire une île ;
∑ éclairer les scènes ;
∑ utiliser le son ;
∑ importer des paquets de ressources ;
∑ importer des modèles 3D externes.
22 Développez des jeux 3D avec Unity
Les ressources
Les modèles utilisés dans ce livre sont disponibles en ligne au format .fbx (format natif
pour Unity qui est commun à la plupart des applications de modélisation 3D).
Lors du téléchargement du contenu nécessaire pour les exercices de ce livre, vous aurez
besoin du système de paquets de ressources de Unity. L’importation et l’exportation de
paquets de ressources dans Unity à l’aide du menu Assets permettent de transférer des
ressources d’un projet à un autre en conservant les dépendances. Une dépendance est tout
simplement une autre ressource liée à celles que vous importez ou exportez. Lors de l’ex-
portation d’un modèle 3D dans le cadre d’un paquet de ressources Unity par exemple (à
destination d’un collaborateur, ou simplement entre vos propres projets Unity), vous devrez
Chapitre 2 Environnements 23
transférer les matériaux adéquats et les textures associées avec les modèles ; ces ressources
connexes sont alors appelées dépendances du modèle.
Dans ce livre, nous vous indiquerons quand télécharger des paquets Unity et les ajouter à
vos ressources. Pour cela, il vous sufira de cliquer sur Assets > Import Package.
Figure 2.1
L’éditeur de terrain
Un éditeur de terrain est indispensable pour tout développeur qui souhaite créer un jeu se
déroulant en extérieur. Unity en intègre un depuis sa version 2.0, ce qui facilite et accélère
la construction des environnements.
Pour Unity, un terrain est simplement un objet de jeu sur lequel on applique certains compo-
sants en particulier. Le terrain que vous allez bientôt créer est, à l’origine, une surface
plane, une forme 3D à une seule face, mais il peut être transformé en un ensemble géomé-
trique complet et réaliste et inclure des détails supplémentaires – arbres, rochers, feuilles
– et même des effets atmosphériques, comme le vent.
Figure 2.2
etc.), les résolutions heightmap comptent toujours un pixel supplémentaire car chaque
pixel déinit un sommet. Ainsi, dans l’exemple d’un terrain de 4 × 4, quatre sommets
seraient présents le long de chaque section de la grille, mais les points où ces sommets se
rencontrent – y compris leurs extrémités – seraient au nombre de cinq.
∑ Detail Resolution. Connue sous le nom de Detail resolution map, c’est la résolution de
la surface stockée par Unity. Celle-ci déinit précisément la manière dont vous pouvez
placer des détails sur le terrain. Les détails regroupent les caractéristiques supplémen-
taires du terrain comme les plantes, les rochers et les arbustes. Plus cette valeur est
élevée et plus vous pouvez positionner les détails avec précision sur le terrain.
∑ Control Texture Resolution. C’est la résolution des textures (appelées Splatmap dans
Unity) lorsqu’elles sont peintes sur le terrain. La valeur de Control Texture Reso-
lution correspond à la taille et, par conséquent, au détail de toutes les textures sur
lesquelles vous allez peindre. Comme pour toutes les résolutions de texture, il est préfé-
rable de conserver une valeur assez basse pour obtenir de bonnes performances. Il est
généralement conseillé de la laisser à sa valeur par défaut (512).
∑ Base Texture Resolution. La résolution de la texture utilisée par Unity pour faire le
rendu des zones de terrain éloignées de la caméra dans le jeu, ou de toutes les textures
sur un ordinateur ancien et peu performant.
Figure 2.3
La boîte de dialogue Create Lightmap est utilisée pour générer un rendu semi-permanent
de l’éclairage sur les textures qui donnent l’apparence à la topographie. Si vous créez un
petit terrain accidenté, par exemple, puis que vous souhaitiez inclure une montagne au
centre, vous devrez choisir les outils de terrain. Toutefois, compte tenu de l’ombre projetée
sur le terrain par cette montagne, vous devez recréer la lightmap ain de faire le rendu des
zones sombres sur les textures situées dans la zone à présent ombragée.
Chapitre 2 Environnements 27
Figure 2.4
Chapitre 2 Environnements 29
Le composant Terrain (Script) comprend sept sections, qui sont facilement accessibles à
l’aide des boutons situés en haut du composant. Voici un rapide aperçu de leurs capacités
respectives.
Figure 2.5
Figure 2.6
30 Développez des jeux 3D avec Unity
Figure 2.7
Cela signiie que vous pouvez déinir la hauteur que vous allez peindre. Lorsque la zone
de terrain dont vous modiiez l’élévation atteint la hauteur spéciiée, elle s’aplatit, vous
permettant de créer des plateaux (voir Figure 2.8).
Figure 2.8
Figure 2.9
Chapitre 2 Environnements 31
Le plateau de la Figure 2.9 présente, par exemple, une pente très abrupte. Pour adoucir les
contours de cette élévation, nous nous servirions de cet outil ain d’arrondir les angles (voir
Figure 2.10).
Figure 2.10
Il s’utilise pour peindre les textures sur la surface du terrain (nommées Splats) dans Unity.
Figure 2.11
Avant de peindre avec des textures, vous devez d’abord les ajouter à la palette dans la zone
Textures de cet outil. Pour cela, cliquez sur le bouton Edit Textures, sélectionnez Add
Textures puis, dans le menu déroulant Splat, choisissez un des ichiers de texture actuel-
lement dans votre projet et déinissez les paramètres de taille de la texture choisie.
32 Développez des jeux 3D avec Unity
La Figure 2.12 montre trois textures ajoutées dans la palette. La première sera peinte sur
tout le terrain par défaut. En combinant ensuite plusieurs textures de différentes opacités et
en peignant à la main sur le terrain, vous pouvez donner un aspect réaliste à tous les types
de surface.
Pour choisir la texture avec laquelle peindre, cliquez simplement sur son aperçu dans la
palette : un contour bleu l’encadre alors.
Figure 2.12
Figure 2.13
Comme pour les textures de l’outil Paint Texture, cet outil dispose d’un bouton Edit
Trees pour ajouter, modiier et supprimer des ressources de la palette.
Chapitre 2 Environnements 33
Figure 2.14
Figure 2.15
34 Développez des jeux 3D avec Unity
Vous pouvez déinir ici différents paramètres qui inluent sur le niveau de détail (LOD,
Level of Detail). Dans le domaine du développement de jeux, le LOD correspond à la
quantité de détails représentés à une certaine distance du joueur. Dans notre exemple –
un terrain –, nous devons pouvoir régler les paramètres comme la distance d’afichage
(Draw Distance). Cette notion, courante dans les jeux 3D, permet de procéder au rendu des
éléments de façon moins détaillée lorsqu’ils se trouvent à une certaine distance du joueur
ain d’améliorer les performances.
La section Terrain Settings vous permet par exemple d’ajuster l’option Base Map
Distance (distance de base) ain de préciser à quelle distance doivent se situer les objets
avant que les graphismes en haute résolution ne soient remplacés par des graphismes en
plus basse résolution, ain de réduire le coût du rendu des objets les plus lointains.
La Figure 2.16 montre un exemple de terrain avec une valeur Base Map Distance faible
(environ 10 mètres). Comme vous pouvez le constater, le niveau de détail des textures
situées au-delà de la distance spéciiée est bien inférieur à celui du premier plan.
Figure 2.16
Vous allez étudier plus en détail les paramètres de la section Terrain (script) en commençant
à sculpter le terrain.
Chapitre 2 Environnements 35
Figure 2.17
36 Développez des jeux 3D avec Unity
Maintenez la touche Maj enfoncée pour que l’outil réduise la hauteur du terrain, puis
peignez sur les contours du terrain pour créer un rivage en pente jusqu’à l’altitude 0 – vous
savez que vous atteignez l’altitude 0 car le terrain sera aplati à cette hauteur minimale.
Bien qu’il ne soit pas nécessaire que le contour de votre île soit identique au nôtre, essayez
de créer une forme assez semblable, car vous aurez besoin d’une étendue de terre plate par
la suite. Une fois que vous avez peint tout autour du contour, vous devriez obtenir un résultat
semblable à celui de la Figure 2.18.
Figure 2.18
Cliquez sur le cube au centre de l’axe 3D situé dans le coin supérieur droit du panneau
Scene pour revenir à une vue en perspective (3D) et admirez votre travail. Si vous n’êtes
pas sûr d’avoir obtenu le bon résultat, comparez votre île avec celle de la Figure 2.19.
Chapitre 2 Environnements 37
Figure 2.19
Continuez avec l’outil Raise/Lower Terrain sur l’île pour améliorer la topographie du
terrain, en augmentant voire en diminuant (avec la touche Maj) l’élévation de certaines
zones. Vous pouvez, par exemple, ajouter une baie ou un lac. Conservez un espace plat au
centre du terrain et une partie libre dans un coin de l’île pour ajouter un volcan.
Étape 3. Le volcan
Vous allez maintenant créer un volcan ! Pour cela, les outils Paint Height, Raise/Lower
Terrain et Smooth Height seront adaptés. Sélectionnez l’outil Paint Height pour
commencer.
Choisissez la première brosse dans la palette, donnez les valeurs 75 à Brush Size, 50 à
Opacity et 200 à Height. Sélectionnez de nouveau la vue Haut en cliquant sur l’axe Y de
l’axe 3D dans le panneau Scene, puis peignez un plateau dans le coin du terrain que vous
avez laissé libre. Rappelez-vous que cet outil arrête de modiier le terrain une fois que la
hauteur spéciiée (200) est atteinte.
Votre île devrait maintenant ressembler à celle de la Figure 2.20 dans la vue Perspective.
38 Développez des jeux 3D avec Unity
Figure 2.20
Ce plateau a un aspect assez peu réaliste. Vous allez remédier à cela, mais vous devez
d’abord créer la bouche du volcan. L’outil Paint Height toujours sélectionné, donnez la
valeur 20 à Height et la valeur 30 à Brush Size.
Cliquez et maintenez et commencez à peindre du centre du plateau vers l’extérieur dans
toutes les directions, jusqu’à ce que vous ayez effectivement creusé le plateau et laissé une
crête étroite autour de sa circonférence (voir Figure 2.21).
Si vous repassez dans la vue en perspective, vous voyez que l’aspect du bord du volcan
est toujours trop abrupt et assez peu réaliste. Vous allez corriger cela : sélectionnez l’outil
Smooth Height, puis donnez les valeurs 30 à Brush Size et 1 à Opacity. Peignez ensuite
avec cet outil sur le pourtour de la crête pour l’adoucir jusqu’à ce que l’arête soit sufisamment
arrondie (voir Figure 2.22).
Maintenant que vous avez donné sa forme au volcan, vous pouvez ajouter une texture à l’île
pour rendre le terrain plus réaliste.
Chapitre 2 Environnements 39
Figure 2.21
Figure 2.22
40 Développez des jeux 3D avec Unity
Figure 2.23
Ces quatre textures vous serviront à peindre le terrain de l’île. Vous devez donc commencer
par les ajouter à votre palette. Assurez-vous que l’objet de jeu Terrain est toujours sélec-
tionné dans le panneau Hierarchy, puis sélectionnez l’outil Paint Texture dans le composant
Terrain (Script) du panneau Inspector.
La procédure de peinture
Cliquez sur le bouton Edit Textures, puis sélectionnez Add Textures dans le menu qui
s’afiche. La boîte de dialogue Add Textures s’ouvre alors pour vous permettre de sélec-
tionner toutes les textures actuellement dans votre projet. Cliquez sur la lèche pointant
vers le bas à droite du paramètre Splat pour choisir une texture sur la liste. Sélectionnez la
texture Grass (Hill).
Chapitre 2 Environnements 41
Figure 2.24
Conservez la valeur 15 pour les paramètres Tile Size X et Tile Size Y. Cette texture
recouvrira toute la carte et cette petite valeur permettra d’obtenir une herbe plus détaillée.
Cliquez sur le bouton Add pour terminer. La texture d’herbe recouvre le terrain : c’est
normal puisqu’il s’agit de la première texture que vous ajoutez. Celles que vous ajouterez
ensuite à la palette devront être peintes à la main.
Répétez l’étape précédente pour ajouter les trois textures Grass&Rock, Cliff (Layered
Rock) et GoodDirt dans la palette. Conservez les paramètres Tile Size, sauf pour Cliff
(Layered Rock), dont les paramètres Tile Size X et Tile Size Y doivent avoir une valeur
de 70. En effet, comme cette texture va être appliquée sur une zone étirée du terrain, elle
serait déformée avec une taille de carreau (unité de terrain ou tile) plus petite.
Figure 2.25
42 Développez des jeux 3D avec Unity
Figure 2.26
Si vous faites une erreur pendant que vous peignez, vous pouvez soit annuler le dernier coup
de pinceau, c’est-à-dire le dernier clic, avec la commande Edit > Undo, soit sélectionner
dans la palette la texture qui doit recouvrir cette zone et repeindre avec celle-ci.
Chapitre 2 Environnements 43
Figure 2.27
Après de nombreux essais, sans doute, votre volcan terminé devrait ressembler à celui de
la Figure 2.28.
Figure 2.28
Avec le paramètre Bend Factor, les arbres semblent se balancer dans le vent. Le coût du
calcul de cet effet étant élevé, nous allons utiliser une valeur faible. Entrez 2 puis validez
(touche Entrée). Si vous remarquez, par la suite, que ce paramètre a un impact négatif sur
les performances du jeu, vous pourrez toujours le redéinir en lui donnant la valeur 0.
Cliquez sur le bouton Add. Un petit aperçu du palmier devrait apparaître dans la palette,
encadré de bleu pour indiquer qu’il s’agit de l’arbre sélectionné à placer.
Donnez les valeurs suivantes : 15 à Brush Size (pour peindre quinze arbres à la fois),
10 à Tree Density (ain que les arbres soient assez dispersés sur la carte), 0,4 à Color
Variation (pour obtenir un ensemble d’arbres varié). Enin, attribuez 150 à Tree Height
et Tree Width avec, pour chacun, 30 comme valeur de Variation.
Disposez des arbres en cliquant simplement autour du rivage de l’île, à proximité des zones
de sable où ce type d’arbres est censé se trouver. Puis, pour compléter le relief de l’île,
placez d’autres palmiers à des emplacements aléatoires à l’intérieur des terres.
Vous pouvez à tout moment effacer des arbres mal placés : pour cela, appuyez sur la touche
Maj et cliquez ou peignez sur ces arbres.
Figure 2.29
Cliquez sur le bouton Add au bas de la boîte de dialogue pour conirmer l’ajout de cette
texture à votre palette.
Vous pouvez peindre l’herbe sur la carte avec la souris de la même façon qu’avec les autres
outils de terrain. Vous devez d’abord choisir une brosse et déinir ses paramètres ain de
créer des touffes d’herbe espacées et disparates sur la carte. Le rendu de l’herbe étant
également coûteux pour l’ordinateur, donnez des valeurs très faibles : 100 pour Brush
Size mais seulement 0,05 pour Opacity et 0,6 pour Target Force de façon que les touffes
d’herbe soient clairsemées. En choisissant en outre une forme de brosse irrégulière (voir
Figure 2.30), vous pouvez peindre des zones d’herbe inégales.
Sélectionnez l’outil Hand, appuyez sur Cmd/Ctrl et faites glisser la souris vers la droite
pour zoomer sur la surface du terrain. Lorsque le niveau de zoom est sufisant, vous pouvez
cliquer sur le terrain pour peindre les zones d’herbe. Déplacez-vous sur l’île mais ne peignez
que quelques zones d’herbe pour des raisons de performances (vous pourrez toujours en
ajouter par la suite si les performances du jeu sont bonnes).
Il est crucial de zoomer en avant sur le terrain lorsque vous peignez des détails.
ce Ain d’économiser de la mémoire, le rendu des détails n’est, en effet, pas visible
Astu
dans le panneau Scene avec un facteur de zoom réduit. Lorsque vous zoomez
en arrière, les détails semblent ainsi souvent disparaître mais, ne vous inquiétez
pas, cela n’est pas le cas.
Chapitre 2 Environnements 47
Figure 2.30
Figure 2.31
Listener à un microphone ou à l’oreille du joueur. Par défaut, les objets de jeu Caméra
de Unity possèdent un composant Audio Listener. Et comme vous disposez toujours d’une
caméra dans votre jeu, il est fort probable que vous n’aurez que les sources sonores à
déinir. Il est également intéressant de noter que le composant Audio Listener n’a pas de
propriétés ajustables – il fonctionne, tout simplement –, et que Unity afiche un message
d’erreur si vous supprimez par inadvertance le dernier écouteur dans une scène.
Stéréo et mono
Unity gère le comportement du son en stéréo (deux canaux) pour le volume sonore constant,
et en mono (un seul canal) pour le son dont le volume varie en fonction de la distance entre
la source d’émission et l’auditeur dans l’univers 3D.
Prenons deux exemples :
∑ La musique dans le jeu. Le son stéréo est préférable, le volume étant constant, où que se
trouve le joueur dans le jeu.
∑ Les effets sonores d’une chaîne hi-i à l’intérieur d’un bâtiment. Le son mono est le
mieux adapté. Bien que vous puissiez choisir de la musique comme effet sonore, l’uti-
lisation de ichiers audio mono permet d’augmenter le volume de la source sonore à
mesure que le joueur s’en approche.
si bien que cette source sonore pourrait se situer sur n’importe quel objet. Il est cependant
logique que l’ambiance sonore de l’île soit liée à cet objet de jeu.
Un composant Audio Source est à présent disponible dans le panneau Inspector du
terrain. Vous pouvez soit choisir le ichier qui doit être lu soit ne rien indiquer si vous avez
décidé de déclencher les sons à l’aide d’un script.
Pour cette étape, vous aurez besoin d’utiliser le premier paquet de ressources de l’archive
que vous avez téléchargée sur le site Pearson (http://www.pearson.fr). Décompressez cette
archive, localisez le ichier nommé Sound1.unitypackage dans le dossier 8181_02_code,
puis revenez à Unity et cliquez sur Assets > Import Package.
Dans la boîte de dialogue Import Package qui s’ouvre alors, parcourez votre disque dur
jusqu’à l’emplacement où vous avez enregistré l’archive décompressée. Sélectionnez ce
dossier, puis cliquez sur Ouvrir. La liste des ressources disponibles s’afiche – par défaut,
Unity part du principe que l’utilisateur souhaite importer toutes les ressources, mais il vaut
mieux importer seulement certaines ressources lors de l’utilisation de plus gros paquets de
ressources.
Le paquet sound1 ne contient qu’un ichier audio au format MP3 ichier appelé hillside.
mp3 placé dans un dossier Sound, si bien que seuls ces deux éléments s’afichent.
Cliquez sur Import pour conirmer l’ajout de ces ichiers dans votre projet. Après leur
conversion, ils devraient apparaître dans le panneau Project – vous devez cliquer sur
la lèche grise à gauche du dossier Sound pour aficher le ichier hillside qu’il contient.
Les ichiers audio s’accompagnent d’une icône en forme de haut-parleur dans le panneau
Project (voir Figure 2.32).
Figure 2.32
Le ichier hillside peut maintenant être appliqué au composant Audio Source du terrain.
Chapitre 2 Environnements 51
Cliquez sur la lèche pointant vers le bas, située à droite du paramètre Audio Clip dans
le composant Audio Source de l’objet de jeu Terrain, ain d’aficher la liste de tous les
ichiers audio disponibles dans le projet. Comme celui-ci ne contient que le ichier audio
hillside, seul ce dernier s’afiche dans le menu contextuel. Sélectionnez-le maintenant.
Figure 2.33
Dans les environnements 3D, vous représentez l’horizon ou le lointain en ajoutant une
skybox. Une skybox est un cubemap (une vue cubique aplatie), c’est-à-dire une série de six
52 Développez des jeux 3D avec Unity
textures placées à l’intérieur d’un cube dont le rendu simule le ciel et l’horizon. Ce cube-
map recouvre le monde en 3D à tout moment et, tout comme l’horizon réel, il ne peut pas
être atteint par un joueur.
Pour appliquer une skybox à la scène, cliquez sur Edit > Render Settings. Le contenu
du panneau Inspector afiche alors les préférences de rendu de cette scène. Cliquez sur
la lèche déroulante située à droite du paramètre Skybox Material, puis sélectionnez
Sunset pour l’appliquer à la skybox. Il est crucial que vous compreniez que chaque skybox
ajoutée sera uniquement visible dans le panneau Game par défaut.
La skybox Sunset du paquet de ressources Standard, comme de nombreuses autres,
dispose d’un soleil prédéini. Cependant, votre scène en a déjà un, représenté visuel-
lement par le relet de la lumière directionnelle. Vous devez donc repositionner celle-ci
pour qu’elle corresponde au soleil de la skybox. Ain que vous puissiez juger de ce
problème par vous-même, vous ajouterez d’abord le personnage du joueur (First Person
Controller).
Vous avez créé une île, celle-ci doit donc être entourée d’eau. L’eau, dans Unity, est réali-
sée à partir d’un matériau animé appliqué à une surface. Bien qu’il soit possible de créer
d’autres effets dynamiques pour l’eau à l’aide des particules, la meilleure façon d’en ajouter
une grande étendue consiste à utiliser un des matériaux fournis avec Unity.
Le paquet de ressources Standard Assets contient deux surfaces prêtes à l’emploi sur
lesquelles le matériau Water est appliqué. Ces objets enregistrés en tant qu’éléments préfa-
briqués peuvent être facilement utilisés depuis le panneau Project. Il vous sufit en effet
d’ouvrir le dossier Standard Assets/Water.
Faites glisser l’élément préfabriqué Daylight Simple Water dans la scène, puis positionnez-
le à (500, 4, 500) en indiquant ces valeurs dans les champs Position X, Y et Z du composant
Transform dans le panneau Inspector. Ain d’augmenter l’échelle de l’élément préfabri-
qué Water pour qu’il forme une mer tout autour de l’île, donnez la valeur 1600 aux para-
mètres X et Z de Scale.
L’eau est ainsi placée au centre de la carte, quatre mètres au-dessus du fond marin. Cela
recouvrira les coins de l’île et masquera la nature carrée du terrain (voir Figure 2.34).
Chapitre 2 Environnements 53
Figure 2.34
Pour voir plus facilement où votre objet personnage est placé, assurez-vous
Info qu’il est sélectionné dans le panneau HierarcHy, placez le curseur sur le pan-
neau Scene et appuyez sur la touche F. La vue dans le panneau Scene se centre
alors sur l’objet sélectionné.
Cliquez maintenant sur le bouton Play pour tester le jeu. Vous devriez pouvoir vous promener
sur votre île !
Les contrôles par défaut du personnage sont les suivants :
∑ Haut/W : avancer ;
∑ Bas/S : reculer ;
∑ Gauche/A : pas sur le côté gauche (aussi connu sous le nom de straing) ;
∑ Droit/D : pas sur le côté droit ;
∑ Souris : examiner les alentours ou faire pivoter le joueur lorsqu’il se déplace.
Grimpez au sommet d’une colline et tournez-vous jusqu’à ce que vous puissiez voir le relet
du soleil. Regardez ensuite à droite du relet : vous constatez que la skybox possède égale-
ment une zone éclairée pour représenter le soleil. Vous devez donc repositionner l’objet
Directional Light ain qu’il corresponde au soleil de la skybox, comme nous l’avons
déjà mentionné.
Cliquez de nouveau sur le bouton Play pour interrompre le test du jeu. Il est essentiel
d’arrêter le jeu lorsque vous effectuez des modiications. Si vous le laissez s’exécuter ou
si vous cliquez sur Pause, les modiications que vous apportez à la scène ne seront que
temporaires – elles seront annulées dès que vous cliquerez de nouveau sur Play ou que vous
quitterez Unity.
Enin, comme nous avons l’objet First Person Controller, nous n’avons désormais plus
besoin de l’objet Main Camera ajouté par défaut. Unity le signale d’ailleurs en afichant
un message (voir Figure 2.35) dans la zone d’aperçu de la console au bas de l’écran lorsque
vous testez le jeu.
Figure 2.35
Pour remédier à ce problème, il sufit de supprimer l’objet Main Camera. Pour cela, sélec-
tionnez-le dans le panneau Hierarchy, puis cliquez sur Edit > Delete ou appuyez sur
Cmd+Retour arrière (Mac OS) ou sur Suppr (Windows).
Maintenant que cet objet a disparu, l’île est terminée. Enregistrez votre scène ain de ne
rien perdre de votre travail. Pour cela, cliquez sur File > Save Scene et nommez la scène
Island Level, par exemple. Unity propose automatiquement de l’enregistrer dans le dossier
Assets de votre projet car toutes les ressources doivent s’y trouver. Pour organiser vos
éléments, vous pouvez créer un sous-dossier Niveaux où enregistrer votre scène.
Félicitations, votre île est prête à être explorée. Cliquez de nouveau sur le bouton Play et
promenez-vous ! N’oubliez pas de cliquer sur Play de nouveau lorsque vous aurez terminé.
Figure 2.36
Laissez tous les ichiers sélectionnés, puis cliquez sur le bouton Import pour valider. Une
fois le contenu du paquet importé, un nouveau dossier de ressources outpost est créé dans le
panneau Project, et donc également dans le dossier Assets de votre projet sur votre disque
dur. Cliquez sur la lèche grise située à côté du nom de ce dossier dans le panneau Project
pour aficher son contenu.
Figure 2.37
Le dossier importé contient le modèle lui-même ainsi que deux sous-dossiers : Materials
pour les matériaux et Textures pour les images qui composent les textures de ces matériaux.
Vous pouvez repérer un modèle 3D dans Unity grâce à son icône, un petit cube accompagné
d’une image de page. Cela permet de le différencier des éléments préfabriqués, dont l’icône
est un simple cube, comme vous le verrez plus loin.
Chapitre 2 Environnements 57
Le maillage (Meshes)
À la section Meshes du composant FBX Importer, vous pouvez déinir les paramètres
suivants :
∑ Scale Factor. Généralement ixé à la valeur 1, ce paramètre indique qu’une unité est
égale à un mètre dans le monde du jeu. Pour utiliser une échelle différente, il sufit
d’ajuster ce paramètre avant d’ajouter le modèle à la scène. Mais vous pouvez toujours
modiier l’échelle des objets lorsqu’ils se trouvent dans la scène grâce aux paramètres
Scale du composant Transform.
∑ Generate Colliders (générer les composants de collisions). Cette option attribue un
Mesh Collider à chaque composant individuel du modèle. Un Mesh Collider
(composant de collisions respectant le maillage) est un collider (composant de colli-
sions) complexe qui s’adapte à des formes géométriques complexes. Il s’agit par consé-
quent du type habituel de collider à appliquer à toutes les parties d’une carte ou d’un
modèle 3D de bâtiment.
∑ Calculate Normals. La normale est la face avant de chaque maillage du modèle 3D,
autrement dit le côté visible après le rendu. En activant cette option, vous permettez à
Unity de s’assurer que le rendu de toutes les surfaces est correctement déini dans le jeu.
∑ Smoothing Angle. Lorsque vous utilisez la fonction Calculate Normals, le lissage
permet de spéciier l’angle qu’une arête doit avoir pour être considérée comme une arête
en dur par le moteur du jeu. Les autres pourront être lissées par exemple pour le rendu
des lumières sur une sphère.
∑ Split Tangents. Ce paramètre permet au moteur de corriger les modèles importés avec
un placage de relief incorrect. Le placage de relief, ou Bump mapping, utilise deux
textures : une image qui représente l’apparence du modèle et une heightmap. En combi-
nant les deux, il permet au moteur de rendu d’aficher des surfaces planes de polygones
comme si elles comportaient des déformations en 3D. Lorsque vous créez ces effets
dans des applications tierces et que vous les transférez dans Unity, les effets d’éclairage
58 Développez des jeux 3D avec Unity
peuvent parfois ne pas être corrects. Cette option est conçue pour corriger ce problème
en interprétant leurs matériaux différemment.
∑ Swap UVs. Ce paramètre sert à corriger les erreurs d’importation des shaders de lumière
depuis des applications tierces.
Les animations
À la section Animations du composant Importer, vous interprétez les animations créées
dans votre logiciel de modélisation de différentes façons. Vous pouvez choisir une des
méthodes suivantes dans le menu déroulant Generation :
∑ Don’t Import. Le modèle est importé sans aucune animation.
∑ Store in Original Roots. Le modèle conserve les animations de chaque objet parent, car
le parent ou la racine (root) des objets peut s’importer de manière différente dans Unity.
∑ Store in Nodes. Le modèle conserve les animations de chaque objet enfant, ce qui
permet un contrôle plus important de l’animation de chaque élément par le script.
∑ Store in Root. Le modèle ne conserve que l’animation de l’objet parent de l’ensemble
du groupe.
La section Animations contient trois cases à cocher supplémentaires :
∑ Bake Animations. Indique à Unity d’interpréter les articulations dans les modèles qui
utilisent une armature pour être animés (cinématique inverse).
∑ Keyframes Reduction. Supprime les images clés inutiles dans les modèles exportés
depuis des logiciels de modélisation. Cette option devrait toujours être sélectionnée car
elle améliore les performances du modèle d’animation puisque Unity n’a pas besoin de
ces images-clés.
∑ Split Animations. Lorsque les animateurs créent des modèles destinés à être utilisés
dans Unity, ils réalisent leurs animations sur une échelle de temps. Après en avoir noté
la durée, ils peuvent disposer chaque partie de l’animation dans son échelle de temps,
Chapitre 2 Environnements 59
en indiquant le nom et les images sur lesquelles chaque animation se déroule. De cette
manière, on peut ensuite appeler chaque animation par son nom à l’aide d’un script.
Les noms de ces animations sont sensibles à la casse quand vous les appelez
Info dans un script. Vous devez donc vous assurer de les écrire exactement comme
nous les indiquons.
L’option Loop du tableau Animations peut être trompeuse pour les nouveaux utilisateurs.
Elle n’est pas conçue pour que l’animation que vous paramétrez soit lue en boucle (c’est
le paramètre Wrap Mode qui gère cela, une fois l’animation insérée dans la scène). En
fait, la fonction Loop permet d’ajouter une image aux animations lues en boucle lorsque
la première et la dernière image des animations provenant d’applications de modélisation
tierces ne correspondent plus après leur importation dans Unity.
60 Développez des jeux 3D avec Unity
Figure 2.38
Lorsque votre modèle d’avant-poste est paramétré comme indiqué, cliquez sur le bouton
Apply pour conirmer ces paramètres d’importation. Le modèle est prêt à être inséré dans
la scène et utilisé dans votre jeu.
Chapitre 2 Environnements 61
En résumé
Ce chapitre vous a donné les bases du développement de votre premier environnement. À
partir d’une surface plate, vous avez créé en très peu de temps une île complète à explorer.
Vous avez également étudié l’éclairage et le son, deux principes de base qui s’appliquent
dans tous les types de projets de jeux que vous rencontrerez.
Souvenez-vous que vous pouvez réactiver à tout moment les outils de terrain décrits ici
ain d’ajouter des détails à votre terrain. Une fois que vous vous sentirez plus en coniance
dans l’utilisation du son, nous reviendrons sur ce sujet et nous montrerons comment ajouter
d’autres sources audio à votre île.
Continuez les exercices de ce livre et vous découvrirez tous les types de nuances supplé-
mentaires que vous pouvez apporter aux environnements ain de les rendre plus crédibles
pour le joueur.
Vous découvrirez comment ajouter une touche dynamique à l’île lorsque nous aborderons
l’utilisation des particules, en ajoutant des feux de camp ainsi qu’un panache de fumée et
des cendres au volcan !
Au prochain chapitre, vous allez intégrer le bâtiment d’avant-poste à votre scène et voir
comment déclencher ses animations lorsque le joueur s’approche de la porte. Pour cela,
nous allons présenter l’écriture de code JavaScript pour Unity ain que vous commenciez à
développer les interactions dans le jeu.
3
Personnages jouables
Vous allez élargir le scénario de l’île que vous avez créée précédemment, en vous tour-
nant vers la construction du personnage du joueur que vous avez déjà ajouté à la scène.
Stocké sous forme d’élément préfabriqué (un modèle de données) offert par Unity Techno-
logies dans le paquet de ressources Standard Assets, cet objet est un exemple de personnage
jouable pour un jeu à la première personne. Vous allez voir comment la combinaison des
objets et des composants qui le constituent permet d’obtenir cet effet.
Vous étudierez les coulisses de cet élément préfabriqué et vous découvrirez comment chacun
de ses composants fonctionne pour constituer le personnage du joueur. Vous découvrirez
également les scripts JavaScript dans Unity. Cet élément préfabriqué étant déjà ajouté à la
scène du jeu, ce serait trop simple de continuer à développer le jeu en partant du principe
que cet objet fonctionne correctement. En effet, chaque fois que vous implémentez une
ressource créée en dehors de Unity, vous devez comprendre son fonctionnement. Dans le
cas contraire, vous aurez des dificultés pour ajuster cet élément ou corriger d’éventuelles
erreurs.
64 Développez des jeux 3D avec Unity
Nous allons aborder les points suivants ain que vous compreniez comment la combinaison
de quelques objets et de quelques composants peut créer un personnage à part entière :
∑ les tags, les calques et les éléments préfabriqués dans le panneau Inspector ;
∑ les relations parent-enfant dans les objets ;
∑ les bases du langage JavaScript ;
∑ l’écriture de script pour les mouvements du joueur ;
∑ le paramétrage de variables publiques dans le panneau Inspector ;
∑ l’utilisation de caméras pour créer le point de vue.
Le panneau Inspector
Comme c’est la première fois que vous disséquez un objet dans le panneau Inspector,
commençons par examiner les caractéristiques de ce panneau, communes à tous les objets.
Le nom de l’objet sélectionné s’afiche en haut du panneau Inspector, précédé d’une icône
d’élément préfabriqué (un cube rouge, vert et bleu) ou d’une icône d’objet de jeu (un cube
bleu clair) ainsi que d’une case à cocher permettant de le désactiver temporairement ou
déinitivement.
Pour l’objet de jeu Directional Light, qui n’est pas créé à partir d’un élément préfabriqué
existant, le haut du panneau Inspector se présente comme à la Figure 3.1.
Figure 3.1
Les faces rouges, vertes et bleues du cube de l’icône, indiquent qu’il s’agit d’un objet de
jeu standard. Vous pouvez renommer cet objet très simplement en cliquant sur le champ du
nom de l’objet, puis en entrant un nouveau nom.
Sous l’icône de l’objet et le champ indiquant son nom se trouvent la case à cocher d’acti-
vation de l’objet et les options Tag et Layer.
Chapitre 3 Personnages jouables 65
Les tags
Les tags sont tout simplement des mots clés qu’on peut assigner à un objet de jeu. Vous
pouvez ensuite utiliser ces mots ou une phrase de votre choix pour faire référence à l’objet
(ou aux objets) de jeu dans le script (un tag peut être utilisé plusieurs fois). Si vous connais-
sez Adobe Flash, vous pouvez comparer les tags aux noms d’occurrences dans Flash, au
sens où il s’agit dans les deux cas de mots clés utilisés pour représenter les objets dans une
scène.
L’attribution d’un tag à un objet de jeu se réalise en deux étapes : ajout du tag à la liste du
Tag Manager, puis application à l’objet.
Pour vous habituer à l’utilisation des tags, vous allez déinir et appliquer votre premier tag à
l’objet Directional Light. Sélectionnez-le dans le panneau Hierarchy, puis cliquez sur
le menu déroulant Tag qui indique pour le moment Untagged.
Ce menu contient la liste des tags existants. Vous pouvez soit choisir l’un d’eux ou en créer
un. Sélectionnez Add Tag au bas du menu ain d’ajouter un tag à la liste du Tag Manager.
Figure 3.2
Le panneau Inspector afiche alors le Tag Manager et non plus les composants de l’objet
sélectionné.
Le Tag Manager contient à la fois les Tags et les Layers. Pour ajouter un nouveau tag,
cliquez sur la lèche grise située à gauche de Tag, pour aficher les paramètres Size et
Element. Vous pouvez alors saisir le nom du tag dans le champ vierge situé à droite de
Element 0.
Entrez le nom Sunlight (vous pouvez nommer les tags comme cela vous convient), puis
appuyez sur Entrée pour valider. La valeur du paramètre Size s’incrémente d’une unité dès
que vous appuyez sur Entrée, et un nouveau champ Element devient disponible pour un
prochain tag.
66 Développez des jeux 3D avec Unity
Figure 3.3
Le paramètre Size correspond ici au nombre de tags actuellement déinis. Unity utilise les
noms Size et Element dans plusieurs menus différents du panneau Inspector, comme vous
le verrez par la suite.
Vous avez ajouté un tag à la liste, mais il n’est pas encore attaché à l’objet Directional
Light. Par conséquent, sélectionnez de nouveau cet objet dans le panneau Hierarchy,
puis cliquez sur le menu déroulant Tag en haut du panneau Inspector. Le tag Sunlight
que vous venez de créer apparaît maintenant sur la liste. Pour l’appliquer, il vous sufit de
le sélectionner dans le menu déroulant (voir Figure 3.4).
Figure 3.4
ils peuvent aussi être utilisés avec une technique physique appelée raycasting (tracé de
rayon), ain d’isoler certains objets de façon sélective.
Après avoir placé des objets sur un calque, vous pouvez les désélectionner à partir du para-
mètre Culling Mask d’une lumière ain qu’ils ne soient pas affectés par celle-ci. Comme
les tags, les calques se créent dans le Tag Manager – ils apparaissent en dessous de la liste
des tags.
Figure 3.5
Trois boutons supplémentaires s’afichent sous les champs Tag et Layer et permettent
d’interagir avec l’objet créé à partir d’un élément préfabriqué.
∑ Select. Permet de localiser et de mettre en évidence l’élément préfabriqué auquel
appartient cet objet dans le panneau Project.
∑ Revert. Annule tous les paramètres des composants de l’objet actif et rétablit les para-
mètres utilisés par l’élément préfabriqué dans le panneau Project.
∑ Apply. Applique les valeurs utilisées dans l’occurrence sélectionnée aux paramètres de
l’élément préfabriqué. Toutes les copies de cet élément préfabriqué intégrées dans la
scène en cours sont également mises à jour.
Maintenant que vous connaissez les paramètres supplémentaires disponibles dans le
panneau Inspector, nous pouvons commencer à étudier le personnage du joueur.
Dans le panneau Hierarchy, cliquez sur la lèche grise à gauche de l’objet First Person
Controller, ain d’aficher les objets qui y sont imbriqués. Lorsque les objets sont imbri-
qués de cette manière, il s’agit d’une relation parent-enfant. Dans cet exemple, l’objet First
Person Controller est le parent, et les objets Graphics et Main Camera, ses enfants.
Les objets enfants s’afichent en retrait dans le panneau Hierarchy ain de montrer leurs
relations à l’objet parent (voir Figure 3.6).
Figure 3.6
Figure 3.7
70 Développez des jeux 3D avec Unity
Cliquez maintenant sur le bouton Play, puis n’importe où dans le panneau Game et
commencez à déplacer le personnage tout en l’observant dans le panneau Scene. Vous
constatez que lorsque vous modiiez la position du personnage avec les touches du clavier
et que vous le faites tourner à l’aide de la souris, la position des objets enfants change
également.
Pour aficher les panneaux Game et Scene en même temps, cliquez sur WindoW >
Info layoutS > 2 by 3, puis déplacez les panneaux à votre convenance.
Figure 3.8
Le composant Transform
Comme tous les objets de jeu actifs, l’objet FPC possède un composant Transform qui
indique ses paramètres de position, de rotation et d’échelle et permet de les ajuster.
Script est le premier paramètre (avant les variables publiques) de tous les com-
ce posants de type script. Il permet de sélectionner un autre script sans devoir
Astu
remplacer le composant.
C’est particulièrement utile lorsque vous améliorez progressivement les scripts
existants – vous pouvez alors simplement dupliquer les scripts, les modiier, puis
les utiliser à tour de rôle en les sélectionnant dans le menu déroulant situé
à droite du nom du script. De cette manière, vous conservez les paramètres
existants des variables publiques dans le panneau inSPector.
Figure 3.9
Figure 3.10
Chapitre 3 Personnages jouables 75
Vous pouvez constater que cet objet possède un composant Transform et que sa position
est (0, 0, 0), car il se situe au centre de l’objet parent First Person Controller. Cet objet
ayant pour seul but d’offrir une représentation visuelle du joueur, il ne dispose que des deux
composants nécessaires pour le rendre visible : Mesh Filter et Mesh Renderer. Mais
que font ces deux composants ?
Le composant Camera
C’est l’élément principal de visualisation, même s’il est généralement accompagné des
composants GUILayer et Flare Layer. Ain de comprendre comment le composant
Camera afiche le monde du jeu, nous allons examiner ses paramètres.
Figure 3.11
Chapitre 3 Personnages jouables 77
∑ Clear Flags. Généralement déini sur sa valeur par défaut, Skybox, pour que la caméra
puisse effectuer le rendu de l’objet Skybox actuellement appliqué à la scène. Ce para-
mètre permet au développeur de déinir et de gérer plusieurs caméras spéciiques ainsi
que de procéder au rendu de certaines parties de l’univers du jeu, en particulier lors de
la conception du jeu. Toutefois, il est peu probable que vous commenciez à utiliser ces
techniques avant de connaître beaucoup mieux Unity.
∑ Back Ground Color. La couleur de fond est celle qui est rendue derrière tous les objets
du jeu si aucun matériau skybox n’est appliqué à la scène. Vous pouvez la modiier, soit
en cliquant sur le bloc de couleur puis en utilisant le sélecteur de couleur, soit en échan-
tillonnant une couleur sur l’écran avec l’outil Pipette située à droite du bloc de couleur.
∑ Normalized View Port Rect. Permet de déinir les dimensions et la position de la vue
Caméra. Généralement, il est déini pour occuper tout l’écran, ce qui est d’ailleurs le cas
de l’objet Main Camera attaché au joueur dans notre exemple.
Les coordonnées X et Y étant déinies à 0, la vision de la caméra commence dans le
coin inférieur gauche de l’écran. Étant donné que les options Width et Height ont
une valeur de 1, la vue de cette caméra emplit tout l’écran, car ces valeurs utilisent le
système de coordonnées de Unity, comprises entre 0 et 1.
Ce système est également utilisé dans d’autres éléments 2D dans Unity, notamment les
éléments de l’interface graphique (GUI).
Déinir la taille et la position de notre vue permet de pouvoir utiliser plus d’une caméra
dans un jeu. Dans un jeu de course automobile, par exemple, vous pourrez placer une
caméra dans le coin supérieur de l’écran pour aficher une vue située derrière la voiture
du joueur ain qu’il puisse repérer les véhicules qui s’approchent de lui.
∑ Near clip plane/Far clip plane. Les clip planes (plans de clipping) désignent la distance
des éléments du jeu dont le rendu doit être effectué ; l’option Near Plane désignant le
plan le plus proche et l’option Far Plane le plan le plus éloigné, ou plutôt la distance
où le rendu se termine.
Ain d’économiser de la mémoire dans la mémoire tampon de la carte graphique (une
partie de la mémoire utilisée pour stocker des informations sur les effets visuels du
monde du jeu), cette technique de clipping est souvent utilisée pour que le décor situé
loin du joueur ne soit pas calculé. Les développeurs recouraient à cette technique dans
les jeux 3D anciens, car les ordinateurs à l’époque avaient moins de mémoire RAM dans
laquelle écrire ; pour économiser la mémoire, seul le rendu des plans les plus proches de
la caméra était effectué ain que le jeu reste luide.
78 Développez des jeux 3D avec Unity
Figure 3.12
∑ Field of view. Déinit la largeur du cône de vision de la caméra en degrés. Cet angle
est ixé à 60, car cette valeur reproduit de façon raisonnable la vision de l’œil humain.
∑ Orthographic et Orthographic Size. Transforment la vision de la caméra en vue
orthographique, par opposition à la vue en perspective 3D standard. Les caméras ortho-
graphiques sont le plus souvent utilisées dans les jeux en vue isométrique comme les
jeux de stratégie en temps réel (RTS) ou les jeux 2D.
∑ Depth. Lorsque vous utilisez plusieurs caméras et que vous passez de l’une à l’autre
à l’aide de scripts, le paramètre Depth permet de déinir un ordre de priorité. Ainsi,
le rendu de la caméra dont la valeur de profondeur est la plus élevée s’effectue avant
celui de la caméra possédant une valeur plus faible. Ce paramètre peut également être
utilisé en association avec le paramètre Normalized View Port Rect, ain de placer
des caméras au-dessus de l’écran principal. Pour le rétroviseur d’un jeu de course, par
exemple, la caméra de la vue arrière doit posséder une valeur Depth plus élevée que la
caméra principale pour que son rendu s’afiche en superposition de la vue principale
(vers l’avant) du jeu.
∑ Culling Mask. Fonctionne avec les calques de jeu de Unity, comme nous l’avons déjà
mentionné, ain que vous puissiez procéder à leur rendu de manière sélective. Si vous
placez certains éléments du jeu sur un calque, il vous sufira de désélectionner ce calque
dans le menu déroulant Culling Mask pour que la caméra ne réalise pas leur rendu.
Actuellement, notre objet Main Camera effectue le rendu de tous les éléments de la
scène, car il s’agit de la seule caméra dans le jeu.
Les problèmes que vous rencontrerez lors de l’écriture de scripts trouvent souvent leur
solution dans ce manuel. Si ce n’est pas le cas, vous pouvez alors demander de l’aide sur
les forums consacrés à Unity ou sur le canal IRC (Internet Relay Chat) du logiciel. Pour
plus d’informations, visitez l’une des adresses suivantes :
http://unity3d.com/support/community (en anglais)
http://www.unity3d-france.com/ (en français)
Que vous rédigiez un nouveau script ou que vous utilisiez un script existant, celui-ci
devient opérationnel seulement après que vous l’avez attaché à un objet de jeu dans la scène
courante. Un script attaché à un objet de jeu en devient un composant et le comportement
écrit dans le script s’applique à cet objet. Cependant, les scripts ne se limitent pas à appeler
(activer ou exécuter en terme de programmation) un comportement de l’objet de jeu auquel
ils appartiennent, ils peuvent également donner des instructions aux autres objets en faisant
référence à leur nom ou à leur tag.
Ain de mieux comprendre, voyons tout d’abord quelques principes de base des scripts.
Les commandes
Les commandes sont des instructions données dans un script. Bien que vous puissiez les
disséminer à l’intérieur d’un script, vous contrôlerez mieux le moment où elles sont appe-
lées si vous les placez dans une fonction. Toutes les commandes en JavaScript doivent se
terminer par un point-virgule de la façon suivante :
vitesse = 5;
Les variables
Les variables sont de simples conteneurs d’informations. Elles sont déclarées (créées) avec
le mot var, suivi d’un ou de plusieurs mots sans espace entre eux. Vous pouvez les nommer
comme vous voulez, à condition de respecter les conditions suivantes :
∑ Le nom ne doit pas être celui d’un terme utilisé dans le code du moteur de Unity.
∑ Le nom doit uniquement contenir des caractères alphanumériques et des traits de souli-
gnement et ne pas commencer par un chiffre. Par exemple, le mot transform existe déjà
pour représenter le composant Transform d’un objet de jeu, si bien que nommer ainsi
une variable ou une fonction pourrait provoquer un conlit.
Chapitre 3 Personnages jouables 81
Les variables peuvent contenir du texte, des chiffres et des références à des objets, des
ressources ou des composants. Voici un exemple d’une déclaration de variable :
var vitesse = 9.0;
Notre variable commence par le mot var, suivi de son nom, vitesse. Sa valeur est ensuite
déinie à l’aide d’un seul symbole égal et se termine comme toute autre commande par un
point-virgule.
Dans l’interface de Unity, les valeurs décimales peuvent s’écrire avec une vir-
ntion gule ou un point (0,2 ou 0.2). Si on écrit 0.2, la valeur est automatiquement
Atte
convertie sous la forme avec une virgule (0,2). Mais dans le code, les valeurs
décimales doivent impérativement s’écrire 0.2. Avec 0,2, un message d’erreur
s’afiche.
Le nom de la variable est suivi de deux-points pour préciser le type de données. Dans cet
exemple, la valeur de la variable est un nombre à une décimale, et nous indiquons que
les données sont de type loat (abréviation de "loating point" pour "virgule lottante" –
autrement dit un nombre décimal).
Préciser le type de données de chaque variable que vous déclarez rend le script plus eficace
car le moteur du jeu n’a pas besoin de décider par lui-même du type de la variable lors de sa
lecture. De plus, cela facilite la détection d’erreur (débogage) et la relecture du code. Voici
quelques-uns des types de données les plus courants que vous utiliserez :
∑ string (chaîne de caractères). Combinaison de texte et de chiffes stockés entre guillemets,
"comme ceci".
∑ int (entier). Abréviation d’integer. S’utilise pour les chiffres entiers sans décimale.
∑ loat. Valeur numérique décimale.
∑ boolean (booléen). Une valeur vraie ou fausse utilisée couramment comme condition
à respecter.
∑ Vector3. Un ensemble de valeurs XYZ.
82 Développez des jeux 3D avec Unity
Notez également que la valeur de la variable moitieVitesse n’est pas déinie dans sa décla-
ration. Elle l’est, en fait, dans la commande suivante où la valeur de la variable vitesse est
divisée par deux.
Figure 3.13
La valeur de chacune de ces variables peut donc être ajustée dans le panneau Inspector.
Chapitre 3 Personnages jouables 83
Si vous ne souhaitez pas régler la valeur d’une variable dans le panneau Inspector, vous
devez alors utiliser le préixe private pour qu’elle ne s’afiche pas. Pour cacher la variable
JumpSpeed, par exemple, vous devriez modiier la déclaration de cette variable dans le script
de la façon suivante :
var speed = 6.0;
private var jumpSpeed = 8.0;
var gravity = 20.0;
Figure 3.14
Les fonctions
Les fonctions sont des ensembles d’instructions qui peuvent être appelées à un moment
précis lors de l’exécution du jeu. Un script peut contenir de nombreuses fonctions et
chacune peut appeler une ou plusieurs autres fonctions au sein du même script. Les scripts
peuvent faire appel à de nombreuses fonctions prédéinies du moteur de Unity pour exécuter
des commandes à des moments précis ou selon les actions de l’utilisateur. Vous pouvez
également écrire vos propres fonctions et les appeler lorsque vous avez besoin de réaliser
des instructions spéciiques.
L’écriture d’une fonction commence par function suivi de son nom, puis d’accolades d’ou-
verture et de fermeture. Le développeur peut ensuite passer des paramètres supplémentaires
entre ces accolades. Voici quelques exemples de fonctions existantes.
84 Développez des jeux 3D avec Unity
Update()
Tout nouveau ichier JavaScript créé dans Unity commence par la fonction Update()
suivante :
function Update(){
}
Toutes les instructions ou les commandes d’une fonction doivent se trouver entre ses acco-
lades d’ouverture et de fermeture, comme dans l’exemple suivant :
function Update(){
speed = 5;
}
Tant que les commandes sont écrites entre les accolades de la fonction, elles se déclenchent
chaque fois que le moteur du jeu fait appel à cette fonction.
Les jeux s’exécutent à un certain nombre d’images par seconde (FPS), si bien que la fonc-
tion Update() est appelée une fois le rendu de chaque image effectué. En conséquence, elle
s’utilise principalement pour toutes les commandes qui doivent être exécutées en perma-
nence ou pour détecter les modiications qui se produisent en temps réel dans le monde du
jeu, comme les commandes en entrée – lorsque le joueur appuie sur des touches ou clique.
Lorsqu’il s’agit de commandes liées aux lois physiques, vous devez de préférence utiliser
la fonction FixedUpdate() car elle est synchronisée avec le moteur physique, tandis que le
déclenchement de la fonction Update() peut varier selon le nombre de FPS.
OnMouseDown()
OnMouseDown() est un exemple de fonction appelée à un moment précis : uniquement
lorsque le joueur clique sur un objet de jeu ou sur un élément graphique dans le jeu.
Elle s’utilise le plus souvent pour les jeux contrôlés à la souris ou pour détecter les clics
dans les menus. Voici un exemple de fonction OnMouseDown() simple qui, lorsqu’elle est
attachée à un objet de jeu, permet de quitter le jeu en cliquant sur un objet :
function OnMouseDown(){
Application.Quit();
}
instructions pour déplacer un objet à un endroit précis dans le monde du jeu, vous pouvez
alors écrire une fonction personnalisée contenant toutes les instructions nécessaires, puis
appeler cette fonction à partir d’autres fonctions de votre script.
Imaginons par exemple que vous deviez replacer le personnage du joueur au début du
niveau, lorsqu’il tombe dans un piège et meurt. Plutôt que d’écrire les instructions néces-
saires sur chaque partie du jeu qui provoque sa mort, vous pouvez les regrouper dans une
seule fonction appelée plusieurs fois. Cette fonction pourrait ressembler à ceci :
function PlayerDeath(){
transform.position = Vector3(0,10,50);
score–=50;
vies--
}
Lorsque cette fonction PlayerDeath() est appelée, les trois commandes qu’elle contient
sont exécutées : la position du joueur est redéinie à X = 0, Y = 10 et Z = 50, une valeur
de 50 est soustraite de la note variable nommée score et une valeur de 1 soustraite d’une
variable nommée vies (les deux symboles de soustraction indiquent une soustraction d’une
unité ; de la même façon ++ dans un script signiie simplement l’ajout d’une valeur de 1).
Pour appeler cette fonction, il vous sufit d’écrire la ligne suivante dans la partie du script
qui provoque la mort du joueur :
PlayerDeath();
Si la condition énoncée entre les crochets de l’instruction if est atteinte, autrement dit si
la variable grounded devient true, alors la valeur de la variable speed est ixée à 5. Sinon,
aucune valeur ne lui est attribuée.
Vous ne devez pas confondre le symbole d’affectation (=), utilisé pour déinir la
ntion valeur de la variable, et le symbole de comparaison d’égalité (==), qui permet
Atte
de vériier si l’information stockée dans la variable correspond à une valeur.
Pour établir une condition alternative, vous pourriez ajouter une déclaration else après le
if ain d’indiquer ce qui doit se produire si les conditions ne sont pas remplies :
Ainsi, à moins que la variable grounded ne soit true, la variable speed est égale à 0.
Pour que la vériication des conditions entraîne davantage de conséquences possibles, vous
pouvez utiliser l’instruction else if avant le else facultatif. Si vous vériiez des valeurs, le
code peut alors s’écrire :
if(speed >= 6){
//faire quelque chose
}
else
if(speed >= 3){
//faire quelque chose d’autre
}
else{
//si aucune des conditions ci-dessus n’est vraie, faire ceci
}
Dans l’exemple précédent, les lignes qui commencent par le symbole // indiquent qu’il
s’agit de commentaires (du code non exécuté).
Chapitre 3 Personnages jouables 87
Pour vériier une condition ou une autre, vous pouvez alors utiliser l’opérateur logique OU,
qui s’écrit ||, de la façon suivante :
if(speed >= 3 || grounded == true){
//faire quelque chose
}
À cette section, vous allez voir comment transmettre des informations entre plusieurs
scripts à l’aide d’une variable statique, et comment traiter l’information de manière hiérar-
chique en utilisant la technique d’écriture de script nommée syntaxe à point.
En programmation orientée objet (POO), les variables globales d’une classe (d’un script)
sont aussi appelées propriétés et les fonctions aussi appelées méthodes.
Si cette variable speed était celle du script FPSWalker, vous pourriez alors accéder à
sa valeur, ou la déinir, depuis un autre script. Pour cela, on utilise le nom du script suivi
d’un point, du nom de la variable, puis de la déinition de la valeur, comme dans l’exemple
suivant :
FPSWalker.speed = 15.0;
De la même manière, il existe des fonctions publiques statiques pouvant être appelées
depuis d’autres scripts. La fonction PlayerDeath(), par exemple, pourrait être une fonction
static, ce qui vous permettrait de l’appeler depuis n’importe quel autre script du jeu sans
même avoir de référence vers l’objet concerné.
La syntaxe à point
Dans l’exemple précédent, nous avons utilisé une technique de script appelé syntaxe à
point. Bien que ce terme semble désigner une forme d’écriture complexe, ce n’est pas
vraiment le cas. On utilise simplement un point pour séparer les éléments auxquels on fait
référence et indiquer leur hiérarchie, depuis l’élément situé le plus haut dans la hiérarchie
jusqu’au paramètre en particulier que l’on souhaite déinir.
Ainsi, pour régler la position verticale d’un objet de jeu, par exemple, vous devez modiier
sa coordonnée Y. Vous devez donc vous adresser aux paramètres de position du composant
Transform de cet objet. Pour cela, on écrit :
transform.position.y = 50;
Les commentaires
Dans beaucoup de scripts prédéinis, vous remarquerez que certaines lignes commencent
par deux barres obliques. Il s’agit simplement des commentaires écrits par l’auteur du
script. Nous vous conseillons d’écrire vos propres commentaires ain d’indiquer comment
fonctionnent vos scripts, en particulier lorsque vous débutez.
Lectures complémentaires
Il est essentiel que vous vous preniez l’habitude de vous référer au manuel de référence
Scripting Manual de Unity installé avec votre copie du programme et également disponible
sur le site web de Unity à l’adresse suivante :
http://unity3d.com/support/documentation/ScriptReference/
Chapitre 3 Personnages jouables 89
Le script FPSWalker
Pour visualiser un script dans Unity, vous devez l’ouvrir dans l’éditeur de script. Pour cela,
sélectionnez le script dans le panneau Project puis double-cliquez sur son icône.
L’éditeur de script fourni par défaut s’appelle Unitron sous Mac OS et Uniscite sous
Windows. Il s’agit, dans les deux cas, d’une application autonome permettant d’éditer
différents formats de ichier texte, comme les scripts JavaScript et C# par exemple.
Vous pouvez également déinir l’éditeur de texte de votre choix pour écrire vos scripts
destinés à Unity. Pour les besoins de cet ouvrage, nous utiliserons les éditeurs de script par
défaut Unitron et Uniscite.
Lancer le script
Sélectionnez l’objet First Person Controller dans le panneau Hierarchy, puis cliquez
sur le nom du ichier de script sous le composant FPSWalker (Script) dans le panneau
Inspector ain qu’il soit surligné en bleu (voir Figure 3.15).
Figure 3.15
Figure 3.16
Figure 3.17
Chapitre 3 Personnages jouables 91
Figure 3.18
Bien qu’il s’agisse du même script, vous voyez que les deux éditeurs utilisent des couleurs
différentes pour mettre en valeur la syntaxe. Cela est propre à l’éditeur lui-même et n’a
aucune incidence sur le fonctionnement du script.
Le script en détail
Nous allons voir le fonctionnement dans la pratique des différents éléments que nous
venons de décrire, en décomposant leur utilisation dans le script FPSWalker.
92 Développez des jeux 3D avec Unity
Les variables publiques des lignes 1 et 3 sont utilisées plus tard dans le script comme coef-
icients de multiplication. Il s’agit de valeurs décimales, donc le type des données devrait
être déini à loat dans l’idéal (comme il s’agit d’un simple exemple de script de Unity
Technologies, le type de données de toutes les variables n’est pas indiqué). Les variables
des lignes 2, 5 et 6 sont des variables privées, car elles ne seront utilisées que dans ce script.
La variable privée moveDirection stocke la direction actuelle du joueur sous la forme d’une
valeur de type Vector3 (un ensemble de coordonnées X, Y, Z). Elle est déinie à (0,0,0) ain
d’éviter que le joueur soit tourné dans une direction aléatoire lorsque le jeu commence.
La variable privée grounded est de type booléen (true ou false). Cette variable est utilisée
plus loin dans le script pour savoir si le joueur est en contact avec le sol ou non. Le person-
nage peut se déplacer et sauter uniquement dans le premier cas, car dans le cas contraire,
cela signiie qu’il se trouve déjà en l’air.
Dans cet ouvrage, une seule ligne de code peut de temps à autre apparaître sur
Info deux lignes différentes en raison de l’indentation et des contraintes de mise en
page. Lorsque vous recopiez ces scripts, assurez-vous que l’extrait en question
se trouve bien sur une seule ligne dans votre script.
Chapitre 3 Personnages jouables 93
La première instruction if dans la fonction s’exécute sur les lignes 9 à 18 (le commentaire
du développeur a été supprimé dans l’extrait suivant) :
if (grounded) {
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0,
„ Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}
}
Quand grounded devient true, cette instruction if agit trois fois sur la variable
moveDirection.
Premièrement, elle lui assigne une nouvelle valeur Vector3 en donnant à sa coordonnée X
la valeur actuelle de Input.GetAxis ("horizontal") et à sa coordonnée Z la valeur de
Input.GetAxis ("vertical"), mais laisse la coordonnée Y déinie à 0 :
Dans cet exemple, Unity Technologies utilise le mot new comme préixe du para-
Info mètre Vector3 utilisé pour déinir la variable moveDirection. Il s’agit d’une
convention du langage C# destinée à faciliter la conversion entre les langages
JavaScript et C#. Toutefois, ce terme n’est pas nécessaire en JavaScript, ce qui
explique pourquoi les autres exemples de ce livre n’utilisent pas ce préixe.
Mais que font les commandes Input.GetAxis ? Elles représentent tout simplement les
valeurs comprises entre –1 et 1 obtenues en entrée à partir des touches directionnelles. Par
défaut, ces touches sont les suivantes :
∑ A (Gauche) et D (Droit) pour l’axe horizontal ;
∑ W (Haut) et S (Bas) pour l’axe vertical.
Lorsque aucune touche n’est utilisée, ces valeurs sont égales à 0, car Unity donne auto-
matiquement un état idle (inactif) aux entrées qui gèrent les axes. Par conséquent, si vous
94 Développez des jeux 3D avec Unity
assigne à la variable moveDirection une valeur Vector3 en fonction des valeurs X et Z des
touches pressées, tout en laissant la valeur Y déinie à 0.
La variable moveDirection est ensuite de nouveau modiiée à la ligne 12 :
moveDirection = transform.TransformDirection(moveDirection);
Puisque speed est une variable publique, multiplier les valeurs XYZ de moveDirection par
speed implique que vous pouvez augmenter la vitesse de déplacement du personnage sans
avoir à éditer le script. Il vous sufit en effet d’augmenter la valeur de speed dans le panneau
Inspector, puisque c’est la valeur de moveDirection ainsi obtenue qui est utilisée plus tard
dans le script pour déplacer le personnage.
L’instruction grounded contient enin une autre instruction if imbriquée aux lignes 15 à 17 :
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}
Cette instruction if se déclenche lorsque la touche nommé Jump est pressée. Par défaut, ce
bouton de saut est affecté à la barre d'espacement. Dès que cette touche est enfoncée, la valeur
de l’axe Y de la variable moveDirection est ixée à la valeur de la variable jumpSpeed. Par
conséquent, à moins que la variable jumpSpeed n’ait été modiiée dans le panneau Inspector,
moveDirection.y prend une valeur de 8.0.
Lors du déplacement du personnage plus loin dans le script, cette modiication soudaine
de la valeur sur l’axe Y (de 0 à 8.0) produira l’effet de saut. Mais comment le personnage
Chapitre 3 Personnages jouables 95
Vous remarquerez que la soustraction ne porte pas uniquement sur la valeur de la gravité
ici, car cela ne produirait pas l’effet d’un saut mais déplacerait plutôt le personnage vers
le haut puis de nouveau vers le bas entre deux images. En fait, cette ligne soustrait de la
valeur de moveDirection.y le résultat obtenu en multipliant la variable gravity par une
commande appelée Time.deltaTime.
En multipliant une valeur à l’intérieur d’une fonction Update() ou FixedUpdate() par
Time.deltaTime, vous ne tenez pas compte de la nature de cette fonction basée sur la
cadence des images ou des appels et vous convertissez l’effet de la commande en secondes.
Autrement dit, en écrivant :
moveDirection.y –= gravity * Time.deltaTime;
la valeur de gravité est soustraite à chaque seconde plutôt qu’à chaque image ou appel.
Déplacer le personnage
Comme le commentaire de la ligne 23 l’indique, les lignes 24 à 26 sont chargées du
mouvement du personnage.
À la ligne 24, une nouvelle variable controller est déclarée avec le type de données
CharacterController. Elle est ensuite déinie pour représenter le composant Character-
Controller à l’aide de la commande GetComponent() :
Time.deltaTime ain que le déplacement soit en mètres par seconde plutôt qu’en mètres
par image.
Vériier grounded
Une valeur est attribuée à la variable moveDirection uniquement si la variable booléenne
grounded est déinie sur true. Alors, comment décider si le personnage est en contact avec
le sol ou non ?
Comme tous les autres colliders, le composant Character Controller (le contrôleur
de collision du personnage) peut détecter les collisions avec d’autres objets. Toutefois,
contrairement aux colliders standard, il dispose de quatre raccourcis de collision spéci-
iques, déinis dans l’ensemble CollisionFlags :
∑ None (aucun) ;
∑ Sides (sur les côtés) ;
∑ Above (au-dessus) ;
∑ Below (en dessous).
Ils sont chargés de vériier les collisions avec la partie spéciique du collider qu’ils décri-
vent – à l’exception de None, qui signiie tout simplement qu’aucune collision ne se produit.
Ces indicateurs (ou lags) sont utilisés pour déinir la variable grounded à la ligne 26 :
grounded = (lags & CollisionFlags.CollidedBelow) != 0;
Cette ligne peut sembler complexe en raison des nombreux symboles d’égalité qu’elle
contient, mais il s’agit simplement d’une forme d’écriture abrégée pour vériier une
condition et déinir une valeur sur une seule ligne.
Premièrement, la variable grounded est déinie à l’aide d’un symbole d’égalité. Puis, dans
la première série de parenthèses, une technique de masque de bits est appliquée ain de
déterminer si les collisions dans la variable lags (le mouvement du contrôleur) corres-
pondent à la valeur déinie en interne CollidedBelow :
(lags & CollisionFlags.CollidedBelow)
L’utilisation d’une seule esperluette (&) indique une opération qui s’effectue entre deux
valeurs sous forme binaire. Vous n’avez pas besoin de comprendre ce que cela signiie pour
le moment, car le système de classe de Unity offre un raccourci pour la plupart des calculs
de ce type.
Si le contrôleur entre en collision avec ce qui se trouve en dessous de lui (le terrain, logi-
quement), alors cette opération sera non nulle.
Chapitre 3 Personnages jouables 97
Cette opération est suivie de !=0. Un point d’exclamation devant un symbole d’égalité
signiie "est différent de". Cette comparaison renvoie donc true (vrai) si l’opération entre
parenthèses est non nulle. Par conséquent, grounded est déini comme true quand une
collision se produit entre le composant Character Controller et ce qui se trouve en
dessous de lui.
Les commandes @script s’utilisent pour réaliser des actions que vous devriez normalement
effectuer manuellement dans l’interface de Unity.
Dans cet exemple, une fonction RequireComponent() est exécutée, ce qui force Unity à
ajouter le composant indiqué entre parenthèses, au cas où l’objet sur lequel est attaché ce
script ne possède pas ce composant. De même, si vous essayez de supprimer ce composant,
Unity indique qu’un autre composant (le script) nécessite sa présence.
Comme ce script s’appuie sur CharacterController pour contrôler le personnage, il est
logique d’utiliser une commande @script pour s’assurer que le composant est présent et
que le script peut donc par conséquent s’adresser à lui. Il est également intéressant de noter
que les commandes @script sont les seuls exemples de commandes qui ne doivent pas se
terminer par un point-virgule.
En résumé
Au cours de ce chapitre, vous avez examiné le premier élément interactif de jeu pour le
moment : l’objet First Person Controller. Vous avez également découvert les bases des
scripts utilisés pour les jeux dans Unity, une première étape importante sur laquelle nous
nous appuierons tout au long de ce livre.
Au chapitre suivant, vous allez commencer à écrire vos propres scripts et vous en appren-
drez plus sur la détection de collision. Pour cela, vous utiliserez le modèle d’avant-poste
que vous avez importé au Chapitre 2, "Environnements", vous l’intégrerez à la scène du
jeu, puis vous le ferez interagir avec le personnage du joueur en combinant animations et
écriture de script.
4
Interactions
Nous allons voir ici, plus en détail, d’autres interactions et nous plonger dans deux éléments
essentiels au développement d’un jeu : la détection de collision et le raycasting (tracé de
rayon).
Pour détecter les interactions physiques entre les objets de jeu, la méthode la plus courante
consiste à utiliser un collider – un ilet invisible tout autour d’un objet chargé de détecter
les collisions avec d’autres objets. La détection de collision regroupe à la fois la détection
et la récupération des informations provenant de ces collisions.
Il est non seulement possible de détecter que deux colliders (composants de collision)
interagissent, mais également d’anticiper une collision et d’effectuer de nombreuses autres
tâches à l’aide d’une technique appelée raycasting, qui dessine un rayon – une ligne vecto-
rielle invisible (non rendue) tracée entre deux points dans l’espace 3D – qui peut aussi être
utilisé pour détecter une intersection avec le collider d’un objet de jeu. Le raycasting permet
également de récupérer de nombreuses autres informations utiles comme la longueur du
rayon (et donc la distance entre deux objets) ou le point d’impact de la in de la ligne.
100 Développez des jeux 3D avec Unity
Dans cet exemple, un rayon pointant vers l’avant part de notre personnage. On peut lui
donner une direction mais également une longueur spéciique, ou le projeter jusqu’à ce
qu’il trouve un objet.
Au cours de ce chapitre, vous travaillerez avec le modèle d’avant-poste que vous avez
importé au Chapitre 2, "Environnements". Nous avons créé pour vous l’animation d’ouver-
ture et de fermeture de la porte et vous allez voir comment les déclencher une fois le modèle
intégré dans la scène en implémentant la détection de collision et le raycasting.
Commençons par examiner la détection de collision et voir quand la remplacer ou la
compléter par le raycasting.
Les collisions
Lorsque des objets entrent en collision dans n’importe quel moteur de jeu, des informations
sur cet événement deviennent alors disponibles. En enregistrant différentes informations
au moment de l’impact, le moteur de jeu peut ensuite réagir de manière réaliste. Dans un
jeu tenant compte des lois physiques par exemple, si un objet tombe au sol d’une certaine
hauteur, le moteur a besoin de savoir quelle partie de cet objet touche le sol en premier pour
contrôler de façon correcte et réaliste la réaction de l’objet à cet impact.
Bien entendu, Unity gère ce type de collisions et stocke ces informations pour vous, si bien
que vous avez seulement à les récupérer ain de déinir la réaction qui doit se produire.
Dans le cas de l’ouverture d’une porte, vous avez besoin de détecter les collisions entre le
collider du personnage du joueur et celui situé sur – ou près de – la porte. Cela n’aurait
guère de sens de détecter les collisions ailleurs, puisque l’animation de la porte doit se
déclencher lorsque le joueur est assez proche pour espérer qu’elle s’ouvre ou pour franchir
le seuil.
Par conséquent, vous allez vériier les collisions entre le collider du personnage et celui de
la porte. Vous devez toutefois étendre la profondeur du collider de la porte ain que celui du
personnage du joueur n’ait pas besoin de s’appuyer contre la porte pour que la collision se
Chapitre 4 Interactions 101
Figure 4.2
X
------ les contours du collider
Le raycasting
Bien qu’il soit possible de détecter les collisions entre le collider du personnage et un
collider qui s’adapte à l’objet porte, il semble plus judicieux que la porte s’ouvre lorsque le
joueur lui fait face et à une certaine distance, ce qui peut être réalisé en projetant un rayon
d’une longueur limitée depuis l’avant du personnage. Ainsi, le joueur n’a pas besoin de
s’avancer jusqu’à la porte ou d’entrer en collision avec un collider étendu pour que le rayon
soit détecté. Cette méthode garantit également que le joueur ne peut pas ouvrir la porte s’il
102 Développez des jeux 3D avec Unity
lui tourne le dos ; avec le raycasting, il doit faire face à l’objet pour l’utiliser, ce qui est plus
logique.
Cette méthode est couramment utilisée lorsque la détection de collision se montre trop
imprécise pour obtenir une réaction correcte, par exemple lorsque les réactions doivent se
produire à un niveau de détail très précis (image par image) car elles se produisent alors
trop rapidement. Dans notre exemple, vous avez besoin de détecter à l’avance si la collision
est susceptible de se produire plutôt que d’y réagir. Prenons un exemple pratique de ce
problème.
L’image manquante
Dans le cas d’un jeu de tir en 3D, le raycasting s’utilise pour prédire l’impact d’une balle
tirée. En raison de la vitesse d’une balle réelle, il est très dificile d’en représenter visuel-
lement le trajet vers la cible de façon satisfaisante pour le joueur, car cette vitesse est
largement supérieure à la cadence des images rendues dans les jeux.
Lors d’un tir au pistolet dans le monde réel, la balle met si peu de temps pour atteindre sa
cible que l’événement semble instantané à l’œil nu. On peut donc admettre que la balle
devrait atteindre son objectif en quelques images seulement dans le jeu, même avec un
rendu supérieur à 25 images par seconde.
Distance parcourue
0 15 3 4,5 6 7,5 9
Balle tirée
1 2 3 4 5 6 7
Images
Figure 4.3
À la Figure 4.3, une balle est tirée d’un pistolet. Pour que son parcours soit réaliste, elle
devrait se déplacer à une vitesse de 150 mètres par seconde. À une cadence de 25 images
par seconde, la balle se déplace donc de 6 mètres par image. Or la circonférence d’un corps
humain est environ de 1,50 mètre, si bien que la balle manquerait très probablement les
ennemis situés à 5 et 7,50 mètres. Voilà pourquoi on utilise la détection a priori.
Chapitre 4 Interactions 103
Figure 4.4
Y
L'ennemi visé
X
------- Le rayon
Le point d'impact
Le joueur
Dans cet exemple de jeu de tir, vous utiliseriez sans doute des scripts pour tuer ou repousser
l’ennemi dont le collider touche le rayon. Comme le rayon est immédiat, cette réaction peut
s’effectuer sur l’image suivant celle sur laquelle le rayon croise le collider de l’ennemi.
La réaction étant enregistrée immédiatement, l’effet produit par le tir est réaliste.
104 Développez des jeux 3D avec Unity
Il est également intéressant de noter que les jeux de tir afichent souvent des rayons norma-
lement invisibles pour aider le joueur à viser. Ne confondez toutefois pas ces lignes avec
le raycasting car ces rayons sont simplement utilisés pour effectuer le rendu des lignes de
la visée.
L’ajout de l’avant-poste
Avant de commencer à utiliser à la fois la détection de collision et le raycasting pour ouvrir
la porte, vous devez intégrer à la scène l’avant-poste que vous avez déini au Chapitre 2,
"Environnements". Plus loin, vous écrirez le script qui contrôle les états d’animation de ce
modèle.
Faites glisser le modèle d’avant-poste depuis le panneau Project dans le panneau Scene.
Souvenez-vous que vous ne pouvez pas positionner le modèle lors du glisser-déposer, mais
seulement une fois que celui se trouve dans la scène (autrement dit, après avoir relâché le
bouton de la souris).
Figure 4.5
Chapitre 4 Interactions 105
Une fois l’avant-poste dans le panneau Scene, son nom apparaît dans le panneau Hierar-
chy et il est automatiquement sélectionné. Vous êtes maintenant prêt à déinir sa position
et à le redimensionner.
Positionner le modèle
Comme la conception de votre terrain peut être différente de la nôtre, sélectionnez l’outil
Transform, puis placez l’avant-poste dans une zone de terrain dégagée en faisant glisser
ses poignées d’axe dans la scène.
Soyez prudent lorsque vous utilisez les poignées d’axe pour déplacer un modèle.
ce Faire glisser le carré blanc où convergent les poignées modiie les trois axes à la
Astu
fois, ce qui est à éviter en vue Perspective. Assurez-vous de faire glisser chaque
poignée individuellement en gardant le curseur à l’extérieur du carré blanc.
Si vous souhaitez que l’objet reste plaqué sur la surface du terrain en vue
Perspective, appuyez sur Cmd/Ctrl et faites glisser le carré blanc.
Figure 4.6
Nous avons placé l’avant-poste à (500, 30.8, 505) mais vous devrez peut-être le déplacer
manuellement. Rappelez-vous qu’après avoir positionné l’objet à l’aide de ses poignées
d’axe dans le panneau Scene, vous pouvez saisir des valeurs spéciiques dans les champs
Position du composant Transform dans le panneau Inspector.
106 Développez des jeux 3D avec Unity
Redimensionner le modèle
Lorsque vous travaillez comme ici avec deux applications – le logiciel de modélisation
dans lequel la ressource outpost a été créée et Unity –, il est courant que la taille du modèle
importé ne corresponde pas aux unités métriques utilisées dans Unity et que vous deviez
modiier ses dimensions.
Bien qu’il soit possible de déinir les valeurs d’échelle dans les champs Scale du panneau
Inspector, il est généralement préférable d’utiliser le paramètre Scale Factor de la
ressource originale. Sélectionnez le modèle outpost dans le dossier Outpost du panneau
Project. Le composant FBXImporter s’afiche alors dans le panneau Inspector. Ses
paramètres d’importation affectent toutes les occurrences du modèle que vous placez dans
le panneau Scene. Dans ce cas précis, modiiez la valeur Scale Factor de 1 à 2, puis
cliquez sur le bouton Apply. Ainsi, la taille de l’avant-poste est sufisante pour que l’objet
Character Controller passe par la porte et la taille de la pièce sera réaliste lorsque le
personnage se trouvera à l’intérieur.
Figure 4.7
Chapitre 4 Interactions 107
La porte est maintenant visible dans le panneau Scene. Cet objet étant sélectionné, ses
composants apparaissent également dans le panneau Inspector, notamment Mesh Colli-
der (un composant de collision respectant le maillage de l’objet). Ce collider précis est
assigné à tous les maillages des objets enfants d’un modèle lorsque l’option Generate
Colliders est activée, ce que vous avez fait pour cette ressource outpost au Chapitre 2,
"Environnements".
Avec cette option, Unity attribue par défaut un composant Mesh Collider à chaque
élément enfant, car le programme ne sait pas quelle quantité de détails sont présents dans
les modèles importés. Chaque Mesh Collider adopte la forme du maillage de l’objet.
Ici, la porte étant une forme cubique simple, vous devez le remplacer par un collider plus
simple et plus eficace en forme de boîte.
Cliquez sur Component > Physics > Box Collider dans le menu principal.
Une première boîte de dialogue, Losing Prefab, signale que l’ajout d’un nouveau compo-
sant entraînera la in de la connexion entre cet objet et l’objet parent dans le panneau
Project. Autrement dit, la copie placée dans le panneau Scene ne sera plus identique à la
ressource d’origine et toute modiication apportée à la ressource dans le panneau Project ne
sera pas répercutée sur cette copie. Cliquez simplement sur le bouton Add pour conirmer.
Figure 4.8
Vous n’avez pas à vous inquiéter de ce message qui s’afiche chaque fois que vous commen-
cez à personnaliser les modèles importés dans Unity. Vous avez généralement besoin
d’ajouter des composants à un modèle, pour cela, vous pouvez créer vos propres éléments
préfabriqués.
Étant donné qu’un collider est déjà assigné à l’objet, une seconde boîte de dialogue appa-
raît dans laquelle vous indiquez si vous voulez ajouter ce collider à votre objet (Add),
le remplacer (Replace) ou annuler l’opération (Cancel). Le moteur physique de Unity
fonctionnant mieux avec un seul collider par objet, le programme vous demande si vous
souhaitez remplacer celui qui existe plutôt que d’en ajouter un nouveau.
Comme nous n’avons plus besoin du Mesh Collider, cliquez sur Replace.
108 Développez des jeux 3D avec Unity
Le composant Box Collider que vous venez d’ajouter apparaît alors autour de la porte,
iguré par un contour vert.
Figure 4.9
Un Box Collider (un composant de collision en forme de boîte) est un exemple de colli-
der primitif, car sa forme est constituée de primitives. Unity dispose de plusieurs colliders de
forme prédéinie de ce type, notamment Box, Sphere, Capsule et Wheel. Tous les compo-
sants colliders primitifs s’afichent sous la forme d’un tracé vert. Vous l’avez peut-être
remarqué lorsque vous avez étudié le collider du contrôleur de personnage, un collider de
type capsule, qui s’afiche donc aussi en vert.
Enin, vous avez besoin d’attribuer un tag à l’objet door, puisque vous y ferez référence
plus tard dans le script. L’objet enfant door étant toujours sélectionné, cliquez sur le menu
déroulant Tag situé en haut du panneau Inspector, puis choisissez Add Tag. Ajoutez le
tag outpostDoor dans le Tag Manager qui s’afiche dans le panneau Inspector (voir
Figure 4.10).
Figure 4.10
Chapitre 4 Interactions 109
Comme l’ajout de balises est un processus en deux étapes, vous aurez ensuite besoin de
sélectionner de nouveau l’objet enfant door dans le panneau Hierarchy pour choisir votre
nouveau tag outpostDoor dans le menu déroulant Tag et l’attribuer à cet objet.
Figure 4.11
110 Développez des jeux 3D avec Unity
Nous avons afiché les options du paramètre animationS ain de visualiser les
Info différents états de l’animation de cet objet.
L’objet outpost est maintenant prêt à interagir avec le personnage du joueur. Vous allez
donc commencer à écrire les scripts pour gérer les collisions avec la porte, en utilisant soit
la détection de collision soit le raycasting.
L’ouverture de la porte
Nous allons étudier les deux méthodes permettant de déclencher l’animation ain que vous
puissiez ensuite utiliser l’une ou l’autre lors du développement de vos jeux en fonction de
la situation. Dans un premier temps, vous utiliserez la détection de collision – une notion
essentielle à connaître lorsque vous commencez à travailler sur des jeux dans Unity. Puis
dans un second temps, vous implémenterez simplement une projection de rayon depuis le
personnage du joueur.
Vous pouvez également identiier le type de ichier d’un script grâce à son icône
Info dans le panneau Project. L’icône des ichiers JavaScript porte la mention "JS",
les ichiers C#, tout simplement "C#" et les ichiers Boo, une image d’un fantôme
Pacman.
Utiliser OnControllerColliderHit
Par défaut, tous les nouveaux scripts JavaScript contiennent la fonction Update(), qui s’af-
iche lorsque vous les ouvrez pour la première fois. Pour commencer, vous allez déclarer
les variables que vous utiliserez.
Ce script doit commencer par la déinition de six variables, trois privées et trois publiques,
dont le but respectif est le suivant :
∑ doorIsOpen. Une variable privée true/false (booléenne) pour vériier si la porte est
ouverte.
∑ doorTimer. Une variable privée numérique décimale, utilisée pour décompter le temps
écoulé après l’ouverture de la porte et la refermer automatiquement une fois terminé le
délai déini.
∑ currentDoor. Une variable privée de type GameObject qui stocke l’état courant de la
porte. Elle évite, si vous ajoutez plus d’un avant-poste dans le jeu, que l’ouverture de
l’une des portes entraîne celle de toutes les autres, en gardant en mémoire la dernière
porte à avoir été touchée.
112 Développez des jeux 3D avec Unity
Avant d’aborder la fonction Update(), vous allez établir la fonction de détection de collision
elle-même. Insérez deux lignes après :
function Update(){
Cette instruction if vériie deux conditions : tout d’abord, si l’objet avec lequel le person-
nage entre en contact a le tag outpostDoor, puis si la variable doorOpen est actuellement
déinie à false. Rappelez-vous que deux symboles d’égalité (==) indiquent une comparai-
son et que deux symboles esperluette (&&) signiient simplement "et". Autrement dit, si le
personnage entre en contact avec le collider de la porte que vous avez marqué d’un tag et
que la porte n’est pas déjà ouverte, une série d’instructions sera exécutée.
Ce script utilise la syntaxe à point pour faire référence à l’objet dont on vériie les colli-
sions, en descendant successivement la hiérarchie depuis hit (la variable qui contient les
informations sur les collisions) à gameObject (l’objet touché), puis au tag sur cet objet.
Si les conditions de cette instruction if se vériient, un ensemble d’instructions doit alors
se réaliser pour ouvrir la porte. Il s’agira de jouer un son, de lancer la lecture d’une des
animations sur le modèle et de déinir la variable booléenne doorOpen à true. Comme
vous allez appeler plusieurs instructions – et que vous aurez peut-être besoin d’utiliser leur
résultat dans une autre condition, par la suite lorsque vous implémenterez la technique du
raycasting –, vous allez les placer dans leur propre fonction personnalisée appelée OpenDoor.
Avant d’écrire cette nouvelle fonction, vous allez ajouter l’appel à cette fonction dans
l’instruction if que vous venez de créer. Pour cela, saisissez la ligne suivante :
OpenDoor();
pour stocker les paramètres éventuels que vous souhaitez passer à la fonction – vous pouvez
ainsi transmettre des comportements supplémentaires aux instructions situées à l’intérieur
de la fonction (voir la section "Des fonctions plus eficaces" de ce chapitre). Ici, les paren-
thèses sont vides, aucun comportement n’ayant encore été passé à la fonction.
Déclarer la fonction
Pour créer la fonction que vous appelez, écrivez tout simplement :
function OpenDoor(){
}
Vous pouvez ensuite écrire entre ses accolades toutes les instructions à effectuer lorsque
cette fonction est appelée, de la même manière que vous avez déini les conditions d’une
instruction if.
audio.PlayOneShot(doorOpenSound);
Cette ligne s’adresse au composant Audio Source attaché à l’objet de jeu auquel ce script
est appliqué (le personnage du joueur, autrement dit l’objet First Person Controller).
Vous aurez donc besoin plus tard de vous assurer que ce composant est bien lié à l’objet car
cette commande provoquerait une erreur si ce n’était pas le cas.
Le fait de désigner le composant Audio Source par le terme audio vous donne ensuite accès
à quatre fonctions : Play(), Stop(), Pause() et PlayOneShot(). On utilise ici PlayOne-
Shot car cette option représente la meilleure façon de jouer une seule occurrence d’un
effet sonore, par opposition à la lecture de plusieurs séquences audio en continu, comme
de la musique. La variable doorOpenSound passée dans les parenthèses de la commande
PlayOneShot permet de déclencher la lecture du ichier audio assigné à cette variable dans
le panneau Inspector. Vous téléchargerez et assignerez ce ichier audio ainsi que celui de
la fermeture de la porte après avoir complété le script.
Chapitre 4 Interactions 115
Lancer l’animation
Au Chapitre 2, "Environnements", vous avez importé le paquet de ressources outpost et
étudié ses différents paramètres avant de l’intégrer dans le jeu au début de ce chapitre. Lors
du processus d’importation, vous avez déini les animations dans le panneau Inspector. En
sélectionnant cette ressource dans le panneau Project, vous avez précisé dans le panneau
Inspector qu’elle contenait les trois animations suivantes :
∑ idle (un état "inactif") ;
∑ dooropen (porte ouverte) ;
∑ doorshut (porte fermée).
Dans la fonction OpenDoor(), vous allez faire appel à une de ces animations à l’aide d’une
chaîne de caractères, ou string. Toutefois, vous devez au préalable indiquer quel objet de la
scène contient l’animation à lire. Comme le script que vous écrivez concerne le personnage
du joueur, vous devez faire référence à un autre objet avant de faire référence au composant
d’animation. Pour cela, ajoutez la ligne :
var myOutpost : GameObject = GameObject.Find("outpost");
Vous déclarez ici une nouvelle variable myOutpost de type GameObject puis vous sélec-
tionnez l’objet de jeu outpost par son nom à l’aide de la commande GameObject.Find. La
commande Find permet de sélectionner dans le panneau Hierarchy un objet présent dans
la scène actuelle par son nom. Elle peut donc s’utiliser comme une alternative aux tags.
116 Développez des jeux 3D avec Unity
À présent qu’une variable représente l’objet de jeu outpost, vous pouvez utiliser la syntaxe
à point ain de la désigner et appeler l’animation de la façon suivante :
myOutpost.animation.Play("dooropen");
Cette ligne désigne le composant d’animation attaché à l’objet outpost et lance la lecture
de l’animation dooropen. La commande Play() peut transmettre n’importe quelle chaîne
de caractères. Toutefois, cela fonctionne uniquement si les animations ont été déinies sur
l’objet en question.
Votre fonction personnalisée OpenDoor() complète doit maintenant être analogue à ceci :
function OpenDoor(){
audio.PlayOneShot(doorOpenSound);
doorIsOpen = true;
var myOutpost : GameObject = GameObject.Find("outpost");
myOutpost.animation.Play("dooropen");
}
Inverser la procédure
Maintenant que vous avez créé un ensemble d’instructions pour ouvrir la porte, comment
allez-vous la refermer ? Pour des raisons de jouabilité, vous n’obligerez pas le joueur à
fermer lui-même la porte. Vous allez donc écrire un script qui la referme après un certain
délai.
Pour cela, vous allez utiliser la variable doorTimer, vous lui ajouterez une valeur de temps
pour que le script commence à décompter dès l’ouverture de la porte, puis vous vériierez
si cette variable atteint une valeur particulière avec une instruction if.
Comme il s’agit d’un décompte dans le temps, vous devez utiliser une fonction constamment
mise à jour, comme la fonction Update() créée en même temps que le script.
Insérez des lignes vierges dans la fonction Update() pour décaler son accolade de ferme-
ture } de quelques lignes vers le bas.
Vous devez premièrement vériier si la porte a été ouverte, car il est évidemment inutile
d’incrémenter la variable de décompte du temps si la porte est fermée. Écrivez l’instruction
if suivante pour augmenter la valeur de la variable dans le temps lorsque la variable door-
IsOpen est déinie à true :
if(doorIsOpen){
doorTimer += Time.deltaTime;
}
Chapitre 4 Interactions 117
Ces lignes vériient si la porte est ouverte – la variable est par défaut déinie à false et
devient true uniquement à la suite d’une collision entre le personnage du joueur et la porte.
Si la variable doorIsOpen est true, on ajoute alors la valeur Time.deltaTime à la variable
doorTimer (écrire, comme ici, uniquement le nom de la variable dans la condition if
équivaut à écrire : doorIsOpen == true).
Vous devez ensuite vériier si la variable doorTimer atteint une certaine valeur, autrement
dit qu’une certaine quantité de temps s’est écoulée. Pour cela, vous allez imbriquer une
instruction if dans celle que vous venez d’ajouter : elle sera seulement vériiée si la condition
doorIsOpen est valide.
Ajoutez les lignes de script suivantes sous la ligne qui incrémente la variable dans la décla-
ration if existante :
if(doorTimer > doorOpenTime){
shutDoor();
doorTimer = 0.0;
}
Cet ajout est constamment vériié dès que la variable doorIsOpen est égale à true puis il
attend que la valeur doorTimer dépasse celle de la variable doorOpenTime. Puisque vous
utilisez Time.deltaTime comme valeur d’incrémentation, trois secondes en temps réel
s’écouleront avant que cela ne se produise, à moins bien sûr que vous ne modiiiez la valeur
de cette variable ixée à 3 par défaut dans le panneau Inspector.
Une fois que la valeur doorTimer est supérieure à 3, une fonction appelée shutDoor()
est appelée et la variable doorTimer remise à 0 ain qu’elle puisse être de nouveau utilisée
la prochaine fois que l’ouverture de la porte sera déclenchée. Sans cette réinitialisation, la
valeur de doorTimer resterait supérieure à 3, si bien que la porte se refermait dès qu’elle
serait ouverte.
Votre fonction Update() complète doit maintenant être comme ceci :
118 Développez des jeux 3D avec Unity
function Update(){
if(doorIsOpen){
doorTimer += Time.deltaTime;
thisDoor.transform.parent.animation.Play(animName);
}
Chapitre 4 Interactions 119
Vous constatez que cette fonction est comparable aux fonctions OpenDoor() et shutDoor()
existantes, mais que sa déclaration compte quatre paramètres : aClip, openCheck, animName
et thisDoor. Il s’agit en fait de variables qui sont déinies lors de l’appel de la fonction et
dont la valeur est utilisée à l’intérieur de celle-ci. Pour ouvrir la porte, par exemple, vous
pourriez appeler cette fonction et déinir chaque paramètre de la façon suivante :
Door(doorOpenSound, true, "dooropen", currentDoor);
OpenDoor();
La variable currentDoor désigne ici le dernier objet à entrer en collision avec le personnage
du joueur. Vous pouvez ensuite passer cette information à votre fonction pour vous assurer
d’ouvrir uniquement la porte – autrement dit, déclencher l’animation – de l’avant-poste
avec lequel le joueur entre en collision, plutôt que celle d’un autre avant-poste possédant
une porte marquée d’un tag.
Dans la dernière ligne de la fonction Door, thisDoor.transform.parent.animation lance
la lecture de l’animation adéquate. La syntaxe à point permet de remonter dans la hiérarchie
jusqu’au composant d’animation sur lequel vous devez agir. La variable thisDoor reçoit
comme valeur l’objet le plus récemment touché – stocké dans la variable currentDoor –,
puis le script fait référence à l’objet parent de la porte, c’est-à-dire l’objet outpost lui-
même, puisque c’est à lui que le composant d’animation est attaché, et non à la porte. Vous
ne pourriez pas par exemple écrire :
thisDoor.animation.Play(animName);
Unity signalerait alors qu’il n’existe aucun élément d’animation. Vous devez donc dési-
gner le composant Transform du parent de l’objet enfant door – l’objet auquel il appar-
tient dans le panneau Hierarchy – pour sélectionner le composant d’animation depuis
ce point.
120 Développez des jeux 3D avec Unity
Enin, comme vous utilisez cette nouvelle méthode pour ouvrir et fermer les portes, vous
devez modiier le code de fermeture de la porte dans la fonction Update(). Dans l’instruc-
tion if qui vériie si la variable doorTimer dépasse la valeur de la variable doorOpenTime,
remplacez l’appel à la fonction shutDoor() par cette ligne :
Vous pouvez maintenant supprimer les deux fonctions originales OpenDoor() et shutDoor(),
puisque la fonction personnalisée Door() les remplace toutes les deux. En créant des fonc-
tions de cette façon, vous évitez les répétitions dans vos scripts, ce qui les rend plus eficaces
et permet de réduire le temps nécessaire à l’écriture de plusieurs fonctions.
Finaliser le script
Pour compléter le script, vous allez vous assurer que l’objet qu’il ajoute possède un compo-
sant Audio Source, ce qui est nécessaire pour lire les extraits sonores puisque votre
fonction Door déclenche du son.
Ajoutez la ligne suivante tout en bas du script, en vous assurant que la ligne NE se termine
PAS par un point-virgule, contrairement à ce qu’on pourrait attendre. En fait, cette
commande est spéciique à Unity, et non d’une partie du code JavaScript.
@script RequireComponent(AudioSource)
Il existe deux méthodes pour attacher un script à un objet dans Unity : faire glisser le
script depuis le panneau Project sur l’objet dans les panneaux Hierarchy ou Scene,
ou tout simplement sélectionner l’objet puis cliquer sur Component > Scripts > Player
Collisions dans le menu principal de Unity. Le sous-menu Scripts du menu Component
contient la liste de tous les scripts disponibles dans le panneau Project : il afichera le
vôtre dès que vous l’aurez créé et sauvegardé.
Le panneau Inspector de l’objet First Person Controller devrait maintenant contenir
le composant Player Collisions (Script). Un composant Audio Source a également été
ajouté automatiquement en raison de l’utilisation de la commande RequireComponent à la
in du script.
Figure 4.12
Vous trouverez les ichiers audio Open Door et Door Close dans l’archive disponible sur
la page dédiée à cet ouvrage sur le site web Pearson (http://www.pearson.fr). Procédez si
nécessaire à l’extraction des ichiers, puis recherchez le paquet doorSounds.unitypackage.
Pour l’importer, revenez dans Unity, cliquez sur Assets > Import Package, parcourez
votre disque dur jusqu’au dossier le contenant puis sélectionnez-le. Cliquez sur Ouvrir pour
aficher les deux ichiers que contient le paquet de ressources dans la boîte de dialogue
122 Développez des jeux 3D avec Unity
Importing package. Il vous sufit de cliquer sur le bouton Import pour conirmer l’impor-
tation des ichiers. Les éléments audio doorSlideOpen et doorSlideShut sont alors dispo-
nibles dans la liste des ressources du panneau Project (voir Figure 4.13).
Figure 4.13
À présent que ces ressources se trouvent dans le dossier de votre projet, faites glisser
chacune d’elles sur la variable publique appropriée du composant Player Collisions
(Script) dans le panneau Inspector (voir Figure 4.14).
Figure 4.14
Vous pouvez maintenant lancer le jeu et essayer d’ouvrir la porte. Pour cela, cliquez sur le
bouton Play en haut de l’interface, marchez jusqu’à la porte de l’avant-poste et entrez en
contact avec elle.
La collision entre le joueur et la porte est détectée, ce qui entraîne l’ouverture de la porte.
Puis celle-ci se referme automatiquement après 3 secondes. Cliquez de nouveau sur le
bouton Play pour terminer le test.
Pour que la porte s’ouvre sans que le joueur ait besoin de la toucher, vous allez agrandir
la taille du collider de la porte, comme nous l’avons évoqué au début du chapitre. Cliquez
sur la lèche grise située devant l’objet de jeu outpost dans le panneau Hierarchy pour
aficher ses objets enfants puis sélectionnez l’objet enfant door. Placez le curseur sur le
panneau Scene et appuyez sur la touche F pour centrer la vue sur cet objet.
Chapitre 4 Interactions 123
Figure 4.15
Dans le panneau Inspector, cliquez sur la lèche située devant le paramètre Size du
composant Box Collider pour aficher ses options et ainsi pouvoir ajuster la valeur Z (la
profondeur) du collider lui-même. Donnez-lui une valeur de 1,5 ain d’étendre le collider
(voir Figure 4.16).
Figure 4.16
Testez de nouveau le jeu. Vous pouvez constater que la porte s’ouvre plus tôt lorsque vous
vous en approchez, puisque la limite du collider dépasse davantage de la porte visible.
Cependant, une collision physique se produit dans le collider, entraînant une réaction de
repoussement. Vous pouvez contrer cet effet en utilisant le mode Trigger (déclencheur) du
collider, comme vous le verrez au chapitre suivant. Pour l’instant, vous allez implémenter
la seconde approche de détection : le raytracing. En projetant un rayon vers l’avant du
personnage du joueur, il n’aura plus besoin de collider pour toucher le collider de la porte.
124 Développez des jeux 3D avec Unity
Méthode 2. Le raycasting
Bien que l’utilisation de la détection de collision ou de déclencheur soit une méthode tout
à fait valable, le raycasting vous permet de vous assurer que le joueur ouvre seulement la
porte de l’avant-poste s’il lui fait face. En effet, le rayon part toujours dans la direction vers
laquelle l’objet First Person Controller est tourné, si bien qu’il ne coupera pas la porte
si le joueur lui tourne le dos, par exemple.
Dans un script, cette barre oblique (ou "slash") suivie d’un astérisque marque le début
d’un commentaire sur plusieurs lignes (par opposition aux deux barres obliques qui sont
utilisées pour les commentaires d’une seule ligne). Allez ensuite à la in de la fonction de
détection de collision et insérez un astérisque suivi d’une barre oblique. La couleur de
toute la fonction devrait avoir changé dans l’éditeur de script et se présenter de la façon
suivante :
/*
function OnControllerColliderHit(hit: ControllerColliderHit){
if(hit.gameObject.tag == "outpostDoor" && doorIsOpen == false){
currentDoor = hit.gameObject;
Door(doorOpenSound, true, "dooropen", currentDoor);
}
}
*/
Chapitre 4 Interactions 125
Ajouter le rayon
Revenez à l’éditeur de script et insérez quelques lignes après l’ouverture de la fonction
Update(). Le raycasting est placé dans la fonction Update() pour la simple raison que le
rayon doit être projeté vers l’avant à chaque image. Ajoutez les lignes suivantes avant la
condition if(doorIsOpen) :
var hit : RaycastHit;
if(Physics.Raycast (transform.position, transform.forward, hit, 5)) {
if(hit.collider.gameObject.tag=="outpostDoor" && doorIsOpen == false){
currentDoor = hit.collider.gameObject;
Door(doorOpenSound, true, "dooropen", currentDoor);
}
}
À la première ligne, on crée un rayon en déclarant une variable privée appelée hit, qui est
de type RaycastHit. Notez que cette variable n’a pas besoin du préixe private pour ne
pas s’aficher dans le panneau Inspector. En effet, il s’agit obligatoirement d’une variable
privée, car elle est déclarée dans une fonction. Elle sera utilisée pour stocker des informa-
tions sur le rayon lorsqu’il croisera des colliders. Nous utiliserons cette variable chaque fois
que nous ferons référence à ce rayon.
Suivent ensuite deux instructions. La première condition if est chargée de la projection du
rayon et utilise la variable créée à la ligne précédente. Comme la projection du rayon se
trouve dans une instruction if, l’appel à l’instruction if imbriquée se produira uniquement
si le rayon frappe un objet, ce qui rend le script plus eficace.
La commande Physics.Raycast de la première condition if projette le rayon. Elle possède
quatre paramètres indiqués entre parenthèses :
∑ Le point d’émission du rayon (transform.position). Indique la position de l’objet
sur lequel ce script s’applique, autrement dit l’objet First Person Controller.
126 Développez des jeux 3D avec Unity
hit.collider.gameObject.tag
currentDoor = hit.collider.gameObject;
Door(doorOpenSound, true, "dooropen");
Testez la jouabilité du jeu une fois de plus et vous remarquerez que, lorsque vous appro-
chez de la porte, celle-ci s’ouvre non seulement avant que vous ne la percutiez, mais aussi
qu’elle s’ouvre uniquement lorsque vous lui faites face. En effet, le rayon qui détecte la
porte est projeté dans le même sens que celui où le personnage du joueur se dirige.
En résumé
Ce chapitre vous a permis d’explorer deux méthodes essentielles pour détecter les interac-
tions entre les objets dans les jeux 3D. Vous devez maîtriser le raycasting et la détection de
collision car vous aurez souvent à les réutiliser dans Unity pour vos futures créations.
Le chapitre suivant s’intéresse à une autre méthode de détection de collision, en utilisant
les colliders des objets comme des déclencheurs. Ce mode Trigger permet de détecter
les collisions sans qu’il y ait besoin qu’un objet soit présent physiquement – le joueur
peut ainsi collecter des objets sans les percuter, par exemple. Considérez les déclencheurs
comme des collisions sans aucun impact. Vous auriez pu adopter cette méthode pour la
Chapitre 4 Interactions 127
porte de l’avant-poste, cependant il est important que vous appreniez d’abord les principes
de base de la détection de collision. Voilà pourquoi nous les présentons dans cet ordre
particulier.
Vous allez créer un mini-jeu de collecte dans lequel le joueur devra trouver quatre piles ain
de recharger le mécanisme d’ouverture de la porte de l’avant-poste. Par conséquent, l’accès
à l’avant-poste lui sera interdit tant qu’il n’aura pas obtenu ces piles.
5
Éléments préfabriqués,
collections et HUD
Au cours de ce chapitre, vous continuerez le travail du Chapitre 4. En utilisant une méthode
analogue à celle du chapitre précédent, vous allez en apprendre plus sur la détection des
collisions en utilisant les colliders (composants de collision) comme déclencheurs.
Les déclencheurs sont souvent considérés comme des composants. Pourtant, pour rester
simple, il s’agit de colliders qui possèdent un mode Déclencheur pouvant être activé avec
l’option Is Trigger dans le panneau Inspector (voir Figure 5.1).
Figure 5.1
130 Développez des jeux 3D avec Unity
Vous avez déjà un avant-poste dont la porte s’ouvre, mais vous allez maintenant forcer
le joueur à trouver certains objets pour qu’il puisse accéder à ce bâtiment. En afichant
des instructions à l’écran lorsque le joueur s’approche de la porte, vous lui ferez savoir
que l’ouverture de la porte nécessite une source d’alimentation. Pour l’inciter à rechercher
plusieurs exemplaires de cet objet disséminés à proximité ain de disposer de sufisamment
de puissance pour actionner le mécanisme d’ouverture de la porte, vous ferez ensuite appa-
raître une pile vide en 2D à l’écran.
En créant ce jeu simple, vous apprendrez à :
∑ travailler avec des objets 2D en utilisant des textures GUI ;
∑ contrôler l’afichage du texte à l’écran avec les éléments GUI Text ;
∑ utiliser des éléments préfabriqués pour créer plusieurs exemplaires d’un objet de jeu et
les stocker comme ressources.
Figure 5.2
Faites glisser le modèle battery depuis le dossier Other Models du panneau Project
sur le panneau Scene. Placez ensuite le curseur sur le panneau Scene et appuyez sur la
touche F pour centrer la vue sur cet objet. La position de la pile est arbitraire, vous la repo-
sitionnerez une fois que vous aurez créé votre élément préfabriqué.
Ajouter un tag
Pour pouvoir détecter une collision avec l’objet battery, vous devez lui assigner un tag
pour l’identiier dans le script que vous allez bientôt écrire. Cliquez sur le menu déroulant
Tag, et sélectionnez Add Tag.
Le panneau Inspector afiche alors le Tag Manager. Ajoutez un tag battery dans le
premier élément disponible (voir Figure 5.3).
Figure 5.3
132 Développez des jeux 3D avec Unity
Appuyez sur Entrée pour valider la création de ce tag. Sélectionnez de nouveau l’objet
battery dans le panneau Hierarchy, puis choisissez le tag battery dans le menu dérou-
lant Tag du panneau Inspector.
Redimensionner la batterie
L’élément que vous créez devra avoir une taille sufisante pour que le joueur puisse le
repérer dans le jeu. Comme nous avons déjà vu comment modiier l’échelle des objets
dans le composant FBXImporter, vous allez ici simplement le redimensionner à l’aide du
composant Transform dans le panneau Inspector. L’objet battery étant toujours sélec-
tionné dans le panneau Hierarchy, donnez une valeur de 6 à tous les paramètres Scale du
composant Transform dans le panneau Inspector.
Insérez une ligne au début de votre nouveau script, avant la fonction Update(), et créez-y
une variable publique à virgule lottante rotationAmount d’une valeur de 5.0 de la façon
suivante :
var rotationAmount : loat = 5.0;
Cette variable vous servira à déinir la vitesse de rotation de l’objet battery. Il s’agit d’une
variable publique (elle se trouve en dehors de toute fonction et n’est pas déclarée comme
private), vous pourrez donc également ajuster cette valeur dans le panneau Inspector une
fois le script attaché à l’objet battery.
Dans la fonction Update(), ajoutez la commande suivante pour faire pivoter l’objet battery
sur son axe Y avec une valeur égale à celle de la variable rotationAmount :
function Update () {
transform.Rotate(Vector3(0,rotationAmount,0));
}
La commande Rotate() attend une valeur de type Vector3 (X, Y, Z). Les valeurs X et Z sont
ici déinies à 0 tandis que la valeur Y est celle de la variable. Comme cette commande se
trouve dans la fonction Update(), elle s’exécutera à chaque image, si bien que la pile effec-
tuera une rotation de 5 degrés de chaque image. Cliquez sur File > Save dans l’éditeur de
script, puis revenez dans Unity.
Pour lier ce script à l’objet battery, assurez-vous que ce dernier est sélectionné dans le
panneau Hierarchy. Cliquez ensuite sur Component > Scripts > RotateObject. Vous
pouvez également simplement faire glisser le script depuis le panneau Project sur l’objet
dans le panneau Hierarchy.
Cliquez sur le bouton Play situé en haut de l’interface pour vous assurer que l’objet
battery tourne bien sur lui-même dans le jeu. Si cela ne fonctionne pas, vériiez que votre
script ne contient pas d’erreur et qu’il est attaché à l’objet adéquat. N’oubliez pas de cliquer
de nouveau sur Play pour terminer vos tests avant de poursuivre.
Créez un dossier dans le panneau Project pour stocker l’élément préfabriqué et ceux que
vous créerez plus tard. Pour cela, assurez-vous d’abord qu’aucun dossier existant n’est
sélectionné en cliquant dans l’espace gris sous les objets dans le panneau Project. Cliquez
ensuite sur le bouton Create et sélectionnez Folder, puis appuyez sur Entrée/F2 et
nommez ce nouveau dossier Prefabs.
Sélectionnez le dossier Prefabs, puis cliquez sur le bouton Create et choisissez Prefab
pour créer un nouvel élément préfabriqué vide dans ce dossier.
L’icône d’un élément préfabriqué vide est un cube gris, tandis que celle d’un
Info élément préfabriqué ayant un contenu est un cube bleu clair.
Renommez l’élément préfabriqué vide battery. Faites ensuite glisser l’objet battery sur
lequel vous avez travaillé depuis le panneau Hierarchy jusque sur l’élément préfabriqué
vide battery dans le panneau Project.
La pile devient alors un élément préfabriqué. Une copie de cet élément préfabriqué est
également créée dans la scène courante. Par conséquent, toute modiication apportée à
l’élément préfabriqué dans le panneau Project se répercute sur sa copie dans la scène. Le
nom des objets de la scène liés à des ressources du projet s’afiche en bleu dans le panneau
Hierarchy, tandis que le nom des objets existant uniquement dans la scène s’afiche en
noir.
Lorsque vous dupliquez des objets dans la scène, les copies sont créées dans
ce la même position, ce qui peut entraîner une certaine confusion. En effet, Unity
Astu
duplique chaque paramètre des objets, y compris leur position. Le plus simple
est de se souvenir que les copies se trouvent dans la même position que l’original
et doivent simplement être déplacées.
Chapitre 5 Éléments préfabriqués, collections et HUD 135
Sélectionnez chacune des quatre piles dans le panneau Hierarchy et utilisez l’outil Trans-
form pour les disposer autour de l’avant-poste. N’oubliez pas que vous pouvez utiliser
l’axe 3D situé dans le coin supérieur droit du panneau Scene pour passer de la vue Pers-
pective aux vues Haut, Bas et latérales. Placez les piles à une hauteur qui ne soit pas trop
élevée pour que le joueur puisse les atteindre.
Une fois que vous avez disposé les quatre piles autour de l’avant-poste, vous devriez obtenir
un résultat comparable à celui illustré à la Figure 5.4.
Figure 5.4
Bien que cette procédure se déroule techniquement en trois étapes, elle peut être réalisée en
une seule. Pour cela, sélectionnez la texture à utiliser dans le panneau Project, puis cliquez
sur GameObject > Create Other > GUI Texture dans le menu principal.
Un nouvel objet auquel est attaché un composant GUI Texture est alors créé. Unity lit les
dimensions de la texture choisie à partir du ichier image, si bien que les valeurs du para-
mètre Pixel Inset sont déjà déinies dans le panneau Inspector (voir Figure 5.5).
Figure 5.5
Chapitre 5 Éléments préfabriqués, collections et HUD 137
Les valeurs du paramètre Pixel Inset déinissent les dimensions et la supericie d’afi-
chage d’un objet. Généralement, les paramètres Width et Height doivent être spéciiés
pour correspondre aux dimensions d’origine de votre ichier de texture, et les valeurs X
et Y être ixées à la moitié de ces dimensions. Lorsque vous créez l’objet après avoir sélec-
tionné la texture, Unity déinit ces valeurs pour vous.
Si vous sélectionnez l’image que vous souhaitez utiliser en premier, vous indi-
ce quez à Unity qu’en créant le nouvel objet, il doit utiliser ce ichier comme
Astu
texture et déinir les dimensions du composant Gui texture en fonction de
celle-ci.
De plus, lorsque vous sélectionnez une image et créez un objet Gui texture
à l’aide du menu principal, l’objet créé est nommé selon le nom de la texture,
ce qui est très utile pour trouver l’objet dans le panneau HierarcHy après sa
création.
Sélectionnez au besoin l’objet battery_nocharge que vous avez créé dans le panneau
Hierarchy, appuyez sur Entrée/F2 et renommez-le Battery GUI.
Figure 5.6
Vous pouvez également aficher les détails 2D dans le panneau Scene en cliquant sur le
bouton Game Overlay (voir Figure 5.7).
Figure 5.7
Chapitre 5 Éléments préfabriqués, collections et HUD 139
Vous avez ensuite besoin de cinq variables pour stocker les textures qui représentent les
cinq états différents de l’objet Battery GUI – la pile vide et les quatre étapes de char-
gement. Pour cela, ajoutez les cinq variables suivantes de type Texture2D sans valeur
déinie :
var charge1tex : Texture2D;
var charge2tex : Texture2D;
var charge3tex : Texture2D;
var charge4tex : Texture2D;
var charge0tex : Texture2D;
Comme il s’agit de variables publiques, vous pourrez assigner chaque ichier image en
faisant glisser les textures du panneau Project sur les champs des variables dans le panneau
Inspector lorsque ce script sera sélectionné.
140 Développez des jeux 3D avec Unity
Pour conigurer les paramètres par défaut du composant GUI Texture, ajoutez la fonction
Start() suivante après les variables que vous venez de déclarer :
function Start(){
guiTexture.enabled = false;
charge = 0;
}
La fonction Start() s’exécutera une fois au début de ce niveau du jeu (ou de la scène, pour
reprendre le terme utilisé dans Unity). Avec la ligne :
guiTexture.enabled = false;
vous vous assurez que le composant n’est pas activé et donc que la pile n’est pas visible
lorsque le jeu commence. La variable charge est déinie également à 0 au début du jeu, ain
que le script considère qu’aucune pile n’a été collectée lorsque la scène commence.
Insérez ensuite quelques lignes avant l’accolade de fermeture de la fonction Update(), puis
ajoutez l’instruction if suivante :
if(charge == 1){
guiTexture.texture = charge1tex;
guiTexture.enabled = true;
}
Ici, le script vériie si la variable charge a une valeur de 1 puis il exécute deux commandes :
∑ guiTexture.texture = charge1tex;. Cette ligne déinit quelle est l’image assignée
à la variable charge1tex qui doit être utilisée comme texture par le composant GUI
Texture de l’objet sur lequel ce script est attaché.
∑ guiTexture.enabled = true;. Cette ligne active le composant lui-même. Vous avez
indiqué que l’objet Battery GUI n’est pas visible (c’est-à-dire inactivé) lorsque le jeu
démarre, ain d’éviter toute confusion pour le joueur et pour éviter d’encombrer l’écran.
La pile vide doit uniquement s’aficher après que le joueur a essayé d’ouvrir la porte.
L’instruction if de cette ligne du script permet donc d’activer l’interface graphique
lorsque le joueur a collecté une pile. Vous ajouterez plus tard quelques lignes de script
au raytracing qui détecte la collision avec la porte dans le script PlayerCollisions ain
d’aficher la pile vide si l’utilisateur essaie d’entrer dans l’avant-poste avant d’avoir
collecté sa première pile.
Vous allez ensuite ajouter trois instructions if supplémentaires dans la fonction Update()
pour vériier l’état de la variable charge. Comme il est impossible que la valeur de la
variable charge soit égale à la fois à 1 et à une autre valeur, vous utiliserez des conditions
Chapitre 5 Éléments préfabriqués, collections et HUD 141
else if, puisque celles-ci sont vériiées uniquement lorsque l’une ou l’autre des autres
instructions if s’exécute déjà.
Si vous deviez utiliser une instruction if pour chacune des conditions suivantes, elles
seraient toutes vériiées simultanément, ce qui rendrait le script ineficace. Ajoutez le code
suivant après l’accolade de fermeture de l’instruction if existante :
else if(charge == 2){
guiTexture.texture = charge2tex;
}
else if(charge == 3){
guiTexture.texture = charge3tex;
}
else if(charge >= 4){
guiTexture.texture = charge4tex;
}
Ces conditions else if indiquent à la texture afichée par le composant GUI Texture
d’utiliser les différentes variables publiques déclarées au début du script (vous assignerez
plus tard les ichiers d’images à ces variables dans le panneau Inspector). Vous n’avez pas
besoin d’activer le composant dans ces conditions else if car il a déjà été activé lorsque le
joueur a ramassé la première pile.
Enin, il sufit d’ajouter une instruction else à la in de la suite de conditions if et else if
au cas où la variable charge aurait une valeur de 0, puisque la déclaration else signiie "si
aucune des conditions qui précèdent n’est vraie, alors procédez comme suit". Autrement
dit, puisque les déclarations if et else if recherchent une valeur de chargement allant
de 1 à 4, l’instruction else se chargera de l’afichage quand le jeu commencera (quand la
variable de charge sera égale à 0). Cela reprend pour l’essentiel la fonction Start() :
else{
guiTexture.texture = charge0tex;
Maintenant que le script est terminé, cliquez sur File > Save dans l’éditeur de script et
revenez à Unity.
Sélectionnez l’objet Battery GUI dans le panneau Hierarchy, puis cliquez sur Compo-
nent > Scripts > BatteryCollect dans le menu principal pour assigner le script à l’objet
Battery GUI. Les cinq variables publiques en attente d’affectation devraient s’aficher
dans le panneau Inspector (voir Figure 5.8).
142 Développez des jeux 3D avec Unity
Figure 5.8
Faites glisser les cinq ichiers de texture depuis le dossier textures du panneau Project que
vous avez importé plus tôt sur les variables publiques appropriées (voir Figure 5.9).
Figure 5.9
À présent que l’interface graphique de la collecte des piles est prête, il vous reste à l’ajouter
au script PlayerCollisions attaché à l’objet First Person Controller, ain de détecter
si le personnage du joueur interagit avec les déclencheurs de collision des objets battery.
Seul le type de données (AudioClip) de la variable est déclaré dans le script. Sa valeur n’est
pas déinie ; elle pourra l’être par la suite dans le panneau Inspector.
Chapitre 5 Éléments préfabriqués, collections et HUD 143
Cette fonction est spéciiquement conçue pour détecter les collisions avec les colliders en
mode Déclencheur. Toute collision avec ce type de collider est placée dans le paramètre
collisionInfo, qui est de type Collider, si bien que pour effectuer une requête sur ces
informations, vous devez faire référence à l’objet attaché au collider qui a été touché.
Ajoutez l’instruction if suivante à l’intérieur de la fonction OnTriggerEnter() (c’est-à-
dire avant son accolade de fermeture) pour interroger tous les déclencheurs avec lesquels le
personnage du joueur entre en collision :
if(collisionInfo.gameObject.tag == "battery"){
BatteryCollect.charge++;
audio.PlayOneShot(batteryCollect);
Destroy(collisionInfo.gameObject);
}
Cliquez sur File > Save dans l’éditeur de script pour enregistrer le script, puis revenez
dans Unity. Sélectionnez l’objet First Person Controller dans le panneau Hierarchy.
Comme vous pouvez le constater, le composant PlayerCollisions (Script) dans le
panneau Inspector possède maintenant une nouvelle variable publique Battery Collect
qui attend que lui soit affectée une ressource Audio Clip (voir Figure 5.10).
Figure 5.10
Restreindre l’accès
Avant de donner des instructions au joueur, vous allez modiier la partie du script Player-
Collisions qui gère l’ouverture de la porte ain qu’elle s’active uniquement lorsque le
joueur a collecté les quatre piles. Au chapitre précédent, vous avez écrit une fonction person-
nalisée Door() dans le script PlayerCollisions dont les paramètres géraient l’ouverture et
la fermeture des portes que le joueur rencontre de la manière suivante :
function Door(aClip : AudioClip, openCheck : boolean, animName : String,
thisDoor : GameObject){
audio.PlayOneShot(aClip);
doorIsOpen = openCheck;
thisDoor.transform.parent.animation.Play(animName);
}
Cette fonction lance la lecture d’une séquence sonore, garantit que la porte ne peut être
rouverte et déclenche l’animation d’ouverture de la porte. Elle est appelée au sein de la
fonction Update(), dans la partie du script consacrée au raycasting (la ligne vectorielle
projetée dans la même direction que le regard du joueur et qui vériie la collision avec la
porte). Ces lignes sont les suivantes :
var hit : RaycastHit;
if (Physics.Raycast (transform.position, transform.forward, hit, 5)) {
if(hit.collider.gameObject.tag=="outpostDoor" && doorIsOpen == false){
currentDoor = hit.collider.gameObject;
Door(doorOpenSound, true, "dooropen", currentDoor);
}
}
Double-cliquez sur le script PlayerCollisions dans le panneau Project pour l’ouvrir,
puis recherchez l’extrait de code de la fonction Update() dans lequel se trouve l’appel à la
fonction Door() qui ouvre la porte :
if(hit.collider.gameObject.tag=="outpostDoor" && doorIsOpen == false){
Door(doorOpenSound, true, "dooropen", currentDoor);
}
146 Développez des jeux 3D avec Unity
Pour que la porte reste fermée aussi longtemps que toutes les piles n’ont pas été collectées,
il sufit d’ajouter une troisième condition à l’instruction if existante, en utilisant une autre
paire d’esperluettes, && :
if(hit.collider.gameObject.tag=="outpostDoor" && doorIsOpen == false &&
„ BatteryCollect.charge >= 4){
Door(doorOpenSound, true, "dooropen", currentDoor);
}
En ajoutant la condition :
BatteryCollect.charge >= 4
vous vériiez si la valeur de la variable statique charge du script BatteryCollect est égale
ou supérieure à 4. Ainsi, la porte ne s’ouvrira pas tant que le joueur n’aura pas ramassé
toutes les piles dispersées dans l’île.
La commande GetComponent()
Une fois que le joueur peut entrer dans l’avant-poste, vous devez supprimer l’objet Battery
GUI de l’écran. Pour cela, vous avez besoin d’accéder à son composant GUI Texture. Le
déclenchement de la porte se trouvant dans le script PlayerCollisions dans lequel vous
travaillez actuellement, vous devez faire référence à un composant attaché à un objet diffé-
rent (Battery GUI) que celui sur lequel se trouve ce script (First Person Controller).
Dans le script BatteryCollect, vous pourriez écrire simplement :
guiTexture.enabled = false;
puisque ce script est attaché au même objet que le composant GUI Texture. Mais cela
n’est pas possible dans un script qui ne se trouve pas sur un objet possédant un composant
GUI Texture.
Vous devez donc utiliser la commande GetComponent(), à la suite de la référence à l’objet
sur lequel se trouve le composant auquel vous voulez vous adresser. En effet, vous pouvez
alors facilement ajuster les composants des objets externes.
Ajoutez la ligne suivante au-dessous de celle qui appelle la fonction Door() dans l’instruction
if que vous venez de modiier :
GameObject.Find("Battery GUI").GetComponent(GUITexture).enabled=false;
Il ne s’agit pas de détruire cet objet, car vous avez encore besoin de ce script dans le
jeu pour référencer le nombre de piles déjà collectées. C’est pourquoi vous désactivez
simplement le composant visuel.
Cliquez sur File > Save dans l’éditeur de script, puis revenez à Unity.
Cliquez sur le bouton Play et testez le jeu. Assurez-vous que vous ne pouvez pas entrer
dans l’avant-poste sans avoir recueilli les quatre piles. Si ce n’est pas le cas, vériiez que
votre script correspond bien à celui que nous vous avons indiqué jusqu’à présent. N’oubliez
pas de cliquer de nouveau sur Play pour terminer le test.
Dans cette instruction else if, vous utilisez la même ligne qui désactive le composant
GUITexture dans la première instruction if mais, cette fois, elle aura au contraire pour effet
de l’activer. Insérez la ligne suivante dans la déclaration else if :
GameObject.Find("Battery GUI").GetComponent(GUITexture).enabled=true;
148 Développez des jeux 3D avec Unity
Cliquez sur File > Save dans l’éditeur de script, puis revenez à Unity. Cliquez sur le bouton
Play et vériiez que si vous approchez de la porte sans aucune batterie, l’objet Battery
GUI s’afiche. Cliquez sur le bouton Play de nouveau pour arrêter l’essai.
L’indice textuel
Le moyen le plus simple pour écrire du texte en 2D qui doit s’aficher à l’écran consiste
à utiliser un composant GUIText. Vous allez donc créer un nouvel objet GUI Text qui
possède les deux composants Transform et GUIText. Cliquez sur GameObject > Create
Other > GUI Text. L’objet GUI Text s’afiche alors dans le panneau Hierarchy. Le texte
2D "Gui Text" apparaît également dans le panneau Scene (voir Figure 5.11).
Figure 5.11
Sélectionnez cet objet dans le panneau Hierarchy, appuyez sur Entrée/F2 et renommez-le
TextHint GUI.
Sélectionnez l’objet GUI Text dans le panneau Hierarchy pour aficher le composant
lui-même dans le panneau Inspector. Vous allez conserver la valeur par défaut (0,5) pour
les coordonnées X et Y du composant Transform. En effet, l’objet GUI Text utilisant
également les coordonnées relatives à l’écran, une valeur de 0,5 sur ces deux axes place le
texte au milieu de l’écran, ce qui est parfait pour attirer l’attention du joueur.
Chapitre 5 Éléments préfabriqués, collections et HUD 149
Figure 5.12
Sélectionnez le dossier Scripts dans le panneau Project, cliquez sur le bouton Create et
choisissez JavaScript dans le menu déroulant.
Renommez ce script TextHints, puis double-cliquez sur son icône pour l’ouvrir dans l’éditeur
de script.
Pour commencer, déclarez les trois variables suivantes au début du script :
static var textOn : boolean = false;
static var message : String;
private var timer : loat = 0.0;
La première variable statique, textOn, est de type booléen, car elle doit agir comme un
simple interrupteur. Nous reviendrons bientôt plus en détail sur ce point.
Ensuite, le script déclare une autre variable statique message de type string, que vous utili-
serez pour transmettre toutes les informations au paramètre Text du composant. Ces deux
variables sont statiques car nous aurons besoin de faire référence à elles depuis le script
PlayerCollisions.
La troisième variable, timer, est privée car elle n’a besoin ni d’être utilisée par d’autres
scripts ni de s’aficher dans le panneau Inspector. Elle servira à décompter le temps écoulé
à partir du moment où le message s’afiche à l’écran, ain de le faire disparaître après un
certain délai.
150 Développez des jeux 3D avec Unity
Ajoutez ensuite la fonction Start() suivante, ain de déinir certains états lorsque la scène
commence :
function Start(){
timer = 0.0;
textOn = false;
guiText.text = "";
}
Ces lignes s’assurent simplement que la variable timer est déinie à 0, que la variable
textOn est false (aucun texte ne doit s’aficher au début du jeu) et qu’aucun texte ne se
trouve actuellement dans le paramètre text du composant guiText. Pour cela, il sufit de
créer une chaîne de caractères vide à l’aide de deux guillemets sans aucun texte entre eux.
Ajoutez ensuite le code suivant à la fonction Update() du script :
function Update () {
if(textOn){
guiText.enabled = true;
guiText.text = message;
timer += Time.deltaTime;
}
if(timer >=5){
textOn = false;
guiText.enabled = false;
timer = 0.0;
}
}
Cliquez sur File > Save dans l’éditeur de script, puis revenez à Unity. Sélectionnez l’objet
TextHint GUI dans le panneau Hierarchy, puis cliquez sur Component > Scripts >
TextHints ain de lier le script que vous venez d’écrire à cet objet.
Maintenant que vous disposez d’un script qui contrôle l’objet TextHint GUI, il vous reste
à déclencher son afichage en appelant les variables statiques qu’il contient. Étant donné
que le moment où les messages doivent apparaître dépend de la collision du personnage
avec la porte, vous allez appeler ces variables statiques depuis le script PlayerCollisions.
Pour cela, commencez par l’ouvrir dans l’éditeur de script.
Trouvez les dernières déclarations else if que vous avez ajoutées à la fonction Update()
(elles accompagnent les lignes qui détectent la projection du rayon sur la porte), puis
écrivez les deux lignes suivantes :
TextHints.message = "le mécanisme de la porte semble manquer de puissance...";
TextHints.textOn = true;
Cette portion du script envoie un texte à la variable statique message du script TextHints et
déinit la valeur de la variable booléenne textOn du même script à true. Voici la déclaration
complète else if :
else if(hit.collider.gameObject.tag=="outpostDoor" && doorIsOpen == false &&
„ BatteryCollect.charge < 4){
GameObject.Find("Battery GUI").GetComponent(GUITexture). enabled=true;
TextHints.message = "le mécanisme de la porte semble manquer de puissance...";
TextHints.textOn = true;
}
Comme vous avez activé le composant en déinissant la variable textOn à true, le script
TextHints se charge du reste ! Cliquez sur File > Save dans l’éditeur de script puis reve-
nez à Unity. Cliquez sur le bouton Play pour tester le jeu. Marchez jusqu’à la porte sans
collecter les quatre piles nécessaires. Un indice textuel s’afiche pendant cinq secondes à
l’écran. Cliquez de nouveau sur Play pour arrêter le test du jeu.
Cliquez sur File > Save dans Unity pour sauvegarder votre travail.
Pour inir, vous allez modiier la police de caractères du texte de l’indice pour améliorer
son apparence.
(Mac OS) ou l’Explorateur (Windows) ou cliquer sur Assets > Import New Asset dans
Unity.
Pour cet exemple, vous emploierez une police libre de droits commerciaux, disponible sur
www.dafont.com (un site web proposant des polices libres de droits, très intéressantes
pour les travaux typographiques). L’utilisation des polices proposées sur certains sites web
peut être soumise à conditions.
Rendez-vous sur ce site et téléchargez une police dont vous aimez l’apparence et qui soit
lisible. N’oubliez pas qu’elle servira à donner des instructions au joueur : elle doit donc
être aisément lisible. Téléchargez la police Sugo si vous souhaitez avoir la même que nous,
décompressez-la, puis appliquez les méthodes mentionnées plus tôt pour ajouter le ichier
Sugo.ttf comme ressource à votre projet.
Une fois cette ressource importée dans votre projet, localisez et sélectionnez la police dans
le panneau Project. Pour la rendre plus lisible, vous allez augmenter sa taille chaque fois
qu’elle est utilisée. À la section True Type Font Importer du panneau Inspector, déi-
nissez une Font Size (taille de la police) de 24, puis cliquez sur le bouton Apply (voir
Figure 5.13). Si vous avez choisi une police différente, la taille à adopter peut être diffé-
rente, mais n’oubliez pas que vous pouvez modiier le paramètre Font Size à tout moment.
Figure 5.13
Pour que l’objet TextHint GUI utilise cette police, sélectionnez-le dans le panneau
Hierarchy, puis choisissez la police dans le menu déroulant situé à droite du paramètre
Font du composant GUIText dans le panneau Inspector. Vous pouvez également faire
glisser la police du panneau Project sur ce paramètre dans le panneau Inspector.
Cliquez maintenant sur le bouton Play et testez votre jeu. Cette fois, si le joueur approche
de la porte en ayant moins de quatre batteries, le message s’afiche à l’écran. Puis il dispa-
raît cinq secondes après que le personnage du joueur n’entre plus en collision avec la porte,
comme vous l’avez déini plus tôt. Cliquez de nouveau sur le bouton Play pour arrêter le
test du jeu, puis cliquez sur File > Save pour sauvegarder vos modiications.
Chapitre 5 Éléments préfabriqués, collections et HUD 153
En résumé
Au long de ce chapitre, vous avez créé et résolu un scénario de jeu. En prévoyant ce que
le joueur s’attend à rencontrer dans le jeu que vous lui présentez – sans tenir compte de ce
que vous savez des événements préalables –, vous pouvez déinir au mieux la méthode à
adopter en tant que développeur.
Essayez de considérer chaque nouvel élément dans le jeu du point de vue du joueur. Pour
cela, entraînez-vous avec des jeux existants, pensez à des situations du monde réel et,
surtout, évitez tout a priori. Les jeux les plus intuitifs sont toujours ceux qui trouvent un
équilibre entre les dificultés des tâches à réaliser et qui informent correctement le joueur
sans le dérouter. Il est crucial que les informations visuelles ou sonores destinées au joueur
soient appropriées ; quel que soit le jeu que vous concevez, vous devez toujours tenir
compte des informations dont le joueur dispose.
Maintenant que vous avez étudié un scénario de jeu de base et vu comment construire et
contrôler les éléments d’une interface graphique, vous allez découvrir un scénario de jeu
plus avancé. Au prochain chapitre, vous découvrirez deux concepts essentiels de plus :
l’instanciation et la physique des corps rigides.
6
Instanciation
et corps rigides
Vous allez étudier deux concepts essentiels à la conception d’un jeu 3D. Nous examinerons
dans la première moitié la notion d’instanciation – le processus de création d’objets au
cours de l’exécution du jeu. Puis vous la mettrez en pratique en utilisant la physique des
corps rigides (Rigid Body dans Unity).
Lorsque vous construisez différentes scènes de jeu, tous les objets nécessaires dans chacune
d’elles ne doivent pas être présents au début du jeu. C’est vrai pour une grande variété de
jeux, notamment les jeux de puzzle comme Tetris. Les pièces de formes aléatoires sont
créées – ou instanciées – en haut de l’écran à intervalles déinis, car toutes ne peuvent pas
y être stockées indéiniment.
Maintenant, prenons l’exemple de votre jeu d’exploration d’une île. Au cours de ce chapitre,
vous allez étudier la physique des corps rigides en créant une méthode qui permette au
personnage du joueur de lancer des noix de coco. Or, les noix de coco ne doivent pas être
présentes au chargement de la scène du jeu. C’est là que l’instanciation entre en scène.
156 Développez des jeux 3D avec Unity
Présentation de l’instanciation
À cette section, vous apprendrez comment reproduire et dupliquer des objets en cours de
jeu. Ce concept est utilisé dans de nombreux jeux pour créer des projectiles, des objets à
collecter, voire certains personnages comme les ennemis.
Le concept
L’instanciation est tout simplement une méthode de création (ou de reproduction) d’objets
pendant l’exécution du jeu à partir d’un modèle (un élément préfabriqué dans Unity).
Elle sert également pour dupliquer des objets de jeu déjà présents dans la scène.
L’instanciation d’un objet se déroule généralement de la façon suivante :
∑ On crée l’objet à instancier dans la scène, puis on lui ajoute les composants nécessaires.
Chapitre 6 Instanciation et corps rigides 157
∑ On crée, dans le projet, un élément préfabriqué, sur lequel on fait glisser l’objet réalisé
auparavant.
∑ On supprime l’objet original de la scène ain de conserver uniquement la ressource
préfabriquée.
∑ On écrit un script contenant la commande Instantiate() qu’on attache à un objet de jeu
actif. On déinit ensuite l’élément préfabriqué comme l’objet créé par cette commande.
Le script
La commande Instantiate() compte trois paramètres et s’écrit de la façon suivante :
Instantiate (objet à créer, position où le créer, rotation à lui donner);
En comprenant comment déinir ces trois paramètres, vous serez ensuite capable d’utiliser
la commande Instantiate() dans toutes les situations.
Passer un objet
Pour transmettre un objet, il sufit d’indiquer le nom d’une variable publique pour le
premier paramètre de la commande Instantiate(). Quand une variable publique de type
GameObject est créée au début d’un script, vous pouvez ensuite, dans le panneau Inspector
de Unity, faire glisser dessus un élément préfabriqué puis utiliser cette variable comme
paramètre de l’objet, comme dans l’extrait de code suivant :
var myPrefab : GameObject;
Instantiate(myPrefab, position où le créer, rotation à lui donner);
Vous pouvez également vous assurer que seuls certains types d’éléments préfabriqués
peuvent être stockés dans la variable myPrefab en déinissant un type de données plus
précis. Vous pourriez ainsi écrire, par exemple :
var myPrefab : Rigidbody;
Instantiate(myPrefab, position où le créer, rotation à lui donner);
Ainsi, seuls les objets préfabriqués dotés d’un composant Rigidbody peuvent être utilisés.
Position et rotation
La position et la rotation des objets à créer doivent être indiquées sous la forme de valeurs
Vector3 (X, Y, Z). Elles peuvent être transmises directement comme suit :
Instantiate(myPrefab, Vector3(0, 12, 30), Vector3(0, 0, 90));
158 Développez des jeux 3D avec Unity
mais elles peuvent également être héritées d’un autre objet en utilisant ses valeurs de
position.
Lorsque vous déinissez la position d’un objet à instancier, vous devez tenir compte, d’une
part, de la position où il sera créé et, d’autre part, s’il doit l’être dans l’espace local ou dans
l’espace global.
Vous allez créer les éléments préfabriqués de noix de coco, par exemple, à un point dans
le monde du jeu déini par un objet de jeu vide, qui sera un enfant de l’objet représentant
le personnage du joueur. Par conséquent, on peut considérer qu’il sera créé dans l’espace
local – à un endroit différent chaque fois mais toujours à une position relative identique
par rapport à l’endroit où se tient le personnage du joueur et à la direction vers laquelle il
se tourne.
Cette décision vous permet de décider où écrire le code, autrement dit à quel objet attacher
le script. Si vous l’attachez à l’objet vide qui représente la position où les noix de coco
doivent être créées, vous pouvez simplement faire référence à la variable transform.posi-
tion à l’aide de la syntaxe à point pour indiquer la position de l’objet dans la commande
Instantiate(). De cette manière, l’objet créé hérite de la position du composant Trans-
form de l’objet vide, puisque c’est sur celui-ci que le script est attaché. Cette méthode peut
également servir pour la rotation de la nouvelle occurrence de l’objet ain qu’elle corres-
ponde à celle de l’objet parent vide.
La commande Instantiate() se présenterait alors de la façon suivante :
Vous mettrez tout cela en pratique plus loin, mais nous allons d’abord voir la physique des
corps rigides et son importance dans les jeux.
Les forces
On appelle force l’inluence du moteur physique sur les objets. Ces forces peuvent être
appliquées de différentes façons à l’aide de composants ou de scripts. Pour être soumis aux
forces de la physique, un objet doit posséder un corps rigide, autrement dit un composant
Rigidbody.
Le composant Rigidbody
Pour qu’un objet puisse utiliser le moteur physique dans Unity, vous devez lui attribuer un
composant Rigidbody. Cela indique simplement au moteur qu’il doit utiliser le moteur
physique pour cet objet en particulier – vous n’avez pas besoin de l’appliquer à toute une
scène. Le moteur physique fonctionne tout simplement en arrière-plan.
Après qu’un composant Rigidbody a été ajouté à un objet, ses paramètres s’afichent dans
le panneau Inspector de la même manière que n’importe quel autre objet (voir Figure 6.1).
Figure 6.1
Les composants Rigidbody possèdent des paramètres que vous pouvez ajuster ou contrôler
à l’aide de scripts :
∑ Mass. Le poids de l’objet en kilogrammes. N’oubliez pas que le fait de déinir la masse
des différents corps rigides les conduit à se comporter de manière réaliste. Par exemple,
si un objet lourd heurte un objet plus léger, celui-ci sera repoussé plus loin.
∑ Drag. La résistance de l’air sur un objet en mouvement. Plus cette valeur est élevée, plus
le déplacement de l’objet dans les airs ralentira rapidement.
∑ Angular Drag. Ce paramètre est analogue au précédent, mais il affecte simplement la
vitesse de rotation. Il déinit à quel point l’air agit sur l’objet pour ralentir sa rotation.
∑ Use Gravity. Comme son nom l’indique, ce paramètre détermine si le corps rigide sera
affecté par la gravité ou non. Lorsque cette option est désactivée, l’objet est toujours
160 Développez des jeux 3D avec Unity
soumis aux forces et aux impacts du moteur physique et réagit en conséquence, mais
comme s’il se trouvait en apesanteur.
∑ Is Kinematic. Cette option permet de disposer d’un objet de corps rigide non soumis
aux lois physiques. Vous pouvez l’utiliser si vous souhaitez qu’un objet repousse un
corps rigide soumis à la gravité mais sans être affecté par le choc – c’est le cas, par
exemple, des lippers qui repoussent la balle d’un billard électrique.
∑ Interpolate. Ce paramètre peut être utilisé si le mouvement des objets de corps rigide
est saccadé. L’interpolation et l’extrapolation permettent de lisser le mouvement, soit en
se basant sur l’image précédente, soit en prévoyant l’image suivante.
∑ Freeze Rotation. Peut être utilisé pour verrouiller les objets ain que les forces appli-
quées par le moteur physique ne les fassent pas pivoter. C’est particulièrement utile pour
les objets qui doivent utiliser la gravité mais ne pas basculer, comme les personnages
de jeux.
Créer le mini-jeu
Pour mettre en pratique ce que vous venez d’apprendre, vous allez créer un jeu de lancer
de noix de coco qui permettra au joueur d’accéder à l’avant-poste. En récompense, le
joueur obtiendra la dernière pile nécessaire pour charger le mécanisme d’ouverture de la
porte.
Vous avez déjà disposé quatre piles dans le jeu, il vous sufit donc d’en enlever une de la
scène de manière que le joueur n’ait accès qu’à trois d’entre elles.
Sélectionnez un des objets battery dans le panneau Hierarchy, puis appuyez sur
Cmd+Retour arrière (Mac OS) ou Suppr (Windows) pour le supprimer.
Un objet sphérique (basé sur une forme primitive) est alors créé dans la scène. Il n’apparaît
pas directement au premier plan, mais vous pouvez facilement zoomer dessus. Pour cela,
placez le curseur sur le panneau Scene puis appuyez sur la touche F (pour focus). Sélec-
tionnez l’objet Sphere dans le panneau Hierarchy, appuyez sur Entrée/F2 et renommez-
le Coconut.
Vous allez modiier ses dimensions et sa forme pour qu’il ressemble davantage à une noix
de coco. Pour cela, vous réduirez sa taille et augmenterez légèrement la valeur sur l’axe Z.
Dans le composant Transform du panneau Inspector, donnez la valeur 0,5 aux para-
mètres Scale X et Z de l’objet Coconut et la valeur 0,6 au paramètre Y.
Les textures à utiliser sur la noix de coco se trouvent dans l’archive disponible sur la page
web consacrée à cet ouvrage (www.pearson.fr). Cliquez sur Assets > Import Package,
parcourez votre disque dur jusqu’au package CoconutGame.unitypackage, sélectionnez-le
puis cliquez sur Import.
Le dossier Coconut Game qui s’afiche dans le panneau Project contient les éléments
suivants :
∑ une image pour la texture de la noix de coco ;
∑ une texture en forme de cible ;
∑ quatre séquences audio ;
∑ deux modèles 3D, platform et target ;
∑ un dossier Materials pour les modèles 3D.
Pour appliquer la texture de la noix de coco, vous avez besoin de créer un nouveau matériau
à lui appliquer. Cliquez sur le bouton Create dans le panneau Project, puis sélectionnez
Material dans le menu déroulant. Appuyez sur Entrée/F2 et nommez ce nouveau matériau
Coconut Skin.
Pour appliquer la texture à ce matériel, faites simplement glisser la texture coconut du
panneau Project sur le rectangle vide situé à droite du paramètre Base (RGB) du matériau
dans le panneau Inspector. Un aperçu du matériau doit s’aficher dans la fenêtre au bas du
panneau Inspector (voir Figure 6.2).
162 Développez des jeux 3D avec Unity
Figure 6.2
Cet aperçu montre l’aspect du matériau sur une sphère. Il s’agit de l’aspect par défaut des
prévisualisations de matériaux dans Unity ; cela n’a rien à voir avec le fait que vous utilisez
ici un objet sphérique.
Ensuite, vous devez appliquer le matériau Coconut Skin sur l’objet Coconut Game
que vous avez placé dans la scène. Pour cela, il vous sufit de faire glisser le matériau du
panneau Project sur le nom de l’objet dans le panneau Hierarchy ou sur l’objet lui-
même dans le panneau Scene.
Cliquez sur le bouton Play pour tester le jeu. Vous constatez que la noix de coco tombe au
sol puis roule dans le panneau Game. Cliquez ensuite de nouveau sur le bouton Play pour
terminer le test.
Figure 6.3
Enfant de l’objet Main Camera, Launcher se déplace et tourne avec son parent. Mais il
doit être repositionné. Commencez par réinitialiser sa position dans le composant Trans-
form du panneau Inspector. Pour cela, vous pouvez soit remplacer toutes les valeurs du
paramètre Position par 0, soit, et cela est plus rapide, cliquer sur le bouton en forme d’en-
grenage et sélectionner Reset Position dans le menu déroulant (voir Figure 6.4).
Figure 6.4
Une fois la position de l’objet enfant Launcher réinitialisée à 0, celui-ci se place exacte-
ment au centre (position identique) de son parent. Bien sûr, ce n’est pas sa position déini-
tive, mais c’est un bon point de départ. Vous ne devez pas le laisser dans cette position pour
les deux raisons suivantes :
∑ Les noix de coco lancées sembleraient sortir de la tête du joueur, ce qui serait assez
bizarre.
∑ Lorsque vous instanciez des objets, vous devez vous assurer qu’ils sont créés à une posi-
tion où leur collider (composant de collision) n’en croise pas un autre, car cela forcerait
le moteur physique à écarter ces colliders, ce qui pourrait interrompre la force appliquée
lors du lancer de la noix de coco.
Chapitre 6 Instanciation et corps rigides 165
Pour éviter cela, vous avez simplement besoin de déplacer l’objet Launcher vers l’avant
et vers la droite de sa position actuelle. Donnez la valeur 1 aux options X et Y du paramètre
Position du composant Transform. Votre objet Launcher devrait maintenant être placé
à l’endroit où est censé se trouver le bras droit du personnage du joueur lorsqu’il lance un
objet (voir Figure 6.5).
Figure 6.5
Enin, pour que la trajectoire de la noix de coco aille vers le centre du champ de vision, vous
devez faire pivoter légèrement l’objet Launcher sur l’axe Y. Dans le paramètre Rotation
du composant Transform, donnez une valeur de 352 à l’axe Y pour que l’objet pivote de
8 degrés.
Vous devez maintenant écrire le script pour instancier la noix de coco et permettre au joueur
de la lancer lorsqu’il appuie sur le bouton de tir.
nouveaux axes en augmentant simplement la valeur Size en haut du panneau Input Manager
– cela crée un axe que pouvez ensuite personnaliser.
Figure 6.6
Pour que le joueur lance des noix de coco vers les cibles – que vous disposerez dans la
scène plus tard –, le script doit implémenter deux étapes clés :
∑ l’instanciation de l’objet Coconut à lancer lorsque le joueur presse le bouton de tir ;
∑ l’attribution d’une vitesse au composant Rigidbody pour que la noix de coco soit
propulsée vers l’avant dès qu’elle a été créée.
Pour cela, commencez par créer un nouveau ichier JavaScript de la façon suivante :
1. Sélectionnez le dossier Scripts dans le panneau Project.
2. Cliquez sur le bouton Create et choisissez JavaScript dans le menu déroulant.
3. Appuyez sur Entrée/F2 et nommez le script CoconutThrow.
4. Double-cliquez sur l’icône du script pour l’ouvrir dans l’éditeur de script.
if(Input.GetButtonUp("Fire1")){
}
Cette instruction vériie la classe Input et attend que les boutons liés à l’entrée Fire1 (la
touche Ctrl gauche et le bouton gauche de la souris) soient relâchés. Vous devez ensuite
placer les actions à exécuter lorsque le joueur relâche l’un ou l’autre bouton dans cette
instruction if.
Pour commencer, un son doit se faire entendre pour indiquer le lancement. S’il s’agissait
d’un jeu de tir, on entendrait certainement la détonation d’une arme à feu. Ici, vous utiliserez
simplement un son de soufle pour représenter le lancement de la noix de coco.
Cette variable est publique ; vous pourrez donc lui assigner la séquence audio dans le
panneau Inspector après avoir écrit ce script.
Vous devez maintenant déinir l’action permettant de lire cette séquence audio. Pour cela,
ajoutez la ligne suivante après l’accolade d’ouverture de votre instruction if :
audio.PlayOneShot(throwSound);
Une variable publique du type de données Rigidbody est alors créée. Bien que la noix de
coco soit stockée comme élément préfabriqué, son instanciation crée un objet de jeu possé-
dant un composant Rigidbody sur la scène. Il est donc important d’indiquer son type de
données pour interdire qu’un objet d’un type de données différent puisse être attribué à cette
variable dans le panneau Inspector. De plus, en limitant strictement le type de données à
168 Développez des jeux 3D avec Unity
Ici, le script déclare une variable locale newCoconut. Cette variable est privée puisqu’elle
est déclarée dans la fonction Update(), si bien qu’il est impossible d’utiliser explicitement
le préixe private. Le script transmet la création (l’instanciation) d’un nouveau Game-
Object – et donc son type de données – dans cette variable.
N’oubliez pas que les trois paramètres de la commande Instantiate() sont le nom de
l’objet, sa position et sa rotation. Vous verrez que nous avons utilisé la variable publique
pour créer une occurrence de notre élément préfabriqué qui hérite des paramètres de posi-
tion et de rotation de l’objet sur lequel ce script est attaché, c’est-à-dire l’objet Launcher.
Ici, le script utilise simplement le nom de la variable, qui fait référence à la dernière occur-
rence créée de l’élément préfabriqué, pour désigner le paramètre name de la variable.
newCoconut.rigidbody.velocity = transform.TransformDirection
„ (Vector3(0,0, throwForce));
Le script fait ici référence à la nouvelle instance de noix de coco par son nom de variable
(newCoconut) puis il utilise la syntaxe à point pour désigner le composant Rigidbody et
déinir sa vitesse.
La vitesse est ixée avec la commande transform.TransformDirection, qui crée une direc-
tion de l’espace local à l’espace global. Vous devez procéder ainsi car l’objet Launcher
sera constamment en mouvement et jamais orienté dans la même direction.
La direction de l’axe Z de l’espace global est toujours la même. Lorsqu’on déinit la vitesse
d’un objet, on peut alors prendre un axe local spéciique en lui attribuant une valeur de type
Vector3. C’est pourquoi les paramètres X et Y de la variable de type Vector3 ont ici une
valeur de 0.
Vous avez donc besoin d’indiquer les deux colliders pour lesquels le moteur physique ne
doit pas réagir et déinir le troisième paramètre à true.
Ajoutez la ligne suivante sous la dernière ligne que vous avez écrite :
Physics.IgnoreCollision(transform.root.collider, newCoconut.collider, true);
Ici, vous aviez besoin de trouver l’objet parent de tous ces objets, mais vous
ce pouvez utiliser la commande transform.parent si vous faites seulement réfé-
Astu
rence au parent direct d’un objet.
Cliquez sur File > Save pour enregistrer votre script et revenez dans Unity.
ajoute le script que vous venez d’écrire en tant que composant, ainsi que le composant
Audio Source requis.
Les valeurs ou les ressources des variables publiques du script CoconutThrow doivent être
déinies puisque vous ne l’avez pas fait manuellement dans le script.
Figure 6.7
Des ressources doivent être attribuées aux deux variables publiques Throw Sound et Coco-
nut Object – vous pouvez facilement les identiier car leur type de données déini dans le
script est indiqué. La troisième variable publique, bien que son type de données déini dans
le script soit indiqué, prend simplement la valeur par défaut dans le format approprié : une
valeur numérique de 0.
Cliquez sur la lèche située à droite de None (Audio Clip) et sélectionnez la séquence
audio throw sur la liste des ressources audio disponibles. Faites glisser l’objet Coco-
nut Prefab du panneau Project sur le champ None (Rigidbody). Ainsi, cet élément préfa-
briqué est directement lié à cette variable, ce qui signiie que le script créera des instances
de cet objet. Enin, donnez une valeur de 25 à la variable Throw Force. Gardez à l’esprit
que le script ne change pas quand vous modiiez les valeurs dans le panneau Inspector ;
cela annule simplement les valeurs précédemment déinies dans le script. N’oubliez pas
non plus que ces variables publiques peuvent être modiiées sans que vous ayez besoin
de recompiler ou de modiier le code source. Pour des raisons de commodité et de gain
de temps, nous vous conseillons de prendre l’habitude d’ajuster les valeurs des variables
publiques dans le panneau Inspector.
Figure 6.8
172 Développez des jeux 3D avec Unity
Il est maintenant temps de tester le script du lancer dans le jeu. Cliquez sur le bouton Play,
puis cliquez du bouton gauche ou appuyez sur la touche Ctrl gauche du clavier pour lancer
une noix de coco. Après avoir vériié que tout fonctionne correctement, cliquez de nouveau
sur le bouton Play pour arrêter le test. Si ce n’est pas le cas, vériiez que votre script corres-
pond au script complet suivant :
var throwSound : AudioClip;
var coconutObject : Rigidbody;
var throwForce : loat;
function Update () {
if(Input.GetButtonUp("Fire1")){
audio.PlayOneShot(throwSound);
var newCoconut : Rigidbody = Instantiate(coconutObject, transform.position,
„ transform.rotation);
newCoconut.name = "coconut";
newCoconut.rigidbody.velocity = transform.TransformDirection
„ (Vector3(0,0, throwForce));
Physics.IgnoreCollision(transform.root.collider, newCoconut.collider, true);
}
}
@script RequireComponent(AudioSource)
Restrictions de l’instanciation
Cette méthode d’instanciation des objets est la mieux adaptée au système d’éléments préfa-
briqués de Unity, car elle permet de facilement créer un objet sur la scène et de le dupliquer
lors de l’exécution du jeu.
Toutefois, la création de nombreux clones d’un objet possédant un corps rigide peut être
coûteuse, car chacun de ces objets fait appel au moteur physique et interagit avec d’autres
objets dans le monde en 3D, ce qui utilise des cycles CPU (sollicite la puissance du proces-
seur). Imaginez que vous permettiez au joueur de créer une quantité ininie d’objets contrô-
lés par le moteur physique… vous comprendrez alors que votre jeu puisse ralentir après un
certain temps. Quand trop de cycles CPU et de mémoire sont utilisés, le nombre d’images
par seconde diminue. Votre jeu auparavant luide devient saccadé, ce qui est évidemment
désagréable pour le joueur et compromet l’avenir commercial de votre création.
Pour éviter qu’un trop grand nombre d’objets ralentissent le jeu, vous allez :
∑ permettre au joueur de lancer des noix de coco seulement dans une zone déinie de
l’univers du jeu ;
∑ écrire un script qui supprime les noix de coco instanciées dans le monde du jeu après
un certain temps.
Chapitre 6 Instanciation et corps rigides 173
Si l’instanciation se déroulait sur une plus grande échelle (lors de la création de balles de
pistolet, par exemple), vous devriez alors ajouter également un délai avant que le joueur ne
puisse "recharger" l’arme. Ce n’est pas nécessaire ici, puisque la commande GetButtonUp()
empêche le joueur de lancer un trop grand nombre de noix de coco à la fois : il doit relâcher
la touche de tir avant qu’une noix de coco ne soit lancée.
Ce préixe static placé avant la variable est le moyen employé par JavaScript dans Unity
pour créer une variable globale – une valeur à laquelle les autres scripts peuvent accéder.
Vous devez maintenant ajouter une autre condition à l’instruction if existante qui permette
le lancer. Pour cela, trouvez la ligne suivante dans la fonction Update() :
if(Input.GetButtonUp("Fire1")){
Pour ajouter une seconde condition, il sufit d’ajouter deux esperluettes && avant l’accolade
de fermeture de l’instruction if et d’indiquer le nom de la variable statique, comme suit :
if(Input.GetButtonUp("Fire1") && canThrow){
Souvenez-vous qu’écrire tout simplement le nom de la variable est l’équivalent abrégé de :
if(Input.GetButtonUp("Fire1") && canThrow==true){
174 Développez des jeux 3D avec Unity
Vous avez déini la variable canThrow à false lorsque vous l’avez déclarée. Comme il
s’agit d’une variable statique (ce n’est donc pas une variable publique), vous avez besoin
d’ajouter quelques lignes de script pour la déinir à true. Puisque le joueur doit se tenir à un
certain emplacement pour pouvoir lancer des noix de coco, la meilleure façon de procéder
consiste ici à utiliser la détection de collision ain de vériier si le joueur est en contact avec
un objet en particulier. Si c’est le cas, cette variable statique est alors déinie à true.
Ouvrez maintenant le script PlayerCollisions et recherchez la fonction OnController-
ColliderHit() suivante placée en commentaires :
/*
function OnControllerColliderHit(hit: ControllerColliderHit){
if(hit.gameObject.tag == "outpostDoor" && doorIsOpen == false){
Door(doorOpenSound, true, "dooropen");
}
}
*/
Supprimez les caractères /* et */ ain que cette fonction ne soit plus en commentaires et
redevienne active. Supprimez ensuite la condition if, puisque vous n’en avez plus besoin
pour gérer l’ouverture et la fermeture de la porte. Il ne devrait plus rester que la fonction
elle-même, comme ceci :
function OnControllerColliderHit(hit: ControllerColliderHit){
Une partie du modèle platform que vous avez téléchargé, appelée mat, constitue la zone
sur laquelle le joueur devra se trouver pour lancer les noix de coco. Vous allez donc vous
assurer que le personnage du joueur est en collision avec cet objet. Ajoutez l’instruction if
else suivante dans la fonction :
if(hit.collider == GameObject.Find("mat").collider){
CoconutThrow.canThrow=true;
}else{
CoconutThrow.canThrow=false;
}
Ici, le script vériie si le collider avec lequel le contact s’effectue est égal au collider de
l’objet de jeu qui porte le nom mat dans la scène (le signe de double égalité est un opérateur
de comparaison). Si cette condition est respectée, le script redéinit à true la valeur de la
variable statique canThrow déclarée dans le script CoconutThrow à l’aide de la syntaxe à
point, ce qui permet à la commande Instantiate() du script CoconutThrow de fonctionner.
Dans le cas contraire, le script s’assure que cette variable est déinie à false, ce qui signiie
Chapitre 6 Instanciation et corps rigides 175
que le joueur ne pourra pas lancer de noix de coco s’il ne se trouve pas sur le pas de tir de
la plate-forme.
Cliquez sur File > Save dans l’éditeur de script, puis revenez dans Unity.
Mais vous pouvez également procéder en plusieurs étapes, en modiiant l’élément préfa-
briqué dans le panneau Scene de la manière suivante :
1. Faites glisser l’élément préfabriqué Coconut dans le panneau Scene ou dans le
panneau Hierarchy.
2. Cliquez sur Component > Scripts > CoconutTidy, cliquez sur Add pour conirmer
que l’ajout du composant mettra un terme à la relation de l’objet à l’élément préfa-
briqué parent.
3. Cliquez sur GameObject > Apply Changes to prefab pour répercuter cette mise à
jour sur l’élément préfabriqué original.
4. Supprimez l’instance de l’objet dans la scène à l’aide du raccourci clavier Cmd+Retour
arrière (Mac OS) ou Suppr (Windows).
Nous vous conseillons d’utiliser la première méthode, en une seule étape. Cependant, dans
certains cas, il peut être utile de placer un élément préfabriqué dans la scène et de le modi-
ier avant d’appliquer les modiications à l’élément préfabriqué lui-même. Par exemple, si
vous travaillez sur un élément visuel, comme un système de particules, vous aurez alors
besoin de voir l’effet de vos modiications ou des nouveaux composants sur cet objet. Il
devient par conséquent indispensable de placer un objet issu de l’élément préfabriqué dans
la scène pour le modiier.
Une fois le script attaché à l’élément préfabriqué, cliquez sur File > Save Project dans
Unity pour sauvegarder votre travail.
Ajouter la plate-forme
Maintenant, vous êtes prêt à implémenter les ressources du mini-jeu que vous avez télé-
chargées plus tôt. Vous allez importer une plate-forme et trois cibles dans la scène. Vous
détecterez ensuite les collisions entre les noix de coco et les cibles et vériierez si les trois
cibles sont renversées à la fois – ce qui est l’objectif du mini-jeu – à l’aide d’un script.
Dans le panneau Project, ouvrez le dossier Coconut Game qui a été importé lorsque vous
avez téléchargé les ressources nécessaires à ce chapitre. Sélectionnez le modèle 3D plat-
form pour aficher ses propriétés dans le panneau Inspector.
La plate-forme
Dans le composant FBXImporter du panneau Inspector, assurez-vous que le composant
FBXImporter a une valeur de 1,25 et que l’option Generate Colliders est activée pour
que Unity assigne un Mesh Collider (un composant de collision respectant le maillage
de l’objet) à chaque partie du modèle. Ainsi, le personnage du joueur pourra marcher sur
la plate-forme.
Pour conirmer ces modiications, cliquez sur le bouton Apply au bas du panneau Inspector.
Faites maintenant glisser le modèle depuis le panneau Project dans le panneau Scene
puis, avec l’outil Transform, positionnez-le à proximité de l’avant-poste, ain que le
joueur comprenne que les deux éléments sont liés. Assurez-vous que le modèle de plate-
forme touche le sol pour que le personnage du joueur puisse monter les marches situées à
l’avant du modèle (voir Figure 6.9).
Figure 6.9
Dans le composant Animations, vous devez déinir et nommer les images pour chaque état
de l’animation de ce modèle, de la même manière que vous l’avez fait pour les animations
de la porte de l’avant-poste. Vous pourrez ensuite les appeler dans vos scripts lorsqu’une
collision se produit entre une noix de coco et la bonne partie de la cible.
Pour ajouter trois états d’animation (voir Figure 6.10), cliquez sur l’icône plus (+) située à
droite dans le tableau Animations, puis indiquez le nom des états dans la colonne Name
ainsi que la première et la dernière image de chaque animation dans les colonnes Start
et End.
Figure 6.10
Une fois le tableau Animations complété, n’oubliez pas de cliquer sur le bouton Apply
au bas du panneau pour conirmer tous les changements que vous avez apportés aux para-
mètres de cette ressource.
Une boîte de dialogue vous informe que l’ajout de cet objet enfant entraînera la perte de
sa connexion avec l’élément préfabriqué. Cliquez sur le bouton Continue. Ce message
indique simplement que les modiications apportées aux composants attachés au modèle
d’origine dans le panneau Project – les paramètres de script, par exemple – ne s’applique-
ront plus à cette copie dans la scène puisque le lien entre cette occurrence et la ressource
originale ou l’élément préfabriqué est rompu.
Une fois que la cible est un enfant de l’objet platform, tous les objets enfants de ce dernier
s’afichent dans le panneau Hierarchy, y compris celui que vous venez d’ajouter.
Comme la cible se place par défaut au centre de la plate-forme, modiiez les valeurs du
composant Transform dans le panneau Inspector pour lui donner une position appropriée.
Placez-la à (0, 1.7, 1.7).
beenHit et timer sont des variables privées. Leurs valeurs sont uniquement utilisées dans
le script et n’ont pas besoin d’être déinies dans le panneau Inspector. Le préixe private
permet de ne pas les y aficher, contrairement aux variables publiques.
La détection de collision
Insérez ensuite la fonction de détection de collision suivante avant la fonction Update()
existante :
function OnCollisionEnter(theObject : Collision) {
if(beenHit==false && theObject.gameObject.name=="coconut"){
audio.PlayOneShot(hitSound);
targetRoot.animation.Play("down");
beenHit=true;
}
}
Réinitialiser la cible
Dans la fonction Update(), vous avez besoin d’utiliser la variable beenHit pour que la
variable timer lance un décompte de trois secondes. Autrement dit, la variable timer
Chapitre 6 Instanciation et corps rigides 181
comptera jusqu’à 3 à partir de l’image où la cible est touchée avant de déclencher sa réini-
tialisation. Pour cela, vous avez besoin de deux instructions if : une pour vériier si la
variable beenHit est true et incrémenter la valeur de la variable timer, l’autre pour vériier
si la variable timer a atteint 3 secondes. Ajoutez les quelques lignes suivantes dans la
fonction Update() :
if(beenHit){
timer += Time.deltaTime;
}
if(timer > 3){
audio.PlayOneShot(resetSound);
targetRoot.animation.Play("up");
beenHit=false;
timer=0.0;
}
La première instruction if attend que la variable beenHit ait la valeur true puis incrémente
la variable timer à l’aide du compteur Time.deltaTime. Ce compteur est indépendant du
nombre d’images par seconde, si bien que le décompte s’effectue en temps réel.
La seconde instruction if attend que la variable timer dépasse trois secondes puis lance la
lecture du son assigné à la variable resetSound, lit l’état d’animation du modèle attribué à
la variable targetRoot et réinitialise les variables beenHit et timer à leurs valeurs d’ori-
gine pour que la cible puisse être atteinte de nouveau.
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
Assigner le script
Dans le panneau Hierarchy, cliquez sur la lèche qui précède le modèle target que
vous avez ajouté à l’objet platform ain de voir les éléments qui le constituent. Afichez
ensuite le contenu du groupe enfant target_pivot pour voir la cible et ses supports (voir
Figure 6.11).
182 Développez des jeux 3D avec Unity
Figure 6.11
Dans cette igure, nous avons sélectionné la cible elle-même. Vous devez faire de même
pour vous assurer que le script que vous venez d’écrire est affecté à cet objet et non à l’objet
parent target. Vous devez vériier les collisions avec cet objet enfant ; en effet, la collision
ne doit pas se déclencher si le joueur lance une noix de coco sur les supports qui soutiennent
la cible, par exemple.
Une fois cet objet sélectionné, cliquez sur Component > Scripts > CoconutCollision
pour lui attacher le script que vous venez d’écrire et un composant Audio Source. Faites
ensuite glisser l’objet parent target du panneau Hierarchy sur la variable publique
Target Root et les ichiers audio targetHit et targetReset du panneau Project sur les
variables publiques adéquates dans le panneau Inspector (voir Figure 6.12).
Figure 6.12
Cliquez sur File > Save Scene dans Unity pour sauvegarder vos progrès. Cliquez ensuite
sur le bouton Play pour tester le jeu ; marchez sur la plate-forme, en veillant à vous placer
Chapitre 6 Instanciation et corps rigides 183
sur le pas de tir – vous devriez maintenant être en mesure de jeter des noix de coco et
d’abattre la cible. Cliquez de nouveau sur Play pour terminer le test.
Pour compléter le mini-jeu, vous allez ajouter trois cibles supplémentaires à l’aide du
système d’éléments préfabriqués.
Gagner la partie
Pour terminer le mini-jeu – le joueur doit obtenir la dernière pile dont il a besoin pour char-
ger le mécanisme de la porte de l’avant-poste. Vous devez écrire un script qui vériie si les
trois cibles sont renversées à la fois.
Sélectionnez le dossier Scripts dans le panneau Project puis cliquez sur le bouton Create
pour créer un ichier JavaScript. Renommez ce script CoconutWin, puis double-cliquez
sur son icône pour l’ouvrir dans l’éditeur de script.
La première variable, targets, est un compteur qui stocke le nombre de cibles abattues.
Cette valeur proviendra d’une modiication que vous apporterez au script CoconutColli-
sion plus tard. La variable privée haveWon est ensuite déinie à true ain qu’il soit impos-
sible de rejouer à ce mini-jeu une fois le challenge remporté.
Les deux variables publiques suivantes stockent respectivement la séquence audio à lire en
cas de victoire et l’élément préfabriqué battery. Cela permet à ce script d’instancier ces
éléments lorsque le joueur abat les trois cibles.
Cette déclaration if a deux conditions : elle garantit que la valeur de targets atteint la
valeur 3, autrement dit que toutes les cibles ont été abattues, et que la variable haveWon est
false, ce qui signiie ce qui signiie que le joueur n’a pas encore remporté ce challenge.
Lorsque ces conditions sont remplies, les commandes suivantes sont exécutées :
∑ Le script réinitialise la variable targets à 0 (ce qui est simplement un autre moyen de
s’assurer que l’instruction if ne se déclenche pas de nouveau).
∑ La séquence audio win est lue pour fournir un signal sonore au joueur.
∑ Une instance de l’objet que vous assignez à la variable battery est instanciée. Sa posi-
tion Vector3 est déinie en fonction des valeurs de position X et Z de la plate-forme
(puisque ce script sera appliqué à cet objet), en ajoutant 2 à la valeur Y.
∑ La variable est déinie à true ain que le joueur ne puisse plus gagner de nouveau à ce
jeu et générer davantage de piles.
Enin, comme vous allez utiliser du son, ajoutez la ligne suivante à la dernière ligne du
script :
@script RequireComponent(AudioSource)
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
Chapitre 6 Instanciation et corps rigides 185
Assigner le script
Sélectionnez l’objet parent platform dans le panneau Hierarchy, puis cliquez sur Compo-
nent > Scripts > Coconut Win.
Pour inir, assignez l’élément préfabriqué battery situé dans le dossier Prefabs du panneau
Project à la variable publique battery et l’effet sonore Win du dossier Coconut Game à la
variable publique Win. Le composant devrait être identique à la Figure 6.13.
Figure 6.13
Augmenter la valeur
Dans la fonction de détection de collision OnCollisionEnter(), l’instruction if contient
une ligne déinissant la variable beenHit à true. Ajoutez la ligne :
CoconutWin.targets++;
sous la ligne :
beenHit=true;
Diminuer la valeur
Comme la réinitialisation de la cible est gérée par la seconde instruction if de la fonction
Update(), vous devez soustraire le nombre de cibles abattues ici. Ajoutez la ligne :
CoconutWin.targets--;
sous la ligne :
beenHit=false;
186 Développez des jeux 3D avec Unity
Dans les deux cas, vous passez par la syntaxe à point pour accéder au script CoconutWin
(qui est, en fait, une classe) puis vous indiquez le nom de la variable, targets.
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
Cliquez sur le bouton Play et testez le jeu. Lancez des noix de coco et abattez les trois
cibles à la fois. Une pile doit alors être instanciée. Appuyez sur la barre d’espacement ain
de sauter par-dessus la barrière et de collecter la pile. Cliquez de nouveau sur Play pour
terminer le test puis sur File > Save Scene dans Unity pour sauvegarder votre travail.
La touche inale
Pour améliorer ce mini-jeu, vous allez ajouter un viseur qui s’afichera lorsque le joueur se
tiendra sur le pas de tir, puis vous utiliserez l’objet TextHint GUI existant pour donner des
instructions au joueur sur le jeu de lancer de noix de coco.
Ajouter le viseur
Pour ajouter le viseur à l’écran, procédez de la façon suivante :
1. Ouvrez le dossier Coconut Game dans le panneau Project.
2. Sélectionnez le ichier de texture Crosshair.
3. Cliquez sur GameObject > Create Other > GUI Texture pour créer un objet GUI
Texture du même nom et aux mêmes dimensions que le ichier de texture Crosshair.
Cet objet est automatiquement sélectionné dans le panneau Hierarchy, si bien que son
composant GUI Texture s’afiche dans le panneau Inspector. L’image en forme de réticule
de visée doit être visible dans le panneau Game et dans le panneau Scene lorsque l’option
Game Overlay est activée. Comme elle est placée au centre de l’objet par défaut, cela
fonctionne parfaitement avec ce ichier de texture de petite taille (64 × 64). Lorsque nous
avons créé le ichier de texture de cet exemple, nous avons veillé à ce que les contours du
viseur soient bien contrastés ain qu’il soit parfaitement visible aussi bien sur un fond clair
que sombre.
Informer le joueur
Vous allez utiliser l’objet TextHints GUI que vous avez créé au Chapitre 5, "Éléments
préfabriqués, collections et HUD", pour aficher un message à l’écran qui indiquera au
joueur ce qu’il doit faire lorsqu’il se trouve sur le pas de tir.
Ajoutez les lignes suivantes dans l’instruction if de la fonction OnControllerColliderHit()
du script PlayerCollisions :
TextHints.textOn=true;
TextHints.message = "Abattez 3 cibles pour obtenir une pile !";
GameObject.Find("TextHint GUI").transform.position.y = 0.2;
188 Développez des jeux 3D avec Unity
Le script afiche l’objet TextHint GUI en déinissant sa variable statique textOn à true
puis il envoie une chaîne de caractères à sa variable statique message. La minuterie du script
TextHints fera disparaître ce message lorsque le joueur quittera l’aire de lancement.
Le script utilise également la commande GameObject.Find pour s’adresser à l’objet
TextHint GUI lui-même et déinir sa position sur l’axe Y à 0,2. En effet, les messages de
l’objet TextHint GUI apparaissent au centre de l’écran, si bien qu’ils chevaucheraient
l’image du viseur. Pour éviter cela, la dernière des trois lignes de l’extrait de code précédent
décale le message vers le bas de l’écran.
Ajoutez maintenant le texte suivant dans l’instruction else de la fonction OnController
ColliderHit() :
Cela réinitialise simplement l’objet TextHint GUI à sa position d’origine lorsque le joueur
a terminé le mini-jeu et quitte le pas de tir.
La fonction OnControllerColliderHit() complète doit être la suivante :
function OnControllerColliderHit(hit: ControllerColliderHit){
var crosshairObj : GameObject = GameObject.Find("Crosshair");
var crosshair : GUITexture = crosshairObj.GetComponent(GUITexture);
if(hit.collider == GameObject.Find("mat").collider){
CoconutThrow.canThrow=true;
crosshair.enabled = true;
TextHints.textOn=true;
TextHints.message = "Abattez 3 cibles pour obtenir une pile !";
GameObject.Find("TextHint GUI").transform.position.y = 0.2;
}
else{
CoconutThrow.canThrow=false;
crosshair.enabled = false;
GameObject.Find("TextHint GUI").transform.position.y = 0.5;
}
}
Cliquez sur File > Save dans l’éditeur de script pour sauvegarder vos modiications puis
revenez dans Unity.
Cliquez sur le bouton Play et testez le jeu. Quand vous vous placez sur le pas de tir, un
message vous indiquant le but du jeu doit apparaître. Quittez l’aire de lancement : le viseur
doit disparaître immédiatement de l’écran, puis le message devenir invisible quelques
secondes plus tard. Cliquez de nouveau sur Play pour terminer le test puis sur File > Save
Project pour sauvegarder votre travail.
Chapitre 6 Instanciation et corps rigides 189
En résumé
Au cours de ce chapitre, nous avons abordé divers sujets essentiels à la création d’un scéna-
rio de jeu. Vous avez vu comment implémenter les objets corps rigides qui utilisent le
moteur physique et vous avez étudié le concept de l’instanciation, qu’il est très important
d’apprendre à maîtriser. En effet, l’instanciation est un outil majeur pour le concepteur car
elle permet de créer ou de cloner n’importe quelle ressource préfabriquée ou n’importe
quel objet de jeu lors de l’exécution.
Vous avez également fourni au joueur des informations supplémentaires, en réutilisant
l’objet TextHint GUI que vous aviez créé au Chapitre 5. Vous avez vu comment envoyer
ces informations à cet objet dans le script.
Vous continuerez à vous servir de toutes ces notions au il des pages de cet ouvrage et dans
vos futurs projets. Au prochain chapitre, nous allons délaisser provisoirement l’écriture de
script pour étudier les effets visuels de Unity. Vous découvrirez les systèmes de particules
visant à créer un feu à proximité de l’avant-poste, ain de donner au joueur une récompense
visuelle après qu’il a gagné le mini-jeu et ouvert la porte.
7
Systèmes de particules
Ce chapitre aborde certains effets de rendu que les développeurs peuvent employer dans
Unity. Pour créer des mondes 3D plus dynamiques, outre les matériaux et les textures
simples, on peut utiliser des effets pour reproduire les caractéristiques du monde réel,
souvent en les exagérant. De nombreux jeux 3D ont ainsi adopté les conventions visuelles
du cinéma, comme les effets de relet sur l’objectif ou les traînées de lumière que l’œil
humain ne perçoit pas dans la réalité.
Vous avez déjà vu l’effet de relet du soleil sur l’objectif au Chapitre 2, "Environnements",
avec lecomposant Light de l’objet Directional Light. Ici, vous allez découvrir comment
obtenir des effets plus polyvalents avec les systèmes de particules dans le monde 3D. Les
jeux utilisent les effets de particules pour de nombreux effets, du brouillard à la fumée en
passant par les étincelles et les lasers. Vous verrez aux sections suivantes comment simuler
l’effet d’un feu grâce à deux systèmes de particules.
Au cours de ce chapitre, vous apprendrez :
∑ de quoi est constitué un système de particules – ses composants et ses paramètres ;
∑ comment créer des systèmes de particules pour simuler le feu et la fumée ;
192 Développez des jeux 3D avec Unity
L’émetteur de particules
Dans tout système de particules, le composant émetteur est chargé de l’instanciation des
particules individuelles. Unity dispose d’un composant Ellipsoid Particle Emitter et
d’un composant Mesh Particle Emitter.
Le composant Ellipsoid Particle Emitter s’utilise généralement pour les effets de
fumée, la poussière et les autres éléments de l’environnement qui peuvent être créés dans
un espace fermé. Il est dit ellipsoïde car il crée des particules à l’intérieur d’une sphère
pouvant être étirée.
Le composant Mesh Particle Emitter crée des particules liées directement à un
maillage 3D et qui peuvent être soit animées le long des sommets du maillage soit émises
sur les points du maillage. Il sert principalement lorsqu’on doit contrôler directement la
position d’une particule. Le développeur, en ayant la possibilité de suivre les sommets d’un
maillage, peut ainsi concevoir des systèmes de particules extrêmement précis et de n’im-
porte quelle forme 3D.
En tant que composants, les deux émetteurs disposent des paramètres communs suivants :
∑ Size. La taille visible d’une particule.
∑ Energy. La durée de vie d’une particule dans le monde avant son autodestruction.
∑ Emission. Le nombre de particules émises à la fois.
∑ Velocity. La vitesse à laquelle les particules se déplacent.
Nous examinerons quelques-uns des réglages spéciiques de chaque type d’émetteur. Pour
créer un feu, vous choisirez Ellipsoid Particle Emitter qui permet d’obtenir un effet
plus aléatoire car il n’est pas lié à un maillage.
Chapitre 7 Systèmes de particules 193
Figure 7.1
L’animateur de particule
Le composant Particle Animator régit le comportement de chaque particule dans le
temps. Pour sembler dynamiques, les particules ont une durée de vie déinie puis elles s’auto-
détruisent. Dans l’exemple d’un feu, l’idéal serait que chaque particule soit animée et change
d’apparence au cours de sa vie dans le monde. Pour reproduire les variations de couleurs d’un
feu dans le monde réel, ce composant est intéressant pour faire varier la couleur et la visibilité
et pour appliquer des forces aux particules elles-mêmes.
Figure 7.2
technique du billboarding est appliquée ain que les particules semblent toujours faire face à
la caméra. Dans Unity, le composant Particle Renderer peut aficher les particules diffé-
remment, mais le billboarding est la méthode la mieux appropriée dans la plupart des cas.
Le composant Particle Renderer gère également les matériaux appliqués au système
de particules. Ces dernières étant rendues comme de simples sprites, si vous appliquez des
shaders de particules aux matériaux dans le composant, vous pouvez créer l’illusion que les
sprites ne sont pas carrés en plaçant tout autour des textures sur une couche alpha (trans-
parente). La Figure 7.3 illustre cette méthode que vous allez bientôt utiliser sur le matériau
feu (la zone sombre de l’image représente les zones transparentes).
Figure 7.3
Grâce à la transparence, les particules n’ont plus l’aspect carré que le rendu donne habituel-
lement aux sprites 2D. En combinant le rendu de la partie visible de cette texture avec des
valeurs d’émission plus élevées, vous pouvez obtenir un effet de densité.
Les moteurs de rendu des particules peuvent aussi animer celles-ci avec l’animation UV de
textures – plusieurs images sont alors utilisées pour modiier les textures d’une particule au
cours de sa durée de vie. Mais comme cette technique dépasse la portée de ce livre, nous
vous conseillons de vous reporter au manuel de Unity plus en savoir plus à ce sujet.
En résumé
Un système de particules fonctionne grâce à la collaboration de ses composants : l’émet-
teur, qui crée les particules ; l’animateur, qui régit leur comportement et leur évolution
Chapitre 7 Systèmes de particules 195
dans le temps ; et le moteur de rendu, qui déinit leur aspect visuel en utilisant différents
matériaux et paramètres d’afichage.
Vous allez maintenant voir comment créer un élément inédit dans votre jeu : un feu composé
de deux systèmes de particules, un pour les lammes et un autre pour le panache de fumée.
Le but du jeu
Pour l’instant, votre jeu consiste à collecter quatre piles pour entrer dans l’avant-poste.
Depuis le chapitre précédent, une de ces piles s’obtient en abattant les trois cibles avec des
noix de coco.
Une fois dans l’avant-poste, le joueur risque d’être assez déçu, car le bâtiment est vide. Vous
allez donc ajouter une boîte d’allumettes au centre de la pièce. Vous créerez également un
feu à proximité de l’avant-poste qui pourra s’allumer uniquement si le joueur possède cette
boîte d’allumettes. En voyant le tas de bois attendant de prendre feu, le joueur sera incité à
trouver les allumettes et donc à remplir les tâches déinies (c’est-à-dire, à ouvrir la porte).
Pour créer ce jeu, vous devez :
∑ installer un paquet de ressources, puis ajouter un modèle de feu de bois à la scène près
de l’avant-poste ;
∑ créer des systèmes de particules pour les lammes et la fumée lorsque le feu est allumé,
puis empêcher qu’ils se déclenchent trop tôt à l’aide d’un script ;
∑ utiliser la détection de collision entre le personnage du joueur et l’objet feu de bois de
façon que l’allumage du feu déclenche le composant émetteur ;
∑ ajouter le modèle d’allumettes dans l’avant-poste et mettre en place une détection de
collision pour que le joueur puisse les collecter et soit ensuite capable d’allumer le feu ;
∑ utiliser l’objet TextHint GUI pour donner des indications au joueur lorsqu’il s’approche
du feu sans posséder les allumettes.
Figure 7.4
Ce modèle doit disposer d’un collider (composant de collision) ain que le joueur ne
puisse pas passer au travers. Pour des modèles aussi complexes, on utilise habituellement
le composant FBX Importer pour créer des Mesh Colliders (composants de collision
respectant le maillage de l’objet) sur chaque maillage du modèle. Toutefois, étant donné
Chapitre 7 Systèmes de particules 197
que vous devez seulement veiller à ce que cet objet constitue un obstacle pour le joueur,
vous pouvez simplement utiliser un collider de type capsule à la place. Cela fonctionnera
tout aussi bien et permettra d’économiser la puissance de calcul car le processeur n’aura
pas à construire un collider sur chaque partie du modèle.
Sélectionnez l’objet feu campfire dans le panneau Hierarchy, puis cliquez sur Compo-
nent > Physics > Capsule Collider. La boîte de dialogue Losing Prefab s’afiche alors
et vous demande de conirmer la suppression de la connexion entre ce modèle et l’original.
Cliquez sur le bouton Add comme d’habitude.
Un petit collider sphérique apparaît alors à la base du modèle de feu. Vous devez augmenter
sa taille ain qu’il recouvre tout le modèle. Dans le nouveau composant Capsule Collider
du panneau Inspector, donnez la valeur 2 au paramètre Radius et la valeur 5 au paramètre
Height. Afichez ensuite les valeurs du paramètre Center puis donnez la valeur 1,5 à Y
(voir Figure 7.5). Testez le jeu pour vériier que le joueur est bloqué par l’objet.
Figure 7.5
Créer le feu
Pour commencer à construire le système de particules du feu, vous allez ajouter un objet
de jeu possédant les trois composants essentiels pour les particules. Pour cela, cliquez sur
GameObject > Create Other > Particle System. Un nouvel objet de jeu Particle
System apparaît alors dans les panneaux Scene et Hierarchy. Appuyez sur Entrée/F2
et renommez-le FireSystem, en vous assurant que le nom ne contient pas d’espace : c’est
essentiel pour le script que vous allez créer ensuite.
Vous n’avez pas besoin de positionner le feu avant d’avoir terminé sa création. Vous pouvez
tout à fait continuer sa conception là où Unity l’a placé de façon aléatoire dans le monde 3D.
Par défaut, les particules prennent l’apparence de petits points blancs aux contours lous et
ressemblent un peu à un nuage de lucioles. Il s’agit tout simplement des paramètres les plus
génériques de chaque composant. Pour le moment, l’émetteur de particules génère le plus
petit nombre possible de particules, l’animateur régit l’apparition et la disparition progres-
sive des particules, et le moteur de rendu n’utilise aucun matériau.
Vous allez maintenant déinir chaque composant individuellement. Lorsque vous réglez les
paramètres dans le panneau Inspector, vous pouvez visualiser un aperçu du système de
particules dans le panneau Scene.
Local Velocity sur un objet pouvant être déplacé et si celui-ci pivotait au cours du jeu,
son axe Y local ne correspondrait alors plus à l’axe Y global.
Un baril enlammé régi par le moteur physique, par exemple, peut tomber, voire rouler au
sol. Pourtant, les lammes doivent toujours s’élever d’un point de vue global. Bien que le
feu de camp ne puisse pas être déplacé, vous devez comprendre la différence entre espace
local et espace global dans ce cas précis.
Déinissez ensuite la valeur Y de Rnd Velocity (Random, pour aléatoire) à 0,2 pour que
des lammes s’élèvent un peu plus haut que les autres, de temps à autre et de façon aléatoire.
Fixez le paramètre Tangent Velocity à 0,2 sur les axes X et Z, en laissant l’axe Y à 0. Ce
paramètre déinit la vitesse originale de chaque particule. Avec une valeur faible sur X et Z,
vous accélérez donc la vitesse des lammes sur le plan horizontal.
Le paramètre Emitter Velocity Scale sert uniquement à contrôler la vitesse à laquelle
les particules se déplacent lorsque l’objet parent du système de particules est en mouve-
ment. Il peut donc être déini à 0 ici, puisque la position de ce feu ne changera pas.
Le paramètre Simulate in Worldspace sera désactivé, puisque les particules doivent être
créées en fonction de la position du système et non selon une position dans l’espace global.
Le paramètre One Shot peut lui aussi rester désactivé, car l’émission des particules doit
être continue. Ce paramètre serait plus utile pour représenter la fumée sortant d’un canon,
par exemple.
Toutes les valeurs du paramètre Ellipsoid peuvent être déinies à 0,1. Cette valeur est
faible, mais l’échelle du système de particules est également réduite – cette valeur devra,
par exemple, être beaucoup plus élevée pour le système de particules du panache de fumée.
Figure 7.6
Le système de particules dans le panneau Scene doit à présent se comporter de façon plus
naturelle grâce aux couleurs et aux valeurs alpha que vous avez déinies.
L’effet du système Color Animation peut être plus ou moins visible selon les
Info shaders spéciiques que les matériaux appliqués au système de particules uti-
lisent, car certains shaders révèlent un peu plus de couleur que d’autres. Ceux
avec de la transparence, par exemple, peuvent montrer les couleurs de manière
moins eficace.
Conservez toutes les valeurs par défaut de 0 sur tous les axes des paramètres World Rota-
tion Axis et Local Rotation Axis, puis donnez la valeur –0,3 au paramètre Size Grow.
Avec une valeur négative, les particules diminuent de taille au cours de leur durée de vie,
ce qui donne un aspect plus dynamique au feu.
Vous allez maintenant ajouter des forces pour rendre le mouvement du feu plus réaliste.
Elles sont différentes des vitesses ajoutées dans le paramètre Emitter, car elles sont appli-
quées lors de l’instanciation – ce qui entraîne une accélération puis une décélération des
particules. Cliquez sur la lèche grise située à gauche du paramètre Rnd Force pour afi-
cher ses options, puis donnez la valeur 1 aux axes X et Z. Afichez ensuite les options du
paramètre Force de la même manière et entrez la valeur 1 pour l’axe Y.
Déinissez la valeur du paramètre Damping à 0,8. Le damping (amortissement) déinit le
ralentissement des particules au cours de leur durée de vie. La valeur par défaut, 1, n’en-
traîne aucun amortissement et les valeurs comprises entre 0 et 1 provoquent un ralentisse-
ment (0 causant le ralentissement le plus important). On utilise ici une valeur de 0,8 ain
que les particules ne ralentissent pas de manière trop artiicielle.
Chapitre 7 Systèmes de particules 201
Vous pouvez laisser le dernier paramètre Autodestruct désactivé. Toutes les particules
s’autodétruisent naturellement à la in de leur durée de vie, mais ce paramètre porte sur l’ob-
jet de jeu parent lui-même. S’il est activé, toutes les particules s’autodétruisent, puis l’objet
de jeu est détruit. On l’utilise seulement lorsque le paramètre One Shot est activé dans le
composant émetteur. Pour un coup de canon, par exemple, l’objet de jeu serait détruit dès
que toutes les particules se seraient autodétruites, ce qui économiserait les ressources du
CPU, du GPU et de la RAM.
Ajouter un matériau
Maintenant que le système de particules est déini, il ne vous reste plus qu’à créer un matériau
qui utilise la texture de feu. Sélectionnez le dossier Fire feature dans le panneau Project,
cliquez sur le bouton Create en haut du panneau et choisissez Material pour créer une
nouvelle ressource New Material dans le dossier. Renommez-la ensuite simplement
Flame, puis sélectionnez-la pour aficher ses propriétés dans le panneau Inspector.
Ouvrez le menu déroulant Shader et choisissez Particles > Additive (soft) pour obtenir
une particule basée sur la couche alpha avec un rendu de la texture que vous appliquez.
Faites glisser la texture appelée Fire 1 du dossier Fire feature dans le panneau Project, sur
la place vide à la droite du paramètre Particle Texture qui indique pour l’instant None
(Texture2D).
Pour appliquer ce matériau, faites-le simplement glisser du dossier Fire feature dans le
panneau Project sur l’objet FireSystem dans le panneau Hierarchy.
Figure 7.7
Créer la fumée
Comme le dit l’adage, "Il n’y a pas de fumée sans feu" et vice versa. C’est pourquoi vous
avez besoin qu’un panache de fumée s’échappe du sommet de votre feu de camp pour le
rendre plus réaliste.
Pour commencer, cliquez sur GameObject > Create Other > Particle System pour
ajouter un système de particules à la scène. Renommez-le SmokeSystem dans le panneau
Hierarchy (encore une fois, vous ne devez pas utiliser d’espace dans le nom de l’objet).
Figure 7.8
Encore une fois, les particules doivent être animées entre deux valeurs alpha égales à 0 ain
qu’elles apparaissent et disparaissent de façon moins abrupte et plus naturelle.
Modiiez ensuite les paramètres suivants :
∑ Size Grow : 0,2 ;
∑ Rnd Force : (1.2, 0.8, 1.2) ;
∑ Force : (0.1, 0, 0.1) ;
∑ Autodestruct : non sélectionné.
Positionnement
Répétez l’étape de positionnement du feu pour la fumée. Faites glisser l’objet Smoke-
System sur l’objet parent campfire dans le panneau Hierarchy. Cliquez ensuite sur
l’icône en forme d’engrenage dans le panneau Inspector et choisissez Reset, puis redé-
inissez la valeur de la position Y à 0,9. Cliquez sur le bouton Play. Le feu devrait main-
tenant s’allumer et le panache de fumée s’élever dans le ciel (voir Figure 7.9). Comme
toujours, n’oubliez pas de cliquer de nouveau sur Play pour arrêter le test.
Chapitre 7 Systèmes de particules 205
Figure 7.9
Allumer le feu
Maintenant que la conception du feu est terminée, vous allez désactiver les systèmes de
particules et l’audio ain qu’il soit éteint au lancement du jeu.
∑ Sélectionnez l’objet campfire dans le panneau Hierarchy, puis désactivez le para-
mètre Play on Awake du composant Audio Source dans le panneau Inspector.
∑ Sélectionnez l’objet enfant FireSystem de l’objet campfire, puis désactivez le para-
mètre Emit dans le composant Ellipsoid Particle Emitter.
∑ Sélectionnez l’objet enfant SmokeSystem de l’objet campfire et désactivez le para-
mètre Emit dans le composant Ellipsoid Particle Emitter.
Il est temps maintenant d’ajouter la boîte d’allumettes à collecter et de créer l’interface qui
indiquera que le joueur possède les allumettes. Pour cela, vous devez :
∑ ajouter dans l’avant-poste le modèle matchbox que vous avez téléchargé plus tôt pour
donner au joueur une raison d’ouvrir la porte ;
∑ créer une interface graphique (Gui Texture) en utilisant une texture du dossier Fire
feature, puis l’enregistrer comme élément préfabriqué ;
∑ modiier le script PlayerCollisions existant et ajouter une détection de collision pour
la boîte d’allumettes ain que celle-ci puisse être détruite, puis instancier l’élément
préfabriqué matchbox GUI.
Vous avez également besoin d’une variable publique pour représenter l’élément préfabri-
qué Matches GUI Texture ain de pouvoir l’instancier lorsque le joueur collecte la boîte
d’allumettes. Ajoutez la variable suivante au début du script :
var matchGUI : GameObject;
Maintenant, faites déiler le script jusqu’à la fonction OnTriggerEnter(), puis ajoutez cette
instruction if à la suite de celle qui y est déjà :
if(collisionInfo.gameObject.name == "matchbox"){
Destroy(collisionInfo.gameObject);
haveMatches=true;
audio.PlayOneShot(batteryCollect);
var matchGUIobj : GameObject = Instantiate(matchGUI, Vector3(0.15,0.1,0),
„ transform.rotation);
matchGUIobj.name = "matchGUI";
}
Cette condition vériie le paramètre collisionInfo, qui enregistre chaque objet avec lequel
le joueur entre en collision. La commande gameObject.name vériie si collisionInfo
208 Développez des jeux 3D avec Unity
contient un objet nommé matchbox puis compare ce nom à la chaîne de caractères "Match-
box". Si ces conditions sont réunies, alors le script :
∑ Détruit l’objet matchbox, en faisant référence à l’objet gameObject courant stocké dans
collisionInfo.
∑ Déinit la variable haveMatches à true.
∑ Lance la lecture de la séquence audio assignée à la variable batteryCollect. Comme le
joueur est déjà habitué à ce son lorsqu’il collecte des objets, il est logique de le réutiliser.
∑ Instancie une occurrence de l’objet de jeu assigné à la variable publique matchGUI et la
positionne à (0.15, 0.1, 0). Souvenez-vous que, pour les objets 2D, l’axe Z permet tout
simplement de superposer plusieurs calques, d’où la valeur 0. La commande trans-
form.rotation permet d’hériter de la rotation de l’objet parent – il est inutile de déinir
un paramètre de rotation pour les objets 2D.
∑ Nomme la nouvelle instance de l’objet à l’aide de la variable matchGUIobj qui est créée
dans la ligne de l’instanciation. Elle sera utilisée plus tard pour supprimer l’interface
graphique de l’écran.
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity. Cliquez sur le
bouton Play et assurez-vous que vous pouvez vous procurer les allumettes si vous entrez
en contact avec elles après être entré dans l’avant-poste. La texture de la boîte d’allumettes
doit également s’aficher dans le coin inférieur gauche de l’écran. Maintenant, vous allez
décider si le feu peut être allumé ou non avec la variable haveMatches.
Allumer le feu
Ain d’allumer le feu, vous devez vériier les collisions entre le joueur et l’objet campfire.
Pour cela, revenez dans l’éditeur de script pour modiier le script Player Collisions. Si
vous l’avez fermé, double-cliquez sur son nom dans le dossier Scripts du panneau Project.
Recherchez la première ligne de la fonction OnControllerColliderHit() :
function OnControllerColliderHit(hit: ControllerColliderHit){
Cette condition permettra de vériier si le joueur touche l’objet campfire. Toutefois, vous
devez également vériier que le joueur dispose des allumettes. Pour cela, ajoutez les lignes
suivantes à l’intérieur de cette instruction if :
Chapitre 7 Systèmes de particules 209
if(haveMatches){
haveMatches = false;
lightFire();
}else{
TextHints.textOn=true;
TextHints.message = "vous avez besoin d’allumettes pour allumer ce feu...";
}
Ici, le script vériie si la variable haveMatches est true. Si ce n’est pas le cas (else), il
utilise le script TextHints pour aficher l’interface graphique TextHint GUI qui indique au
joueur ce qu’il doit faire.
Si haveMatches est true, le script appelle une fonction lightire(), que vous allez écrire,
pour lancer la lecture de la séquence audio et déclencher les systèmes de particules. Placez-
vous à la in du script et ajoutez la fonction suivante avant la ligne @script :
function lightFire(){
var campire : GameObject = GameObject.Find("campire");
var campSound : AudioSource = campire.GetComponent(AudioSource);
campSound.Play();
Destroy(GameObject.Find("matchGUI"));
}
Cette ligne nomme la variable, déclare son type de données sur GameObject et utilise la
commande Find pour la déinir comme égale à l’objet de jeu campire.
Puis il s’adresse à un composant spéciique de cet objet à l’aide de la variable qui vient
d’être établie et de la commande GetComponent :
var campSound : AudioSource = campire.GetComponent(AudioSource);
On déclare là encore une nouvelle variable pour représenter le composant, on ixe son type
de données sur AudioSource et on utilise cette variable pour appeler une commande :
campSound.Play();
Comme la commande Play est spéciique aux composants Audio Source, Unity sait exac-
tement quoi faire et lance simplement la lecture de la séquence audio assignée dans le
panneau Inspector.
La méthode est la même dans la deuxième et dans la troisième opération, sauf que le script
concerne le paramètre emit du composant Particle Emitter, comme à la ligne suivante :
lameEmitter.emit = true;
Enin, cette fonction exécute la commande Destroy(), qui trouve tout simplement l’objet
GUI qui afiche la boîte d’allumettes, autrement dit l’objet nommé matchGUI à l’instan-
ciation (reportez-vous à la section "La collecte des allumettes").
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
Comme vous avez créé une variable publique pour l’élément préfabriqué MatchGUIprefab
dans le script PlayerCollisions, vous devez maintenant lui assigner une valeur. Cliquez
sur les lèches grises qui précèdent tous les objets parents dans le panneau Hierarchy pour
que seuls ceux-ci restent afichés, puis sélectionnez l’objet First Person Controller ain
d’aficher ses composants dans le panneau Inspector.
Localisez le composant Player Collisions (script) puis faites glisser l’élément préfabri-
qué MatchGUIprefab à partir du dossier Fire feature du panneau Project sur la variable
publique Match GUI.
Félicitations ! Le feu est maintenant terminé. Cliquez sur File > Save Scene dans Unity
pour sauvegarder votre projet.
Tests et conirmation
Chaque fois que vous modiiez votre jeu, il est essentiel d’effectuer des tests. Au Chapitre 9,
vous verrez comment optimiser le jeu, comment vous assurer que les tests fonctionnent
comme ils sont censés le faire, ainsi que différentes options pour diffuser votre jeu.
Chapitre 7 Systèmes de particules 211
Pour l’instant, vous devez vous assurer que votre jeu fonctionne normalement. Même si
aucune erreur ne s’est afichée dans la console de Unity (pour l’aficher, appuyez sur Cmd/
Ctrl+Maj+C), vous devez toujours vous assurer qu’aucune erreur ne se produit pendant les
différentes étapes de la partie.
Cliquez sur le bouton Play puis collectez les piles, lancez les noix de coco, récupérez la
boîte d’allumettes et allumez le feu pour vous assurer que tous ces éléments fonctionnent.
Si une erreur se produit, vériiez que vos scripts correspondent bien à ceux indiqués dans
cet ouvrage.
En cas d’erreurs pendant les tests, le bouton PauSe situé en haut de l’interface
Info de Unity permet de mettre le jeu en pause, de regarder l’erreur indiquée dans
la console, puis de relancer le jeu. Lorsqu’une erreur s’afiche dans la console,
double-cliquez dessus pour aficher la ligne du script qui la contient ou, du
moins, l’emplacement où le script rencontre un problème.
De là, vous pouvez diagnostiquer l’erreur ou vériier le script à l’aide du manuel
de référence Scripting Manual de Unity pour vous assurer que votre approche
est la bonne. Si vous ne parvenez pas à résoudre les erreurs, demandez de l’aide
sur les forums de la communauté Unity ou sur le canal IRC. Pour de plus amples
renseignements, consultez la page suivante :
http://unity3d.com/support/community.
En résumé
Vous venez de voir comment intégrer les particules pour donner une touche plus dynamique
à votre jeu. Les particules s’utilisent dans de nombreuses situations de jeu différentes, qu’il
s’agisse de représenter la fumée qui s’échappe du pot d’échappement d’une voiture, des
tuyères des vaisseaux spatiaux, du canon des armes à feu, ou encore la vapeur des systèmes
de ventilation. La meilleure façon d’en apprendre plus sur ce sujet consiste à effectuer
des essais. Les paramètres sont nombreux, si bien qu’il vous faudra un certain temps pour
savoir ce que vous pouvez réaliser et pour obtenir les meilleurs résultats.
Au prochain chapitre, vous allez voir comment créer des menus pour votre jeu. Pour cela,
vous utiliserez la classe GUI de Unity dans vos scripts, les ressources GUI Skin et vous
créerez des comportements pour vos interfaces. La classe GUI est un élément particulier
du moteur de Unity utilisé spéciiquement pour créer des menus, des HUD (Heads Up
Displays, afichage tête haute). En combinant la classe GUI et les ressources GUI Skin,
vous pouvez créer des éléments totalement personnalisables et réutilisables. Les ressources
GUI Skin peuvent en effet être appliquées à autant de scripts de la classe GUI que vous le
souhaitez. Vous pouvez ainsi créer un style cohérent dans tous vos projets Unity.
8
Conception de menus
Ain de créer un exemple de jeu complet, vous allez voir au long de ce chapitre comment
créer une scène distincte de la scène de l’île qui servira de menu. Plusieurs méthodes exis-
tent pour concevoir des menus dans Unity, qui combinent des comportements intégrés et
des textures 2D.
Les composants GUI Texture s’utilisent pour les écrans de démarrage incluant les logos
des développeurs ou les écrans de chargement. Par contre, pour les menus interactifs, deux
manières différentes sont possibles. La première repose sur l’utilisation des composants
GUI Texture – que vous avez étudiés au Chapitre 6, "Instanciation et corps rigides",
pour ajouter un viseur, et au chapitre précédent, pour aficher la boîte d’allumettes. L’autre
méthode se base sur les classes UnityGUI et sur les ressources GUI skin pour créer une
interface graphique personnalisée.
Au cours de ce chapitre, vous apprendrez à :
∑ concevoir une interface de deux manières différentes ;
∑ contrôler les composants GUI Texture avec des événements souris scriptés ;
∑ rédiger un script simple UnityGUI ;
214 Développez des jeux 3D avec Unity
menus ain de créer un lien visuel entre le concept du jeu et son interface. Ainsi, la navi-
gation dans le menu d’ouverture permet déjà au joueur de s’amuser.
Dans LittleBigPlanet de Media Molecule, ce concept est poussé encore plus loin, puisque
le joueur doit apprendre à contrôler le personnage jouable pour pouvoir naviguer dans le
menu.
Comme pour toute création, l’important est de rester cohérent. Dans notre exemple, vous
devez veiller à utiliser des couleurs et une typographie en harmonie avec le contenu du jeu.
Vous avez peut-être déjà rencontré des jeux mal conçus et qui utilisent trop de polices de
caractères différentes ou trop de couleurs qui jurent. Or, le menu étant le premier élément
que le joueur découvre, ces erreurs créent d’emblée un sentiment peu agréable et nuisent à
la viabilité commerciale du jeu.
Les textures employées pour créer le menu de notre exemple de jeu sont disponibles sur
la page web consacrée à cet ouvrage (www.pearson.fr). Décompressez si nécessaire
le ichier nommé Menu.unitypackage puis revenez dans Unity. Cliquez sur Assets >
Import package, parcourez votre disque dur jusqu’à l’emplacement de ces ressources et
importez-les.
Une fois l’importation terminée, un dossier Menu s’afiche dans le panneau Project.
Il contient les éléments suivants :
∑ des textures pour le menu principal du jeu et trois boutons : Play, Instructions et
Quit ;
∑ une séquence audio (un bip pour les boutons de l’interface).
Créer la scène
Pour ces menus, l’environnement insulaire que vous avez créé va vous servir. En plaçant
l’île à l’arrière-plan dans le menu, vous éveillerez la curiosité du joueur en lui présentant
l’environnement qu’il pourra explorer lors du lancement de la partie. Ce type d’incitation
216 Développez des jeux 3D avec Unity
visuelle peut sembler anodin, mais cela encourage le joueur à tester le jeu de manière quasi
subliminale.
Un exemple visuel
La Figure 8.1 montre l’aspect qu’aura votre menu une fois terminé. Cet exemple est obtenu
en suivant la méthode 1 ; les éléments de menu créés avec la méthode 2 auront un aspect
différent.
Figure 8.1
Dupliquer l’île
Pour commencer, vous réutiliserez la scène Island Level que vous avez créée aux chapitres
précédents. Pour faciliter la gestion des éléments, vous regrouperez les ressources essen-
tielles de cet environnement ain de les distinguer des objets dont vous n’avez pas besoin,
comme l’avant-poste et les piles. De cette façon, il vous sufira ensuite de tout supprimer
à l’exception du groupe que vous allez créer dans la copie du niveau. Il est aussi facile de
regrouper des éléments dans Unity que d’imbriquer des objets enfants dans un objet parent
vide.
Chapitre 8 Conception de menus 217
Dupliquer la scène
Suivez les étapes suivantes pour dupliquer la scène :
1. Cliquez sur File > Save Scene pour vous assurer que la scène Island Level est
enregistrée, puis sélectionnez la ressource Island Level dans le panneau Project.
2. Cliquez sur Edit > Duplicate ou utilisez les raccourcis clavier Cmd/Ctrl+D. Lors
de la duplication, Unity ajoute simplement un numéro au nom de l’objet ou de la
ressource, si bien que cette copie est baptisée Island Level 1. Assurez-vous qu’elle est
sélectionnée dans le panneau Project puis renommez-la Menu.
3. Double-cliquez sur cette scène dans le panneau Project pour la charger et commencer
à la modiier.
4. La scène Menu étant ouverte, vous pouvez maintenant supprimer tous les objets
inutiles. Appuyez sur Cmd/Ctrl puis cliquez sur tous les objets dans le panneau
Hierarchy à l’exception du groupe Environment pour les sélectionner.
5. Appuyez sur Cmd+Retour arrière (Mac OS) ou Maj+Suppr (Windows) pour les
supprimer de cette scène.
Comme l’illustre la Figure 8.1, l’île apparaîtra vue de loin et dans le coin inférieur de
l’écran dans le menu, tandis que le titre du jeu et le menu s’aficheront en surimpression
du ciel et de la mer. Pour reproduire cela, vous devez ajouter une nouvelle caméra dans la
scène, car la seule caméra existante était celle attachée à l’objet First Person Control-
ler. Il n’y a donc aucune caméra dans la scène actuelle, rien qui permette de visualiser le
monde 3D, si bien que le point de vue dans le panneau Game est maintenant complètement
vide.
Pour créer une caméra, cliquez sur GameObject > Create Other > Camera. Assurez-
vous que ce nouvel objet Camera est sélectionné dans le panneau Hierarchy, puis entrez
les valeurs de Position suivantes dans le composant Transform du panneau Inspector :
(150, 250, –650).
218 Développez des jeux 3D avec Unity
Ajouter le titre
Maintenant, vous avez besoin d’un logo pour le jeu. Le plus simple consiste à partir d’une
texture que vous avez conçue et à la déinir comme un objet GUI Texture dans Unity.
Positionnement
La plupart des ordinateurs actuels sont capables de gérer des résolutions égales ou supé-
rieures à 1 024 × 768 pixels. Vous allez donc utiliser cet objet comme une norme pour tester
votre menu. Vous déinirez sa position de façon dynamique avec la classe Screen, ain que
cela fonctionne dans d’autres résolutions. Le menu déroulant situé dans le coin supérieur
gauche du panneau Game (voir Figure 8.2) permet de spéciier différents ratios d’écran et
résolutions. Cliquez dessus et sélectionnez Standalone (1024 × 768) pour aficher un
aperçu de cette résolution.
Figure 8.2
Par défaut, tous les objets GUI Texture se placent à (0.5, 0.5, 0), ce qui correspond au
milieu de l’écran. On se souvient que les éléments 2D utilisent les coordonnées de l’écran
comprises entre 0 et 1.
Déinissez la position de l’objet MainTitle à (0.5, 0.8, 0) dans le composant Transform
du panneau Inspector pour placer le logo du titre principal du jeu en haut et au centre
de l’écran. Maintenant, vous allez ajouter trois boutons à l’aide d’objets GUI Texture
supplémentaires.
220 Développez des jeux 3D avec Unity
La première variable stockera le nom du niveau à charger lorsque le joueur cliquera sur le
bouton sur lequel ce script est appliqué. Le fait de placer ces informations dans une variable
Chapitre 8 Conception de menus 221
permet d’appliquer ce script à tous les boutons, puisque le niveau à charger est déini par
le nom de la variable.
Les deuxième et troisième variables sont déclarées comme des variables de type Texture2D.
Aucune texture en particulier n’est déinie ain qu’elles puissent être assignées ensuite par
glisser-déposer dans le panneau Inspector.
Enin, la variable de type AudioClip permet de lancer la lecture d’un son au clic de la souris.
Ajoutez maintenant la fonction suivante pour déinir la texture utilisée par le composant
GUI Texture lorsque le curseur survole la zone que la texture occupe (on appelle généra-
lement cet état rollover ou survolé) :
function OnMouseEnter(){
guiTexture.texture = rollOverTexture;
}
Le paquet de ressources Menu que vous avez importé contient une texture pour l’état normal
et l’état survolé de chaque bouton. Cette fonction OnMouseEnter() déinit simplement que
la texture utilisée dans le composant correspond à la valeur attribuée à la variable publique
rollOverTexture dans le panneau Inspector. Ain de savoir quand le curseur s’éloigne ou
sort de la limite de cette texture, ajoutez la fonction suivante :
function OnMouseExit(){
guiTexture.texture = normalTexture;
}
Sans cette seconde fonction, la texture rollOverTexture resterait afichée. Le joueur verrait
alors cette option de menu toujours en surbrillance.
Pour gérer le son et le chargement de la scène appropriée, ajoutez la fonction suivante :
function OnMouseUp(){
audio.PlayOneShot(beep);
yield new WaitForSeconds(0.35);
Application.LoadLevel(levelToLoad);
}
La première commande concerne le son. Elle permet d’être sûr qu’il se lancera avant le
chargement de la scène suivante et qu’il ne sera pas coupé. La commande yield placée
entre le déclenchement du son et le chargement de la scène suivante indique au script de
faire une pause du nombre déini de secondes. Vous pouvez ainsi créer rapidement un délai
sans devoir utiliser une commande timer.
La commande yield sert ici à créer un retard, mais elle peut également servir à exécuter
tout un ensemble d’instructions avant la ligne de code suivante. En programmation, on
222 Développez des jeux 3D avec Unity
appelle cette unité de traitement une coroutine pour la distinguer des autres procédures –
les routines.
Ensuite, la commande Application.LoadLevel() charge la scène dans le jeu, en utilisant
la valeur de la variable publique levelToLoad indiquée dans le panneau Inspector pour
trouver le ichier approprié.
Comme vous lancez la lecture d’un son, vous devez vous assurer que l’objet possède
un composant AudioSource en ajoutant la ligne RequireComponent suivante à la in du
script :
@script RequireComponent(AudioSource)
Cliquez sur File > Save dans l’éditeur de script puis revenez dans Unity. Sélectionnez
l’objet PlayBtn dans le panneau Hierarchy, puis cliquez sur Component > Scripts >
Main Menu Btns pour lui appliquer le script que vous venez d’écrire. Le script doit alors
apparaître sur la liste des composants de l’objet PlayBtn dans le panneau Inspector. En
raison de la ligne RequireComponent, l’objet dispose également d’un composant Audio
Source.
Figure 8.3
Chapitre 8 Conception de menus 223
Tester le bouton
Cliquez sur le bouton Play pour tester la scène. Lorsque vous placez le curseur sur le
bouton Play Game, la texture PlayBtnOver doit s’aficher (le texte s’afiche en couleur
et s’accompagne d’un motif de lamme sur la droite). Lorsque vous éloignez le curseur du
bouton, la texture par défaut doit s’aficher de nouveau.
Cliquez maintenant sur le bouton. Le message suivant s’afiche alors dans la console
d’erreur au bas de l’écran :
Level Island Level couldn’t be loaded because it is not added to the build
settings (Le niveau Island Level n’a pas pu être chargé car il n’est pas ajouté aux
paramètres Build).
Unity cherche ainsi à s’assurer que vous n’oublierez pas d’ajouter tous les niveaux inclus
dans les paramètres Build Settings. Ces paramètres de compilation correspondent aux
paramètres d’exportation de votre jeu ini ou de la version de test. Ils doivent contenir
la liste de toutes les scènes incluses dans le jeu. Pour corriger cette erreur, cliquez sur le
bouton Play pour arrêter le test du jeu puis sur File > Build Settings.
À la section Scenes to build du panneau Build Settings, cliquez sur le bouton Add
Current pour ajouter la scène Menu sur laquelle vous travaillez actuellement. L’ordre
des scènes sur la liste, représenté par le nombre à droite du nom de la scène, indique l’ordre
dans lequel ces scènes apparaîtront dans le jeu. Vous devez vous assurer que la première
scène qui se chargera sera toujours en position 0.
Faites glisser la scène Island Level du panneau Project sur la liste actuelle des scènes
du panneau Build Settings ain qu’elle apparaisse sous la scène Menu.unity (voir
Figure 8.4).
Figure 8.4
après la lecture du son menu_beep. Cliquez de nouveau sur le bouton Play pour arrêter le
test et revenir à la scène Menu.
Lorsque cette variable sera déinie à true, le clic du bouton – la fonction OnMouseUp() –
exécutera la commande quit(). Lorsqu’elle sera déinie à false – son état par défaut – le
niveau assigné à la variable levelToLoad se chargera.
Pour cela, vous devez restructurer la fonction OnMouseUp() avec une instruction if else,
comme le montre l’extrait de code suivant :
function OnMouseUp(){
audio.PlayOneShot(beep);
yield new WaitForSeconds(0.35);
if(QuitButton){
Chapitre 8 Conception de menus 225
Application.Quit();
}
else{
Application.LoadLevel(levelToLoad);
}
}
La fonction ainsi modiiée lance la lecture du son et la commande yield (pause) quel
que soit le bouton sur lequel on a cliqué. Toutefois, il existe maintenant deux options :
si quitButton est true, alors la commande Application.Quit() est appelée ; dans le cas
contraire (else), le niveau est chargé normalement.
Cliquez sur File > Save dans l’éditeur de script puis revenez dans Unity.
Sélectionnez la texture QuitBtn dans le dossier Menu du panneau Project puis cliquez
sur GameObject > Create Other > GUI Texture pour créer un objet nommé QuitBtn
dans le panneau Hierarchy. Déinissez ensuite sa position à (0.5, 0.4, 0) dans le composant
Transform du panneau Inspector.
L’objet QuitBtn étant toujours sélectionné dans le panneau Hierarchy, cliquez sur
Component > Scripts > Main Menu Btns pour lui attacher le script. Déinissez ensuite
les valeurs des variables publiques dans le panneau Inspector comme précédemment, en
laissant vide le champ de la variable level To Load, puis activez l’option de la nouvelle
variable Quit Button.
Voici le script dans son intégralité pour que vous puissiez vériier le vôtre :
var levelToLoad : String;
var normalTexture : Texture2D;
var rollOverTexture : Texture2D;
var beep : AudioClip;
var QuitButton : boolean = false;
function OnMouseEnter(){
guiTexture.texture = rollOverTexture;
}
function OnMouseExit(){
guiTexture.texture = normalTexture;
}
function OnMouseUp(){
audio.PlayOneShot(beep);
yield new WaitForSeconds(0.35);
if(QuitButton){
Application.Quit();
}
else{
226 Développez des jeux 3D avec Unity
Application.LoadLevel(levelToLoad);
}
}
@script RequireComponent(AudioSource)
Cliquez maintenant sur File > Save Scene, pour mettre à jour le projet, puis sur le bouton
Play pour tester le menu. La scène Island Level doit se charger lorsque vous cliquez sur
le bouton Play Game. Un clic sur le bouton Instructions entraîne l’afichage de l’erreur
"level could not be loaded" (le niveau ne peut pas être chargé), comme nous l’avons vu
précédemment, puisque cette scène n’a pas encore été créée. Le bouton Quit Game ne
provoque aucune erreur mais ne produit aucun effet dans Unity ; vous ne pourrez pas tester
son fonctionnement tant que vous n’aurez pas créé une version complète du jeu.
N’oubliez pas de cliquer de nouveau sur le bouton Play pour terminer le test. La création
d’un menu par la première méthode est terminée.
Une commande de débogage peut être enregistrée sur une liste pour aficher des messages
dans la console d’erreur. Elle se présente généralement comme suit :
Debug.Log("Cette partie fonctionne !");
En écrivant cette ligne de code à l’endroit où vous prévoyez que le script s’exécutera, vous
pouvez découvrir si certaines parties de celui-ci fonctionnent effectivement. Si vous la
placez après la commande Application.Quit() dans notre exemple, vous aurez alors la
preuve que la commande s’exécute sans problème. Ajoutez cette ligne à votre script comme
dans l’extrait de code suivant :
if(QuitButton){
Application.Quit();
Debug.Log("Cette partie fonctionne !");
}
Chapitre 8 Conception de menus 227
Cliquez sur File > Save dans l’éditeur de script pour enregistrer le script, puis revenez dans
Unity. Cliquez sur le bouton Play pour tester de nouveau le menu. Cliquez sur le bouton
Quit Game pour aficher le message de la commande de débogage au bas de l’interface
de Unity. Si nécessaire, appuyez sur Cmd/Ctrl+Maj+C pour ouvrir la console de Unity et
aficher le message (voir Figure 8.5).
Figure 8.5
Cette technique peut être très utile pour diagnostiquer des problèmes dans les scripts. Elle
l’est aussi lorsque vous concevez un script de façon théorique sans indiquer les véritables
commandes.
Vous allez maintenant voir comment créer un menu fonctionnel à l’aide de la fonction
OnGUI() (cette fonction est appelée GUI 2.0 system dans Unity car elle est apparue dans
la version 2.0 du programme).
Ce script crée la même variable beep que dans la première méthode, puis une variable pour
la ressource GUI skin à appliquer et enin deux variables numériques permettant de déinir
la taille globale de la zone occupée par l’interface graphique.
Chapitre 8 Conception de menus 229
La fonction OnGUI()
Ajoutez ensuite la fonction suivante :
function OnGUI(){
GUI.skin = menuSkin;
}
Ainsi, l’aspect de tous les éléments GUI placés dans cette fonction OnGUI() (les boutons
et les formulaires, notamment) sera régi par le style de thème (skin) appliqué à la variable
menuSkin. Il est alors facile de permuter les skins et donc de modiier totalement l’appa-
rence de l’interface graphique en une seule opération.
Leur valeur est égale au résultat d’une soustraction composée de deux parties :
((Screen.width * 0.5) - (areaWidth * 0.5));
Dans la ligne qui précède, (screen.width * 0.5) utilise le paramètre width (largeur) de la
classe Screen (écran) pour obtenir la largeur actuelle de l’écran. En divisant ensuite cette
valeur par deux, on obtient le centre de l’écran.
Notez que le script utilise * 0.5 plutôt que /2. En effet, une multiplication néces-
Info site environ cent cycles CPU de moins qu’une division pour obtenir des valeurs
dans Unity.
230 Développez des jeux 3D avec Unity
(areaWidth * 0.5) prend la largeur de la zone occupée par l’interface graphique et trouve
son centre en divisant cette valeur par deux. On soustrait ensuite celle-ci du centre de
l’écran car le point d’origine du tracé des zones GUI se trouve toujours à gauche. Cette
zone serait par conséquent décalée sur la droite si elle était tracée depuis le centre de l’écran
(voir Figure 8.6).
Zone
GUI
Zone GUI
En soustrayant la moitié de la largeur de l’interface graphique, on obtient une position
centrale (voir Figure 8.7).
Figure 8.7
Centre de l'écran
Zone
GUI
Les deux parties de la somme sont placées entre parenthèses ain que la soustraction porte
sur leur résultat, qui devient la valeur de la variable. Ce processus se répète ensuite pour
une seconde variable, screenY, ain de déinir la position verticale de l’interface graphique.
Il est essentiel de déinir la zone occupée par l’interface graphique pour la classe GUILayout.
Sans cela, la fonction OnGUI() suppose que vous tracerez un menu sur toute la surface de
l’écran, depuis son coin supérieur gauche. Vous devez donc utiliser la commande Begin-
Area() et préciser quatre paramètres :
GUILayout.BeginArea(Rect(distance depuis la gauche de l’écran, distance depuis
le haut de l'écran, largeur, hauteur));
Ajoutez la ligne suivante dans la fonction OnGUI() à la suite des deux variables privées que
vous venez de déclarer :
GUILayout.BeginArea (Rect (ScreenX,ScreenY, areaWidth, areaHeight));
Le dessin de la zone doit également être fermé à l’aide de la commande EndArea(). Cela
marquant la in du tracé de la zone, tout le code de l’interface graphique doit se trouver
avant cette ligne dans la fonction. Insérez plusieurs lignes après la commande BeginArea(),
puis ajoutez la ligne suivante pour terminer le tracé de l’interface graphique :
GUILayout.EndArea();
Un nouveau bouton GUILayout.Button est réalisé sur lequel est inscrit le mot Play. En
plaçant cette instruction dans une condition if, le script crée non seulement le bouton
mais indique également à Unity l’action à effectuer lorsqu’on clique dessus. Cette instruc-
tion appelle une fonction personnalisée nommée OpenLevel() possédant un seul paramètre
– le nom du niveau. Vous écrirez la fonction OpenLevel() une fois la fonction OnGUI()
complétée.
Ajoutez ensuite les deux conditions suivantes pour créer les deux autres boutons :
if(GUILayout.Button ("Instructions")){
OpenLevel("Instructions");
}
if(GUILayout.Button ("Quit")){
Application.Quit();
}
Cette fonction contient un paramètre nommé level de type String. Cela signiie que, tant
que l’on passe une chaîne de caractères pour appeler la fonction, on peut ensuite utiliser
le terme level pour désigner le texte transmis. Or, dans la fonction OnGUI(), vous venez
d’ajouter l’appel suivant :
OpenLevel("Island Level");
Dans cet exemple, les mots "Island Level" sont passés au paramètre level de la fonction
OpenLevel(). Notez qu’il est inutile d’écrire level = "Island Level" puisque le script
sait qu’il doit appliquer ce texte au paramètre de la fonction OpenLevel(). Une erreur
s’afiche si le type de données transmis n’est pas le bon (un chiffre ou un nom de variable,
par exemple), car seules les données de type String sont appropriées pour le paramètre
level.
Le script lira la chaîne de caractères transmise chaque fois que le paramètre level sera
utilisé.
Ajoutez maintenant les trois commandes suivantes dans cette fonction :
audio.PlayOneShot(beep);
yield new WaitForSeconds(0.35);
Application.LoadLevel(level);
Vous avez utilisé ces commandes dans la méthode 1. Vous pouvez vous y reporter, si néces-
saire, mais la différence essentielle à noter ici tient à l’utilisation du paramètre level pour
passer la chaîne de caractères dans la commande Application.LoadLevel(). Pour complé-
ter le script, assurez-vous que la séquence audio sera lancée en ajoutant la ligne Require-
Component habituelle à la in du script :
@script RequireComponent(AudioSource)
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
Voici le script en intégralité si vous souhaitez vériier que vous n’avez pas fait d’erreur :
var beep : AudioClip;
var menuSkin : GUISkin;
Chapitre 8 Conception de menus 233
Figure 8.8
Vous allez donc lui appliquer un style pour améliorer son apparence à l’aide des ressources
GUI skins.
Pour cela, une ressource GUI skin doit être assignée à la variable menuSkin. Sélectionnez
le dossier Menu dans le panneau Project, puis cliquez sur le bouton Create et sélection-
nez GUI Skin dans le menu déroulant. Renommez MainMenu la nouvelle ressource New
GUISkin.
Le premier paramètre – Font (police) – est commun à tous les éléments régis par le thème
(skin). Pour commencer, sélectionnez la police utilisée dans le jeu (la police Sugo si vous
avez pris la même que nous) dans le panneau Project et déposez-la sur ce paramètre.
Ce thème (skin) va vous servir à déinir le style des éléments boutons. Cliquez sur la lèche
grise à gauche de l’élément Button du composant GUISkin dans le panneau Inspector
pour aficher ses paramètres (voir Figure 8.9).
Figure 8.9
Cliquez sur la lèche grise qui précède les paramètres Normal, Hover et Active ain
d’aficher les options Background et Text Color de chacun d’eux (voir Figure 8.10).
Le paramètre Background déinit la texture utilisée pour le fond du bouton – par défaut,
Unity utilise une image aux coins arrondis et légèrement différente pour les états Hover et
Active ain de les mettre en surbrillance. Conservez-les pour l’exemple de ce livre, mais
n’hésitez pas à essayer d’autres couleurs lorsque vous créerez les menus de vos propres
jeux. Pour le moment, cliquez sur chaque bloc de couleur de l’option Text Color puis,
avec la pipette, choisissez une couleur pour les états Normal, Hover (au survol) et Active
(au clic de la souris) du bouton.
236 Développez des jeux 3D avec Unity
Figure 8.10
Afichez ensuite les options du paramètre Padding et donnez la valeur 6 aux options Top et
Bottom pour augmenter l’espace entre les bords supérieur et inférieur du bouton et le texte
lui-même. Ce paramètre fonctionne de la même façon qu’avec les CSS.
Pour espacer davantage les boutons verticalement, vous devez augmenter la marge du bas.
Pour cela, afichez les options du paramètre Margin, puis donnez la valeur 10 à l’option
Bottom.
Maintenant que vous avez ajusté ces paramètres, vous êtes prêt à les appliquer au script
GUI. Sélectionnez l’objet Menu2 dans le panneau Hierarchy, puis faites glisser l’ob-
jet MainMenu depuis le panneau Project sur la variable publique Menu skin dans le
composant Main Menu GUI2.
Cliquez sur le bouton Play pour vériier que le skin a été appliqué et pour aficher le rendu
du script GUI (voir Figure 8.11).
Figure 8.11
Le menu a maintenant un aspect plus professionnel et il s’intègre mieux au logo du jeu car
sa police est la même que celle du jeu. Le menu complet doit maintenant ressembler à celui
de la Figure 8.12.
Chapitre 8 Conception de menus 237
Figure 8.12
Cliquez sur le bouton Play pour terminer le test du jeu puis sur File > Save Scene dans
Unity.
En résumé
Nous venons d’étudier les deux principales méthodes de création des éléments d’interface
dans Unity : les scripts GUI et les GUI Texture. Vous devriez maintenant savoir comment
implémenter l’une ou l’autre méthode pour réaliser des interfaces. Nous n’avons abordé ici
que les notions essentielles dont vous aurez besoin chaque fois que vous écrirez un script
GUI, mais cette méthode offre beaucoup plus de possibilités.
Il vous reste encore à créer la scène Instructions contenant des informations destinées
au joueur. Ne vous inquiétez pas, vous allez le faire au prochain chapitre en découvrant de
nouvelles techniques d’animation, tout en apportant certaines retouches au jeu lui-même.
9
Dernières retouches
Vous allez ici apporter les dernières retouches à l’île ain de transformer ce simple exemple
de jeu en un produit prêt à être déployé. Jusqu’à présent, nous vous avons présenté un seul
exemple à la fois ain que vous appreniez différentes compétences. Vous allez maintenant
revoir certaines des notions déjà abordées et voir en détail la façon d’ajouter certains effets
qui ne sont pas essentiels à la jouabilité, ce qui explique pourquoi il est préférable de les
réaliser à la in du cycle de développement.
Un jeu repose avant tout sur ses mécanismes de fonctionnement. Vous devez mettre en
place ses éléments physiques fonctionnels avant de pouvoir ajouter des illustrations et
améliorer l’aspect visuel de l’environnement. Dans la plupart des cas, vous serez contraint
par le temps pour créer votre jeu, que cela soit de votre fait ou imposé par l’éditeur pour
lequel vous travaillez. Vous devez consacrer tout votre temps à l’élément le plus important
du jeu – le gameplay (la jouabilité) – et procéder aux dernières retouches à la toute in du
cycle de développement seulement.
Pour les besoins de cet ouvrage, nous partons du principe que les mécanismes de votre jeu
sont terminés et fonctionnent comme prévu. Voyons maintenant ce que vous pouvez ajouter
à l’environnement de l’île et du jeu en général pour l’améliorer.
240 Développez des jeux 3D avec Unity
Le volcan
Pour cette étape, vériiez que la scène Island Level est ouverte dans Unity. Si ce n’est
pas le cas, double-cliquez sur son ichier dans le panneau Project ou cliquez sur File >
Open Scene, puis sélectionnez-la dans le dossier Assets. Les ichiers de scène sont faciles
à repérer car ils utilisent le logo du programme Unity comme icône.
Au Chapitre 2, "Environnements", vous avez créé une île et le cratère d’un volcan avec
l’éditeur de terrain. Pour rendre ce volcan un peu plus réaliste, vous allez lui ajouter un
panache de fumée et une source audio mono, qui reproduit le bouillonnement de la lave en
fusion. Grâce à ces éléments sonores et visuels, l’environnement devient plus dynamique et
réaliste, ce qui devrait améliorer le sentiment d’immersion du joueur dans le jeu.
Cliquez sur GameObject > Create Other > Particle System pour créer un système
de particules dans Unity. Assurez-vous ensuite que ce système de particules, Particle
System, est sélectionné dans le panneau Hierarchy, puis renommez-le Volcano Smoke.
Dans ce cas, vous devez utiliser l’axe 3D du panneau Scene. Commencez par cliquer sur
l’axe Y (vert) de l’axe 3D pour passer de la vue Perspective à une vue du dessus de l’île.
Le mot Top s’afiche alors sous l’axe 3D.
Figure 9.1
Pour voir où se trouve le système de particules, assurez-vous qu’il est sélectionné dans le
panneau Hierarchy, puis sélectionnez l’outil Transform (touche W) ain d’aficher ses
axes dans le panneau Scene.
Le système de particules a été créé au centre de la vue actuelle dans le panneau Scene,
aussi devez-vous le repositionner à l’intérieur du volcan dans cette vue du dessus (Top).
Vous devez voir à la fois les axes du système de particules et le volcan lui-même. Si vous
devez zoomer en arrière, activez l’outil Hand (touche Q), appuyez sur Cmd/Ctrl puis
faites glisser la souris vers la gauche. Sélectionnez ensuite l’outil Transform (touche W) de
nouveau pour aficher les poignées d’axes de l’objet.
À l’aide de l’outil Transform, faites glisser l’une après l’autre les poignées des axes X
(rouge) et Z (bleu) pour placer le système de particules au centre du cratère (voir Figure 9.2).
Figure 9.2
242 Développez des jeux 3D avec Unity
Ne vous inquiétez pas si la poignée d’axe que vous sélectionnez s’afiche en jaune, il s’agit
toujours de la bonne poignée !
Cliquez ensuite sur la poignée de l’axe X (rouge) sur l’axe 3D en haut du panneau Scene
ain d’aficher une vue latérale de l’île. Avec l’outil Transform, faites glisser la poignée
d’axe Y (vert) du système de particules pour le placer au centre du volcan (voir Figure 9.3).
Figure 9.3
À la igure précédente, notez que la poignée d’axe verte est actuellement sélectionnée et
s’afiche donc en jaune. Enin, cliquez sur le cube blanc au centre de l’axe 3D en haut du
panneau Scene pour aficher de nouveau la vue en perspective.
Figure 9.4
Prenez maintenant le temps de régler ces paramètres ain que le système de particules s’in-
tègre au mieux à votre terrain.
Chapitre 9 Dernières retouches 245
Tester le volcan
Maintenant que le volcan est terminé, vous devez tester l’eficacité des dernières modii-
cations apportées. Cliquez d’abord sur File > Save Scene, ain de vous assurer de ne pas
perdre votre travail, puis sur le bouton Play et marchez jusqu’au volcan. Les particules
devraient s’élever dans le ciel. Plus vous approchez du volcan et plus le volume sonore
devrait augmenter. S’il n’est pas assez fort à votre goût, modiiez simplement les valeurs
du paramètre Volume ; s’il ne porte pas assez loin, diminuez la valeur du paramètre Rolloff
Factor dans le composant Audio Source.
Souvenez-vous que toutes les modiications que vous apportez dans le panneau
ce inSPector lors du test du jeu sont annulées lorsque vous cliquez de nouveau sur
Astu
le bouton Play pour interrompre le test. Après les avoir testées, vous devez donc
de nouveau entrer ces valeurs dans le panneau inSPector lorsque vous avez
cessé de tester le jeu.
Pour les tests, vous souhaiterez peut-être augmenter la vitesse de déplacement de l’objet
First Person Controller ain d’atteindre les différentes parties de l’île plus rapidement.
Pour cela, sélectionnez cet objet dans le panneau Hierarchy pendant le test du jeu. Donnez
à la variable publique Speed du composant FPSWalker(script) la valeur souhaitée. Ce
paramètre est modiié uniquement pour la durée du test et reprend sa valeur précédente
lorsque vous cliquez de nouveau sur le bouton Play. Vous pouvez donc tout à fait déinir
une vitesse totalement irréaliste pour le test sans modiier la vitesse du personnage dans
le jeu.
Traînées de lumière
Vous allez maintenant améliorer l’aspect visuel du jeu en ajoutant des traînées de lumière
à l’élément préfabriqué coconut. Ainsi, lorsque le joueur lancera les noix de coco, une
traînée lumineuse suivra la trajectoire du projectile, ce qui devrait donner un effet visuel
intéressant.
Project dans le panneau Scene ain de la modiier. Vous pourriez éditer les ressources
directement dans le panneau Project, mais il est préférable de les placer dans la scène ain
de visualiser et de tester l’effet que vous créez. Souvenez-vous que vous pouvez zoomer
directement à l’emplacement de l’objet sélectionné en appuyant sur la touche F lorsque le
curseur se trouve sur le panneau Scene.
Afichez les options du paramètre Colors ain d’animer l’apparition de la traînée en modi-
iant sa couleur et sa visibilité (ses paramètres alpha). Vous conserverez les couleurs de la
texture de lamme et modiierez simplement la transparence de la traînée. Cliquez sur le
premier bloc de couleur, puis modiiez sa valeur A (alpha) à 80. Répétez la même opération
sur les autres blocs de couleur en réduisant chaque fois la valeur alpha de 20, jusqu’à ce
que la dernière soit égale à 0.
Figure 9.5
Figure 9.6
Les autres paramètres peuvent être laissés à leurs valeurs par défaut. Le paramètre Min
Vertex Distance déinit la distance la plus courte entre deux points de la ligne – plus le
nombre de points est important et plus la ligne est détaillée, mais plus son coût est élevé.
Le paramètre Autodestruct n’a pas besoin non plus d’être activé, car le script Coconut
Tidy que vous avez écrit au Chapitre 6, "Instanciation et corps rigides" est attaché à cet
objet et gère déjà la suppression de ces éléments préfabriqués.
Chapitre 9 Dernières retouches 249
Figure 9.7
Une fois l’élément préfabriqué mis à jour, vous n’avez plus besoin de l’instance dans la
scène. Sélectionnez-la puis appuyez sur Cmd+Retour arrière (Mac OS) ou Maj+Suppr
(Windows).
Pour visualiser l’effet, testez et essayez le mini-jeu de lancer de noix de coco. Vous devriez
voir une traînée lamboyante suivre chaque noix de coco que vous lancez.
améliore le réalisme visuel du terrain. Vous avez déjà vu les paramètres Far Clip Plane
au Chapitre 3, "Personnages jouables", lorsque vous avez étudié l’objet First Person
Controller. Maintenant, vous allez ajuster cette valeur pour réduire la distance à laquelle
la caméra procède au rendu des objets et ainsi améliorer les performances du jeu.
∑ Cliquez sur la lèche grise à gauche de l’objet First Person Controller dans le
panneau Hierarchy pour aficher ses objets enfants.
∑ Sélectionnez l’objet enfant Main Camera.
∑ Donnez la valeur 600 au paramètre Far Clip Plane du composant Camera dans le
panneau Inspector. En réduisant cette distance, exprimée en mètres, vous diminuez la
portée de la vision du joueur, mais la brume masquera cette différence.
Cliquez sur Edit > Render Settings pour remplacer le panneau Inspector par le
panneau Render Settings. Activez l’option Fog, puis cliquez sur le bloc de couleur à
droite du paramètre Fog Color pour déinir la couleur et la transparence du brouillard.
Déinissez une valeur Alpha (A) de 60 % environ et une valeur Fog Density de 0,004
(voir Figure 9.8).
Figure 9.8
Avec les valeurs par défaut ou des valeurs supérieures pour les paramètres alpha de Fog
Color et de Fog Density, le brouillard réduirait tant la portée de la vision du joueur que les
particules du volcan deviendraient invisibles, à moins qu’il ne se tienne tout près du volcan.
La lumière ambiante
Le panneau Render Settings dispose également d’un paramètre Ambient Light pour la
scène. Bien que l’objet Directional Light gère l’éclairage principal, en agissant comme
le soleil dans notre exemple, le paramètre Ambient Light permet de déinir la luminosité
générale et donc de simuler différentes heures du jour ou de la nuit. Cliquez sur le bloc de
couleur à droite de ce paramètre puis, avec la pipette de la boîte de dialogue Color, testez
différentes valeurs.
Chapitre 9 Dernières retouches 251
La scène Instructions
Pour inaliser le jeu, vous allez compléter le menu que vous avez réalisé au Chapitre 8, en
créant la scène Instructions que le joueur devra lire. Pour cela, vous implémenterez une
animation à l’aide de scripts et vous utiliserez une nouvelle commande appelée Linear
interpolation.
Pour que la scène Instructions imite le reste du menu, vous prendrez la scène Menu
comme point de départ. Avant cela, cliquez sur File > Save Scene pour vous assurer que la
scène Island Level est enregistrée. Sélectionnez ensuite la scène Menu dans le panneau
Project puis appuyez sur Cmd/Ctrl+D pour la dupliquer.
Renommez cette copie Instructions puis double-cliquez sur son icône pour l’ouvrir.
Figure 9.9
Le nom de ces variables indique leurs fonctions respectives – les variables startPosi-
tion et endPosition contrôlent la position du texte selon les coordonnées de l’écran (d’où
la valeur de –1 pour la position de départ, c’est-à-dire en dehors de l’écran). Il s’agit de
variables publiques que vous pourrez ajuster dans le panneau Inspector. La variable speed
servira à multiplier la vitesse de l’animation au cours du temps, donc sa valeur par défaut
est 1.
Chapitre 9 Dernières retouches 253
Enin, la variable StartTime de type loat est utilisée uniquement dans le script, aussi est-
elle déclarée comme privée. Elle stockera la valeur de temps déjà écoulée au moment où
la scène est chargée. Sans cela, les instructions seraient présentes à l’écran si le joueur
revenait à cette scène, car la valeur de temps que vous allez utiliser décompte à partir du
premier chargement du jeu.
Pour déinir la valeur de cette variable, vous enregistrerez la commande time de Unity lors
du chargement de la scène à l’aide de la fonction suivante :
function Start(){
StartTime = Time.time;
}
À présent, la variable StartTime utilise cette valeur au chargement de la scène. Elle va vous
servir à créer l’animation du texte.
Insérez quelques lignes avant l’accolade de fermeture de la fonction Update() puis ajoutez
la ligne suivante :
transform.position.x = Mathf.Lerp(startPosition, endPosition,
„ (Time.time-StartTime)*speed);
Puis il déinit cette valeur comme égale à une fonction mathématique – Mathf –, appelée
lerp (pour linear interpolation), qui effectue une interpolation linéaire entre deux valeurs.
Les valeurs transmises à cette fonction sont déinies par les variables startPosition et
endPosition, si bien que la fonction lerp fournit un chiffre compris entre ces deux nombres
pour la position du texte sur l’axe X.
Le troisième paramètre de la fonction lerp correspond à l’importance de l’interpolation ;
avec une valeur de 1, la valeur renvoyée passe complètement de la valeur de début à la
valeur de in, tandis qu’aucun changement ne se produit avec une valeur de 0. Comme cette
interpolation doit se dérouler dans le temps, le script n’utilise pas une seule valeur mais la
commande prédéinie time.time de Unity pour compter le temps écoulé et lui soustraire la
valeur de StartTime déinie plus tôt – une réinitialisation réelle de sa valeur ain de compter
à partir de 0. Enin, cette ligne modiie le temps en multipliant le résultat par la variable
speed. Actuellement, cette variable speed est déinie à 1, donc aucun changement ne sera
apporté, mais toute valeur supérieure à 1 aura pour effet d’augmenter la vitesse, et toute
valeur inférieure à 1 de la diminuer.
254 Développez des jeux 3D avec Unity
Cette commande doit être placée dans la fonction Update(), car les changements progres-
sifs produits par la fonction lerp doivent s’effectuer à chaque image. Cela ne fonctionnerait
pas si vous la placiez dans une fonction Start() par exemple.
Voici le script complet pour que vous puissiez le vériier :
var startPosition : loat = -1.0;
var endPosition : loat = 0.5;
var speed : loat = 1.0;
private var StartTime : loat;
function Start(){
StartTime = Time.time;
}
function Update () {
transform.position.x = Mathf.Lerp(startPosition, endPosition, (Time.time-
StartTime)*speed);
}
Cliquez sur File > Save dans l’éditeur de script puis revenez dans Unity.
Maintenant, vous allez appliquer le script et régler les paramètres des variables publiques
dans le panneau Inspector pour vous assurer qu’il réalise ce que vous souhaitez. Sélec-
tionnez l’objet Instructions Text dans le panneau Hierarchy puis cliquez sur Compo-
nent > Scripts > Animator pour ajouter ce script comme composant.
Les valeurs par défaut des variables publiques déinies dans le script s’afichent.
Figure 9.10
Pour voir cet effet en action, vous devez lancer la lecture de la scène. Mais avant, vous
devez supprimer le menu qui a été dupliqué depuis la scène Menu originale. Si vous avez
choisi le menu basé sur l’objet GUI Texture, vous devez alors désactiver les trois objets
boutons. Si vous utilisez le menu basé sur le script, désactivez l’objet sur lequel ce script
est attaché en tant que composant. Reportez-vous au chapitre précédent pour en savoir plus
sur la désactivation des éléments, si nécessaire.
Chapitre 9 Dernières retouches 255
Une fois le menu désactivé, revenez à l’objet Instructions Text. Déinissez le paramètre
Anchor sur Middle Center et le paramètre Alignment sur Left dans le composant
GUIText, puis cliquez sur le bouton Play pour visualiser l’animation. Votre texte doit se
déplacer sur l’axe X et apparaître depuis la gauche de l’écran pour se placer à une position
centrale de 0,5. Cliquez de nouveau sur Play pour terminer le test avant de poursuivre.
Pour que l’apparition du texte se produise de la droite vers la gauche, la valeur de la
variable publique Start Position doit être supérieure à 1,0 – puisque cela correspond aux
coordonnées du bord droit de l’écran. En revanche, pour que l’animation se déroule sur
l’axe Y, vous devriez modiier l’axe dans le script, en indiquant par exemple : transform.
position.y = Mathf (...).
Revenir au menu
La scène sur laquelle vous travaillez est distincte du menu principal et vous avez donc
besoin d’intégrer un bouton qui permettra au joueur de revenir à la scène Menu elle-même.
Sinon, il resterait coincé sur cet écran Instructions !
Pour cela, vous choisirez la technique d’écriture de scripts GUI abordée au chapitre précé-
dent et vous dupliquerez une partie des travaux existants, ce qui vous fera gagner du temps.
Sélectionnez le script MainMenuGUI2 dans le dossier Scripts du panneau Project, puis
dupliquez-le (Cmd/Ctrl+D). Unity numérote les objets et les ressources qu’il crée, cette
copie se nomme donc MainMenuGUI3. Renommez ce script BackButtonGUI, puis double-
cliquez sur son icône pour l’ouvrir dans l’éditeur de script.
Dans la première instruction if de la fonction OnGUI(), modiiez le texte sur le bouton pour
que le mot Back s’afiche au lieu de Play. Remplacez ensuite la chaîne de caractères Island
Level dans l’appel à la fonction OpenLevel() par Menu. La condition doit être :
if(GUILayout.Button ("Back")){
OpenLevel("Menu");
}
Ce script doit seulement générer un bouton ; vous devez supprimer les deux autres instruc-
tions if de la fonction pour ne conserver que celle qui concerne le retour à la scène Menu. Le
seul problème concerne ici le positionnement du bouton. Comme nous utilisons la variable
screenY du script MainMenuGUI2, la zone de l’interface graphique dans laquelle est
dessiné le bouton se trouve au centre de l’écran, si bien que ce dernier risque de chevaucher
le texte. Pour contourner ce problème et décaler le bouton vers le bas, modiiez la décla-
ration de la variable screenY pour qu’elle utilise une valeur légèrement inférieure :
var ScreenY = ((Screen.height / 1.7) - (areaHeight / 2));
Ainsi, le bouton sera placé plus bas que le texte contenant les instructions.
256 Développez des jeux 3D avec Unity
function OnGUI(){
GUI.skin = menuSkin;
var ScreenX = ((Screen.width / 2) - (areaWidth / 2));
var ScreenY = ((Screen.height / 1.7) - (areaHeight / 2));
GUILayout.BeginArea (Rect (ScreenX,ScreenY, areaWidth, areaHeight));
if(GUILayout.Button ("Back")){
OpenLevel("Menu");
}
GUILayout.EndArea();
}
Cliquez sur File > Save dans l’éditeur de script puis revenez à Unity.
Comme pour tous les éléments d’interface gérés par le script, vous devez attacher le script
à un objet pour que ce bouton s’afiche. Aussi, cliquez sur GameObject > Create Empty
pour créer un objet de jeu vide pour ce script. Renommez ensuite ce nouvel objet Back
Button dans le panneau Hierarchy, puis cliquez sur Component > Scripts > Back
Button GUI pour lui attacher le script que vous venez d’écrire. Les valeurs des variables
publiques du script doivent être déinies. Vous devez donc :
∑ faire glisser la séquence audio menu_beep depuis le dossier Menu du panneau Project
sur la variable Beep ;
∑ faire glisser la ressource MainMenu du dossier Menu sur la variable Menu Skin ;
∑ déinir la variable Area Width à 200 ;
∑ déinir la variable Area Width à 75, puisque l’écran ne compte qu’un seul bouton.
Le bouton Back est maintenant terminé. Avant de tester le menu entier, vous devez ajouter
la scène Instructions aux paramètres Build Settings du projet pour que Unity la charge
pendant les tests. Cliquez sur File > Build Settings puis sur le bouton Add Current.
Chapitre 9 Dernières retouches 257
La liste des niveaux dans les paramètres Build Settings doit maintenant correspondre à
celle de la Figure 9.11.
Figure 9.11
Fermez la boîte de dialogue Build Settings puis cliquez sur le bouton Play pour tester
la scène. Le bouton Back doit s’aficher et l’animation de l’apparition du texte se dérouler.
Cliquez sur le bouton Back pour aficher la scène Menu. Si rien de tout cela ne fonctionne,
vériiez que votre script correspond aux changements énumérés précédemment.
La Figure 9.12 illustre l’aspect que doit avoir l’écran présentant les instructions.
Figure 9.12
Terminez le test de la scène, puis cliquez sur File > Save Scene pour la sauvegarder.
258 Développez des jeux 3D avec Unity
La première variable stocke la texture blanche prête à être étirée sur toute la surface de
l’écran. La seconde est un nombre à virgule lottante que vous utiliserez pour stocker une
valeur de temps.
Pour transmettre la valeur Time.time à la variable StartTime lors du chargement du niveau,
ajoutez la fonction suivante à votre script, sous les deux variables :
function OnLevelWasLoaded(){
StartTime = Time.time;
}
Cette variable permet de saisir la durée écoulée car Time.time s’exécute au moment où la
première scène du jeu (le menu) est chargée. Ce menu est le premier élément du jeu que
voit le joueur, aussi Time.time n’est pas égal à 0 quand la scène Island Level se charge.
Chapitre 9 Dernières retouches 259
Vous soustrairez ensuite cette valeur de la variable qui stocke le temps courant ain d’obtenir
une valeur à partir de laquelle compter.
Insérez le script suivant dans la fonction Update() :
if(Time.time-StartTime >= 3){
Destroy(gameObject);
}
Cette instruction if contrôle la valeur actuelle de Time.time et lui soustrait le temps écoulé
au chargement de la scène courante, StartTime. Si cette valeur est supérieure ou égale à 3,
alors le script détruit l’objet de jeu sur lequel ce script est attaché après trois secondes. En
effet, une fois que l’effet fondu s’est produit, cet objet n’a plus aucune utilité dans la scène.
Ici, le script s’adresse directement à la classe GUI. La première ligne désigne le paramètre
color et le déinit comme égal à une constante prédéinie de la classe Color nommée white.
Une fois cette couleur déinie, le script utilise la commande GUI.color.a pour désigner
son paramètre alpha – sa visibilité. La même commande Mathf.Lerp que vous avez utilisée
pour animer l’objet GUI Text plus tôt crée ici une interpolation de la valeur alpha de 1.0
(entièrement visible) à 0.0 (invisible). Le troisième paramètre de la boucle déinit la durée
de cette interpolation. Comme celle-ci dépend du résultat de la soustraction Time.time-
StartTime, le décompte commence effectivement à 0.0, puis sa valeur augmente à mesure
que le temps passe. Ainsi, l’interpolation linéaire évolue dans le temps et produit un effet
de fondu.
La troisième ligne procède au rendu de la texture elle-même, à l’aide de la commande
DrawTexture de la classe GUI. Le paramètre Rect sert à tracer une zone rectangulaire à
partir de 0.0 – le coin supérieur gauche de l’écran – puis à s’assurer que cette texture s’étire
sur la totalité de l’écran à l’aide de screen.width et screen.height. En adaptant ainsi
automatiquement la taille de la texture à celle de l’écran, le fondu fonctionnera quelle que
soit la résolution.
Cliquez sur File > Save dans l’éditeur de script et revenez dans Unity.
260 Développez des jeux 3D avec Unity
Dans Unity, cliquez sur GameObject > Create Empty pour créer un objet GameOb-
ject dans le panneau Hierarchy. Renommez-le Fader puis cliquez sur Component >
Scripts > Fade Texture pour lui attacher le script que vous venez d’écrire. Ensuite, faites
glisser la texture white depuis le dossier Volcano du panneau Project sur la variable
publique theTexture dans le panneau Inspector.
Cliquez sur le bouton Play. L’écran doit s’aficher en blanc puis la scène apparaître
en fondu avant que l’objet white du panneau Hierarchy ne soit supprimé après trois
secondes. Terminez le test, puis cliquez sur File > Save Scene pour sauvegarder le projet.
Notiier la in du jeu
Pour inir, vous allez indiquer au joueur qu’il a terminé avec succès le jeu quand le feu est
allumé, le but à atteindre.
Ouvrez le script PlayerCollisions dans le dossier Scripts du panneau Project puis faites
déiler son contenu vers le bas. Vous allez ajouter quelques commandes supplémentaires
dans la dernière fonction du script, lightire(). Pour cela, insérez quelques lignes avant
son accolade de fermeture, à la suite de cette ligne :
Destroy(GameObject.Find("matchGUI"));
Ces lignes utilisent l’objet GUI TextHints pour aficher à l’écran la chaîne de caractères :
"Vous avez allumé le feu…". La commande yield met ensuite le script en pause pendant
cinq secondes, puis charge le niveau Menu du jeu, ain que le joueur puisse recommencer
la partie.
Cliquez sur le bouton Play et testez le jeu dans son intégralité. Vous devez pouvoir collecter
trois piles, gagner la quatrième en abattant les trois cibles à coups de noix de coco, entrer
dans l’avant-poste, ramasser les allumettes et enin allumer le feu. Le message du script
précédent doit alors s’aficher et vous devez revenir à l’écran du menu principal.
Après avoir vériié cela, arrêtez le test, puis cliquez sur File > Save Scene pour sauvegarder
votre projet.
Chapitre 9 Dernières retouches 261
En résumé
Nous venons de voir comment apporter différentes touches de inition aux jeux. Les effets
visuels, de lumière et les animations abordés ici ne font qu’efleurer la surface de ce qu’il
est possible de faire avec Unity. Cependant, même si Unity permet de polir l’aspect de
votre jeu ain qu’il se démarque vraiment, vous devez garder à l’esprit que ces opérations
s’effectuent uniquement une fois que le gameplay de votre projet est terminé. Comme leur
nom l’indique, les initions sont un excellent moyen de inaliser un projet, mais la jouabilité
doit toujours primer.
À présent que le jeu est terminé, vous verrez au prochain chapitre comment le compiler
et tester différentes versions et vous apprendrez ce que recouvre ce processus de déploie-
ment. Vous découvrirez également certaines optimisations supplémentaires et la manière de
publier votre jeu en tant que développeur indépendant.
10
Compilation et partage
Ain de transformer ce simple exemple de jeu en une version de test, vous devez tenir
compte des différentes plates-formes sur lesquelles il sera déployé et l’adapter à une diffu-
sion sur le Web. La meilleure méthode pour un développeur consiste à partager son travail.
Unity permet de créer différentes versions d’un jeu, à différentes tailles et avec plusieurs
niveaux de compression des textures et des ressources. Vous devez également implémenter
une méthode de détection de la plate-forme pour les jeux destinés au Web. En effet, certains
paramètres devront être ajustés lors du déploiement en ligne, ce qui est inutile pour une
application autonome.
Les versions standard et Pro de Unity permettent de créer des applications autonomes pour
Mac OS et Windows, des widgets pour le Dashboard (Tableau de bord) de Mac OS X ou
des jeux destinés aux navigateurs web (le joueur doit télécharger un plugin).
Au cours de ce chapitre, vous découvrirez de quelle manière personnaliser les ressources
selon que vous créez un jeu destiné au Web ou une application autonome. Vous verrez
comment :
∑ ajuster les paramètres Build Settings ain d’exporter le jeu ;
∑ concevoir une version web et une version autonome du jeu ;
264 Développez des jeux 3D avec Unity
∑ détecter la plate-forme client pour supprimer des éléments dans le jeu destiné au Web ;
∑ partager les jeux avec d’autres personnes et en savoir plus sur le développement dans
Unity.
Figure 10.1
Dans la boîte de dialogue Build Settings, les créations destinées à une utilisation sous
Mac OS sont marquées par le préixe OS X, la génération actuelle de ce système d’exploi-
tation. Plusieurs options sont disponibles car il existe différentes générations de Mac dont
vous devez tenir compte : la génération précédente utilisait le processeur PowerPC tandis
que la génération actuelle s’articule autour des processeurs Intel. Le paramètre Universal
Binary crée un ichier binaire OS X qui peut s’exécuter aussi bien sur les anciens systèmes
PowerPC que sur les nouveaux systèmes Intel. Le ichier est alors plus volumineux, puisque
l’application contient dans les faits deux copies de votre jeu.
Chapitre 10 Compilation et partage 265
Dans notre exemple, la boîte de dialogue Build Settings contient la liste des scènes que
vous avez ajoutées au projet jusqu’à présent, à commencer par la scène Menu. Il est impor-
tant que la première scène vue par le joueur soit le premier élément de la liste Scenes to
build. Si votre menu ou la première scène n’est pas en tête de cette liste, faites glisser le
nom des scènes vers le haut ou vers le bas pour modiier leur ordre d’apparition dans le jeu.
Commençons par examiner les différentes options et voir ce que chacune d’elles permet
d’obtenir.
Les lecteurs web utilisent le navigateur pour charger le code HTML contenant l’appel au
plugin. Par conséquent, le navigateur sollicite déjà le processeur de l’ordinateur sur lequel
le jeu s’exécute. Il est donc conseillé de réduire la résolution du jeu par rapport à celle que
vous utiliseriez pour une application autonome. Le jeu de notre exemple a été conçu avec
une résolution d’entrée de gamme de 1 024 × 768 pixels. Toutefois, lors du déploiement sur
un site web, la taille de l’écran doit être réduite (640 × 480 par exemple). Cela permet de
diminuer la charge sur le processeur car les images qu’il doit créer sont plus petites, ce qui
améliore les performances.
Pour régler ces paramètres, vous devez étudier les paramètres Player Settings. Cliquez
sur Edit > Project Settings > Player pour aficher les paramètres du projet dans le
panneau Inspector. Lors de la inalisation du jeu, votre projet se place effectivement dans
un lecteur – qui appelle lui-même le plugin une fois sur le Web. Les paramètres Player
Settings vous permettent de déinir certains éléments que le joueur utilisera, comme la
résolution de l’écran.
266 Développez des jeux 3D avec Unity
Figure 10.2
Vous devez commencer par indiquer certains détails sur votre projet. Ajoutez le nom de
l’entreprise dans le champ Company Name et le nom du produit dans le champ Product
Name (rien de très oficiel dans notre exemple). Indiquez ensuite la largeur et la hauteur de
l’écran par défaut dans les champs Default Screen Width et Default Screen height,
en entrant 1024 × 768, soit la résolution à laquelle le jeu a été conçu.
Donnez aux paramètres Default Web Screen Width et Default Web Screen Heigth
les valeurs 640 et 480 respectivement (voir Figure 10.2). Le seul autre paramètre important
pour le déploiement du lecteur web, First Streamed Level With Resources, permet
de choisir le premier niveau sur votre liste pour lequel un ensemble de ressources doit
être chargé. Vous pouvez ainsi créer des écrans de chargement dans votre jeu. Si tel est le
cas, vous devez alors utiliser ce paramètre pour choisir le premier niveau qui contient les
ressources à charger en indiquant son numéro sur la liste de la boîte de dialogue Build
Settings.
Dans notre exemple, le premier écran (le menu) contient les ressources de l’île, si bien que
vous pouvez conserver la valeur par défaut, 0, pour ce paramètre. Nous étudierons bientôt
plus en détail les paramètres du lecteur lorsque vous verrez comment créer une application
autonome.
Ce facteur est absolument essentiel lorsque vous présentez votre création sur un portail
de jeux comme www.shockwave.com, www.wooglie.com ou www.blurst.com. Pour ces
sites, votre jeu doit être jouable dès que 1 Mo de données environ a été téléchargé. En
acceptant ces directives, vous augmentez vos chances de voir ces sites présenter votre jeu,
ce qui vous permet de toucher une plus large audience. Pour plus d’informations à ce sujet,
visitez le site web de Unity.
Figure 10.3
268 Développez des jeux 3D avec Unity
Dans l’idéal, les jeux déployés en tant que widgets doivent rester simples. Il est en effet
préférable d’éviter le chargement de nombreuses données dans un widget car ce dernier
reste en mémoire et le jeu se poursuit lorsque le Dashboard est activé et désactivé.
Générer le jeu
Maintenant que vous êtes prêt à générer le jeu, vous devez examiner ces différentes
méthodes de déploiement et adapter votre projet pour le diffuser sur le Web et en tant que
jeu autonome.
if(Application.platform == RuntimePlatform.OSXWebPlayer ||
„ Application.platform == RuntimePlatform.WindowsWebPlayer)
Cette ligne vériie le paramètre platform de la classe Application ain de savoir si le jeu
est en cours d’exécution sous Mac OS (OSXWebPlayer) ou sous Windows (WindowsWeb-
Player) – le symbole || signiie simplement "OU". Autrement dit, si le jeu est en cours
d’exécution sur un lecteur web, le script doit réaliser une opération. Vous devez en outre
combiner cette condition avec une instruction else car le rendu du bouton Quit doit être
effectué si le jeu n’est pas déployé pour le Web.
Localisez l’instruction if chargée de créer le bouton Quit dans la fonction OnGUI() :
if(GUILayout.Button ("Quit")){
Application.Quit();
}
Nous avons laissé une ligne vide lorsque la condition if est satisfaite et placé le code du
bouton Quit dans la partie else, ain qu’il soit créé uniquement si le script détecte que le
jeu ne s’exécute pas sur le Web.
Maintenant localisez les deux instructions if qui procèdent au rendu des boutons Play et
Instructions :
if(GUILayout.Button ("Play")){
OpenLevel("Island Level");
}
if(GUILayout.Button ("Instructions")){
OpenLevel("Instructions");
}
et placez-les dans la partie de l’instruction if que vous venez d’ajouter, ain que le script
soit le suivant :
if (Application.platform == RuntimePlatform.OSXWebPlayer ||
„ Application.platform == RuntimePlatform.WindowsWebPlayer){
if(GUILayout.Button ("Play")){
OpenLevel("Island Level");
}
if(GUILayout.Button ("Instructions")){
OpenLevel("Instructions");
}
}
else{
if(GUILayout.Button ("Quit")){
Application.Quit();
}
}
Ainsi, le script effectue le rendu des boutons Play et Instructions si la détection initiale
découvre que le jeu s’exécute en ligne et le rendu du bouton Quit si le jeu n’est pas en
ligne.
Mais vous avez également besoin des boutons Play et Instructions pour l’application
autonome. Pour cela, copiez et collez la partie du code de ces boutons dans l’instruction
else également. L’instruction de détection terminée doit être la suivante :
if (Application.platform == RuntimePlatform.OSXWebPlayer ||
„ Application.platform == RuntimePlatform.WindowsWebPlayer){
if(GUILayout.Button ("Play")){
OpenLevel("Island Level");
}
Chapitre 10 Compilation et partage 271
if(GUILayout.Button ("Instructions")){
OpenLevel("Instructions");
}
}
else{
if(GUILayout.Button ("Play")){
OpenLevel("Island Level");
}
if(GUILayout.Button ("Instructions")){
OpenLevel("Instructions");
}
if(GUILayout.Button ("Quit")){
Application.Quit();
}
}
Comme vous pouvez le constater, seuls les boutons Play et Instructions sont concer-
nés dans la condition if, tandis que la condition else agit sur le rendu des boutons Play,
Instructions et Quit. Cliquez sur File > Save dans l’éditeur de script puis revenez dans
Unity. Le rendu du bouton Quit s’effectue automatiquement si le jeu n’est pas diffusé sur
le Web.
Vous disposez maintenant d’un ensemble de ressources de scène qui peuvent être placées
sur la liste des paramètres Build Settings avec le niveau Island Level pour le lecteur web
Player ou Web Player Streamed.
Maintenant, voyons comment créer à la fois les versions Web et autonome du jeu.
La Figure 10.4 illustre l’aspect la boîte de dialogue Resolution Dialog par défaut
(version Mac OS) :
Figure 10.4
La plupart des développeurs préfèrent garder cet écran activé, car il permet au joueur de
choisir la résolution et la qualité d’afichage qui correspondent le mieux à son ordinateur.
Cependant, vous pouvez le désactiver si vous souhaitez forcer les utilisateurs à jouer dans
une résolution en particulier.
Pour désactiver cet écran, cliquez sur Edit > Project Settings > Player et sélectionnez
Disabled pour le paramètre Display Resolution Dialog. Enin, vous pouvez activer l’op-
tion Default is Full Screen pour que le jeu s’exécute obligatoirement en mode plein
écran, si vous ne voulez que le jeu s’ouvre dans une fenêtre, comme c’est le cas par défaut.
Néanmoins, les joueurs peuvent toujours aficher la boîte de dialogue Resolution Dialog
en appuyant sur la touche Alt (aussi appelée Option sous Mac OS) lors du lancement de
l’application (ce raccourci peut être très utile pour les versions de test).
Pour intégrer une bannière graphique qui s’afiche dans la partie supérieure de
ce la boîte de dialogue reSolution dialoG, vous devez enregistrer une image de
Astu
432 × 163 pixels dans votre projet, puis la sélectionner dans le menu déroulant
reSolution dialoG banner du panneau Player SettinGS.
Chapitre 10 Compilation et partage 273
Cliquez sur File > Build Settings et veillez à ce que les trois scènes suivantes s’afichent
sur la liste Scenes to build :
∑ Menu.unity
∑ Island Level.unity
∑ Instructions.unity
Si une scène ne igure pas sur la liste, vous pouvez toujours la faire glisser
Info depuis le panneau Project sur la liste build SettinGS.
Il est important que la scène Menu soit en première position sur la liste car elle doit se
charger en premier. Aussi, assurez-vous qu’elle est en position 0.
La compression des textures permet au jeu de se charger plus rapidement mais la première
compilation du jeu peut prendre plus de temps, car les textures sont compressées pour la
première fois.
Sélectionnez le format à utiliser : Windows, pour créer une application pour Windows XP,
Vista 7 et les versions suivantes, ou Mac OS – en tenant compte des processeurs PowerPC,
Intel ou des deux (universal binary).
Cliquez sur le bouton Build au bas de la fenêtre de dialogue pour indiquer où vous souhai-
tez sauvegarder votre jeu. Parcourez ensuite le disque dur jusqu’à l’emplacement de votre
choix, indiquez le nom du jeu dans le champ Nom du fichier ou Enregistrer sous, puis
cliquez sur Enregistrer pour valider.
Attendez ensuite que Unity crée votre jeu. Différentes barres de progression indiquent que
les ressources sont compressées, puis l’avancement de la compilation de chaque niveau.
Une fois le processus terminé, le jeu inalisé, prêt à être utilisé, s’ouvre dans une fenêtre du
système d’exploitation.
Pour lancer le jeu, double-cliquez sur l’application (Mac OS) ou ouvrez le dossier conte-
nant le jeu, puis double-cliquez sur le ichier .exe (Windows). Gardez à l’esprit que, si vous
construisez une version Windows sous Mac OS, ou vice versa, vous ne pouvez pas la tester
en mode natif.
Figure 10.5
Les différences entre les deux versions, comme le manque d’ombres dynamiques dans la
version gratuite, sont énumérées à l’adresse suivante :
http://unity3d.com/unity/licenses.html.
Pour lancer le jeu, ouvrez le ichier HTML dans le navigateur web de votre choix.
Figure 10.6
Comme vous pouvez le constater (voir Figure 10.6), les paramètres de chaque option sont
déinis de manière très différente :
∑ Pixel Light Count. Le nombre de lumières au pixel qui peut être utilisé dans une scène.
Le rendu des lumières dans Unity s’effectue sous la forme d’un pixel ou d’un sommet,
un processus qui améliore l’aspect des pixels mais qui est plus coûteux pour le proces-
seur. Ce paramètre Pixel Light Count permet de déinir le nombre de lumières au
pixel (les autres lumières étant rendues comme des lumières au sommet). C’est pour-
quoi il est déini sur 0 dans le réglage prédéini Fastest, avec lequel la qualité est la
moins élevée.
∑ Shadows. Cette fonctionnalité est seulement effective dans la version Pro de Unity.
Elle permet d’indiquer que le jeu ne doit pas utiliser les ombres dynamiques mais les
ombres aux contours durs seulement ou les ombres aux contours durs et adoucis (les
deux niveaux de qualité de l’ombre).
Chapitre 10 Compilation et partage 277
∑ Shadow Resolution. Ce paramètre, effectif, lui aussi, uniquement dans Unity Pro,
permet de déinir la qualité du rendu des ombres. Cela peut être utile pour améliorer les
performances lorsque plusieurs objets ont des ombres dynamiques dans la scène – choi-
sir une basse résolution permet d’optimiser les ombres sans les désactiver entièrement.
∑ Shadow Cascades. Unity Pro proite de Cascade Shadow Maps pour améliorer l’aspect
des ombres sur les lumières directionnelles dans la scène en utilisant la même carte pour
les ombres sur des zones plus importantes en fonction de la distance. Les zones les plus
proches de la caméra du joueur ont une carte d’ombres plus détaillée, ce qui améliore
la qualité.
∑ Shadow Distance. Analogue au paramètre Far Clip Plane, qui limite la distance de
rendu de la caméra, ce paramètre est un autre niveau de réglage des détails. Il peut être
utilisé pour déinir la distance après laquelle le rendu des ombres n’est pas effectué.
∑ Blend Weights. Sert lorsque des personnages disposent d’une ossature d’animation, en
contrôlant son niveau de complexité. Unity Technologies conseille d’utiliser l’option
2 Bones pour obtenir un bon compromis entre performance et qualité visuelle.
∑ Texture Quality. Comme son nom l’indique, ce paramètre déinit l’importance de la
compression des textures.
∑ Anisotropic Textures. Le iltrage anisotropique peut contribuer à améliorer l’apparence
des textures vues sous un angle prononcé, comme les collines, mais le coût en termes de
performances est important. Gardez à l’esprit que vous pouvez également conigurer le
iltrage de chaque texture dans les paramètres Import Settings des ressources.
∑ Anti Aliasing. Pour adoucir les contours des éléments en 3D, ce qui améliore considé-
rablement l’aspect du jeu. Comme pour les autres iltres cependant, le coût est élevé.
∑ Soft Vegetation. Permet aux éléments de terrain de Unity, comme la végétation et les
arbres, d’utiliser le paramètre alpha blending. Cela donne un meilleur aspect aux
zones transparentes des textures utilisées pour représenter la végétation.
∑ Sync to VBL. Ce paramètre force le jeu à se synchroniser avec le taux de rafraîchis-
sement du moniteur du joueur. En général, cela entraîne une dégradation des perfor-
mances mais permet d’éviter l’effet de "déchirure" entre les éléments dans le jeu : les
sommets semblent mal alignés si bien que les textures s’afichent décalées et séparées
par une coupure horizontale.
278 Développez des jeux 3D avec Unity
Vous pouvez modiier ces réglages prédéinis si cela apporte un avantage pour le joueur,
puisque ce dernier aura la possibilité de les redéinir dans la boîte de dialogue Résolution
Dialog (voir la section "Créer une version autonome" de ce chapitre) lors du lancement du
jeu, à moins que vous n’ayez désactivé cette option. Toutefois, nous vous conseillons, dans
la plupart des cas, d’utiliser les réglages prédéinis de Unity comme guides et de simple-
ment ajuster certains paramètres en particulier, si cela est nécessaire.
Figure 10.7
Dans Unity, cliquez sur Edit > Project Settings > Input pour aficher les axes de
contrôle disponibles dans le panneau Inspector. La valeur Size indique simplement le
nombre de contrôles existants. En augmentant cette valeur, vous pouvez créer vos propres
contrôles. Vous pouvez également cliquer sur la lèche grise à gauche de chaque paramètre
d’entrée pour aficher les axes disponibles et ajuster leurs valeurs.
Chapitre 10 Compilation et partage 279
Figure 10.8
Vous pouvez voir comment lier ces axes dans le script CoconutThrow que vous avez écrit
plus tôt :
if(Input.GetButtonUp("Fire1")
Ici, l’axe Fire1 est référencé par son nom. En changeant la valeur du paramètre Name dans
les paramètres d’entrée, vous pouvez déinir ce qui doit être écrit dans le script. Pour plus
d’informations sur les touches que vous pouvez lier à ces paramètres, reportez-vous à la
page Input du manuel de référence de Unity disponible à l’adresse suivante :
http://unity3d.com/support/documentation/Manual/Input.html.
280 Développez des jeux 3D avec Unity
En résumé
Vous avez vu comment exporter votre jeu sur le Web et en tant qu’application autonome.
En conclusion, nous allons revoir tout ce que nous avons abordé au cours de ce livre et nous
vous indiquerons comment améliorer vos compétences et où chercher de l’aide pour vos
futurs développements dans Unity.
11
Procédures de tests et
lectures complémentaires
Nous avons abordé tout au long de cet ouvrage les sujets essentiels pour vous aider à déve-
lopper avec le moteur de jeu Unity. Vous découvrirez que chaque nouvel élément de jeu
que vous développerez dans Unity vous offrira de nouvelles possibilités d’améliorer vos
connaissances. Mieux vous connaîtrez le fonctionnement des scripts et plus vous aurez des
idées et des concepts de jeux. Au cours de ce chapitre, nous allons voir :
∑ comment tester et inaliser votre travail ;
∑ comment mesurer le nombre d’images par seconde pour les testeurs ;
∑ où trouver de l’aide sur Unity et ce que vous devez étudier ensuite.
Pour améliorer vos compétences, vous devriez prendre le temps d’approfondir vos connais-
sances dans les domaines suivants :
∑ le script ;
∑ le script ;
∑ le script.
282 Développez des jeux 3D avec Unity
Ce n’est pas de l’humour ! Unity s’enorgueillit d’offrir une interface graphique et des outils
intuitifs permettant de créer des scènes et des objets de jeu et de développer des jeux d’une
manière visuelle, mais vous devez absolument apprendre les classes et les commandes qui
constituent le moteur de Unity lui-même.
En lisant le manuel de Unity, ainsi que les guides de référence Component Reference et
Script Reference, qui s’installent avec le programme Unity et sont également disponibles en
ligne, vous verrez quelles sont les meilleures méthodes pour créer tous les types d’éléments
de jeu. Elles peuvent ne pas s’appliquer à votre projet en cours mais elles devraient vous
aider à travailler plus eficacement sur le long terme :
∑ le manuel de référence des composants (http://www.unity3d.com/support/
documentation/Components/) ;
∑ le manuel de référence des scripts (http://www.unity3d.com/support/documentation/
ScriptReference/) ;
∑ le manuel de Unity (http://www.unity3d.com/support/documentation/Manual/).
On appelle version bêta la version publique du jeu proposée à plusieurs testeurs – la version
alpha étant la version de test que d’autres développeurs et vous-même testez. En forma-
lisant ce processus, vous pouvez obtenir des retours très utiles. Pour cela, établissez un
questionnaire commun pour tous les testeurs ain de connaître leur avis sur le jeu mais
également ain de recueillir des informations sur chacun d’eux en tant que joueur. De cette
façon, vous pouvez tirer certaines conclusions sur votre jeu. Par exemple :
"Les joueurs de 18 à 24 ans comprennent le but du jeu et aiment ses méca-
nismes mais les joueurs de plus de 45 ans ne comprennent pas ce qu’ils doivent
faire sans lire les instructions."
en plus des informations techniques suivantes :
"Les joueurs dont le processeur a une fréquence inférieure à 2,4 GHz trouvent
que le jeu réagit lentement."
Cliquez sur File > Save dans l’éditeur de script puis revenez dans Unity. Assurez-vous que
l’objet FPS Displayer est toujours sélectionné dans le panneau Hierarchy, puis donnez la
valeur 0,9 ou 1 à son paramètre Position Y. Cliquez ensuite sur Component > Scripts >
FPS display. Testez ensuite votre scène. L’objet GUI Text indiquant le nombre d’images
par seconde s’afiche en haut de l’écran.
Votre jeu se comporte différemment en dehors de l’éditeur de Unity. Par conséquent, vous
devez tenir compte uniquement des mesures qu’afiche l’objet FPS Displayer après avoir
compilé le jeu, qu’il s’agisse d’une version destinée au Web ou d’une application auto-
nome. Demandez ensuite aux testeurs de noter les valeurs maximales et minimales ain
de disposer de données utilisables. Demandez également si certaines parties de votre jeu,
comme les animations complexes de particules, ne sont pas particulièrement exigeantes.
Demander des relevés distincts peut être intéressant lorsque ces éléments sont actifs.
Comme le jeu fonctionne différemment à l’intérieur et en dehors de l’éditeur de Unity, les
valeurs afichées dans le jeu seront différentes de celles données dans l’onglet Stats du
panneau Game (voir Figure 11.1).
Figure 11.1
286 Développez des jeux 3D avec Unity
nécessaire. Mais cette méthode se révèle souvent nuisible à long terme, car elle crée de
mauvaises habitudes que l’on conserve ensuite – à tel point qu’on en arrive à utiliser des
méthodes ineficaces.
C’est pourquoi nous vous conseillons de prendre le temps de lire la documentation ofi-
cielle chaque fois que vous le pouvez. Même si vous êtes bloqué sur un problème de déve-
loppement en particulier, elle peut souvent vous aider à le considérer sous un jour différent.
En résumé
Vous avez vu comment dépasser le cadre de cet ouvrage et comment recueillir des infor-
mations auprès des testeurs pour améliorer votre jeu.
Il ne nous reste plus qu’à vous souhaiter bonne chance pour vos développements futurs
dans Unity. Toutes les personnes qui ont contribué à la création de cet ouvrage vous remer-
cient de l’avoir lu et espèrent que vous l’avez apprécié – ce n’est que le commencement !
Index
Symboles A
@script (commandes) 97 Animations
3D déclencher par script 115
caméras 9 désactiver 109
coordonnées 8 Application.LoadLevel() (commande) 222
éléments Assets (menu) 22
corps rigides 11 Audio
détection de collision 12 composant Audio Source 51
polygones 10 formats 49
shader 10 paramètres 51
textures 10 Rolloff Factor 51
espace local et espace global 8 stéréo et mono 49
matériaux 10 Axe Z 8
modèles 60
ajouter dans la scène 196, 206
B
animations 58 Boîtes de dialogue
format de ichier 57 Create Lightmap 26
importer 176 Project Wizard 23
matériaux 58 Resolution Dialog 271
paramètres communs 57 Build Settings (paramètres)
rotation 206 OS X Dashboard Widget 267
programmes de modélisation externe 22 OS X/Windows Standalone 268
vecteurs 9 Web Player Streamed 266
290 Développez des jeux 3D avec Unity
C E
Caméras Éditeur de terrain
FOV 9 composant Terrain (Script) 28
Main Camera (objet) 76 Terrain Settings 33
Collisions, détection conigurer le terrain 35
a priori 103 arbres 44
audio 48
collecte d’objets 144
contour 35
Composants
détails 45
Animation 18
lumières 47
Collider 12, 99 textures 40
Ellipsoid Particle Emitter 192 fonctionnalités, Mass Place Trees 27
FBX Importer 57 outils
Meshes 57 Paint Details 33
GUI Texture 136 Paint Height 30
Importer 58 Paint Texture 31
Mesh Collider 12 Place Trees 32
Mesh Particle Emitter 192 Raise/Lower Terrain 29
Particle Animator, Color Animation 200 Smooth Height 30
références 282 Éléments préfabriqués
réinitialiser 164, 202 corps rigides 162
Rigidbody 12 créer 160
supprimer 164 dans le panneau Inspector 67
Trail Renderer 247 enregistrer 163
Transform 18 mettre à jour 249
vériier la présence (script) 169 modiier 246
Coordonnées cartésiennes 8 rupture du lien 179, 197
Corps rigides 160 texture 161
composant Rigidbody 159 Enregistrer, scripts 133
paramètres 159 Espaces 3D, de l’objet 8
forces 159
F
CSS (Cascading Style Sheets ou feuilles de
styles en cascade) 214 First Person Controller 53, 79
Audio Listener 79
D Camera 76
Character Controller 71
Destroy() (commande) 175, 210 contrôle au clavier 54
Détection de collision 127 FPSWalker (Script) 71
cibles 179 Graphics 74
composant Capsule Collider 197 GUILayer 78
désactiver 124 Mesh Filter 75
mode Déclencheur 129, 132 Mesh Renderer 75
supprimer les collisions inutiles 169 Mouse Look (Script) 73, 79
DrawTexture (commande) 259 Transform 71
Index 291
G pour le Web
bouton quitter 269
Game Object 13 intégration HTML 275
gameObject.name (commande) 207 résolution 19
Game (panneau) 19 tester
GetButtonUp() (commande) 173 dans Unity 54, 211
GIF (Graphics Interchange Format) 218 tests publics 285
GUI.color.a (commande) 259
L
H
Lightmap 26
Heightmaps 25 Lumières
ambiante 250
I directionnelle 47, 54
point 47
IgnoreCollision() (commande) 170
spot 47
Instanciation 158
élément préfabriqué 167 M
nommer les occurrences 168
Mathf.Lerp (commande) 259
restreindre 172
Menus 238
script 157
boutons 257
supprimer des objets 175 choix de la méthode 237
vitesse 168 créer 215, 218
Instantiate() (commande) 157, 168 une scène 215
Interfaces graphiques 142 et interfaces 214
aficher un objet 207 GUI skin 214, 237
classe GUI (script) 259 boutons 231
GUI Text 148, 152, 251 lancer des scènes 232
interpolation linéaire 252 modiier l’apparence 233
indices pour le joueur 152 script 233
animations 147 GUI Texture 214, 227
informer le joueur 187 bouton
positionner 229 Instructions 224
textures Play 220
GUI Texture 138 quitter 224
résolution 219
viseur 186
Terrain
J heightmaps
importer et exporter 25
Jeu résolution 25
collecte d’objets 144, 207 Moteur physique 11
paramètres, Build Settings 268 propriétés 12
292 Développez des jeux 3D avec Unity
O d’entrée 279
qualité 278
Objets pour le Web 271, 275
collecter dans le jeu 144 résolution 265
de jeu (GO) 13
désactiver 227 R
dupliquer 183
Raycasting 104, 126
effet de rotation 132
RequireComponent() (commande) 181, 222
éléments préfabriqués
Ressources, importer 23, 195, 215, 242
créer 134
dupliquer 134 S
enregistrer 133
importer 130 Scènes
tags 131 apparition en fondu 259
relations parent-enfant 8, 68 dupliquer 217
Outils enregistrer 55
Hand 17 Instructions 255
Scale 17 placer un modèle 3D 105
Translate 17 redimensionner un modèle 3D 106
regrouper les objets 217
P Scripts
attacher à un objet 123, 170, 182, 185
Panneaux bases 89
aficher en plein écran 219 cibles
Game 19 réinitialiser 180
Hierarchy 17 vériier le nombre de cibles abattues 185
Inspector 18, 67 classes
calques 66 Collision 180
tags 65 Input 167
Project 19 Physics 170
bouton Create 19 collecte d’objets 207
Scene 17 commandes 80
outils 17 Application.LoadLevel() 222
Performances, améliorer 250, 286 Destroy() 143, 210
distance d’afichage 249 DrawTexture 259
PNG (Portable Network Graphics) 136, 218 GameObject.Find() 146
Programmation 79 gameObject.name 207
Projet 23 GetComponent() 146
application autonome 273 GUI.color.a 259
diffusion 280 Instantiate() 157, 168
dossiers 19 Mathf.Lerp 259
générer 280 RequireComponent 222
lecteur web 268 @script 97
paramètres time() 253
Index 293
Unity
• Environnements
avec
• Personnages jouables
• Interactions
ISBN : 978-2-7440-4141-9
Pearson Education France
47 bis, rue des Vinaigriers 75010 Paris
Tél. : 01 72 74 90 00
Fax : 01 42 05 22 17
www.pearson.fr