# TP Unity (suite)
## Partie 2
### Préparation
- Créez un nouveau projet 3D (URP)
- Supprimez tous les dossiers sauf *Settings*
- Télécharger le package "TP.unitypackage" et importez le dans votre projet : *Assets > Import Package > Custom Package*.
- Ouvrez la scene *Scenes/Main.unity*
Vous retrouvez ce que nous avons réalisé lors du TP précédent, sauf que les matériaux ont une couleur bizarre (rose). C'est normal, car la pipeline de rendu utilisée dans ce projet ([URP](https://unity.com/srp/universal-render-pipeline)) est différente de celle qui a été utilisée pour créer cette scène. Pour régler ce problème, modifiez les shaders des trois matériaux présents dans le dossier *Materials* :
- Sélectionnez le matériau
- Dans l'inscpector, tout en haut, modifiez le *Shader*. Sélectionnez *Universal Render Pipeline/Lit*
###
Les Triggers ressemblent très fortement aux collisions. En effet, les Triggers sont un type particulier de Colliders. Ils ne vont pas chercher à détecter les collisions, mais plus simplement détecter lorsqu’un collider entre dans l’espace d’un autre collider sans qu’il n’y ait de collision. Pour créer un trigger, il suffit de modifier la propriété IsTrigger d’un collider en modifiant sa valeur pour qu’elle soit égale à true (ou alors tout simplement cocher la case IsTrigger d’un collider dans l’inspector).
Comme il n’y a pas de collision dans un Trigger, c’est la méthode `OnTriggerEnter()` qui est appelée lorsqu’un collider pénètre dans l’espace.
- Créez un *gameobject* vide et ajoutez à cet objet un *Box Collider*.
- Modifiez la taille du collider pour représenter une zone de taille moyenne
- Ajouter un script à cet objet qui permettra d'afficher un message lorsque la boule entre dans cette zone.
## Partie 3
###
Unity dispose de packages “standards” correspondant à des éléments de base utilisés dans la majorité des projets. Ces éléments sont disponibles depuis Assets > Import packages. C’est ce qui nous a permis de pouvoir utiliser le nouveau système de gestion des inputs. Si ces packages sont très utiles, ils doivent être utilisés à bon escient car il est important de connaître et maîtriser le fonctionnement global des éléments que l’on importe dans un projet.
Nous allons aujourd’hui utiliser le package « Character ». Créez un nouveau projet.
Auparavant, les packages standard étaient directement accessibles depuis Unity, ce n’est plus le cas depuis la version 2019. On va donc devoir passer par l’Asset Store qui, depuis la version 2021, n’est plus accessible directement sur Unity…
- [Allez dans l'asset store de Unity](https://assetstore.unity.com/)
- Cherchez le "Starter Assets - First Person Character Controller"
- Ouvrez le dans Unity, téléchargez-le, puis importez-le dans votre projet

Pour tester votre package, vous pouvez ouvrir la scène de démonstration *Playground* qui se trouve dans : *Assets > StarterAssets > FirstPersonController > Scenes*

Dans le dossier StarterAssets, vous trouverez un fichier de documentation qui vous indiquera comment utiliser l’asset (une bonne habitude à prendre pour les projets…). Vous avez plusieurs prefabs à votre disposition, dont deux « caméra ». Glissez l’objet PlayerCapsule sur la scène pour qu’on puisse l’analyser.
Notre objet PlayerCapsule possède une propriété *CharacterController*, 3 scripts et un *Player Input*
Supprimez la MainCamera de la scène et glissez celle des prefabs. Il y a un petit dessin dans la Hierarchy à côté de la MainCamera, ça indique l’utilisation de l’asset CinemachineBrain (mais ce n’est pas le sujet du TD !) : glissez juste le prefab « PlayerFollowCamera », dans l’inspector à l’option « Follow » glissez-y le GameObject « PlayerCameraRoot » (c’est un enfant de « PlayerCapsule »).

On souhaite désormais pouvoir saisir des objets dans l’environnement virtuel. On va pour cela utiliser le ray casting. Le principe du ray casting est de créer un rayon, depuis une position d’origine et dans une direction particulière. Ce rayon va nous indiquer s’il est entré en collision avec un objet ou non. Pour davantage d’information sur le ray casting, c’est [ici](https://docs.unity3d.com/ScriptReference/Physics.Raycast.html).

Le principe du ray casting est simple : la fonction renvoie True si le rayon « laser » a détecté un objet, False sinon. Les informations concernant l’objet détecté (s’il y en a un) se retrouvent dans la variable hitInfo passée en paramètre de la fonction.
Nous allons utiliser le ray casting pour cibler les objets que l’on pourra déplacer. Pour cela, créez un script RayCasting.
On souhaite que le rayon parte de la caméra, dans la direction de la position du curseur dans l’environnement. Vous trouverez des informations utiles pour générer ce type particulier de ray casting [ici](http://docs.unity3d.com/Manual/CameraRays.html).
Il nous faudra donc :
- Connaître la position de la caméra
- Récupérer la position du curseur
Pour débugger et voir où se trouve votre rayon, vous pouvez utiliser les fonctions ``Debug.DrawLine`` ou ``Debug.DrawRay``. Attention ! Ces fonctions n’affichent le rayon que dans la fenêtre Scene, pas dans la fenêtre Game ! Vous pouvez changer le layout Unity vers 2 by 3 pour voir les deux fenêtres simultanément.
Le rayon suivant désormais les mouvements de la souris, attaquons-nous à la saisie d’objets. Nous vous proposons l’algorithme suivant :
```
Si un objet est saisi
déplacer l'objet en fonction du rayon
si Click sur le bouton droit
Relacher l'objet
Sinon
Si le Raycast détecte une collision avec un objet
saisir l'objet
désactiver ces propriétés physiques
```
Quelques indications :
- Voir la propriété IsKinematic
- Utilisez MovePosition() pour changer la position de l'objet saisi à chaque frame
Une des grandes problématiques lorsqu’on travaille en environnement virtuel est de rendre les interactions possibles facilement compréhensible pour l’utilisateur. On imagine bien que dans un environnement plus riche que le nôtre, certains objets seront manipulables, d’autres non. De la même manière, il est intéressant d’avoir des indicateurs nous permettant de savoir si l’on est en train de saisir un objet ou non. Nous allons ici utiliser de très simples métaphores visuelles en jouant sur les curseurs. Nous vous proposons trois types de curseurs :

Figure : Une croix verte : objet saisissable détecté mais non saisi à l’instant T

Figure : Une croix rouge : objet saisi

Figure : Une croix noire : aucun objet saisissable détecté dans le rayon.
On utilisera la fonction ``Cursor.SetCursor``
## Game Manager
Créez un *GameObject* vide et ajoutez un script *GameManager* à cet objet. Ce GameManager sera responsable des choses suivantes :
- Instanciation automatique des cubes dans la scène.
- Détection de la fin du jeu lorsque le joueur aura détruit tous les cubes et mis la boule à l'endroit spécifié.
Indications :
- Au démarrage de l’application, le script doit récupérer la position et la taille du plan, ainsi que la taille du prefab Cube. Il est possible de récupérer le *Renderer* d’un objet grâce à la méthode ``GetComponent``.
Informations utiles :
- Les informations concernant la taille et la position peuvent être retrouvées depuis les bounds du renderer. Le Renderer d’un gameObjet étant récupérable en appelant la méthode GetComponent sur cet objet.
```csharp
Renderer objectRenderer = object.GetComponent<Renderer>();
```
- Il est possible de générer une variable aléatoire comprise entre une valeur maximale min et une valeur maximale max grâce à la méthode Range de la classe Random.
- La fonction à utiliser pour créer un objet depuis un prefab est la fonction `Instantiate`. Ne vous occupez pas du troisième argument de cette fonction pour le moment, et utilisez *Quaternion.identity*.
Prenez l’habitude d’utiliser la console pour debugger votre application. Il peut être judicieux d’écrire un message lorsque l’on détruit un cube, ainsi que lorsque l’on en crée un nouveau.