Les Scripts Unity 3D en C# Khalid NAFIL 13-02-2018 Auteur : Khalid Nafil Ecole : ENSIAS Filière : IWIM Twitter : @khalidnafil Version : 1.1 Année : Février 2018 Unity version : 2017.3.0f3 Ce document présente les scripts de base d’Unity qui permettent d’élaborer des jeux simples à base du langage C#. Plusieurs concepts fondamentaux sont également présentés. La lecture de ce document est nécessaire pour comprendre la philosophie ainsi que la logique de Unity 3d. Il est à noter également que ce document s’inspire des éléments de script présents sur le site officiel de Unity 3d. Table des matières Table des matières Activer les GameObjects Exemple Les fonctions Translate et Rotate Exemple LookAt Exemple Destroy Exemple GetButton et GetKey Exemple Script GetAxis Exemple Script OnMouseDown Exemple Script GetComponent Exemple Script DeltaTime Exemple Script Data Types Exemple Script Les Classes Exemple Script Instantiate Exemple Script 1 1 4 4 5 5 5 6 8 8 10 10 11 12 13 13 13 13 14 14 14 15 16 17 17 17 17 18 20 20 24 24 26 1 Arrays Exemple Script Invoke Exemple Script Enumerations Exemple Script Switch Statements Exemple Script Collision Étapes TP Cubes à Colorer et Redimensionner Script “ColoriageAleatoire” : 26 26 27 28 28 29 29 30 30 32 32 33 34 34 36 36 2 Activer les GameObjects Pour activer ou désactiver un objet via le scripting, on peut utiliser la fonction SetActive. Cela va permettre de faire switcher l’objet entre les deux états ‘on’ et ‘off’ au niveau de la scène. Dans l’exemple ci dessous, nous avons une simple fonction Start qui contient gameObject.SetActive(false). Pour ce faire, créer un objet GameObject et lui associer le composant script “ActiveObjects”. En exécutant le jeu, vous allez voir que GameObject n’est plus actif, (Vous pouvez associer ce script comme composant de l’objet “Lumière”). Cependant, si nous travaillons avec la hiérarchie des objets, il est important de souligner qu’un objet parent peut être désactivé, ce qui va rendre tous ses objets fils désactivés dans la scène. Cependant il va rester actif avec sa hiérarchie. Exemple //Script 1 using UnityEngine; using System.Collections; public class ActiveObjects : MonoBehaviour { void Start () { gameObject.SetActive(false); } } 3 Les fonctions Translate et Rotate Les fonctions Translate et Rotate sont communément utilisées pour changer la position et la rotation d’un GameObject. Dans l’exemple ci-dessous, on essaie de voir la fonction Translate. On peut voir que l’argument de Translate prend un Vector3. Dans cet exemple on va uniquement translater l’axe des Z par 1 par frame puisque le script est situé dans la fonction Update. Dans ce script on multiplie la vitesse de translation par le paramètre Time.deltaTime pour que le déplacement soit mesuré en mètre par seconde et non en mètre par frame. La fonction Rotate fonctionne de la même façon que la fonction Translate quoique elle est responsable d’appliquer la rotation à l’objet en question. Pour cela, créez le script suivant et l’associer au gameobject ‘Sphere’ que vous allez ajouter pour cette fin. NB : veuillez modifier GetKey par GetKeyDown pour voir la différence entre les deux. Exemple using UnityEngine; using System.Collections; public class TransformFunctions : MonoBehaviour { public float moveSpeed = 10f; public float turnSpeed = 50f; void Update () { if (Input.GetKey (KeyCode.UpArrow)) transform.Translate (Vector3.forward * moveSpeed * Time.deltaTime); if (Input.GetKey (KeyCode.DownArrow)) transform.Translate (-Vector3.forward * moveSpeed * Time.deltaTime); if (Input.GetKey (KeyCode.LeftArrow)) transform.Rotate (Vector3.up, -turnSpeed * Time.deltaTime); if (Input.GetKey (KeyCode.RightArrow)) 4 transform.Rotate (Vector3.up, turnSpeed * Time.deltaTime); } } //Vector3.up c’est pour faire tourner l’objet selon l’axe des Y à 1 degré par seconde. 5 LookAt LookAt peut être utilisée pour permettre à un GameObject de suivre le mouvement d’un autre objet cible. Dans cet exemple, nous allons permettre au Cube de suivre le mouvement de l’objet Sphere. Pour ce faire, nous allons modifier le script Comportement associé à l’objet Cube et après nous allons faire glisser à partir de la hiérarchie l’objet Sphere au niveau du paramètre target du Cube au niveau de la fenêtre Inspecteur. Exemple using UnityEngine; using System.Collections; public class Comportement : MonoBehaviour { public Transform target; void Update () { transform.LookAt(target); } } 6 Destroy La fonction Destroy peut être utilisée pour supprimer les GameObjects ou les composants à partir des GameObject en mode exécution. Cela peut être fait aussi avec un time delay en utilisant son deuxième paramètre, un nombre float Destroy(GameObject/Composant , optional delay). Pour supprimer un GameObject par exemple, nous pouvons simplement faire référence au GameObject avec qui le script est attaché. Dans cet exemple, considérons le script DestroyBasic que nous allons associer à un nouvel objet Plan(1) que nous allons créer. En mode exécution, lorsqu’on va appuyer sur la touche “espace”, l’objet Plan(1) va être supprimé. Considérons maintenant le script DestroyOther associé toujours avec le même objet Plan(1). Dans ce script, nous avons ajouté un attribut public “other” de type GameObject. En mode édition, nous allons glisser l’objet Cube à partir de la fenêtre Hiérarchie vers le paramètre “other” de l’objet Plan(1) au niveau de la fenêtre Inspecteur. En mode Play, lorsqu’on appuie sur la touche “Espace” l’objet Cube est alors supprimé. Pour le troisième script DestroyComponent, nous allons l’associer par exemple à l’objet Sphere. En mode play, lorsqu’on va appuyer sur la touche “Espace”, le composant MeshRenderer est alors supprimé et du coup l’objet Sphere n’est plus visible dans le jeu mais il n’est pas supprimé du jeu. Nous pouvons toujours associer le paramètre delay avec la fonction Destroy pour que la suppression puisse avoir lieu après une attente en secondes définie par le paramètre delay. Par exemple, Destroy(gameObject, 3f) va supprimer l’objet “gameObject” après 3 secondes. Exemple public class DestroyBasic : MonoBehaviour { void Update () { if(Input.GetKey(KeyCode.Space)) { Destroy(gameObject); 7 } } } public class DestroyOther : MonoBehaviour { public GameObject other; void Update () { if(Input.GetKey(KeyCode.Space)) { Destroy(other); } } } public class DestroyComponent : MonoBehaviour { void Update () { if(Input.GetKey(KeyCode.Space)) { Destroy(GetComponent<MeshRenderer>()); } } } 8 GetButton et GetKey Dans Unity, GetKey et GetButton sont utilisés pour recevoir des entrées à partir des touches de clavier ou à partir des boutons joystick au niveau des manettes de jeu. La différence principale entre les deux est que le GetKey attribue des noms de touches en utilisant les codes de touches. Par exemple, la barre d’espace est représentée par “KeyCode.Space”. Cela fonctionne bien avec le clavier, par contre il est recommandé d’utiliser le GetButton à la place et spécifier vos propres contrôles. Le “Gestionnaire des entrées” vous donne la possibilité de nommer une entrée et lui associer une clé ou un bouton et pourrait être accessible en choisissant Edit > Project Setting > Input. On peut référencer un nom en utilisant une chaîne. Par exemple “Jump”, est une entrée par défaut représentée par la barre d’espace, mais on peut mettre à la place un code bouton ou une clé différente pour changer l’entrée qui peut représenter “Jump”. En appelant ce bouton, nous pouvons référencer le nom en utilisant la chaîne “Jump”. Pour savoir quoi écrire dans le bouton positif, il va falloir consulter la référence dans la documentation ou suivre ce lien https://docs.unity3d.com/Manual/class-InputManager.html Lorsque nous utilisons les entrées GetKey ou GetButton, nous disposons alors de trois états qui retournent tous un booléen. Le premier est GetKey ou GetButton. Cela va enregistrer true ou false, dépendamment du bouton s’il a été pressé ou non. Si la clé n’a pas été pressée, alors GetButton va retourner false. Lorsque nous appuyons sur la clé la première fois, elle va retourner true au niveau de la première frame, après lorsque nous progressons à travers les autres frames, appuyer sur le bouton GetButtonDown va retourner false. GetButton est toujours égal à true, donc on peut vérifier si le bouton est toujours appuyé. Après, lorsqu’on relâche le bouton, GetButtonUp retourne true, mais seulement lors du premier frame. En continuant, toutes les valeurs affichent false, donc, lorsque le bouton n’est pas appuyé, tout est faux, lorsque nous appuyons la première fois sur le bouton, nous vérifions cela au niveau de GetButtonDown, qui va retourner true. De plus, GetButton va retourner true. Après la première frame, GetButtonDown retourne à false, nous pouvons utiliser cela pour des tâches telles que tirer avec son arme la première fois. En continuant d’appuyer, seul GetButton retourne true. Lorsqu’on relâche le bouton, GetButtonUp retourne true pour un seul frame et après retourne à false. Notons que GetKey se comporte exactement de la même façon, seulement le code qui est écrit diffère un peu. Pour vérifier l’état d’un bouton, nous utilisons la chaîne du titre placée dans le gestionnaire des entrées (Input Manager), Jump (bool down = Input.GetButtonDown(“Jump”)). Lorsque nous vérifions l’état pour une clé spécifique nous pouvons utiliser KeyCodes parce que cela ne concerne que la clé exacte, par 9 ailleurs il est recommandé d’utiliser GetButton et spécifier les entrées en utilisant le gestionnaire des entrées. Exemple Dans cet exemple, nous utilisons un objet “GamePlayer” où on va placer un objet “Sphere” par exemple. Nous allons associer le script ci-dessous au GamePlayer. Cela consiste à faire bouger l’objet “Sphere” sur l’axe des “Z” lorsqu’on appuie sur les flèches de direction haut et bas, et sur l’axe des “X” lorsqu’on appuie sur les flèches de direction droite et gauche en utilisant Input.GetKey (voir exemple). On pourrait également faire sauter l’objet “Sphere” sur l’axe des “Y” en utilisant Input.GetAxis(“Jump”) (voir exemple). Script using UnityEngine; using System.Collections; public class TransformPlayer : MonoBehaviour { private Transform playerTransform; private float decalMove = 1.0f; private float coefMove = 3.0f; private float jumpCoeff = 5.0f; void Start () { playerTransform = GetComponent<Transform> (); } // Update is called once per frame void Update () { if (Input.GetKey(KeyCode.UpArrow)){ playerTransform.position = new Vector3 (playerTransform.position.x, playerTransform.position.y, playerTransform.position.z + decalMove); } if (Input.GetKey(KeyCode.DownArrow)){ playerTransform.position = new Vector3 (playerTransform.position.x, playerTransform.position.y, playerTransform.position.z - decalMove); } 10 if (Input.GetKey(KeyCode.RightArrow)){ playerTransform.position = new Vector3 (playerTransform.position.x + decalMove, playerTransform.position.y, playerTransform.position.z); } if (Input.GetKey(KeyCode.LeftArrow)){ playerTransform.position = new Vector3 (playerTransform.position.x decalMove, playerTransform.position.y, playerTransform.position.z); } transform.Translate (0,Input.GetAxis("Jump") * Time.deltaTime * jumpCoeff, Input.GetAxis("Vertical") * coefMove * Time.deltaTime); } } 11 GetAxis Input.GetAxis fonctionne de la même façon que GetButton et GetKey mais avec des différences majeures. GetKey et GetButton retournent tous les deux un booléen, bouton pressé ou non, alors que GetAxis retourne une valeur de type float entre -1 et 1. Les axes sont prédéfinis dans le Gestionnaire des entrées (Input Manager) qu’on peut accéder via le menu Edit > Project Settings > Input. Lorsque le bouton est pressé nous allons considérer la valeur positive, alors qu’avec Axis nous devons considérer à la fois les boutons positifs et négatifs. Exemple Dans cet exemple, nous créons un GameObject auquel on va ajouter un composant GUI Text en sélectionnant Component > Rendering > GUI Text. Nous repositionnons correctement ce composant pour qu’il apparaisse sur la vue “Game”. Nous créons après un objet “Sphere” auquel nous associons le script ci-dessous. Au niveau de l’éditeur, nous allons faire glisser le GameObject vers le champ “textOutPut” de l’objet “Sphere”. Dans ce script, nous récupérons la position sur l’axe horizontal de l’objet “Sphere” que nous multiplions par une constante “range” à définir au niveau de l’éditeur. À l’aide de l’instruction transform.position, nous allons faire déplacer l’objet “Sphere” sur l’axe Horizontal. Script public float range; public GUIText textOutput; void Update () { float h = Input.GetAxis("Horizontal"); float xPos = h * range; transform.position = new Vector3(xPos, 2f, 0); textOutput.text = "Value Returned: " + h.ToString("F2"); } 12 OnMouseDown L'événement “OnMouseDown” peut être utilisé pour détecter le clic sur un Collider ou un élément GUI Text. Exemple Dans cet exemple, nous avons un objet “Cube” qui dispose d’un Box Collider et d’un Rigidbody. Nous allons disposer notre objet “Cube” sous forme de porte entre deux autres objets “Cube” qui chacun dispose d’un Rigidbody. Nous associons une masse à notre objet “Cube” égale à 0.20 pour qu’il puisse bouger correctement suite à l’application de notre force (voir script ci-dessous). N’oubliez pas de décocher la case “Gravity” de l’objet “Cube”. Script using UnityEngine; using System.Collections; public class MouseClick : MonoBehaviour { void OnMouseDown () { GetComponent<Rigidbody>().AddForce(-transform.forward * 500f); GetComponent<Rigidbody>().useGravity = true; } } 13 GetComponent La fonction GetComponent permet d’adresser les propriétés des autres scripts ou composants qui constituent la scène. Exemple Dans cet exemple, nous considérons deux cubes “Cube1”, “Cube2” et trois scripts “UsingOtherComponent”, “AnotherComponent”, “YetAnotherComponent” (voir ci dessous). Nous associons les deux premiers scripts à “Cube1” et le dernier à “Cube2”. Nous glissons après “Cube2” sur le paramètre “GameObject” de “Cube1”. Vérifiez aussi que “Cube2” dispose d’un “BoxCollider”. Script //UsingOtherComponent Script using UnityEngine; using System.Collections; public class UsingOtherComponents : MonoBehaviour { public GameObject otherGameObject; private AnotherScript anotherScript; private YetAnotherScript yetAnotherScript; private BoxCollider boxCol; void Awake () { anotherScript = GetComponent<AnotherScript>(); yetAnotherScript = otherGameObject.GetComponent<YetAnotherScript>(); 14 boxCol = otherGameObject.GetComponent<BoxCollider>(); } void Start () { boxCol.size = new Vector3(3,3,3); Debug.Log("The player's score is " + anotherScript.playerScore); Debug.Log("The player has died " + yetAnotherScript.numberOfPlayerDeaths + " times"); } } //AnotherScript script using UnityEngine; using System.Collections; public class AnotherScript : MonoBehaviour { public int playerScore = 9001; } //YetAnotherScript script using UnityEngine; using System.Collections; public class YetAnotherScript : MonoBehaviour { public int numberOfPlayerDeaths = 3; } 15 DeltaTime Le terme Delta veut dire différence entre deux valeurs. La propriété deltaTime de la classe “time” est essentiellement le temps écoulé entre deux appels de fonction update ou fixed update. Cela peut être invoqué pour lisser les valeurs utilisées pour le mouvement et autres calculs incrémentiels. Le temps entre les frames n’est pas constant. Nous utilisons cette propriété pour que le jeu soit indépendant du taux des frames. Si vous utilisez ce script par exemple : float translation = Time.deltaTime * 10; c’est que vous exprimez le besoin de déplacer l’objet de 10 mètres par seconde au lieu de 10 mètres par frame. Exemple Créez un objet “Sphere” et lui associer ce script. En mode play, l’objet “Sphere” va bouger d’un taux de 10 mètre par seconde au lieu de 10 mètre par frame. Script using UnityEngine; using System.Collections; public class ExampleClass : MonoBehaviour { void Update() { float translation = Time.deltaTime * 10; transform.Translate(0, 0, translation); } } 16 Data Types Toutes les variables sous Unity possèdent un Data Type. Unity dispose de deux types de Data Types : Value et Reference. Le type de données Value contient par exemple des variables tels que : int, float, double, bool, char, Structs (tel que : Vector3 et Quaternion). Le type de données Reference contient par exemple des classes. Parmi les classes les plus utilisées on trouve Transform et GameObject. Exemple Dans cet exemple, nous considérons un objet “Sphere” auquel nous associons le script ci-dessous. Dans la première partie, la sphère ne va pas bouger parce que nous avons utilisé une variable de type Valeur, par contre dans la deuxième partie, la sphère va bouger puisque nous avons utilisé une variable de type Reference. Script using UnityEngine; using System.Collections; public class DatatypeScript : MonoBehaviour { void Start () { //Value type variable Vector3 pos = transform.position; pos = new Vector3(0, 2, 0); //Reference type variable Transform tran = transform; 17 tran.position = new Vector3(0, 4, 0); } } 18 Les Classes Dans Unity, chaque script contient une définition pour une classe. Si les variables sont considérées comme des boîtes et les fonctions comme des machines, alors les classes seront considérées comme les usines qui vont contenir ces boîtes et machines. Chaque fois que vous créez un script, automatiquement Unity crée une classe ( public class …) pour vous si vous programmez en C#. Cette classe aura le même nom que celui du script. La classe est un conteneur de variables et de fonctions et fournit, moyennant d’autres choses un bon moyen de grouper les objets qui travaillent ensemble. C’est un outil organisationnel qui nous permet d’organiser un seul script en plusieurs scripts, chacun jouant un seul rôle par exemple. Une classe est censée être dédiée à une seule tâche. Exemple Dans cet exemple, nous avons un script qui manipule un certain nombre de tâches, que nous allons éclater en trois petits scripts pour le rendre plus facile à gérer. Ce script par exemple manipule l’inventaire, le mouvement et le tir de balles. Ce script va être attaché à notre objet “Cube” à créer. Pour ce faire, nous allons créer un objet “Cube” que nous positionnons à (0, 1.30, 0). Nous positionnons ensuite l’objet “Camera” à (0.2, 1, -5). Nous créons ensuite un objet “Sphere” que nous positionnons à (-1.5, 1.3, 0) et sa taille à (0.1, 0.1, 0.1) et nous lui ajoutons après un composant “Rigidbody”. Après nous glissons l’objet “Sphere” dans le dossier “Prefabs” et nous le supprimons de la hiérarchie. Nous créons ensuite un GameObject vide auquel nous ajoutons un composant “Rigidbody” et nous décochons “Gravity”. Nous glissons après ce Gameobject dans le dossier “Prefabs” et nous le supprimerons ensuite de la hiérarchie. Après nous glissons le Gameobject depuis le dossier “Prefabs” à l’intérieur de l’objet “Cube”. Nous positionnons ensuite “GameObject” à (-0.15, -0.05, 0.2). Après avoir associé le script “SingleCharacterScript” à l’objet “Cube”, nous allons apercevoir dans l’inspecteur cinq paramètres. Nous mettons respectivement les valeurs des paramètres Speed, TurnSpeed et Bullet Speed à 7, 90 et 900. Après nous glissons le “GameObject” vers le paramètre “Fire Position” et l’objet “Sphere” vers le paramètre “Bullet Prefab”. 19 Script //Premier Script avec une seule classe “SingleCharacterScript” using UnityEngine; using System.Collections; public class SingleCharacterScript : MonoBehaviour { public class Stuff { public int bullets; public int grenades; public int rockets; public Stuff (int bul, int gre, int roc) { bullets = bul; grenades = gre; rockets = roc; } } public Stuff myStuff = new Stuff (10, 7, 25); public float speed; public float turnSpeed; public Rigidbody bulletPrefab; public Transform firePosition; public float bulletSpeed; void Update () { Movement(); Shoot(); } void Movement () { float forwardMovement = Input.GetAxis("Vertical") * speed * Time.deltaTime; 20 float turnMovement = Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime; transform.Translate(Vector3.forward * forwardMovement); transform.Rotate(Vector3.up * turnMovement); } void Shoot () { If (Input.GetButtonDown("Fire1") && myStuff.bullets > 0) { Rigidbody bulletInstance = Instantiate(bulletPrefab, firePosition.position, firePosition.rotation) as Rigidbody; bulletInstance.AddForce(firePosition.forward * bulletSpeed); myStuff.bullets--; } } } // // //Notre classe SingleCharacterScript on va l’éclater en trois classes : Inventory, MovementControls et Shooting // //Script classe Inventory // using UnityEngine; using System.Collections; public class Inventaire : MonoBehaviour { public class Munition { public int bullets; public int grenades; public int rockets; public float fuel; public Munition (int bul, int gre, int roc) { bullets = bul; 21 grenades = gre; rockets = roc; } public Munition (int bul, float fu) { bullets = bul; fuel = fu; } // Constructor public Munition () { bullets = 1; grenades = 1; rockets = 1; } } // Creating an Instance (an Object) of the Stuff class public Munition maMunition = new Munition (50, 5, 5); public Munition monAutreMunition = new Munition (50, 1.5f); void Start() { Debug.Log (maMunition.bullets); } } // //Script de la classe MovementControls // using UnityEngine; using System.Collections; public class MovementControls : MonoBehaviour { public float speed; public float turnSpeed; 22 void Update () { Mouvement (); } void Mouvement () { float forwardMouvement = Input.GetAxis ("Vertical") * speed * Time.deltaTime; float turnMouvement = Input.GetAxis ("Horizontal") * turnSpeed * Time.deltaTime; transform.Translate (Vector3.forward * forwardMouvement); transform.Rotate (Vector3.up * turnMouvement); } } // //Script de la classe Shooting // using UnityEngine; using System.Collections; public class Shooting : MonoBehaviour { public Rigidbody bulletPrefab; public Transform firePosition; public float bulletSpeed; private Inventory inventory; void Awake () { inventory = GetComponent <Inventory> (); } void Update () { Shoot (); 23 } void Shoot () { if (Input.GetButtonDown ("Fire1") && inventory.maMunition.bullets > 0) { Rigidbody bulletInstance = Instantiate (bulletPrefab, firePosition.position, firePosition.rotation) as Rigidbody; bulletInstance.AddForce (firePosition.forward * bulletSpeed); inventory.maMunition.bullets--; } } } 24 Instantiate Instantiate est une fonction utilisée pour créer des clones pour les GameObjects. Généralement, elle est utilisée dans le contexte de cloner un prefab. Un prefab est simplement un objet préconfiguré sauvegardé dans les assets du projet. Exemple Dans cet exemple nous considérons des tirs de rockets à partir d’un Bazooka. Chacune des rockets a besoin d’être instanciée dans le jeu pour qu’on puisse la tirer. Nous utilisons dans cet exemple “Fire1” pour déclencher une fonction Instantiate. La forme la plus basique de la fonction Instantiate est lorsqu’elle prend un seul paramètre : l’objet que nous voulons cloner. Dans cet exemple, nous avons créé une variable public appelée “rocketPrefab” que nous passerons dans la commande Instantiate comme paramètre. Cependant cela veut dire que le prefab va être instancié à sa position par défaut, qui est 0. Dans notre exemple, cette position est le centre du jeu, le centre où la “bazooka” est positionnée pour le moment. C’est ainsi que lorsqu’on appuie sur “Play”, ces rockets apparaissent au centre du “bazooka”. Pour changer cela, nous aurons besoin de trois paramètres de Instantiate, l’objet à instancier qui est dans notre cas la “rocketPrefab”, et la position et rotation à attribuer au nouveau clone du prefab. Pour cela, nous créons un GameObject vide qui va être positionné devant la barell du bazooka. Nous allons pour ce faire utiliser une variable public appelée “BarellEnd” et nous utiliserons les valeurs de la position et la rotation de ce composant comme valeurs à attribuer au nouveau clone du prefab “rocket”. Donc en glissant cette nouvelle location vide sur notre script dans l’inspecteur nous pouvons dès lors recevoir la transform position et rotation en utilisant la variable “barellEnd”. Script // // Script de la classe UsingInstantiate // using UnityEngine; using System.Collections; public class UsingInstantiate : MonoBehaviour 25 { public Rigidbody rocketPrefab; public Transform barrelEnd; void Update () { if(Input.GetButtonDown ("Fire1")) { Rigidbody rocketInstance; rocketInstance = Instantiate (rocketPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody; rocketInstance.AddForce (barrelEnd.forward * 5000); } } } // //Script de la classe RocketDestruction // using UnityEngine; using System.Collections; public class RocketDestruction : MonoBehaviour { void Start() { Destroy (gameObject, 1.5f); } } 26 Arrays Les tableaux permettent de stocker une collection de données de même type. Exemple Dans cet exemple, nous créons trois GameObjects auxquels nous assignons le tag à “Player”. À partir du script ci dessous, nous allons chercher ces trois objets par leur tag et nous allons les placer dans une structure de tableau. Après, nous pouvons dérouler une boucle pour afficher le nom de ces trois objets successivement. Script using UnityEngine; using System.Collections; public class Arrays : MonoBehaviour { public GameObject[] players; void Start () { players = GameObject.FindGameObjectsWithTag("Player"); for(int i = 0; i < players.Length; i++) { Debug.Log ("Player Number "+i+" is named "+players[i].name); } } } 27 Invoke La méthode Invoke permet de contrôler l’exécution de fonctions en définissant un temps d’attente au niveau de son paramètre. Exemple Dans cet exemple, au niveau de la classe InvokeScript, nous faisons appel à la méthode Invoke avec les deux paramètres “SpawnObject” et 2. Cela veut dire que la fonction “SpawnObject” va être appelée 2 secondes après le Start. Pour ce faire, nous allons créer un GameObject vide dans lequel nous allons mettre un objet “Sphere” et le tout on va le glisser vers le dossier “Fablabs”, après le GameObject sera supprimé de la hiérarchie. On remarque que la fonction “SpawnObject” est invoquée une seule fois. Si par contre nous voulons que cette fonction soit invoquée plusieurs fois dans le temps, alors dans ce cas nous allons utiliser la fonction “InvokeRepeating” à la place de la fonction “Invoke” et qui prend trois paramètres : le premier c’est la fonction à invoquer, le deuxième c’est la durée de temps à attendre avant d’invoquer la fonction, le troisième est la durée de temps à attendre avant d’invoquer la fonction pour les prochaines fois et c’est répétitif, voir script “InvokeRepeating”. Par ailleurs, pour pouvoir arrêter l’exécution de InvokeRepeating, on va faire appel à la fonction “CancelInvoke” en lui passant comme paramètre le nom de la fonction à arrêter et que nous allons placer au niveau de la fonction Start() par exemple. Script // // Script de la classe InvokeScript // using UnityEngine; using System.Collections; 28 public class InvokeScript : MonoBehaviour { public GameObject target; void Start() { Invoke ("SpawnObject", 2); } void SpawnObject() { Instantiate(target, new Vector3(0, 2, 0), Quaternion.identity); } } // // Script de la classe InvokeRepeating // using UnityEngine; using System.Collections; public class InvokeRepeating : MonoBehaviour { public GameObject target; void Start() { InvokeRepeating("SpawnObject", 2, 1); } void SpawnObject() { float x = Random.Range(-2.0f, 2.0f); 29 float z = Random.Range(-2.0f, 2.0f); Instantiate(target, new Vector3(x, 2, z), Quaternion.identity); } } 30 Enumerations L’Enumeration nous permets de créer une collection de constantes reliées. Les valeurs d’une énumération par défaut sont des entiers. La première valeur d’une énumération est attribuée à 0, la deuxième à 1, etc. Sinon on peut changer ces valeurs par défaut (voir documentation officielle). Exemple Dans cet exemple nous définissons une énumération Direction qui va contenir quatre valeurs : North, South, East and West. Après nous allons faire des tests successifs sur ces valeurs via le script Unity. Script using UnityEngine; using System.Collections; public class EnumScript : MonoBehaviour { enum Direction {North, East, South, West}; void Start () { Direction myDirection; myDirection = Direction.North; } Direction ReverseDirection (Direction dir) { 31 If (dir == Direction.North) dir = Direction.South; else if (dir == Direction.South) dir = Direction.North; else if (dir == Direction.East) dir = Direction.West; else if (dir == Direction.West) dir = Direction.East; return dir; } } 32 Switch Statements Les états switch sont utilisés pour comparer une seule variable avec une série de constantes. Exemple Dans cet exemple, nous définissons une variable “intelligence” initialisée à 5. Après nous utilisons l’instruction switch combinée à case pour évaluer la valeur de la variable “intelligence” et la comparer avec les valeurs successives 5, 4, 3, 2, 1 et defaut au cas où la variable est différente de toutes les valeurs proposées. Script // // Script de la classe ConversationScript // using UnityEngine; using System.Collections; public class ConversationScript : MonoBehaviour { public int intelligence = 5; void Greet() { switch (intelligence) { case 5: print ("Why hello there good sir! Let me teach you about Trigonometry!"); break; 33 case 4: print ("Hello and good day!"); break; case 3: print ("Whadya want?"); break; case 2: print ("Grog SMASH!"); break; case 1: print ("Ulg, glib, Pblblblblb"); break; default: print ("Incorrect intelligence level."); break; } } } 34 Collision Dans ce Tp, nous allons considérer une sphère et un cube en prefabs. Le jeu va générer aléatoirement plusieurs cubes qui vont tomber du ciel, et la sphère pouvant se déplacer horizontalement doit essayer de ne toucher aucun de ces cubes, sinon elle est écrasée suite à cette collision. Étapes 1. Créez un nouveau projet sous Unity 3d. 2. Créez un objet Sphère. 3. Créez le script ‘seDeplacer’ et l’associer à l’objet ‘Sphère’ : a. void Update() { b. transform.position += new Vector(Input.GetAxis(“Horizontal”), 0, 0); c. } d. void OnCollisionEnter() { e. Destroy(gameObject); f. } 4. Créez un objet Cube et lui ajouter le composant ‘Rigidbody’. 5. Ajouter ce cube comme Prefabs puis le supprimer de la scène. 6. Créez le script ‘cubes’ et l’associer à l’objet ‘Camera’ : a. public float delay = 0.1f; b. public GameObject cube; c. void start() { d. InvokeRepeating (“Spawn”, delay, delay); e. void Spawn() { f. Instantiate (cube, new Vector3(Random.Range(-6, 6), 10, 0), Quaternion.identity); g. } 7. Glissez l’objet cube du prefab vers l’attribut cube de l’objet Camera. 8. Lancez le jeu. 35 TP Cubes à Colorer et Redimensionner Dans une scène nous disposons de 20 cubes (4 x 5). Nous créons ensuite un Gameobject vide. Nous glissons les vingt cubes sur ce GameObject. Nous créons ensuite le script suivant : Script “ColoriageAleatoire” : public GameObject [] cubes; Color[] couleurs = new Color[]; public int[] height; void Start(){ couleurs = new Color[cubes.Length]; height=new int[cubes.Length]; for (int i=0; i<height.Length; i++){ height[i]=Random.Range(1, 10); } for (int i=0; i<couleurs.Length; i++){ couleurs[i]=new Color(Random.Range(0f, 1f),Random.Range(0f, 1f),Random.Range(0f, 1f)); } for (int i=0; i<cubes.Length; i++){ cubes[i].transform.localScale=new Vector3(1,height[i],1); cubes[i].GetComponent<Renderer>().material.color=couleurs[i]; } } 36