TD1 : Fondamentaux Unity

Rémy Frenoy, Florian Jeanne, Yann Soullard, Yohan Bouvet (maj 2022 & 2023)

Unity est un logiciel et un moteur de jeu multi-plateforme (PC, Mac, Linux, mobiles, tablettes, consoles de jeux et applications web). Il est principalement utilisé dans le domaine des jeux vidéo, mais également en réalité virtuelle.

Site de la documentation officielle : https://docs.unity.com/
(Attention à votre version d’Unity, les docs de chaque version ne contiennent pas forcement la même chose)

Création d’un projet

Lors du lancement de Unity, ce n’est pas le logiciel qui s’ouvre, mais le « Unity Hub », qui sert à gérer vos projets ainsi que les différentes versions d’Unity installées. Sur vos machines est installée une version 2021 de Unity (pensez-y lorsque vous faites des recherches sur Internet pour vous aider !).

Figure : Si l’interface n’est pas sombre, pas de panique, c’est normal! C’est une préférence personnelle ; )

Créez un nouveau projet en sélectionnant le template « 3D » et nommez-le “TD1_nombinome1-nombinome2”.

Il est conseillé de regrouper l’ensemble de vos TDs dans un dossier “RV01” sur votre disque « Z » afin de pouvoir accéder à vos sources facilement lors des TDs suivants.

Interface graphique de Unity

Figure : Interface principale de Unity pour l’édition d’un projet

1 (rouge) Hierarchy – Hiérarchie des éléments disposés sur la scène.

2 (vert) Project – Ensemble des ressources du projet.

2 bis (vert) Console – Sortie des erreurs de compilation en mode Scene, et les outputs console en mode Game (ex: messages de Debug.Log(« message »))

3 (bleu) Scene – Scène d’édition, permet d’ajouter, modifier, supprimer des éléments de l’environnement.

3 bis (bleu) Game – Affiche l’application une fois celle-ci lancée.

4 (orange) Inspector – Affiche les propriétés et les options de configuration de l’objet sélectionné.

5 (violet) Control bar – Permet de lancer, suspendre et arrêter l’application en cours.

Dans l’écran de scène, les boutons de votre souris sont configurés ainsi :
– Bouton de gauche : sélectionner un/des objet(s) ou agir sur les outils de transformation (position, rotation, échelle)
– Bouton centrale : translater la vue
– Scroll : zoom
– Bouton de droite : rotation autour d’un point.
(Astuce : pour qu’un gameobject devienne le centre de rotation de la vue, il suffit de double-cliquer sur son nom dans la hiérarchie. Ceci ne fonctionne qu’en vue « ISO »)

 

Sauvegarder la scène

Lors de la création d’un nouveau projet, Unity crée une première scène, qui est déjà enregistrée dans les ressources (Assets), dans le dossier Scenes. En ouvrant le dossier, vous pouvez observer que le nom de l’objet correspond à celui qui est tout en haut de la hiérarchie. Pour signifier que ceci va être notre scène principale, faites un clic-droit sur l’objet SampleScene et renommez-la en Main. Unity va vous indiquer que ce changement nécessite de recharger la scène, pas de problème, nous n’avons encore rien fait ! Après recharge, vous pouvez voir que l’objet, dans la fenêtre Hierarchy, a été renommé.

(Pour info dans les versions antérieures à 2021, le dossier « Assets > Scenes » n’est pas automatiquement créé et votre scène n’est pas automatiquement sauvegardée, vous devez le faire manuellement !)

La quantité de ressources présentes dans un projet Unity peut rapidement être imposante.

Ces ressources sont très variées (scènes, scripts, textures, matériaux, objets 3D, characters, animations, imports, …). Nous nous attacherons donc à organiser rigoureusement nos ressources dans des dossiers correspondants à leur nature (les scènes dans un dossier “Scènes”, les scripts dans le dossier “Scripts”… enfin vous saisissez l’idée). Toutes les ressources Unity sont considérées comme des “assets”, ainsi tous les dossiers que vous créerez seront à placer dans le dossier “Assets”.

Figure : On prépare le terrain !

Créer un objet

Nous sommes maintenant familiarisés avec l’interface. Cependant, la scène est vide… Ou presque ! Comme nous pouvons le voir dans la fenêtre Hierarchy, il y a deux éléments :

Main Camera et Directional Light, qui sont une caméra par défaut et une lumière d’ambiance.

Nous allons commencer par créer des objets simples, comme une balle et un sol par exemple (dans Unity, les objets sont appelés Game Objects). Pour cela, il vous suffit d’aller dans le menu puis dans GameObject > 3D Object > Plane, pour le sol. L’objet apparaît dans la scène et dans la hiérarchie des objets. Il est déjà sélectionné et prêt à être renommé, comme ce sera le sol, renommons-le en “Ground” dans la fenêtre Hierarchy. (Si vous avez cliqué ailleurs et que l’objet n’est plus sélectionné, vous pouvez toujours faire un clic droit sur l’objet “Plane”, puis Rename).

Faites la même chose pour la balle que l’on nommera “Ball” : GameObject > 3D Object > Sphere.

Néanmoins, comme on peut le constater visuellement dans la scène, notre balle est coincée dans le sol, pas très pratique… Il nous faut donc la déplacer.

Sélectionnez la sphère avec la souris à partir de la scène ou tout simplement en cliquant sur l’objet dans la fenêtre Hierarchy. Dans la fenêtre Inspector, localisez la partie Transform. C’est ici que nous allons pouvoir modifier la position, la taille et l’orientation des objets. Tous les GameObjects possèdent un component Transform. Dans Unity, l’axe par défaut pour la hauteur est l’axe Y.

Ampoule et engrenageSi vous avez du mal à vous souvenir quel axe représente la hauteur, une astuce : les axes X, Y, Z sont représentés par les couleurs R, V, B. L’axe Y est vert : vert comme vertical 😉

Il nous faut donc modifier la valeur de la position comme ceci, avec une valeur de 2 par exemple :

Figure :Notre balle est au-dessus du sol, voyez l’ombre projetée!

Déplacer un objet

Maintenant que notre scène possède des objets, il serait intéressant de pouvoir les déplacer.

Pour cela, nous allons devoir ajouter un nouveau component (propriété) à notre balle  afin de lui ajouter des contraintes physiques. Sélectionnez donc la balle puis ajoutez-lui un rigidbody : dans la fenêtre Inspector, cliquez sur le bouton Add Component, ou dans le menu Component > Physics > Rigidbody. Un nouveau component est alors ajouté à notre balle dans l’Inspector.

Lancez la scène grâce au bouton Play. Miracle, la gravité est rétablie et la balle tombe !

Cependant, nous ne pouvons toujours pas la déplacer. C’est ici qu’on va parler d’interaction !

Programmer les interactions

Les interactions consistent à lier une commande, par exemple l’appui sur une touche, avec un comportement. Lorsque vous faites un clic droit avec la souris, vous interagissez avec l’application. Pour notre balle, c’est la même chose : on veut pouvoir la déplacer, par exemple grâce aux flèches directionnelles du clavier. Depuis la version de Unity 2019, un nouveau système de gestion des commandes (Inputs) a été développé. Pour comprendre la différence, il faut comprendre comment se fonctionne l’application.

Lorsque vous cliquez sur Play pour lancer la scène (et voir votre balle tomber), des scripts se lancent. Parmi eux, certains seront créés par nous, pour pouvoir « faire ce qu’on veut ». Le comportement qui permet de dire qu’un GameObject qui possède une propriété RigidBody est automatique : la présence de la propriété RigidBody fait que l’objet sera considéré comme ayant un corps soumis aux lois physiques. Pourquoi peut-on voir l’objet tomber, pour finalement s’arrêter sur le sol ? Car il existe des fonctions qui tournent en boucle, et qui permettent d’actualiser l’état du monde, qui sera ensuite affiché. Un peu comme au cinéma, où un film n’est qu’une succession de photos.

Lorsqu’on clique sur Play, tous les objets de la scène lancent un script nommé « Start », qui permet de les initialiser dans le monde. Par exemple, on aurait pu laisser notre balle coincée dans le sol et se servir du script « Start » pour changer sa position initiale.

Une fois cela fait, à chaque « photo » du monde (frame), tous les objets lancent leur fonction Update. C’est là qu’on va pouvoir calculer les changements qui peuvent avoir lieu, par exemple, si on a demandé à la balle de se déplacer, c’est ici qu’on va calculer de combien elle doit se déplacer en fonction du temps écoulé et de la durée d’appui sur une touche.

Avant la version 2019 de Unity, on devait donc tester nous-mêmes, dans un script qu’on aurait créé, dans cette fonction Update, si, à chaque frame, il y a eu un appui sur une touche, et si c’est le cas, faire les changements appropriés.

Figure : Gestion des inputs dans les versions de Unity inférieures à 2019

Comme on ne peut pas changer le code d’un script « pendant » que l’application est lancée, si on veut finalement utiliser une autre touche, il faut avoir pensé à tester tous les cas possibles dans notre fonction Update. Depuis la version 2019, ce n’est plus le cas, et un nouveau système a été développé. À présent, lors de la fonction Update, on va juste tester si la commande liée à l’action qu’on veut faire a été activée ou non.

Figure : Gestion des inputs dans les versions de Unity depuis la version 2019

Nous allons ici vous présenter le nouveau système, mais vous avez en Annexe : Input Manager (Old) « l’ancienne » façon de faire. Pour changer la façon dont les commandes sont gérées, allez dans le menu Edit > Project Settings > Player et chercher dans la partie « Configuration ». Si la propriété « Active Input Handling » est à « Input Manager (Old) », cela veut dire que Unity s’attend à ce que les inputs soient gérés dans la boucle Update. Cliquez sur la propriété et changez-la par « Input System Package (New) » ou  « Both ». Ce dernier est très pratique puisqu’il permet d’utiliser les deux en même temps 😉
Unity va vous prévenir qu’il doit se relancer pour prendre en compte le changement. Acceptez. Une fois Unity relancé, vous pouvez fermer la fenêtre Project Settings.

Allez dans le menu Window > Package Manager, cliquez sur le bouton « Packages : In My Project » pour sélectionner « Packages : Unity Registry », et chercher le package Input System. Cliquez dessus et installez-le.

Cela va nous permettre de créer un nouvel asset : dans la fenêtre Project, faites un clic droit et Create > Input Actions. Ce nouvel asset va vous servir à lier des actions (dont l’activation sera testée dans les fonctions Update) et des commandes. Cliquez sur l’objet, puis dans l’Inspector, Open.

Figure : Ça paraît lourd, mais ça vous aidera pour développer sans avoir besoin de casque!

Input System Package

Une nouvelle interface s’est ouverte, nous allons la détailler.

Figure : Nous avons renommé notre asset « AllControls », d’où le nom affiché en haut.

1 (rouge) Control Scheme : la configuration matérielle qu’on va utiliser (par exemple, quand vous jouez à un jeu vidéo et que vous avez la possibilité d’alterner entre souris/clavier et manette…)

2 (bleu) Action Maps : des groupes d’actions qu’on va développer (pensez aux jeux vidéo, quand vous vous déplacez à pied puis en voiture…)

3 (vert) Actions : les actions qui seront testées, et les commandes qui les déclenchent.

4 (orange) Properties : les propriétés des commandes

Avant tout chose, cochez la boîte « Auto-save », sinon il vous faudra cliquer manuellement sur le bouton « Save Asset » pour que vos changements soient pris en compte…

Vide, l’interface n’est pas très parlante, alors commençons à remplir pour comprendre. Tout d’abord, nous allons créer un Control Scheme : cliquez sur « No Control Scheme » puis sélectionnez « Add Control Scheme ». Nommez le schéma « MainControls », puis cliquez sur le petit « + » sous la liste vide : c’est là où nous allons préciser quel matériel est nécessaire (ou optionnel) pour commander notre balle. Restons simples et sélectionnons « Keyboard ». Cliquez sur « Save » : ça y est, on a défini que pour pouvoir interagir, nous aurons besoin d’un clavier.

Dans Action Maps, comme notre application est simple, cliquez sur le « + » et nommez le groupe « Main ». Une nouvelle action s’est automatiquement créée ! Cliquez sur le petit triangle à gauche pour l’ouvrir.

Pour l’instant, notre action se nomme « New action » et n’est liée à aucune commande. Comme nous voulons déplacer la balle, renommons l’action en « MoveBall » (double-clic ou clic droit sur l’action). Dans les propriétés, nous pouvons voir que l’action a un type, ici « Button ». Il existe en fait 3 types d’actions, mais nous en utiliserons principalement 2 :

  • Button : l’action va être liée à un seul input binaire (l’appui sur la touche Espace permet de sauter)
  • Value : l’action va être liée à une commande sur la durée (tant qu’on appuie sur la flèche droite, on se déplace à droite)

Comme nous gérons ici le mouvement, le type de l’action va être « Value ». Tant qu’on appuiera sur une touche, la balle se déplacera dans un sens. Mais le fait d’avoir une « valeur » renvoyée va nous permettre de pouvoir appuyer sur plusieurs touches en même temps et d’aller dans la bonne direction (si on veut aller en diagonale par exemple) car le calcul sera fait automatiquement !
Dans Control Type, sélectionner « Vector 2 » pour indiquer que nous souhaitons un control sur 2 vecteurs. Il est à noter que ce sélecteur conditionne les choix possibles du cadre « Action ».

 Figure : Ils sont sympas, ils nous préparent même les directions pour qu’on sache à quoi ça correspond !

Définissons maintenant quelles touches nous allons utiliser : faites clic-droit sur l’action MoveBall, nous voulons que la balle se déplace selon 2 axes (X et Z), donc ajoutons un « 2D Vector Composite». (Le « No Binding » est inutile, vous pouvez le supprimer en faisant clic droit dessus et Delete)

Nous avons presque fini la création de nos inputs. Cliquez sur une direction, et dans les propriétés, cliquez sur « Path » : la liste des matériels disponibles (quand vous avez créé le Control Scheme) s’affiche. Naviguez dans Keyboard pour trouver la touche que vous voulez utiliser, ou bien dans la barre de recherche.

Ampoule et engrenage La partie « Usages » propose les touches les plus couramment utilisées dans les applications pour l’interaction, mais ne sont pas forcément en accord avec le matériel que vous avez choisi… Mieux vaut ne pas l’utiliser. Il y a également la solution de facilité, qui consiste à cliquer sur le bouton « Listen » puis à appuyer sur la touche (ou le bouton d’une manette, ou un clic de souris) désirée, ce qui va réduire les choix. Pour illustrer les possibles problèmes vous pouvez cliquer sur « listen » puis appuyez sur la touche Z de votre clavier … Eh oui, Unity est anglophile et donc le code de la touche A vaut pour lui le W.

Pour le TD nous utiliserons les flèches du clavier. En « écoutant » la touche « flèche bas », l’application me propose la touche, mais également « n’importe quelle touche ». Comme je veux utiliser la flèche vers le bas, je sélectionne la première proposition.

Maintenant que j’ai affectée une touche à chacune des directions, je vais pouvoir mettre en place le script pour contrôler la balle.

Ampoule et engrenageInformation importante concernant l’ancien système d’input dans la section « Pour aller plus loin » en fin de page !

Ça roule !

Sélectionnez la balle. Pour qu’elle puisse adapter sa position, il faut qu’elle puisse savoir si des inputs ont été activés. Pour cela, dans la fenêtre Inspector, ajoutez un nouveau Component > Input > Player Input. Il faut maintenant lui préciser quelles sont les commandes et les actions qui lui seront appliquées : pour cela, faites un glisser-déposer de l’asset InputActions que vous venez de créer dans le champ « Actions ».

L’objet Ball est maintenant au courant des actions qui peuvent être activées. Il ne nous reste plus qu’à lui dire quoi faire lorsque c’est le cas.

Pour cela, nous allons utiliser des scripts.

Unity supporte différents langages de programmation : le Javascript, le C# et le Boo (un langage propre à Unity). Durant les TDs, vous pourrez utiliser le langage qui vous plaît le plus. Néanmoins, le code que nous vous fournirons est en C#.

Avant de créer notre premier script et dans un souci de propreté, nous allons créer un dossier Scripts dans notre projet où seront stockés tous nos scripts (si vous ne l’aviez pas déjà fait !). Pour cela, faites un clic droit dans la fenêtre Project > Create > Folder. Maintenant, faites un clic droit dans le dossier nouvellement créé puis Create > C# Script (ou allez dans Assets > Create > C# Script à partir du menu). Un fichier apparaît dans l’explorateur du projet. Renommez-le “BallController”. Ce script va nous servir à contrôler le déplacement de notre balle. Il faut donc l’associer au GameObject “Ball”. Un simple glisser-déposer de l’objet BallController sur la balle, que ce soit dans la scène ou dans la hiérarchie, suffit. Vous pouvez également le faire depuis l’Inspector avec le bouton Add Component (Scripts > Ball Control). Le script apparaît maintenant comme component.

Unity est associé à Visual Studio. Pour éditer notre script, double-cliquez sur lui et Visual Studio s’ouvrira alors automatiquement. Le script comprend par défaut deux méthodes : Start() et Update(). Start() contient les instructions qui seront exécutées au chargement du script, à sa première exécution. Elle n’est donc appelée qu’une seule fois ; Update() est appelée à chaque frame, et contient donc les instructions qui seront exécutées en boucle.

Avec le nouveau système de gestion des inputs, l’appui sur les touches que nous avons liées à notre action MoveBall permet de lancer un signal à notre objet Balle. Chaque action entraîne la création d’une méthode dont le nom est structuré de la même façon : On[Le_Nom_De_Votre_Action]. Ici, notre action s’appelle MoveBall, nous aurons donc une fonction dans notre script qui s’appellera OnMoveBall. Si on avait créé une action ChangeColor, la fonction qu’on devrait créer s’appellerait OnChangeColor, etc.

Le script agit comme un component de la balle, il a donc accès aux autres composants de celle-ci ; c’est pour cela que nous le lions à la balle.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class BallController : MonoBehaviour
{
private Rigidbody rb;
//La fonction Start est appelée lors du clic sur Play, une seule fois
void Start()
{
rb = GetComponent<Rigidbody>();
}
private Vector2 moveValue;
//La fonction Update est appelée une seule fois par frame, la fonction FixedUpdate peut être appelée plusieurs fois, selon les calculs liés à la physique
//Ici, nous bougeons la position d'un corps "physique", donc on utilise FixedUpdate
void FixedUpdate()
{
rb.AddForce(moveValue.x, 0, moveValue.y);
}
//Lorsqu'un des inputs est activé, cette fonction est appelée et la valeur modifiée
void OnMoveBall(InputValue value)
{
moveValue = value.Get<Vector2>();
}
}

Sauvegardez le script et retournez sur l’interface de Unity. S’il y a des erreurs, celles-ci apparaîtront dans l’onglet Console, juste à côté de l’onglet Projet.

Appuyez sur play et amusez-vous (svp) en utilisant les touches… Attention à ne pas dépasser le sol !

La position de la caméra n’est pas franchement idéale pour observer notre balle bouger. Nous allons donc la déplacer !

Placer la caméra

Unity place automatiquement une caméra sur la scène. Vous pouvez sélectionner cette caméra en choisissant Main Camera dans la fenêtre Hierarchy. Un pop-up Camera Preview s’ouvre et affiche la vue depuis la caméra sélectionnée. Vous remarquerez, en scrutant l’Inspector, que la caméra est positionnée en (0, 1, -10). Déplacez la caméra de telle sorte que vous puissiez voir le plan et la sphère dans Camera Preview.

Lancez l’application. Déplacez la sphère afin qu’elle sorte du champ de la caméra. On ne la voit plus (c’était le but de l’opération…). Une question existentielle se pose : comment faire pour que la caméra suive la sphère ?

Mieux placer la caméra


La hiérarchie des objets permet de définir un objet comme étant enfant d’un autre. Glissez-déposez l’objet Main Camera sur Ball dans la fenêtre Hierarchy : la caméra est désormais “enfant” de la sphère.

Lorsqu’un objet est enfant d’un objet parent, sa position devient relative à la position du parent, c’est-à-dire que le référentiel de l’objet enfant n’est plus le centre de la scène (0,0,0) mais le centre de son objet “parent”. Relancez l’application. La position initiale de la caméra ne change pas. Déplacez la sphère. La caméra se déplace désormais en suivant les déplacements de la balle. Ça vous plaît ? J’espère que vous avez le cœur bien accroché…

La méthode consistant à placer la caméra comme étant l’enfant d’un objet que l’on souhaite suivre est pertinente dans le cas d’un personnage à la première/troisième personne par exemple. En vue à la première personne, disposer la caméra comme “enfant” permet par exemple de suivre les déplacements et les mouvements de la tête. Attention toutefois aux déplacements de l’objet “parent” ! Lorsque celui-ci est amené à faire de nombreuses rotations (typiquement le cas d’une sphère !), mieux vaut utiliser une autre méthode…

Correctement placer la caméra

On souhaite que la caméra suive les translations de la sphère dans l’espace, mais pas les rotations. La caméra ne peut donc pas avoir comme référentiel celui de la balle. Dans la hiérarchie, faites donc en sorte que la caméra ne soit plus enfant de la sphère.

Figure : S’émanciper dans Unity, c’est facile ! Il suffit de glisser.

On se retrouve dans la configuration initiale, avec une caméra fixe. Pour modifier cela, ajoutons un script CameraController à nos assets, et affectons-le à l’objet Main Camera. Ouvrez le script dans Visual Studio. Dans ce script, on souhaite que tout changement de position (c’est à dire une translation dans l’espace) d’un GameObject modifie de la même manière la position de la caméra. Nous avons donc besoin de deux variables :

  • Une variable que l’on nommera baseObject, de type GameObject et qui correspondra à l’objet que l’on souhaite suivre.
  • Une variable que l’on nommera offset, de type Vector3 et qui correspond au vecteur représentant l’écart entre la position initiale de la caméra et la position initiale de l’objet à suivre.

L’esprit de ce script est donc de repositionner la caméra afin que l’offset soit constant.

Il suffit donc de calculer l’offset au chargement de la scène (donc dans la méthode Start) de la façon suivante :

offset = transform.position - baseObject.transform.position;

A chaque frame (donc dans la méthode Update), on modifie la position de la caméra comme étant la position de l’objet à suivre plus l’offset.

transform.position = baseObject.transform.position + offset;

On obtient alors le code suivant :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject baseObject; //l'objet à suivre
private Vector3 offset; //la distance initiale entre l'objet et la caméra

// On calcule l'offset avant même que la balle ne tombe!
void Start()
{
offset = transform.position - baseObject.transform.position;
}

void Update()
{
transform.position = baseObject.transform.position + offset;
}
}

Lancez l’application.

Figure : Une erreur de compilation sauvage apparaît!

Oups ! En effet, nous avons déclaré avoir besoin d’une variable baseObject dans le script, mais Unity n’a aucune idée de quel objet il s’agit. C’est donc à nous de lui donner cette information.

Sélectionnez la caméra dans la fenêtre Hierarchy afin que ses propriétés apparaissent dans la fenêtre Inspector. Dans le cadre Camera Controller, vous voyez votre script, et vous voyez également la variable Base Object qui est pour l’instant à None, d’où l’erreur de compilation !

Figure : On peut voir cette variable car nous l’avons déclarée « public » dans le script

Toujours depuis la fenêtre Hierarchy, glissez-déposez la balle vers la valeur de BaseObject dans la fenêtre Inspector. Vous obtenez ceci :

Figure : Etudiant de RV01 utilisant l’attaque « affectation de variable ». C’est très efficace !

Lancez l’application, et déplacez la balle. Vous remarquez que la caméra suit les déplacements de la balle, sans en subir les rotations. Parfait !

Ampoule et engrenageSi vous avez des problème de clic intempestif qui vous empêche de maintenir l’inspector en focus sur le GameObject Camera, il y a un petit cadenas que vous pouvez activer pour « figer » l’inspector sur la sélection en cours.

C’est beau, c’est… texturé

Cette scène est un peu terne (et surtout, on a du mal à voir que notre balle roule). Ajoutons-y un peu de couleur. Pour modifier l’apparence d’un objet, celui-ci doit avoir un material. Commençons par créer un dossier “Materials” dans la fenêtre Project, qui permettra de stocker l’ensemble des materials utilisés dans un projet. Pour créer un material, faites un clic droit > Create > Material. Renommez-le “RedColor”. Pour donner une couleur rouge à votre material, modifier la propriété “Albedo” dans la fenêtre Inspector et attribuez-lui la couleur rouge. Pour appliquer un material sur un objet, il suffit de glisser-déposer le material depuis la fenêtre Project vers l’objet dans la scène.

Figure 14: Wow, such shiny, much red !

Il est également possible d’utiliser des images plutôt que de simples couleurs. Créez un dossier Images dans le dossier Assets. Copiez-y la ressource “gravels.jpg” que vous pouvez télécharger ici.

Créez maintenant un nouveau material “Gravels”. Sélectionnez ce nouveau material afin qu’il s’affiche dans la fenêtre Inspector. Cliquez sur le petit cercle à gauche de l’option Albedo et choisissez l’image gravels dans la fenêtre qui apparaît.

Comme nous l’avons fait précédemment pour la sphère, glissez-déposez le nouveau material sur le sol de la scène.

En cliquant à nouveau sur le material Gravels, vous pouvez modifier les paramètres Tilling et Offset dans l’inspector pour ajuster les dimensions et la position de la texture sur le sol. Par exemple, avec un Tilling x=2 et y=2, la texture se répétera deux fois sur la largeur et deux fois sur la longueur du sol, soit 4 fois en tout et les graviers seront un peu plus petits. Toutefois, attention à ne pas trop contracter les textures, sinon l’effet visuel perdra en réalisme. Essayez avec x=10 et y=10, le motif de répétition devient bien trop flagrant.

Export

Notre projet terminé, nous souhaitons l’exporter (si votre TD n’est pas terminé, exportez-le quand même, c’est facile mais important). Pour cela, dans le menu tout en haut, faites Assets > Export Package.

Vérifiez bien que tout est coché, puis confirmez. Vous obtenez un fichier portant l’extension

unitypackage. Vous pouvez désormais importer dans n’importe quel projet (nous le ferons lors du TD2) les assets (dont la scène) que vous venez d’exporter.

Pour aller plus loin

Les lumières

Comme son nom l’indique, la lumière placée automatiquement lors de la création d’une scène est directionnelle. Vous pourrez trouver de nombreux autres types de lumière (Point Light, Spot Light, Area Light) dans GameObject >Light. Vous pouvez également modifier les propriétés de ces lumières dans la fenêtre Inspector, une fois la lumière sélectionnée. Vous pouvez ainsi créer une ambiance particulière dans votre scène.

L’Asset Store

Unity possède un asset store qui permet de télécharger des contenus gratuits ou payants afin de les intégrer à un projet. Il faut cependant un compte Unity pour pouvoir y accéder.

https://assetstore.unity.com

Les contenus sont classés par catégories (3D Models, Textures and Materials, …).

Parmi les contenus, vous trouverez notamment des fichiers portant les extensions .fbx et

.obj. FBX et OBJ font partie des principaux formats de fichiers de modèles 3D. Des logiciels de modélisation tels que Blender ou 3ds Max permettent de créer de tels fichiers.

Annexe : Input Manager (Old)

Avant la version 2019, pour pouvoir créer des interactions, on n’avait pas besoin d’assets InputAction permettant de définir des actions. Mais beaucoup de gens avaient développé des applications en utilisant l’ancienne façon, et passer à la nouvelle demanderait trop de travail. C’est pourquoi les deux systèmes existent.

Malheureusement, pour vos projet, il vous faudra utiliser le plugin SteamVR, qui utilise l’ancien système d’input. Vous devrez connaitre et utiliser les deux système au cours du semestre : le nouveau pour le médian sur machine, et l’ancien pour vos projets.

Pour ceux qui souhaiteraient avoir un exemple de script permettant le déplacement « old fashion » de la base, en voici le code commenté.

Dans notre script BallController, définissons une nouvelle méthode nommée KeyboardMovements(). Cette méthode a pour objectif de tester les touches du clavier qui sont utilisées et d’appliquer une force sur notre balle dans la direction souhaitée. Nous aurons besoin d’une vitesse et de récupérer la référence au « corps » de l’objet, le Rigidbody. Nous avons les éléments pour définir KeyboardMovements() qui sera appelée dans notre Update.

Comme indiqué dans la documentation Unity, le paramètre de la fonction AddForce est un Vector3. Il existe des Vector3 de base qui sont préétablis, comme Vector3.left qui correspond au vecteur (-1, 0, 0). En fonction de la touche appuyée, nous multiplierons le Vector3 correspondant à la direction par la variable speed que nous avons créée.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OldBallController : MonoBehaviour
{
public float speed = 1f;
private Rigidbody rb;

// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}

// Update is called once per frame
void Update()
{
//D'abord, on teste et applique les déplacements
KeyboardMovements();

//Par la suite, on peut mettre à jour d'autres choses...

}

void KeyboardMovements()
{
//Si on utilise des else if, on autorise l'appui sur une seule touche à la fois
//Si on veut pouvoir aller en diagonale, il faudrait faire le AddForce à la fin et gérer l'ajustement des valeurs dans les if, sans qu'il y ait de else

if(Input.GetKey("right"))
{
rb.AddForce(Vector3.right * speed);
}
else if(Input.GetKey("left"))
{
rb.AddForce(Vector3.left * speed);
}
else if(Input.GetKey("up"))
{
rb.AddForce(Vector3.forward * speed);
}
else if(Input.GetKey("down"))
{
rb.AddForce(Vector3.back * speed);
}
}
}

Sauvegardez, puis lancez l’application. Les scripts sont automatiquement compilés par Unity.