<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Unity Gems</title>
	<atom:link href="http://unitygems.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://unitygems.com</link>
	<description>Tutorials &#38; Articles For Unity Developers</description>
	<lastBuildDate>Fri, 17 May 2013 07:12:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Bases de l&#8217;IA &#8211; Space Shooter</title>
		<link>http://unitygems.com/ia-space-shooter/</link>
		<comments>http://unitygems.com/ia-space-shooter/#comments</comments>
		<pubDate>Mon, 22 Apr 2013 14:25:36 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Beginner]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1830</guid>
		<description><![CDATA[<p>IA pour Space Shooter Dans cette partie du tutoriel, nous développons les bases d&#8217;un simple jeu de tir spatial. Nous commençons avec un environnement 2D pour apprendre l&#8217;IA. Notre jeu utilisera le gameplay de base de défilement vers la droite, ce qui signifie notre vaisseau va vers la droite, tandis que les ennemis viennent de &#8230;<br /><a class="excerpt" href="http://unitygems.com/ia-space-shooter/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h1>IA pour Space Shooter</h1>
<p>Dans cette partie du tutoriel, nous développons les bases d'un simple jeu de tir spatial. Nous commençons avec un environnement 2D pour apprendre l'IA. Notre jeu utilisera le gameplay de base de défilement vers la droite, ce qui signifie notre vaisseau va vers la droite, tandis que les ennemis viennent de droite à gauche. Notre but est d'essayer de donner un peu de vie à nos vaisseaux ennemis.</p>
<p>Nous allons utiliser les principes de base de la trigonométrie, la programmation orientée objet (héritage, polymorphisme, ...) ainsi que un peu d' algèbre vectoriel. Si vous êtes familier avec ceux-ci, ce ne sera pas un problème, si vous ne l'êtes pas, ceux-ci sont rapidement expliqués dans cet article. C'est à vous d'aller chercher plus d'informations car nous ne pouvons pas répondre à tous ici ...</p>
<div class="alert green">Le projet est téléchargeable<a href="http://unitygems.com/Downloads/Ship.zip"> ici</a>. Notez qu'il vous faudra peut-être modifié certaines valeurs</div>
<p>Voici une video qui montre ce que vous allez faire (en anglais).</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/w8AAo0GMUVs?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<ul>
<li><a href="#Create">Création de notre vaisseau</a></li>
<li><a href="#Move">Bouger notre vaisseau </a></li>
<li><a href="#Shoot">Un vaisseau qui tire</a></li>
<li><a href="#Pattern">Donner des trajectoires avec un peu de trigonométrie</a></li>
<li><a href="#Spin">Tourner en rond</a></li>
<li><a href="#Shrink">Rétrécir et grossir</a></li>
<li><a href="#Ellipse">Forme elliptique </a></li>
<li><a href="#Hide">Cache-cache (premier FSM)</a></li>
<li><a href="#Kamikaze">Vaisseau kamikaze </a></li>
<li><a href="#ShipSee">Vaisseau qui peut voir (devant lui)</a></li>
</ul>
<h2><a name="Create"></a></h2>
<h2>Création de notre vaisseau</h2>
<p>Premièrement nous allons créer notre propre vaisseau. Ce n'est pas de l'IA vu que nous créons un code que le joueur utilise. La partie AI vient juste après. Donc, si vous avez téléchargé le projet, vous devez avoir un objet SpaceShip. Il a déjà tout ce qu'il faut et la plupart des informations que vous devez savoir sont écrites comme commentaires sur le script. (Cette partie viendra avec le projet, promis ca vient au plus vite!!!)</p>
<p>Maintenant, nous devons créer le NPC (Non-Player-Character) ou dans notre cas, Non-Player-Ship qui signifie le vaisseau que le joueur ne controle pas. Notre première tâche consiste à instancier un nombre aléatoire de vaisseaux à des emplacements aussi aléatoires. Dans le dossier SpawnObject est le script ci-dessous, il l'a déjà été ajouté à l'objet Spawn de la Hiérarchie. Vous pouvez simplement cocher sur.</p>
<pre>using UnityEngine;
using System.Collections;

public class CreateRandom : MonoBehaviour {
    public GameObject ship;
    Transform _transform; 
    void Start () {
         _transform= GetComponent&lt;Transform&gt;();
         InvokeRepeating("CreateRandomShip",0.01f,2.0f);
    }

    void CreateRandomShip(){
        Vector3 vec= new Vector3(_transform.position.x,0,Random.Range (-1f,-9f));
        Instantiate(ship,vec,transform.rotation);
    }
}</pre>
<p>Toute la magie se trouve dans  <em>Vector3 vec  = new Vector3 (22,0, Random.Range (-1f,-9f));</em> Maintenant, qu'est-ce que cela fait? cela crée un vector3 avec x = 22 qui est juste devant notre écran de sorte que nos ennemis n'apparaissent pas soudainement au milieu de l'écran, y = 0 parce que nous sommes en 2D et y n'est pas utilisé ici. Enfin, nous utilisons un nombre aléatoire restreint dans un ordre de valeurs pour définir la valeur de z. C'est la commande qui est responsable de l'aspect désordonné de nos vaisseaux.</p>
<div class="alert red">Il se peut que les valeurs nécessitent des changement en fonction de votre projet.</div>
<p>Notre projet a un objet Spawn qui est un simple objet vide. Attachez le script sur cette objet. La fonction CreateRandomShip est appelée avec InvokeRepeating toutes les 2 secondes.</p>
<h2><a name="Move"></a></h2>
<h2>Bouger notre vaisseau</h2>
<p>Maintenant, pour la deuxième partie, la création des vaisseaux c'est bien, mais ils ont aussi besoin de se déplacer. C'est là que la programmation orientée objet entre en jeu. Nous sommes sur le point de déclarer une classe qui servira à représenter le comportement de base de nos vaisseaux. Si nous voulons des vaisseaux avec des action splus spécifiques, nous déclarons une nouvelle classe qui hérite de notre classe de base (aussi appelé classe parent). La classe dérivée (aussi appelée classe enfant) précisera quels sont les comportements qui doivent être modifiés et quels comportements doivent être utilisés en tant que tels.</p>
<p>Ci-dessous est notre class de base ennemi. Nous allons y revenir plus tard pour ajouter un peu plus d'actions de base. Ajoutez ceci à la prefab ennemi dans le panneau Projet.</p>
<div class="alert red">Faites bien attention à suivre lorsqu'il est dit de retirer ou modifier un composant ou c'est la fin des haricots </div>
<pre>using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

	protected Vector3 velocity;
	public Transform _transform;
	public virtual void Start () {
                _transform = GetComponent&lt;Transform&gt;();
                velocity = new Vector3(Random.Range(0.5f,1.5f),0,0);
	}
        public virtual void Update(){
              _transform.Translate ( -velocity.x*Time.deltaTime,0,velocity.z*Time.deltaTime,Space.World);
        }

       void OnTriggerEnter(Collider other){
		if(other.gameObject.tag == "EnemyDeath")Destroy(gameObject);
	}
}</pre>
<p>Cela sera notre classe de base. Toute classe ennemie héritera de celle-ci de sorte que tout membre que nous voulons  universel à tous les ennemis soit ajouté ici. C'est pourquoi la plupart des variables sont déclarées protégées (<em>protected</em>) ou public jusqu'à présent.</p>
<p>Notez que la plupart des fonctions sont déclarées <em>virtual</em> comme nous allons probablement les remplacer plus tard dans nos classes dérivées. Notez également que la fonction <em>OnTriggerEnter</em> n'est pas virtuelle. Nous voulons que tous les vaisseaux soient détruits en sortant de l'écran (il y a des <em>ColliderBox</em> de chaque côté de l'écran dans notre projet). Il s'agit d'un comportement commun à tous nos navires. Nous n'aurons pas à le réécrire plus tard.</p>
<p><em>velocity =new Vector3(Random.Range(0.5f,3.0f),0,0);</em> encore nous utilisons une valeur aléatoire pour définir la vélocité (vitesse) de nos vaisseaux.</p>
<p>Nous avons maintenant un premier niveau tout simple. Vous pouvez y ajouter des astéroïdes de manière à avoir deux sortes d'ennemi.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_109-Nov.-05-21.41.jpg"><img title="RandomShip" alt="RandomShip" src="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_109-Nov.-05-21.41-1024x691.jpg" width="940" height="634" /></a></p>
<p>Nos vaisseaux bougent mais nous voulons aussi qu'ils tirent</p>
<p>Nous pourrions aussi utiliser InvokeRepeating pour modifier le composant z de la vélocité de nos vaisseaux. Ainsi, ils n'iraient pas tout le temps vers la gauche directement mais parfois un peu vers le haut et parfois un peu vers le bas:</p>
<p><a name="Shoot"></a></p>
<pre>public virtual void Start(){
    InvokeRepeating("ChangeZ",2.0f,1.0f);
}
public virtual void Update(){
     _transform.Translate( -velocity.x*Time.deltaTime,0,
         velocity.z*Time.deltaTime,Space.World);
}

void ChangeZ(){
    velocity.z = Random.Range(-1.0f,1.0f);
}</pre>
<p>Comme vous pouvez le constater, cela crée un beau bazar (pour rester poli) mais qui sait, cela peut être l'effet recherché.</p>
<h2>Un vaisseau qui tire</h2>
<p>Pusique  nos vaisseaux ont deux canons, nous sommes sur le point de leur donner la possibilité de "recharger" avant de tirer à nouveau. Eh bien, en fait, nous allons juste alterner les coups de feu entre les canons de gauche et de droite. Le vaissaue dispose de deux gameobjects vides (empty GameObject) comme enfants devant les canons que nous allons utiliser pour notre tir. Le code ci-dessous est ajouté à notre classe de base:</p>
<pre>Transform _primaryShoot;
Transform _secondaryShoot;
bool side = true; 
public GameObject proj; 

protected void Shoot(){
    if(_primaryShoot){
        if(_secondaryShoot){
            if(side)
                Instantiate (proj,_primaryShoot.position,Quaternion.identity);
            else
                Instantiate (proj,_secondaryShoot.position,Quaternion.identity);
             side = !side;
        }else
             Instantiate (proj,_primaryShoot.position,Quaternion.identity);
   }
}
void OnCollisionEnter(Collision other){
      if(other.gameObject.tag == "Ship"){
           Destroy (gameObject);
           other.gameObject.SendMessage("DecreaseHealth",15);
      }
}</pre>
<p>Jetez un coup d'œil à la fonction Shoot. La principe est  que les ennemis pourraient avoir un, deux ou aucune arme. On pourrait penser que s'il n'y a pas d'arme pourquoi essayer de tirer, vous n'êtes jamais sans erreur ... Vous pouvez effectivement ajouter une instruction else en fin qui lancerait  un avertissement du genre "Vous shootez mais cet objet n'a pas arme ". Sans la première vérification if, vous planter votre jeu.</p>
<p>Maintenant, nous devons ajouter notre première classe de base ennemi. Dans le dossier EnemyScript, trouver le BasicEnemy et ajouter le à la préfabriqué Enemy. Vous pouvez effectivement désactiver ou supprimer le composant Enemy. Puisque BasicEnemy est un enfant d' Enemy, Unity va automatiquement ajouter tous les membres publics et protégés de la classe parent:</p>
<pre>using UnityEngine;
using System.Collections;

public class BasicEnemy : Enemy {

	public override void Start () {
		base.Start();
		_primaryShoot = transform.Find ("SpawnLeft").transform;
		_secondaryShoot = transform.Find ("SpawnRight").transform;	
               InvokeRepeating("Shoot",Random.Range(2.0f,4.0f),Random.Range(2.0f,4.0f));
	}

	public override void Update () {
		base.Update ();
	}
}</pre>
<p>Nous surchargeons la fonction Start mais comme certains membres sont affectés dans la fonction Start parent nous l'appelons avec base.Start (); Ensuite, nous retrouvons nos deux armes et commençons à appeler la fonction Shoot. Vous pourriez vous demander pourquoi je n'appelle pas base.Shoot (), la fonction Shoot est protégée dans ma classe de base de sorte qu'elle est héritée. Vous  utilisez la base lorsque vous voulez utiliser un membre de la classe parente qui est redéfinie dans la classe dérivée.</p>
<p>Et voilà. Ils sont prêts à tirer, il vous suffit de glisser et déposer le préfabriqué ProjectileEnemy. Vous la trouverez dans le dossier Projectile sous ProjectileEnemy (c'est juste une sphère colorée). J'ai également ajouté une fonction de collision dans le cas où le joueur frappe levaisseau. Gardez à l'esprit que la mort est aussi une sorte de AI.</p>
<p>Si vous utilisez le projectile du projet, il a déjà le script associé avec ce code:</p>
<pre>using UnityEngine;
using System.Collections;

public class ProjEnemy : MonoBehaviour {

	Transform _transform;
	void Start () {
		_transform = GetComponent&lt;Transform&gt;();
	}

	void Update () {
		_transform.Translate ( speed*Time.deltaTime,0,0,Space.World); 
	}
	void OnCollisionEnter(Collision other){
		if(other.gameObject.tag == "Ship"){
			other.gameObject.GetComponent&lt;ShipControl&gt;().DecreaseHealth(10);
			Destroy(gameObject);
		}
	}
	void OnTriggerEnter(Collider other){
		if(other.gameObject.tag == "EnemyDeath")Destroy(gameObject);
	}
}</pre>
<p>Rien d'extravagant encore. La fonction de collision envoie un message au vaisseau pour réduire la vie. Notez que si vous décidez de créer des projetiles plus avancés, vous pouvez toujours hériter de ce projetile de base.</p>
<h2><a name="Pattern"></a></h2>
<h2>Donner des trajectoires avec un peu de trigonométrie</h2>
<p>Prenons un second type de mouvement IA vraiment basique. Nous sommes maintenant sur ​​le point d'entrer dans le royaume des oscillations et des vagues. Ce que vous allez voir ici est simplement l'équation de base du principe de l'univers. Ouais, je sais, cela semble un peu trop insistant mais j'y suis pour rien c'est comme ça.</p>
<p>Donc, en utilisant des fonctions simples comme cosinus ou sinus, on peut facilement obtenir de jolies formes.</p>
<div class="alert green">Que vous utilisiez sinus ou cosinus n'a pas vraiment d'importance en quelque sorte. Vous obtiendrez la même forme, mais l'une commence à 0, car sin (0) = 0 et l'autre commence à 1 car cos (0) = 1. Encore une fois, je n'ai pas choisi.</div>
<div class="alert green">Une fonctionnalité intéressante de sin et cos, c'est que le résultat est continu et restreint entre -1 et 1. Nous pouvons obtenir une variable qui ira constamment de 1 à -1 et retour à 1 et ainsi de suite en passant par toutes les valeurs. </div>
<div class="alert blue">Tout ce qui n'est pas privé dans la classe Enemy est accessible dans la classe dérivée EnemyShip. Si un membre n'est pas privé, il est soit public ou protected (il y a aussi interne, mais on va le laisser de côté pour le moment). Public est accessible par n'importe quel objet n'importe où (voir le tutoriel GetComponent), private ne se voit que dans le fichier / classe dans lequel la variable/fonction est déclarée, une classe enfant n'hérite pas des membres privés de la classe de base. Protected est semblable à private en ce qui concerne l'accession par des objets externes, mais l'enfant hérite des membres protected. </div>
<p>Nous allons déclarer une nouvelle classe et créer du mouvement pour notre vaisseau. Le code va simplement bouger notre vaisseau de haut en bas de manière oscillatoire.</p>
<pre>using UnityEngine;
using System.Collections;

public class ShipOsc : Enemy {

    float amplitude = 2;
    float omega = 0.5f;
    float index;
    float zPos;

    public override void Start(){
        base.Start ();
        _transform.position = new Vector3(22f,0f,-5f);    
        _primaryShoot = transform.Find ("SpawnLeft").transform;
        _secondaryShoot = transform.Find ("SpawnRight").transform;
        zPos=_transform.position.z;
        InvokeRepeating("Shoot",Random.Range(2.0f,4.0f),Random.Range(2.0f,4.0f));
    }

    public override void Update(){
        index += Time.deltaTime;
        float zPos=amplitude*(Mathf.Cos(omega*index))*Time.deltaTime;
        _transform.Translate ( -velocity.x*Time.deltaTime,0,zPos,Space.World);
    }
}</pre>
<div class="alert green">Voici la fonction cosin/sin: Amplitude*Mathf.Cos(omega*Time.time+phase);</div>
<p>Une explication rapide sur l'équation, Amplitude aura une incidence sur la taille de la vague, oméga influe sur la fréquence de l'onde, en quelque sorte la vitesse d'un sommet à l'autre, time is utilisé pour modifer la valeur. La phase correspond à la valeur en radians va décaler le point de départ de l'onde. Nous verrons un exemple plus tard.</p>
<p>Cette classe d'ennemi a aussi la possibilté de tirer.</p>
<p>L'image ci-dessous montre que la position est fonction du temps (time), si tous les vaisseaux ont la même valeur pour time, ils ont tous la même position. L'indice (index) est incrémenté à chaque nouveau vaisseau, chaque vaisseau a une valeur unique.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Sin.png"><img title="Sin" alt="Sin" src="http://unitygems.com/wp-content/uploads/2012/12/Sin.png" width="562" height="459" /></a></p>
<p>Et voilà!!! Nos vaisseaux semblent se suivre avec un joli mouvement.</p>
<p><div class="one_half"><a href="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_111-Nov.-05-21.56.jpg"><img title="OscShip" alt="OscShip" src="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_111-Nov.-05-21.56-300x203.jpg" width="300" height="203" /></a></div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_110-Nov.-05-21.55.jpg"><img title="OscShip2" alt="OscShip2" src="http://unitygems.com/wp-content/uploads/2012/12/ScreenHunter_110-Nov.-05-21.55-300x202.jpg" width="300" height="202" /></a></div><div class="clear"></div></p>
<p>Sur la première photo, la valeur donnée à Omega est plus grande que dans la deuxième image. En conséquence, la vague des vaisseaux est réduite. Si vous donnez une valeur inférieure à l'amplitude, la vague portera sur une plus petite distance du haut vers le bas. Il vous suffit de jouer avec l'amplitude et l'oméga pour avoir un premier aperçu sur les oscillations et les vagues. Cela n'est pas seulement utile pour faire bouger nos vaisseaux, mais il s'avère que cela gère de nombreuses lois de physiques.</p>
<p>Vous pourriez penser à aussi utiliser ce principe pour vos projectiles.  Vous avez l'outil pour le faire, maintenant c'est à vous.</p>
<h2><a name="Spin"></a></h2>
<h2>Tourner en rond</h2>
<p>Nous continuons à modifier nos fonctions trigonométriques et cette fois nous sommes sur le point de tourner autour d'un point. Ce que nous voulons réaliser, c'est un ensemble de vaisseaux placés en cercle autour d'un point et tournant autour alors que le point se déplace vers notre vaisseau du joueur. Mmm, pas sûr que ce soit bien clair, mais vous verrez ce n'est pas de la magie, juste des maths.</p>
<p>Nous avons besoin d'un nouveau script qui va prendre notre objet spawn et le déplacer le long de l'axe des x.</p>
<pre>using UnityEngine;
using System.Collections;

public class CirclePattern : MonoBehaviour {

	void Update () {
		_transform.Translate ( -Time.deltaTime,0,0,Space.World);
	}
}</pre>
<p>Ceci va sur l'objet Spawn pour le faire bouger</p>
<p>Nous devons maintenant déclarer une fonction qui va instancier et positionner nos vaisseaux autour de cet objet Spawn. Le fait est que nous voulons aussi pouvoir réutiliser cette fonction avec le moins de problème possible. Disons que nous voulons placer 10 vaisseuax, mais la prochaine fois nous voulons seulement 5 vaisseauxde sorte que ça casse un peu le modèle.</p>
<p>Nous devons maintenant penser en termes de cercle unité. Il s'agit d'un simple cercle de rayon 1 qui contient la valeur correspondante de cos et sin en radians tout autour.</p>
<p><div class="one_half"><a href="http://unitygems.com/wp-content/uploads/2012/12/300px-Unit_circle_angles_color.svg_.png"><img title="Unit_circle_angles_color.svg" alt="Unit_circle_angles_color.svg" src="http://unitygems.com/wp-content/uploads/2012/12/300px-Unit_circle_angles_color.svg_.png" width="300" height="300" /></a></div><div class="one_half last">Nous devons trouver un moyen pour que chaque vaisseau reçoivent un repère unique sur le cercle unité. Donc si on veut 4 vaisseaux, on les veut sur les coordonnées principales: nous voulons donc 0, PI/2, PI et enfin 3PI/2. Si nous obtenons 8 vaisseaux, nous voulons les coordonnées principales et les coordonnées rouge. Par conséquent, nos vaisseaux sont régulièrement positionnés autour de notre objet spawn. </div><div class="clear"></div></p>
<pre>using UnityEngine;
using System.Collections;

public class CirclePattern : MonoBehaviour {

	public GameObject ship;
	public int amount; //Give a value in the Inspector for how many ships
	void Start () {
		for(int i = 0 ;i&lt; amount ;i++){
			//Créer un objet et le parenter à l'objet Spawn
                        GameObject obj = (GameObject) Instantiate (ship, transform.position, transform.rotation);	
			obj.transform.parent = transform;

                        PlaceShip (obj,i,amount);

                        // Obtenir l'angle entre le vaisseau et l'objet Spawn
                        // et l'utiliser comme shift
			CircleMove sc = obj.GetComponent&lt;CircleMove&gt;();
			float angle = Vector3.Angle(obj.transform.localPosition, transform.forward);
    		        Vector3 cross = Vector3.Cross(obj.transform.localPosition, transform.forward);
    		        if (cross.y &lt; 0) angle = -angle;
			     sc.phase = angle * Mathf.Deg2Rad;
		}
	}

	void Update () {
		_transform.Translate ( -Time.deltaTime,0,0,Space.World);
	}

        // Avec l'index de notre objet récemment créé dans la boucle
        // On le divise par le nombre d'objet et on multiplie par 2PI (Cercle entier)
	void PlaceShip(GameObject obj, int i, int amount){
		float u = ((float)i / (float)(amount)) * (Mathf.PI*2);
		float x = (float)Mathf.Cos(u);
                float z = (float)Mathf.Sin(u);

		obj.transform.localPosition = new Vector3(x, 0,z)*2;
	}
}</pre>
<p>Notez que nous devons ajouter un script CircleMove à notre vaisseau avec un membre appelé phase. Vous obtiendrez également quelques erreurs pour des variables que nous n'avons pas encore déclarées.</p>
<p>La fonction PlaceShip est simplement le principe de gâteau d'anniversaire. Combien de personnes nous avons et diviser le gâteau en parts égales.</p>
<p>Le vaisseau utilise le script suivant:</p>
<pre>using UnityEngine;
using System.Collections;

public class CircleMove : Enemy {

    public float phase;
    public override void Start () {
        base.Start();
        _primaryShoot = transform.Find ("SpawnLeft").transform;
        _secondaryShoot = transform.Find ("SpawnRight").transform;    
        InvokeRepeating("Shoot",Random.Range(2.0f,4.0f),Random.Range(2.0f,4.0f));
    }

    public override void Update () {
        transform.localPosition= new Vector3(Mathf.Cos (Time.time+phase ),0,Mathf.Sin (Time.time+phase));
    }
}</pre>
<p>Grâce à notre héritage, nous traitons uniquement le mouvement, et nos vaisseaux tirent toujours. Les vaisseaux sont déplacés dans localPosition parce que nous voulons qu'ils tournent autour de cet objet Spawn qui en quelque sorte est maintenant notre point d'origine. Grâce à la variable  phase, les vaisseaux sont uniformément placés autour du centre. Essayez de changer la quantité de navires et vous verrez que, tant que vous ne donnez pas une valeur trop grande, ça va.</p>
<p>Essayer de supprimer les deux variables phase dans l'Update et ils sont tous au même endroit. Supprimer une seule, ils sont alignés.</p>
<p>Vous pouvez également essayer de déclarer une seconde variable phase et l'utiliser comme ceci:</p>
<pre>	public float phase;
	float phaseA;

	public override void Start () {
		phaseA =phase +30f;
	}

	public override void Update () {
		transform.localPosition= new Vector3(Mathf.Cos (Time.time+phaseA ),0,Mathf.Sin (Time.time+phase));
	}</pre>
<p><a name="Shrink"></a></p>
<h2>Rétrécir et grossir</h2>
<p>Nous voulons maintenant que nos vaisseaux tournent autour du centre mais aussi vont et viennent vers le centre.</p>
<pre>	public override void Update () {
		transform.localPosition= new Vector3((Mathf.Cos (Time.time)+2)*Mathf.Cos (Time.time + phase),0,
			(Mathf.Cos (Time.time)+2)*Mathf.Sin (Time.time+phase));
	}</pre>
<p>Rappelez-vous quand j'ai dit que cosin et sin interpolent et  sont contraints entre 1 et -1, je me sers de cette fonction ici. La distance entre les vaisseaux et le centre est en constante croissance et décroissance. Le+2 est utilisé pour donner une distance minimale avec le centre, pour que vous n'ayez pas tout le monde qui s'empile au milieu bien que ce soit peut être ce que vous voulez (encore une fois enlevez la variable pour voir ce qu'il se passe). Ce n'était pas trop dur, vous voyez.</p>
<h2><a name="Ellipse"></a></h2>
<h2>Forme Elliptique</h2>
<p>Viens notre dernière modification sur les fonctions trigonométriques, nous allons créer une ellipse ou en quelque sorte une forme similaire. Réfléchissons une seconde ce qu' est une ellipse. D'abord qu'est-ce qu'un cercle? Il s'agit d'une forme géométrique qui a chacun de ces points équidistants du centre. Une ellipse est alors basé sur une forme de cercle qui a certains points plus proches du centre que d'autres.</p>
<p>Donc, nous voulons obtenir certains points plus proches et d'autres plus loin, mais la différence de distance ne peut pas être brusque, ce qui pourrait déplacer les vaisseaux soudainement. Rappelez-vous encore que cos et sin interpolatent et sont constraints. Nous pouvons tout simplement appliquer cela à nos valeurs x et z de manière à avoir deux mouvements indépendants.</p>
<pre>	public override void Update () {
		transform.localPosition= new Vector3((Mathf.Cos (Time.time<strong>+phase</strong>)+2)*Mathf.Cos (Time.time + phase),0,
			(Mathf.Cos (Time.time)+2)*Mathf.Sin (Time.time+phase));
	}</pre>
<p>J'ai ajouté une variable et c'est tout. Notez que ce n'est pas une ellipse parfaite puisque l'équation de l'ellipse est différent, c'est juste elliptique.</p>
<p>Pour une véritable ellipse, c'est effectivement plus simple <img src='http://unitygems.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  il vous suffit de donner des amplitudes différentes pour vos fonctions cosin et sin:</p>
<pre>	void Update () {
		transform.localPosition= new Vector3(2*Mathf.Cos (Time.time + phase),0,
			3*Mathf.Sin (Time.time+phase));
	}</pre>
<p>Comme je l'ai mentionné au début, le but est de vous montrer ce qui peut être fait pour donner vie à votre objet. Vous pouvez développer un space shooter et utiliser ces conseils comme ils sont.Vous pouvez également les utiliser dans un jeu d'horreur. Vous pourriez avoir un objet de jeu vide avec un AudioSource joint qui émet un bruit de "Booooooo". Avec un modèle elliptique autour du joueur, l'objet semble tourner autour avec un mouvement de va-et-vient. Avec un peu plus variables de peaufinage vous pouvez créer un effet audio déroutant.</p>
<h2><a name="Hide"></a></h2>
<h2>Cache-cache (première FSM)</h2>
<p>Nous voilà sur le point d'introduire un nouveau mot, Finite-State-Machine (FSM). Qu'est-ce qui se cache derrière ce mot fantaisiste? Simplement un ensemble d'action en fonction d'autres actions ou situations. Cela signifie que votre IA effectue une action après analyse de l'entourage et de son propre état.  Il y a un tutoriel avancé pour ce sujet <a href="http://unitygems.com/fsm1/" target="_blank">ici</a>, mais croyez-moi, il est avancé.</p>
<p>Pour notre petit vaisseau, nous allons créer un simple (ou une je sais pas) FSM où le vaisseau peut se cacher derrière un rocher pour se protéger et continuer son voyage. Avant de sauter dans le codage, il est toujours recommandé de prendre le temps de penser à votre script.</p>
<ol>
<li>Levaisseau se déplace vers la gauche jusqu'à ce qu'il se fasse tirer dessus</li>
<li>Le vaisseau est attaqué et avance vers la couverture si la couverture n'est pas derrière lui</li>
<li>Le vaisseau attend un petit moment puis retourne à son voyage</li>
<li>Le vaisseau atteint l'autre extrémité ou est tué sur la route</li>
</ol>
<p>Le graphique ci-dessous montre les états du FSM et l'arbre de décision (en anglais).</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/FSMShip.png"><img title="FSMShip" alt="FSMShip" src="http://unitygems.com/wp-content/uploads/2012/12/FSMShip.png" width="868" height="647" /></a></p>
<p>Vous devez d'abord ajouter un public int santé, à notre classe de base Enemy.cs.</p>
<p>Maintenant, la grande partie:</p>
<pre>using UnityEngine;
using System.Collections;

public class ProtectScript :Enemy {

	Transform cover;
	Transform [] wayout = new Transform[2];
	public int way;
	enum State{Forward,Hiding,Moving};
        State Current;
	public bool hit;
	public override void Start () {
		base.Start ();
		health = 3;
		cover = GameObject.Find ("Cover").GetComponent&lt;Transform&gt;();
		GameObject[] obj = GameObject.FindGameObjectsWithTag("Wayout");
		for(int i = 0;i&lt;obj.Length;i++)wayout[i] = obj[i].GetComponent&lt;Transform&gt;();
		way = -1;
		hit =false;
                Current = State.Forward
                _primaryShoot = _transform.Find ("SpawnLeft").GetComponent&lt;Transform&gt;();
		_secondaryShoot = _transform.Find ("SpawnRight").GetComponent&lt;Transform&gt;();
		InvokeRepeating("Shoot",0.01f,Random.Range(2.0f,4.0f));
	}

	public override void Update () {
		switch(Current){
			case State.Forward:
				_transform.Translate ( -velocity.x*Time.deltaTime,0,velocity.z*Time.deltaTime,Space.World);
				break;
			case State.Hiding: 
				ToTarget (_cover);
				if(Vector3.Distance (cover.position,_transform.position) &lt;= 0.5f &amp;&amp;way&lt;0 ) {		
					StartCoroutine(ChangeSwitch(Random.Range (1.0f,3.0f)));	
					way = Random.Range (0,2);
				}
                                break;
			case State.Moving:
				ToTarget (_wayout[way]);
				if(Vector3.Distance (wayout[way].position,_transform.position) &lt; 0.2f) current = State.Forward;	
				break;
		}
	}

	IEnumerator ChangeSwitch(float time) {
		yield return new WaitForSeconds(time);
		Current = State.Moving;
	}

	public override void OnCollisionEnter(Collision other){
		if(other.gameObject.tag == "ProjectileShip"){
			Destroy(other.gameObject);
			health-=1;
			if(health&lt;=0)Destroy(gameObject);
			if(Current ==State.Forward &amp;&amp;_transform.position.x &gt;cover.position.x )
                             Current =State.Hiding;
		}
	}
	void ToTarget(Transform tr){
		Vector3 direction = tr.position - _transform.position;
		direction.Normalize();
		_transform.Translate ( direction.x*Time.deltaTime,0,direction.z*Time.deltaTime,Space.World);
	}
}</pre>
<p>Vous devez ajouter le RockPrefab et le positionner correctement sur ​​le niveau. Assurez-vous que le rocher et les deux sorties de rochers sont à y = 0.</p>
<p>Nous utilisons une énumération pour définir l' état du vaisseau. Le bon point de l'énumération, c'est que vous ne pouvez pas attribuer une valeur erronée. L'utilisation d'un switch ou un if avec des integers ou string, pour certaines raisons, vous pourriez vous retrouver avec une mauvaise valeur. Cela ne peut pas arriver avec Enum car seules les valeurs déclarées peuvent être utilisés.</p>
<p>Dans l' Update, nous utilisons un switch avec l'état <em>current</em>. Si notre vaisseau est attaqué pour la première fois, nous changeons l'état de <em>forward</em> à <em>hiding</em> et le navire se dirige vers le rocher. Il y attend un temps aléatoire jusqu'à ce qu'un <em>wayout</em> soit choisi et l'état est changé en <em>moving</em>. Le vaisseau quitte sa couverture. Lorsque vous atteignez le<em> wayout</em>, <em>Current</em> est alors changé pour <em>forward</em>. Si le rocher est déjà passé alors que le vaisseau est attaqué, il ne changera pas sa trajectoire considérant qu'il ne peut revenir en arrière.</p>
<p><em>if(Current ==State.Forward &amp;&amp;<strong>_transform.position.x &gt; cover.position.x</strong> )current =State.Hiding; </em></p>
<p>Cela assure que si la position est plus petite que la position de couverture (nous nous dirigeons vers la gauche et x est réduit) <em>current</em> ne peut plus être modifié.</p>
<p>ToTarget est appelée pour obtenir le nouveau vecteur pour faire avancer notre bateau.</p>
<p>Lancez le jeu, si vous ne faites rien, le navire fera son chemin vers la gauche. Si vous prenez assez tôt, sa direction va changer et les différents états seront utilisés. Tirez de nouveau après couverture, cela n'affectera pas plus.</p>
<h2><a name="Kamikaze"></a></h2>
<h2>Vaisseau kamikaze</h2>
<p>Le comportement suivant est assez simple, nous voulons que le vaisseau se "suicide"  dans le nôtre. Mais nous allons ajouter un peu plus de chose. Nous ne voulons pas que le vaisseau revienne en arrière pour nous attaquer.</p>
<p>Comme nous voulons réutiliser la fonction ToTarget du paragraphe précédent, nous la bougeons dans un autre fichier pour pouvoir l'appeler n'importe où nous en avons besoin.</p>
<p>Le projet a un script GameManager qui contient déjà nos méthodes d'extension:</p>
<pre>	public static void Target(this Transform _transform, Transform target){
		Vector3 direction = target.position - _transform.position;
		direction.Normalize();
		_transform.Translate ( direction.x*Time.deltaTime,0,direction.z*Time.deltaTime,Space.World);
	}</pre>
<p>Nous créons un nouveau script que nous attachons à notre vaisseau:</p>
<pre>using UnityEngine;
using System.Collections;

public class Banzai : Enemy {

	Transform target;
	public override void Start () {
		base.Start ();
		_primaryShoot = transform.Find ("SpawnLeft").GetComponent&lt;Transform&gt;();
		_secondaryShoot = transform.Find ("SpawnRight").GetComponent&lt;Transform&gt;();
		target = GameObject.FindGameObjectWithTag("Ship").GetComponent&lt;Transform&gt;();
	}

	public override void Update () {
		_transform.Target(_target);
	}
}</pre>
<p>Si nous lançons le jeu, le vaisseau nous suivra constamment. Comme nous l'avons dit, nous voulons seulement être attaqué si le vaisseau ennemi est en face de nous.</p>
<pre>	public override void Update () {
		if(_transform.position.x &gt; _target.position.x)
			_transform.Target(_target);
		else 
			base.Update();
	}</pre>
<p>Donc, si nous sommes sur la gauche de l'ennemi, nous utilisons notre méthode Target, autrement nous appelons le comportement de base de notre classe de base.</p>
<p>Vous pouvez facilement appliquer le même comportement au projectile ennemi, de sorte que le vaisseau et le projectile soient dirigées vers le vaisseau du joueur. Vous pouvez également l'utiliser uniquement sur ​​le projectile en utilisant l'un des comportements précédents. Encore plus! Que faire si vous essayez de créer un projectile oscillant!</p>
<p>N'oubliez pas que vous pourriez essayer de convertir les algorithmes que nous avons utilisés précédemment en méthodes d'extension, tout comme Target, de sorte que vous pouvez facilement les appeler sur n'importe quel objet.</p>
<h2><a name="ShipSee"></a></h2>
<h2>Vaisseau qui peut voir (devant lui)</h2>
<p>Enfin, dans notre dernière partie, nous allons revenir à notre premier algorithme qui  crée des vaisseaux à des positions aléatoires. Nous allons également supprimer notre rocher. Rappelez-vous, chaque navire reçoit une vitesse différente. En conséquence, certains vont aller plus vite que d' autres (Capitaine Evident pour vous servir). Cela signifie que certains d'entre eux vont se retrouver au-dessus des autres et on ne veut pas que cela se produise. Donc, nous allons donner des "yeux" à nos vaisseaux afin qu'ils puissent vérifier en face d'eux si quelque chose est là et modifier leur comportement en fonction de cela.</p>
<p>Le comportement que nous devons recréer est la ligne de vision. The image ci-dessous montre le principe de base. La flèche verte est la transform.forward, nous avons juste besoin de voir si quelque chose se trouve dans la zone de 45 degrés (ou autre) de ce vecteur dans une plage définie par le cercle bleu.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Présentation1.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-2008" alt="Présentation1" src="http://unitygems.com/wp-content/uploads/2012/11/Présentation1-300x225.png" width="300" height="225" /></a></p>
<p>Pour parvenir à ce principe, il y a différentes façons. Celle que j'ai choisi utilise le moteur de physique fourni par Unity. Je vais donc ajouter une sphère de collision à ma préfab de l'ennemi et définir son rayon de 3. Vous obtiendrez un avertissement qu'une box collider est déjà attachée, juste cliquez sur Ajouter. Cliquez IsTrigger .</p>
<p>Maintenant, définissons un script simple:</p>
<pre>using UnityEngine;
using System.Collections;

public class SeeFront : Enemy {

	float angle =45;
	public override void Start () {
		base.Start ();
	}

	public override void Update () {
		base.Update ();
	}

	void OnTriggerEnter(Collider other){
		if(other.gameObject.tag == "EnemyShip"){
			if(Vector3.Angle(other.gameObject.transform.position - _transform.position, transform.forward) &lt;= angle){
				SeeFront sc = other.GetComponent&lt;SeeFront&gt;();
				velocity = sc.velocity;
			}
		}
	}
}</pre>
<p>Tout ce que je fais est une régulation du trafic. Dans le cas où un vaisseau entre en collision avec un autre par l'arrière, il vérifie s'il existe un angle inférieur à 45 degrés, et si oui, il trouve la vitesse de l'autre vaisseau et l'applique à lui-même. Notez que je ne leur ai pas donné la possibilité de tirer mais vous devriez savoir comment le faire maintenant.</p>
<p>Ce principe pourrait également être utilisé dans un jeu de simulation de trafic comme SimCity ou GTA.</p>
<h2>Conclusion</h2>
<p>Nous avons atteint la fin de ce tutoriel. J'espère que vous avez appris quelques trucs que vous utiliserez dans votre propre jeu. Nous sommes passés par un peu de trigonométrie de base avec notre cercle unité et la façon d'utiliser ses fonctionnalités via sin et cos. Nous avons créé des formes et des cercles elliptiques fantaisistes. Nous avons vu un peu d'algèbre de vecteur de base comme la recherche de l'angle entre deux vecteurs ou la distance entre deux points. Nous sommes aussi allés à travers certaines caractéristiques de la POO de base comme l'héritage, override,  fonctions virtuelles, polymorphisme et autres.</p>
<p>Maintenant, c'est à vous de mélanger les différentes fonctionnalités que vous venez de voir et de créer des NPC qui accumulent de nombreux comportements. Gardez à l'esprit que l'IA devient rapidement cher sur le CPU. Vous pouvez vouloir soulager un peu avec InvokeRepeating afin que les calculs ne soient effectués que toutes les x secondes.</p>
<p>Dans l'ensemble, j'espère que cela vous a été utile.</p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/ia-space-shooter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sauvegarde de Données &#8211; Vous vous rappelez de moi!</title>
		<link>http://unitygems.com/sauvegarde/</link>
		<comments>http://unitygems.com/sauvegarde/#comments</comments>
		<pubDate>Thu, 27 Dec 2012 14:08:23 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[Beginner]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Binary]]></category>
		<category><![CDATA[BinaryFormatter]]></category>
		<category><![CDATA[Débutant]]></category>
		<category><![CDATA[PlayerPrefs]]></category>
		<category><![CDATA[sauvegarde]]></category>
		<category><![CDATA[Save]]></category>
		<category><![CDATA[Serialization]]></category>
		<category><![CDATA[UnitySerializer]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1798</guid>
		<description><![CDATA[<p>Motivation Vous devriez lire cet article si: Vous voulez savoir comment sauvegarder des données de manières persistantes Vous devez stocker des données plus complexes que de simples données primitives Introduction Le stockage de données avec Unity est un peu de la science. Si vous souhaitez enregistrer des scènes entières, la position des joueurs etc alors &#8230;<br /><a class="excerpt" href="http://unitygems.com/sauvegarde/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Vous devriez lire cet article si:</p>
<ul>
<li>Vous voulez savoir comment sauvegarder des données de manières persistantes</li>
<li>Vous devez stocker des données plus complexes que de simples données primitives</li>
</ul>
<h2>Introduction</h2>
<p>Le stockage de données avec Unity est un peu de la science. Si vous souhaitez enregistrer des scènes entières, la position des joueurs etc alors la tâche peut être intimidante. J'ai construit le <a href="http://whydoidoit.com/unityserializer">UnitySerializer</a> qui rend ce processus beaucoup plus facile et les futurs tutoriels de cette série porteront sur une solution de sauvegarde complète. Ce tutoriel couvre quelques-unes des autres manières de stocker des données et de les faire passer entre les versions du jeu, par exemple à travers une connexion RPC ou d'un serveur.</p>
<h2>Les bases</h2>
<p>Ok, donc les bases. Si vous voulez un morceau de données qui doit être enregistré avec Unity, votre premier recours est probablement PlayerPrefs. PlayerPrefs vous permet de stocker des valeurs fondamentales de primitives avec une simple string. C'est souvent une bonne idée de choisir des noms  significatifs au cas où vous commencer à piétiner partout dans vos propres données plus tard!</p>
<pre>//C# &amp; US

PlayerPrefs.SetInt("Score", currentScore);
PlayerPrefs.SetInt("HighScore1", currentScore);
PlayerPrefs.SetString("HighScore1Name", currentPlayerName);

//Obtenir les valeurs

highScore1 = PlayerPrefs.GetInt("HighScore1");
highScore1Name = PlayerPrefs.GetString("HighScore1Name", "N/A"); //Valeur par defaut optionelle</pre>
<h2>Valeurs dans le jeu</h2>
<p>Si vous souhaitez faire passer des données d'une scène vers une autre, la meilleure solution sera une classe statique:</p>
<pre>//US

public static class PermanentVariables
{
    public var playing : boolean;
    public var playerName : String;
}

//C#

public static class PermanentVariables
{
    public static bool playing;
    public static string playerName = "";
}</pre>
<p>et pour accéder:</p>
<pre>PermanentVariables.playerName = "whydoidoit";</pre>
<p>The downside with classes like this is that you can't set the variables using the Inspector - so if you want to use a combination of Inspector and code access you want to consider a <em>DontDestroyOnLoad</em>object that is present in each scene or your starting  scene.   You could do that like this:</p>
<p>L'inconvénient avec les classes de ce genre est que vous ne pouvez pas définir les variables à l'aide de l'inspecteur - si vous souhaitez utiliser une combinaison d' Inspector et aussi l'accessibilité des codes, pensez à l'objet <em>DontDestroyOnLoad</em>  qui est présent dans chaque scène ou la scène de départ. Vous pouvez le faire comme ceci:</p>
<pre>public class SharedBehaviour : MonoBehaviour {

	public static SharedBehaviour current;

	public Transform somePrefab;

	public int score;
	public string playerName;

	void Awake()
	{
		if(current != null &amp;&amp; current != this)
		{
			Destroy(gameObject);
		}
		else
		{
			DontDestroyOnLoad(gameObject);
			current = this;
		}
	}

}</pre>
<p>Ou avec US</p>
<pre>	static var current : NameOfYourScript;

	var somePrefab : Transform;

	var score : int;
	var playerName : String;

	function Awake()
	{
		if(current != null &amp;&amp; current != this)
		{
			Destroy(gameObject);
		}
		else
		{
			DontDestroyOnLoad(gameObject);
			current = this;
		}
	}</pre>
<p>static assure que peu importe dans combien de scènes l'objet est utilisé (utile pour les tests), il n'y a qu' une copie en mémoire. Vous devez accéder à des variables comme ceci:</p>
<pre>var x = SharedBehaviour.current.somePrefab;</pre>
<h2>Stocker des choses plus complexes</h2>
<p>Ok so we had a look at a high score method using PlayerPrefs - what a total load of rubbish that was - having to know it was HighScore1Name - ugh. We'd be better off defining a high score table like this:</p>
<p>Ok, donc nous avons jeté un coup d’œil à une méthode high score utilisant PlayerPrefs - ce dégât quand il faut  savoir que la varible s'appelle HighScore1Name et pas autrement - mouaip. Nous ferions mieux de définir un tableau des hi-score comme ceci:</p>
<pre>public class ScoreEntry
{
     public string name;
     public int score;
}

public List&lt;ScoreEntry&gt; highScores = new List&lt;ScoreEntry&gt;();

//Utilisation
highScores.Add(new ScoreEntry { name = currentPlayerName,score = score });

//Affichage
void OnGUI()
{
     foreach(var score in highScores)
     {
         GUILayout.Label(string.Format("{0} : {1:#,0}",
            score.name, score.score));
     }
}
class ScoreEntry
{
     var name : String;
     var score : int;
}

var highScores = new List.&lt;ScoreEntry&gt;();

//Utilisation
var entry = new ScoreEntry();
entry.name = currentPlayerName;
entry.score = score;
highScores.Add(entry);

//Affichage

function OnGUI()
{
     for(var score in highScores)
     {
         GUILayout.Label(String.Format("{0} : {1:#,0}",
            score.name, score.score));
     }
}</pre>
<p>Mais comment pourrions-nous conserver cela dans PlayerPrefs - BinaryFormatter vient à la rescousse! Avec BinaryFormatter nous pouvons convertir n'importe quelle classe avec un constructeur sans paramètre dans un tableau d'octets et de là dans une string qui est adapté pour stocker dans PlayerPrefs. Il vous suffit d'inclure quelques namespaces et c'est tout:</p>
<pre>// UnityScript
//Ces namespaces sont nécessaires
//pour BinaryFormatter
import System;
import System.Runtime.Serialization.Formatters.Binary;
import System.IO;

class ScoreEntry
{
     var name : String;
     var score : int;
}

//High score
var highScores = new List.&lt;ScoreEntry&gt;();

function SaveScores()
{
	//Nouveau BinaryFormatter
	var b = new BinaryFormatter();
	//Creation d'un MemoryStream
	var m = new MemoryStream();
	//Sauvegarde des scores
	b.Serialize(m, highScores);
	//Addition à PLayerPrefs
	PlayerPrefs.SetString("HighScores", Convert.ToBase64String(m.GetBuffer()));
}

function Start()
{
	//Trouver les données
	var data = PlayerPrefs.GetString("HighScores");
	//Si non-nul, charger
	if(!String.IsNullOrEmpty(data))
	{
		//Binary formatter pour le nouveau chargement
		var b = new BinaryFormatter();
		//Création d'un MemoryStrea, avec les données
	        var m = new MemoryStream(Convert.FromBase64String(data));
	        //Charger le nouveau score
	        highScores = b.Deserialize(m) as List.&lt;ScoreEntry&gt;;
         }
}

// C#
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.Collections;
//Ces namespaces sont nécessaires 
//pour BinaryFormatter
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public class HighScores : MonoBehaviour {

	//High score 
	public class ScoreEntry
	{
		//Nom du joueur
	     public string name;
		//Score
	     public int score;
	}

	//High score 
	public List&lt;ScoreEntry&gt; highScores = new List&lt;ScoreEntry&gt;();

	void SaveScores()
	{
		//Création d'un BinaryFormatter 
		var b = new BinaryFormatter();
		//Création d'un MemoryStream
		var m = new MemoryStream();
		//Sauvegarde des scores
		b.Serialize(m, highScores);
		//Addition à PlayerPrefs
		PlayerPrefs.SetString("HighScores", 
			Convert.ToBase64String(
				m.GetBuffer()
			)
		);
	}

	void Start()
	{
		//Obtenir les données
		var data = PlayerPrefs.GetString("HighScores");
		//Si non-nul, charger
		if(!string.IsNullOrEmpty(data))
		{
			//BinaryFormatter puis renvoyer les données
			var b = new BinaryFormatter();
			//Création d'un MemoryStream avec les données
			var m = new MemoryStream(Convert.FromBase64String(data));
			//Charger les nouveaux scores
			highScores = (List&lt;ScoreEntry&gt;)b.Deserialize(m);
		}
	}

}</pre>
<h2>Stocker des objets Unity</h2>
<p>It can be tricky to store actual Unity objects so there's often a need to create a class that mirrors the data in a Unity object that you actually use for storage.  So for example if you wanted to pass a bunch of AnimationStates across an RPC call then you will need to create a class that represents the transmitted AnimationState.  The same is true for a bunch of other Unity objects, but the work is trivial.</p>
<p>il peut être difficile de stocker des objets Unity de sorte qu'il est souvent nécessaire de créer une classe qui reflète les données dans un objet Unity que vous utilisez réellement pour le stockage. Ainsi, par exemple, si vous vouliez passer un tas de AnimationStates à travers un appel RPC alors vous aurez besoin de créer une classe qui représente la AnimationState transmis. La même chose est vraie pour un tas d'objets Unity autres, mais le travail est trivial.</p>
<h2>Envoyer Via RPC</h2>
<p>Il apparaît donc clairement que le dernier code parvient à transformer une vieille classe en string, donc on peut utiliser le même principe pour envoyer n'importe quel type de paramètre via RPC! <div class="alert green"> Cela n'est pas documenté mais RPC peut également envoyer un byte [], que l'on peut obtenir directement de notre BinaryFormatter, nous permettant d'économiser beaucoup de temps de conversion vers et à partir d'une string. </div> Ajouter la possibilité d'envoyer nos meilleurs scores à un autre joueur est soudainement très très facile:</p>
<pre>	[RPC]
	void ReceiveHighScores(byte[] highScores)
	{
		var b = new BinaryFormatter();
		var m = new MemoryStream(highScores);
		var otherPlayersScores = (List&lt;ScoreEntry&gt;)b.Deserialize(m);
	}

	void UpdateScores()
	{
		var b = new BinaryFormatter();
		var m = new MemoryStream();
		b.Serialize(highScores, m);
		networkView.RPC("ReceiveHighScores", RPCMode.Others, m.GetBuffer());
	}</pre>
<h2>Parler à la toile</h2>
<p>L' envoi de données vers des serveurs Web à l'aide WWWForm est facile, mais il peut être plus facile de convertir les données binaires dans une string comme nous l'avons vu avec Convert.ToBase64String () même si ce n'est pas nécessaire en fonction de la configuration de votre serveur.</p>
<h2>Saving to a file</h2>
<p>Sauvegarder un fichier est également facile, Unity fournit Application.persistentDataPath comme un emplacement pour vos fichiers et vous venez d'utiliser l'objet FileStream en place du MemoryStream.</p>
<pre>void SaveScores()
	{
		//Créer un BinaryFormatter
		var b = new BinaryFormatter();
		//Créer un fichier
		var f = File.Create(Application.persistentDataPath + "/highscores.dat");
		//Sauvegarder les scores
		b.Serialize(f, highScores);
                f.Close();
	}

	void Start()
	{
		//Si non-nul, charger
		if(File.Exists(Application.persistentDataPath + "/highscores.dat"))
		{
			//BinaryFormatter pour charger les nouvelles données
			var b = new BinaryFormatter();
			//Créer le fichier
			var f = File.Open(Application.persistentDataPath + "/highscores.dat", FileMode.Open);
			//Charger les scores
			highScores = (List&lt;ScoreEntry&gt;)b.Deserialize(f);
			f.Close();
		}
	}</pre>
<h2>Conclusion</h2>
<p>J'espère que vous avez appris quelques nouveaux trucs pour enregistrer les données et déplacez entre les différentes instances du même jeu, que ce soit en tant que valeur stockée ou via une connexion RPC.</p>
<p>N'oubliez pas que si vous souhaitez enregistrer des scènes complexes et des instances de prefab vous consulter <a href="http://whydoidoit.com/unityserializer">Unity Serializer</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/sauvegarde/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quaternion &#8211; Rotation &#8211; Plan d&#8217;attaque</title>
		<link>http://unitygems.com/quaternion-rotation-attaque/</link>
		<comments>http://unitygems.com/quaternion-rotation-attaque/#comments</comments>
		<pubDate>Thu, 06 Dec 2012 13:03:36 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[Beginner]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[attaque]]></category>
		<category><![CDATA[beginner]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Débutant]]></category>
		<category><![CDATA[Finite State Machine]]></category>
		<category><![CDATA[one axis rotation]]></category>
		<category><![CDATA[Quaternions]]></category>
		<category><![CDATA[rotation]]></category>
		<category><![CDATA[yield]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1722</guid>
		<description><![CDATA[<p>Dans ce tutorial Pourquoi les Quaternion sont utiles Faire que l&#8217;ennemi regarde le joueur avec réalisme Orienter du texte face à la caméra Combiner plusieurs Quaternions Orienter un billboard face à la caméra Ajouter des mouvements Plus de states Le projet du tutoriel Pourquoi les Quaternion sont utiles Les quaternions sont utilisés pour décrire les &#8230;<br /><a class="excerpt" href="http://unitygems.com/quaternion-rotation-attaque/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Dans ce tutorial</h2>
<ul>
<li><a href="#1">Pourquoi les Quaternion sont utiles</a></li>
<li><a href="#2">Faire que l'ennemi regarde le joueur avec réalisme</a></li>
<li><a href="#3">Orienter du texte face à la caméra</a></li>
<li><a href="#4">Combiner plusieurs Quaternions</a></li>
<li><a href="#5">Orienter un billboard face à la caméra</a></li>
<li><a href="#6">Ajouter des mouvements</a></li>
<li><a href="#7">Plus de states</a></li>
</ul>
<h2>Le projet du tutoriel</h2>
<p><div class="one_half">Vous pouvez télécharger le projet <a href="http://unitygems.com/Downloads/quaternions.unitypackage">ici</a>.</p>
<p>Le projet est organisé de telle sorte que chaque scène montre une partie différente du tutoriel.</p>
<p>Chaque scène, script et objet utilisés sont situés sous Tutorial/Part1.</p>
<p>Vous verrez un indicateur lorsque le tutoriel change de scène.</p>
<div class="alert green">Tutoriel Scene 1</div>
<p>Le tutoriel utilise un certain nombre d'assets gratuits de l'Asset Store.</div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/10/project.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-57" title="project" src="http://unitygems.com/wp-content/uploads/2012/10/project.png" alt="" width="472" height="580" /></a></div><div class="clear"></div></p>
<h2><a name="1"></a></h2>
<h2>Pourquoi les Quaternion sont utiles</h2>
<p>Les quaternions sont utilisés pour décrire les rotations dans Unity, ils sont le format utilisé en interne plutôt que les matrices de transformation.</p>
<p>Il ya une confusion immédiate avec quaternions pour de nombreux utilisateurs - et cela est dû au fait que lorsque vous regardez un objet dans l'inspecteur, la rotation est représentée avec un Vector3 avec des rotations autour de X, Y et Z. Ce sont en fait les  <a href="http://docs.unity3d.com/Documentation/ScriptReference/Quaternion-eulerAngles.html">eulerAngles</a> de la rotation - et non le Quaternion lui-même. Cette confusion est aggravée par le fait que les quaternions ont des propriétés appelées x, y et z - mais ceux-ci n'ont rien à voir avec les valeurs spécifiées dans l'inspecteur (ou du moins très peu)!</p>
<p>Il ya plusieurs façons de faire un Quaternion - à partor d'un Vector3 d' angles, vous utilisez Quaternion.Euler soit avec les 3 axes de rotation comme paramètres ou comme un Vector3 décrivant la rotation. Pour faire une rotation qui regarde dans une direction, vous utilisez Quaternion.LookRotation (directionVector). Dans ce tutoriel, vous allez apprendre d'autres façons d'utiliser les quaternions et comment les combiner.</p>
<p>De nombreux débutants tombent dans le piège suivant:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">transform.rotation = new Vector3(100,100,100);
transform.rotation = new Quaternion(100,100,100,1);</pre>
<p>La première ligne renverra une erreur de conversion. La seconde passera le cap de la compilation mais pas celui de votre compréhension. Vous voulez que votre objet ait une rotation de (100,100,100) cependant dans l'inspecteur vous voyez des valeurs différentes. Pourtant vous avex passé (100,100,100,1) (c'est quoi ce 1...?). En fait vous n'avez pas donné une rotation mais plutôt un vecteur vers lequel l'objet regarde. Le 1 de fin est la quatrième dimension ou le domaine des nombres complexes/imaginaires. En simplifié, nous passons un vector3 cible que nous interpolons avec le 1 (cette valeur peut être 1 ou -1 mais apparait le plus souvent comme 1).</p>
<div class="alert yellow">Ne pas manipuler les x, y, z et w d'un Quaternion si vous n'êtes pas sûr de ce que vous faites. Ces valeurs ne sont pas directement liées aux valeurs affichées dans l'Inspecteur.</div>
<h3>Résumé sur eulerAngles et Quaternions:</h3>
<h3><strong>EulerAngles:</strong></h3>
<p><strong>Avantages:</strong></p>
<ul>
<li>Facile à comprendre et à visualiser puisqu'ils utilisent un vector 3D.</li>
<li>Ils sont calculés plus rapidement du simple fait qu'ils ne contiennent que 3 valeurs (4 pour le Quaternion).</li>
</ul>
<p><strong>Inconvénients:</strong></p>
<ul>
<li>Une rotation peut produire différent résultats. Différents logiciels utilisent des ordres différent (x,y,z) ou (y,x,z) ou autres. Le résultat est différent à chaque fois.</li>
<li>l'effet Gimbal Lock. Quand une rotation s'aligne avec une autre, elles se bloquent ensemble et une dimension est perdue.</li>
</ul>
<h3>Quaternions:</h3>
<p><strong>Avantages:</strong></p>
<ul>
<li>Evitent l'effet de Gimbal Lock</li>
<li>La rotation est basée sur un vecteur cible et non un ensemble de rotations indépendantes.</li>
</ul>
<p><strong>Inconvénients:</strong></p>
<ul>
<li>Ils sont légèrement plus lents que les eulerAngles du fait de la valeur en plus.</li>
<li>Un humain normalement constitué ne peut les comprendre et les maitriser entièrement en une seule vie.</li>
</ul>
<p>Vous pouvez combiner des rotations multiples en utilisant l'opérateur * (qui vous sera utile plus tard dans ce tutoriel) et vous pouvez également modifier un Vector3 en multipliant par un quaternion, cela renvoie une version tournée du vecteur. L'ordre de la manipulation Quaternion est significatif.</p>
<pre>var newVector = Quaternion.AngleAxis(90, Vector3.up) * Quaternion.LookRotation(someDirection) * someVector;</pre>
<div class="alert yellow">Vous n'additionez ou ne combinez pas deux Quaternions avec + (plus).  L'opérateur * (multiplication) agit comme un moyen de cumuler plusieurs Quaternions .</div>
<div class="alert blue"> Une des raisons pour l'utilisation de Quaternion plutôt que Vector3 pour décrire les rotations, c'est que si un Vector3 peut décrire une rotation, il n'est pas possible de faire pivoter un objet en déplaçant les trois valeurs rotation de l'axe vers un ensemble de valeurs cibles. Cela est dû à un effet appelé Gimbal Lock qui affecte les EulerAngles, si vous êtes intéressés, vous pouvez en apprendre plus à ce sujet sur <a href="http://en.wikipedia.org/wiki/Gimbal_lock">Wikipedia.</a> Il se produit en raison de la nécessité de déplacer chaque valeur individuellement et dans certaines combinaisons ce qui crée une situation où la valeur cible ne peut pas être atteinte dans une dimension due aux mouvements dans les autres. Les Quaternions éliminent ce problème en faisant une rotation complète en une seule étape autour d'un axe unique - essentiellement en utilisant 4 dimensions d'espace!</div>
<p>EulerAngles sont faciles à représenter, mais sont beaucoup moins puissants que les Quaternions. Avec Unity, il est facile de se déplacer entre les deux représentations afin que vous puissiez choisir celle qui convient le mieux à chaque fois. Si vous restraindre les rotations, par exemple, vous pouvez trouver les eulerAngles d'un Quaternion, puis appliquez votre opération de restriction avec Mathf.Clamp puis tournez les angles de nouveau dans un quaternion en mettant à jour la variable eulerAngles ou en créant un nouveau Quaternion avec Quaternion.Euler (yourAngles).</p>
<p>Lorsque vous voulez combiner des rotations, comme une inclinaison de la tête et une rotation du corps, vous pouvez utiliser les deux approche, mais dès que les rotations ne sont plus autour de l'axes général (world axis), par exemple votre personnage peut aussi être penché en avant, alors vous préfèrerez les Quaternions. Il est très simple d'utiliser un Quaternion pour créer une simple rotation autour de chaque axe que vous souhaitez, puis les combiner.</p>
<p>Unity fournit également des axes très utiles transform.forward, transform.right et transform.up qui peuvent être utilisés en conjonction avec Quaternion.AngleAxis pour créer des rotations qui peuvent être appliquées en plus d'une rotation de l'objet existant.</p>
<pre>transform.rotation = Quaternion.AngleAxis(degrees, transform.right) * transform.rotation;</pre>
<h2><a name="2"></a></h2>
<h2>Faire que l'ennemi regarde le joueur avec réalisme</h2>
<p>Une chose bien commune que nous devons faire souvent est de faire quelque chose regarder dans une direction. Dans un jeu spatial en 3 dimensions où regarder sous tous les angles est possible, ce n'est pas un problème - mais lorsque les ennemis doivent se tenir debout sur le sol, les ennuis commencent.</p>
<div class="alert green">Tutorial Scene 1</div>
<p>La manière la plus évidente pour qu'un ennemi regarde dans une direction est d'utiliser Transform.LookAt (somePosition). Dans notre premier exemple, nous avons un joueur qui est une capsule avec une caméra attachée dessus, elle se déplace en utilisant l' Input de base pour les mouvement FPS.</p>
<p>Il ya quatre ennemis dans notre scène. Nos ennemis sont assez stupides dans cette première scène, ils vont juste pointer vers le joueur, en utilisant BasicLookAtPlayer.cs</p>
<pre>using UnityEngine;
using System.Collections;

public class BasicLookAtPlayer : MonoBehaviour {
	void Update () {
		transform.LookAt(Camera.main.transform.position);
	}
}</pre>
<p>Comme vous pouvez le voir, on utilise la commande LookAt pour pointer l'ennemi vers la caméra principale, dans notre cas le joueur. Malheureusement, cela a un inconvénient assez important lorsque le joueur ou l'ennemi sont à différentes hauteurs! L'ennemi peut se retrouver couché sur le dos d'une manière improbable ou tout simplement à regarder vers le bas...</p>
<p><div class="one_half"><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.21.39.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-79" title="Screen Shot 2012-10-13 at 22.21.39" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.21.39.png" alt="" width="1290" height="1206" /></a></div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.22.42.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-80" title="Screen Shot 2012-10-13 at 22.22.42" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.22.42.png" alt="" width="238" height="258" /></a></div><div class="clear"></div></p>
<h3>Rotation sur l'axe-y seulement</h3>
<p>Nous devons faire tourner l'ennemi seulement autour de l'axe Y de sorte qu'il regarde en direction du joueur, sans tourner autour des axes x et z qui le feraient pencher de façon improbable.</p>
<div class="alert green">Tutorial Scene 2</div>
<p>Heureusement, c'est assez simple à accomplir. Dasn cette scène, nous utilisons le script LookAtPlayerOnOneAxis.cs</p>
<pre>using UnityEngine;
using System.Collections;

public class LookAtPlayerOnOneAxis : MonoBehaviour {

	void Update () {
		var newRotation = Quaternion.LookRotation(Camera.main.transform.position - transform.position).eulerAngles;
		newRotation.x = 0;
		newRotation.z = 0;
		transform.rotation = Quaternion.Euler(newRotation);
	}
}</pre>
<p>Tout d'abord nous créons un nouveau Quaternion qui regarde depuis la position actuelle de l'ennemi vers la caméra principale (notre joueur). Quaternion.LookRotation prend une direction, que l'on peut obtenir facilement en faisant la soustraction de la position de la caméra moins la position de l'ennemi. Lorsque nous avons le Quaternion nous le changeons en une représentation de l'angle en Vector3 avec eulerAngles et nous le plaçons dans newRotation.</p>
<p>La rotation que nous avons créé est exactement la même que celle obtenue en utilisant la méthode LookAt dans la première scène.</p>
<p>Pour faire en sorte que cela ne soit qu'une rotation sur l'axe-y, nous avons simplement mis le x et z des éléments à 0 - puis nous changeons la valeur actualisée de nouveau en un Quaternion en utilisant Quaternion.Euler.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.37.49.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-91" title="Screen Shot 2012-10-13 at 22.37.49" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-13-at-22.37.49.png" alt="" width="484" height="796" /></a></p>
<h3>Faire la rotation en douceur</h3>
<p>At the moment the enemies just snap to a rotation facing the player - that's not very realistic and will start to look strange when we start having them move around the scene.</p>
<p>Pour le moment, les ennemis se tournent brusquement vers le joueur - ce n'est pas très réaliste et ça peut sembler étrange quand nous commencerons à les déplacer autour de la scène.</p>
<p><div class="alert green">Tutorial Scene 3</div><br />
Nous pouvons utiliser Quaternion.Slerp pour interpoler entre la rotation actuelle du personnage et la rotation cible vers le joueur.</p>
<pre> using UnityEngine;
using System.Collections;

public class SmoothLookAtPlayerOnOneAxis : MonoBehaviour {

	void Update () {
		var newRotation = Quaternion.LookRotation(Camera.main.transform.position - transform.position).eulerAngles;
		newRotation.x = 0;
		newRotation.z = 0;
		transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(newRotation), Time.deltaTime);
	}
}</pre>
<p>Encore une fois nous faisons la rotation à l'aide de LookRotation et un angle de zéro sur les axes x et z. Ensuite, nous utilisons Slerp pour interpoler entre la rotation actuelle et la cible.</p>
<p>Slerp prend trois paramètres. Le premier (1) est la rotation de départ, le seconde (2) est la rotation cible et le troisième est un nombre compris entre 0 et 1 indiquant le ratio de translation entre 1 et 2 . Une valeur de 0 ne change rien, une valeur de 1 termine la rotation  et une valeur de 0,5 reviendra à mi-chemin entre les deux.</p>
<div class="alert blue">Si vous voulez faire que la position entre le début et la fin ne soit pas une ligne droite,  alors vous pouvez appliquer une fonction qui "adoucit" la valeur. Une fonction d'"adoucissement" (...) a un paramètre compris entre 0 et 1 et renvoie une valeur comprise entre 0 et 1, mais la valeur retournée se trouve sur une courbe. Le résultat pratique de ceci est que le mouvement peut être fait pour être lent au début, puis plus rapide au milieu et enfin ralentir vers la fin - ou pratiquement tout ce que vous voulez - tant que vous avez une fonction pour cela.</div>
<p>Dans notre cas, nous voulons mettre à jour la rotation potentiel à chaque iframe, nous n'avons donc pas vraiment une bonne valeur de départ et de fin et une quantité connue de temps entre les deux. Pour atteindre notre objectif et faire que la rotation semble lisse, nous prenons la rotation actuelle et la mettons à jour pour se rapprocher de la rotation finale par un ratio à chaque frame. Pour ce faire, nous avons mis le troisième paramètre à Time.deltaTime.</p>
<p>L'effet de ceci est que le personnage va se mettre à tourner plus rapidement, puisque le ratio de départ représente une plus grande valeur - utiliser Time.deltaTime signifie que nous bougeons n% vers la rotation cible à chaque frame (où n% serait de 10% si Time.deltaTime était de 0,1 s). Le frame suivant, nous commençons plus près de la rotation cible (en supposant que le joueur ne soit pas en mouvement) et nous déplaços n% de la différence. Alors que nous approchons de la rotation cible notre vitesse de rotation va ralentir et nous donner une attrayante rotation en ralentissement.</p>
<div class="alert red">Comme la rotation se rapproche de la cible, la différence sera très faible, mais nous sommes encore en approche de n%, de sorte qu'il y aura un temps très long avant que la rotation soit définitivement terminée. Ce principe est similaire à la limite en algèbre, la limite se rappoche d'une valeur (asymptote) sans jamais l'atteindre. Il peut être nécessaire de faire en sorte que le paramètre 3 croit avec le temps de manière à fermer la boucle.</div>
<h3>Rotation en douceur avec une vitesse maximum</h3>
<p>The problem of our last example is that  should the rotations be very different the character may start rotating very quickly, perhaps unrealistically.  We probably want a way of making a smooth rotation that is limited to a maximum number of degrees per second.</p>
<p>Le problème de notre dernier exemple est que, si les rotations sont très différentes, le personnage peut se mettre à tourner très rapidement, peut-être de manière irréaliste. Nous avons probablement besoin d'un moyen de créer une rotation en douceur qui est limiteé à un nombre maximum de degrés par seconde.</p>
<div class="alert green">Tutorial Scene 4</div>
<p>Dans la quatrième scène nous utilisons le script RotateToPlayerWithAMaximumSpeed.cs</p>
<pre>using UnityEngine;
using System.Collections;

public class RotateToPlayerWithAMaximumSpeed : MonoBehaviour {

	public float maximumRotateSpeed = 40;
	public float minimumTimeToReachTarget = 0.5f;
	Transform _transform;
	Transform _cameraTransform;
	float _velocity;

	void Start(){
		_transform = transform;
		_cameraTransform = Camera.main.transform;
	}

	void Update () {
		var newRotation = Quaternion.LookRotation(_cameraTransform.position - _transform.position).eulerAngles;
		var angles = _transform.rotation.eulerAngles;
		_transform.rotation = Quaternion.Euler(angles.x, Mathf.SmoothDampAngle(angles.y, newRotation.y, ref _velocity, minimumTimeToReachTarget, maximumRotateSpeed),
			angles.z);
	}
}</pre>
<p>A partir de cet exemple, nous allons commencer à faire une incursion dans le monde de l'optimisation. Nous allons donc cacher nos Transforms pour la caméra et l'enemi.</p>
<div class="alert blue">L'utilisation de la Transform peut sembler être une simple utilisation de variable, mais non. Quand vous lancez la commande transform.position , le compilateur lance GetComponent&lt;Transform&gt;().position -cela peut alterer le rendement si vous lancez cet commande plusieurs fois en Update.</div>
<p>Donc, pour effectuer notre rotation avec une vitesse maximum nous appelons Mathf.SmoothDampAngle - cette fois nous allons également combiner les eulerAngles existants de la rotation avec une nouvelle valeur pour la rotation Y. Les fonctions SmoothDampXXXX (disponible sur Vector3 et Mathf) prennent une vitesse actuelle, une vitesse maximale et un temps prévu pour compléter le mouvement. La vitesse actuellet est seulement utilisée par la routine et nous devons fournir un float pour le contenir - nous ne l'assignons pas nous-mêmes.</p>
<pre>Mathf.SmoothDampAngle(angles.y, newRotation.y, ref _velocity, minimumTimeToReachTarget, maximumRotateSpeed)</pre>
<p>maximumRotateSpeed needs little explaining, but minimumTimeToReachTarget allows us to have a slower smoothed start and finish to our rotation.  When set to 0 the rotation will complete as fast as possible without exceeding the maximumSpeed, a larger value indicates that we are happy that the rotation be slower so that it will complete closing the continually updated rotation distance in the ideal time.  The practical upshot of that is that rotations will smoothly slow down as the target value is approached.</p>
<p>maximumRotateSpeed est assez clair cependant minimumTimeToReachTarget nous permet d'avoir un rythme plus lent et plus lissée en début et en fin de rotation. Lorsqu'elle est réglée sur 0, la rotation est complétée aussi vite que possible sans dépasser le maximumSpeed, une valeur plus élevée indique que nous voulons que la rotation soit plus lente afin qu'elle achève de fermer la distance de rotation continuellement mis à jour en temps idéal. La conséquence pratique en est que les rotations ralentissent en douceur quand la valeur cible est approchée.</p>
<pre>	void Update () {
		var newRotation = Quaternion.LookRotation(_cameraTransform.position - _transform.position).eulerAngles;
		var angles = _transform.rotation.eulerAngles;
		_transform.rotation = Quaternion.Euler(angles.x, Mathf.SmoothDampAngle(angles.y, newRotation.y, ref _velocity, minimumTimeToReachTarget, maximumRotateSpeed),
			angles.z);
	}</pre>
<p>L'Update fonctionne sur notre rotation cible, prend la rotation actuelle de l'ennemi et remplace l'axe de rotation Y avec le SmoothDampAngle pour faire tourner l'ennemi vers notre joueur. Un effet très utile.</p>
<h2><a name="3"></a></h2>
<h2>Orienter du texte face à la caméra</h2>
<p>Nos ennemis sont assez ennuyeux et nous allons vouloir leur donner un peu d' IA. La première chose que nous allons faire est de les faire dormir jusqu'à ce que le joueur soit proche d'eux - nous voulons indiquer leur sommeil avec un signe de ronflement Zzzzz sau-dessus d'eux quand ils sont dans cet état.</p>
<div class="alert green">Tutorial Scene 5</div>
<p>Nous allons commencer par ajouter le commencement d'un Finite State Machine à chacun des enemis. Cela se trouve dans MovementStateMachine.</p>
<pre>using UnityEngine;
using System.Collections;

public class MovementStateMachine : MonoBehaviour {

	public bool sleeping = true;
	public Transform sleepingPrefab;

	IEnumerator Start () {
		var t = transform;
		while(true){
			yield return new WaitForSeconds(Random.value * 3f + 2);
			if(sleeping)	{
				Instantiate(sleepingPrefab, t.position + Vector3.up * 3f, t.rotation);
			}
		}
	}
}</pre>
<p>Nous avons un state machine très simple qui dit endormi ou non. Pas grand chose se passe quand il se réveille cependant. Et en fait il n'y a toujours rien pour le réveiller dans notre code. Mais cela suffit pour démontrer comment faire tourner un objet pour qu'il soit en face de la caméra</p>
<p>Quand le script se lance, il rentre dans une coroutine qui va créer une prefab au-dessus de la tête de l'enemi si le script est endormi à ce moment.</p>
<p><div class="one_half"><div class="alert blue">Voyez comment on peut cacher les composants dans des variables locales quand nous utilisons une coroutine.</div></p>
<p>La prefab est un simple TextMesh et MeshRenderer avec un script qui les fait monter au fil du temps, et notre script BasicLookAtPlayer de la scène 1.Le script de montée est aussi très simple.</div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-00.02.21.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-109" title="Screen Shot 2012-10-14 at 00.02.21" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-00.02.21-254x300.png" alt="" width="254" height="300" /></a></div><div class="clear"></div></p>
<pre>using UnityEngine;
using System.Collections;

public class GentleRiseAndDestroy : MonoBehaviour {

	public float timeToLive = 2f;
	Transform _transform;

	void Start () {
		_transform = transform;
		Destroy(gameObject, timeToLive);
	}

	void Update () {
		_transform.position += Vector3.up * Time.deltaTime;
	}
}</pre>
<p>Le script détruit l'objet au bout de quelques secondes, et fait l'objet s'élever lentement à chaque frame.</p>
<p><div class="one_half">L'effet que nous recherchons est que le Zzzzzz apparaisse droit face la caméra, peu importe où il est - plutôt que de devoir se déplacer . Mais il y a encore quelques problèmes ici.</p>
<p>Tout d'abord le Zzzzzz apparaît à l'envers du fait que Unity veut que l'avant d'un TextMesh pointe dans la direction opposée de la caméra pour que le texte puisse être lu correctement de gauche à droite.</div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-00.15.07.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-120" title="Screen Shot 2012-10-14 at 00.15.07" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-00.15.07-300x184.png" alt="" width="300" height="184" /></a></div><div class="clear"></div></p>
<div class="alert yellow">Unity offre quelque singularités quand il s'agit de la direction vers laquelle les objets pointent. Les plans générés par Unity ont face vers le haut au lieu de vers l'avant (<em>Vector3.forward</em>) alors que les TextMesh pointent vers l'avant<em>.</em> </div>
<p>When you get close to the enemies you see that there is another problem, the Zzzzzz aren't pointing outwards from the screen.  A lot of people are confused by this (I know I was) - we have a script that says LookAt the camera - why isn't it looking at it?</p>
<p>Lorsque vous vous approchez des ennemis vous voyez qu'il y a un problème, les Zzzzzz ne sont pas orientés vers l'extérieur de l'écran. Beaucoup de gens sont confus par cela (je l'étais) - nous avons un script qui dit LookAt (regarde) la caméra - pourquoi est-ce que cela ne regarde pas la caméra?</p>
<h3>Modifier des vecteurs de Transform</h3>
<p>Le problème avec LookAt, c'est que cela regarde vers l'emplacement de la caméra. Mais la caméra est située en un point fixe dans le monde, tandis que l'image qu'elle projette représente les choses vues sur son plan focal. Les objets regardent vers un seul point et, selon l'endroit où ils sont, ce n'est pas par rapport à l'emplacement où ils sont rendus à l'écran par la caméra.</p>
<div class="alert green">Tutorial Scene 6</div>
<p>Il y a une astuce pour ce faire, mais elle n'est pas conseillé dans de nombreux cas et nous allons voir une autre façon dans la section suivante. Vous savez probablement que transform.forward représente la direction vers l'avant d'un objet de la même manière que Vector3.forward représente l'avant en coordonnées du monde. Ce que beaucoup de gens ne savent pas, c'est que vous pouvez également <strong>définir</strong> transform.forward et il va faire pivoter l'objet!</p>
<p>Ce que nous voulons, c'est notre TextMesh de pointer vers le plan focal de la caméra, et non y regarder. En fait, nous voulons que l'object adopte le <em>forward</em> de la caméra.</p>
<div class="alert yellow">Rappelez-vous que les TextMeshes sont réfléchis. S'il s'agissait d'un modèle normal, nous voudrions qu'il adopter transform.forward pour lui permettre de faire face à la caméra.</div>
<pre>using UnityEngine;
using System.Collections;

public class ReversedCameraDirection : MonoBehaviour {

	Transform _transform;
	Transform _cameraTransform;

	void Start () {
		_transform = transform;
		_cameraTransform = Camera.main.transform;
	}

	void Update () {
		_transform.forward = _cameraTransform.forward;
	}
}</pre>
<p>Nous ajoutons ce script ReverseCameraDirection à la prefab Zzzzz Sleeping Text en place du script BasicLookAtPlayer et c'est parti.</p>
<div class="alert yellow">Régler le vecteur transform.forward, .up ou .right, et semble juste très puissant et vous permet de penser en termes de vecteurs plutôt que rotations - mais attention, lorsque vous définissez l'une de ces valeurs, vous ne contrôlez pas les autres vecteurs  et vous trouverez parfois des objets retournés ou pivotés de manière inattendue..</div>
<h2><a name="4"></a></h2>
<h2>Combiner plusieurs Quaternions</h2>
<p>So our Zzzzzz themselves aren't very interesting and they could give us an opportunity to demonstrate how we can use Quaternion combinations.  Let's have the Zzzzzz slowly rotate as they drift upwards - what I mean is, have them face the camera but spin slowly around on the plane of the screen.</p>
<p>Donc, notre Zzzzzz  ne sont pas très intéressants et ils pourraient nous donner l'occasion de montrer comment on peut utiliser des combinaisons de quaternions. Nous allons faire que nos Zzzzzz tournent lentement pendant qu' ils dérivent vers le haut - ce que je veux dire, c'est les avoir face à la caméra, mais tournant lentement autour du plan de l'écran.</p>
<div class="alert green">Tutorial Scene 7</div>
<p>Pour faire cette rotation, nous créons un nouveau script SpinAroundForward.</p>
<pre>using UnityEngine;
using System.Collections;

public class SpinAroundForward : MonoBehaviour {

	Transform _transform;
	float _rotatingFactor;

	void Start(){
		_transform = transform;
		_rotatingFactor = 0.2f + (Random.value * 0.8f);
	}

	void Update () {
		_transform.rotation = _transform.rotation * Quaternion.AngleAxis(Time.deltaTime * 20 * _rotatingFactor, Vector3.forward); 
	}
}</pre>
<p>Ce script crée un facteur de rotation au hasard dans la fonction Start et l'applique dans la fonction Update.</p>
<p>Vous pouvez voir comment nous combinons la rotation actuelle de l'objet avec une rotation autour de Vector3.forward. Quaternion.AngleAxis crée un quaternion qui est un nombre de degrés de rotation autour d'un axe donné. Nous utilisons l'opérateur * pour le combiner avec la rotation actuelle du Zzzzzz.</p>
<p>Maintenant, si vous exécutez ceci dans la scène tutoriel, vous verrez que le texte tourne, mais ne fait pas face à la caméra. Il y a une bonne raison à cela: notre script ReverseCameraDirection est désactivé! Si vous cliquez sur <em>Sleeping Text 3</em> et activez le script ReverseCameraDirection vous verrez alors que le  Zzzzzz fait face à la caméra, mais ne tourne pas. Voici l'un des pièges de la définition d'un vecteur de transform directement - il mélange vos combinaisons de rotation. Nous avons besoin d'une approche différente si nous voulons atteindre notre objectif.</p>
<div class="alert green">Tutorial Scene 8</div>
<p>En Scene 8 on remplace ReverseCameraDirection avec une version Quaternion de AdjustForwardToPointToCamera.</p>
<pre>using UnityEngine;
using System.Collections;

public class AdjustForwardToPointToCamera : MonoBehaviour {

	Transform _transform;
	Transform _cameraTransform;

	void Start () {
		_transform = transform;
		_cameraTransform = Camera.main.transform;
	}

	void Update () {
		_transform.rotation = Quaternion.FromToRotation(_transform.forward, _cameraTransform.forward) * _transform.rotation;
	}
}</pre>
<p>Quaternion.FromToRotation est très puissant quand vous avez des vecteurs qui ont besoin de réglage! Elle peut être utilisée pour faire pivoter un objet vers la surface de la chose sur lequel il repose  en réglant le vecteur <em>up</em>  de l'objet pour être la normale de la surface, par exemple. Dans notre cas, nous allons l'utiliser pour faire tourner la transform.forward de notre Zzzzzz pour être le même que transform.forward de la caméra.</p>
<div class="alert yellow">Juste un rappel, n'oubliez pas que les TextMesh sont inversés - si c'était un objet normal nous réglerions le transform.forward de l'objet sur transform.forward de la caméra de sorte qu'il braque sur elle.</div>
<p>Nous combinons le Quaternion que nous avons créé à partir du <em>forward</em> en rotation vers l'angle correct avec la rotation actuelle (qui est également modifiée par notre script SpinAroundForward) et c'est tout, nous avons une caméra en face, en rotation, Zzzzzz. (Qui aurait cru cela!)</p>
<h2><a name="5"></a></h2>
<h2>Faire tourner un plan pour faire face à la caméra</h2>
<p>Ok, donc nous avons convenablement réglé nos TextMeshes face à la caméra - maintenant nous allons nous occuper des plans. Un plan créé avec Unity est un bon endroit pour mettre une texture 2D et la montrer au joueur. Faisons un plan 2D billboard qui fait toujours face à l'écran.</p>
<p>Pour nous donner une raison de faire cela, nous allons donner à nos ennemis une "humeur". Fondamentalement, ils vont commencer avec un niveau de bonheur et progressivement plus malheureux au fil du temps. Dans un jeu, nous pourrions trouver beaucoup d'autres raisons pour lesquelles cela pourrait être intéressant.</p>
<p>Le joueur va être capable de voir l'état d'esprit des ennemis quand ils regardent droit sur eux. Nous allons afficher une émoticônes qui  lorsque le joueur regarde directement vers eux - la couleur du smiley sera également une description plus précise de l'état d'esprit, vert, heureux er rouge, en colère.</p>
<p>Cela va introduire quelques scripts.</p>
<p>D'abord nous allons réfléchir à la façon de «regarder directement" un ennemi. Nous devons attacher un script au joueur qui permettra de tester ce qui est juste en face de lui.</p>
<pre>using UnityEngine;
using System.Collections;

public class LookTrigger : MonoBehaviour {

	Transform _transform;

	void Start () {
		_transform = transform;
	}

	void Update () {
		RaycastHit hit;
		if(Physics.SphereCast(_transform.position + _transform.forward * 0.5f, 3f, _transform.forward, out hit, 400)){
			hit.collider.SendMessage("LookedAt", SendMessageOptions.DontRequireReceiver);
		}
	}
}</pre>
<p>Nous envoyons un SphereCast à partir du joueur et, si elle heurte quelque chose, nous envoyons à l'objet touché un message indiquant qu'il a été "LookedAt".</p>
<div class="alert blue"> Nous utilisons une SphereCast car elle offre un peu d'inexactitude quand on regarde les choses qui pourraient être très loin. </div>
<p>Ok, donc ça a été facile - maintenant nous avons besoin de l'ennemi pour avoir son humeur. Nous avons un nouveau script appelé EnemyMood.</p>
<pre>using UnityEngine;
using System.Collections;

public class EnemyMood : MonoBehaviour {

	public MoodIndicator moodIndicatorPrefab;
	public float _mood;

	Transform _transform;
	MoodIndicator _currentIndicator;

	void Start () {
		_transform = transform;
		mood = Random.Range(30,99);
	}

	void Update () {
		mood -= Time.deltaTime/2;
	}

	void LookedAt(){
		if(_currentIndicator)
			return;

		_currentIndicator = Instantiate(moodIndicatorPrefab, _transform.position + Vector3.up * 3.5f,
			Quaternion.identity) as MoodIndicator;

		_currentIndicator.enemy = this;
	}
}</pre>
<p><div class="one_half">Nous commençons par initialiser une variable d'humeur avec une valeur comprise entre 30 et 99 , alors nous décrémentons lentement dans l'Update.</p>
<p>Nous avons ajouté une variable prefab pour le plan pour afficher l'humeur et donné à cette prefab un script MoodIndicator que nous allons examiner brièvement.</p>
<p>Lors de la réception d'un message EnemyMood LookedAt il vérifie s'il existe déjà un MoodIndicator actuel et retourne s'il existe.</p>
<div class="alert blue">Unity fera cette variable null/false quand le MoodIndicator est détruit.</div>
<p>S'il n'y avait aucun MoodIndicator, il en crée un et le place juste au-dessus de l'ennemi - alors il enseigne l'indicateur sur l'ennemi qu'il représente.</p>
<p>Le MoodIndicator gère l'affichage de plan et choisit le bon graphique à faire apparaître.</div><div class="one_half last"><a href="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-02.41.42.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-127" title="Screen Shot 2012-10-14 at 02.41.42" src="http://unitygems.com/wp-content/uploads/2012/10/Screen-Shot-2012-10-14-at-02.41.42-300x231.png" alt="" width="300" height="231" /></a></div><div class="clear"></div></p>
<pre>using UnityEngine;
using System.Collections;

public class MoodIndicator : MonoBehaviour {

	public Texture2D[] moodIndicators;
	public Color happyColor = Color.green;
	public Color angryColor = Color.red;
	public float fadeTime = 4f;
	public EnemyMood enemy;

	Transform _transform;
	Transform _cameraTransform;
	Material _material;
	Color _color;
	Quaternion _pointUpAtForward;

	void Start () {
		_pointUpAtForward = Quaternion.FromToRotation(Vector3.up, Vector3.forward);

		_material = renderer.material;

		//Définit le graphique
		_material.mainTexture = moodIndicators[
			Mathf.Clamp(
				Mathf.RoundToInt( enemy.mood/(100/moodIndicators.Length)),
				0,
				moodIndicators.Length-1)
			];

		//Calcule la couleur
		var moodRatio = enemy.mood/100;
		_material.color = _color = new Color(
			angryColor.r * (1 - moodRatio) + happyColor.r * moodRatio,
			angryColor.g * (1 - moodRatio) + happyColor.g * moodRatio,
			angryColor.b * (1 - moodRatio) + happyColor.b * moodRatio
		);

		Update();
	}

	void Awake(){
		_transform = transform;
		_cameraTransform = Camera.main.transform;
	}

	public void Update () {

		//Pointe le plan vers la caméra
		_transform.rotation = Quaternion.LookRotation(-_cameraTransform.forward, Vector3.up)
			* _pointUpAtForward;

		//Le graphique disparait
		_color.a -= Time.deltaTime/fadeTime;
		_material.color = _color;
	}
}</pre>
<p>C'est notre premier vrai script alors nous allons le démanteler.</p>
<pre>	public Texture2D[] moodIndicators;
	public Color happyColor = Color.green;
	public Color angryColor = Color.red;
	public float fadeTime = 4f;
	public EnemyMood enemy;</pre>
<p>Nos variables publiques sont dans un tableau des images pour les utiliser comme indicateurs de l'humeur - ce sont des smileys pour triste, heureux, etc Il y en a 4 dans l'exemple. Nous disposons d'une couleur heureuse et une couleur en colère, alors nous voulons faire disparaître l'indicateur au fil du temps, nous avons donc une variable qui contient le nombre de secondes avant que le plan tout entier deviennent transparent. Enfin, nous avons l'ennemi qui contient cet indicateur. Tous ces éléments seront définis quand nous arrivons à la fonction Start.</p>
<pre>	void Start () {
		_pointUpAtForward = Quaternion.FromToRotation(Vector3.up, Vector3.forward);

		_material = renderer.material;

		_material.mainTexture = moodIndicators[
			Mathf.Clamp(
				Mathf.RoundToInt( enemy.mood/(100/moodIndicators.Length)),
				0,
				moodIndicators.Length-1)
			];

		var moodRatio = enemy.mood/100;
		_material.color = _color = new Color(
			angryColor.r * (1 - moodRatio) + happyColor.r * moodRatio,
			angryColor.g * (1 - moodRatio) + happyColor.g * moodRatio,
			angryColor.b * (1 - moodRatio) + happyColor.b * moodRatio
		);

		Update();
	}</pre>
<p>La première chose à faire est de créer un quaternion en cache qui permet de transformer un objet pour que son vecteur<em> up</em> pointe vers son vecteur <em>forward</em>. Rappelez-vous c'es ce que nous devions faire pour faire face à la caméra.</p>
<p>Ensuite, nous sélectionnons une texture qui représente l'état d'esprit en divisant l'humeur actuelle (un nombre entre 0 et 98) par un facteur qui sera mis dans la gamme de textures que nous avons fournis - nous restraignons les valeurs pour nous assurer de toujours obtenir une texture valide .</p>
<p>Ensuite, nous décidons d'une couleur pour le smiley en utilisant une proportion de colère et heureux selon l'humeur.</p>
<p>Enfin, nous appelons Update pour que le code de rotation soit appelé immédiatement.</p>
<p>La fonction Update se présente comme suit:</p>
<pre>public void Update () {
		//Pointer le plan vers la caméra
		_transform.rotation = Quaternion.LookRotation(-_cameraTransform.forward, Vector3.up)
			* _pointUpAtForward;

		//Le graphique disparait
		_color.a -= Time.deltaTime/fadeTime;
		_material.color = _color;
	}</pre>
<p>D'abord nous travaillons sur la rotation qui pointe vers la normal de l'objet vers la caméra en utilisant la fonction Quaternion.LookRotation, en passant le transform.forward de la caméra, puis nous combinons cela avec notre rotation en cache qui pointe le <em>up</em> de l'objet vers le <em>forward</em> . Notre plan est maintenant correctement aligné.</p>
<p>La deuxième partie de la routine  estompe l'alpha de l'image dans le temps.</p>
<p>C'est tout - si vous essayez, vous verrez les indicateurs surgissent lorsque vous centrez l'ennemi à l'écran. Ils se fâchent rapidement!</p>
<h2><a name="6"></a></h2>
<h2>Ajouter des mouvements</h2>
<p>Ok so it's time for our enemies to go and attack the player.  We are going to use Quaternions again, to set the target position of the enemy to be a different rotation around the player in an attempt to have them sneak up, and space out when attacking.  That at the moment is in the future - let's have a look at our new MovementStateMachine3.  Warning - it's grown up a bit!</p>
<p>Ok, donc il est temps pour nos ennemis d' attaquer le joueur. Nous allons utiliser les Quaternions à nouveau, pour faire en sorte que la position cible de l'ennemi soit une rotation différente autour du joueur  dans le but de les voir se faufiler et s'espacer quand ils attaquent. C'est pour le moment une futur action - nous allons jeter un oeil à notre nouveau MovementStateMachine3. Attention - il a un peu grandi!</p>
<p><br clear="none" /><span class="collapseomatic " id="id6672"  title="<strong>MovementStateMachine3.cs</strong>"><strong>MovementStateMachine3.cs</strong></span><div id="target-id6672" class="collapseomatic_content "></p>
<pre>using UnityEngine;
using System.Collections;

public class MovementStateMachine3 : MonoBehaviour {

	public bool sleeping = true;
	public Transform sleepingPrefab;
	public float attackDistance = 5;
	public float sleepDistance = 30;
	public float speed = 2;
	public float health = 20;
	public float maximumAttackEffectRange = 1f;

	Transform _transform;
	Transform _player;
	public Transform target;

	public EnemyMood _mood;

	CharacterController _controller;
	AnimationState _attack;
	AnimationState _die;
	AnimationState _hit;
	Animation _animation;

	float _attackDistanceSquared;
	float _sleepDistanceSquared;
	float _attackRotation;
	float _maximumAttackEffectRangeSquared;
	float _angleToTarget;

	bool _busy;

	// Initialisation
	IEnumerator Start () {
		_transform = transform;
		_player = Camera.main.transform;

		_mood = GetComponent&lt;EnemyMood&gt;();

		_attackDistanceSquared = attackDistance * attackDistance;
		_sleepDistanceSquared = sleepDistance * sleepDistance;
		_maximumAttackEffectRangeSquared = maximumAttackEffectRange * maximumAttackEffectRange;

		_controller = GetComponent&lt;CharacterController&gt;();

		_animation = animation;
		_attack = _animation["attack"];
		_hit = _animation["gothit"];
		_die = _animation["die"];

		_attack.layer = 5;
		_hit.layer = 5;
		_die.layer = 5;

		_controller.Move(new Vector3(0,-20,0));

		while(true){
			yield return new WaitForSeconds(Random.value * 6f + 3);
			if(sleeping)	{
				var newPrefab = Instantiate(sleepingPrefab, _transform.position + Vector3.up * 3f, Quaternion.identity) as Transform;
				newPrefab.forward = Camera.main.transform.forward;
			}
		}
	}

	void Update(){
		//Verifie si quelque chose d'autre controle 
		if(_busy)
			return;

		if(sleeping){
			if((_transform.position - _player.position).sqrMagnitude &lt; _attackDistanceSquared){
				sleeping = false;
				target = _player;
				//Where this enemy wants to stand to attack
				_attackRotation = Random.Range(60,310);
			}
		}else{
			//Si la cible est morte alors retourne en mode sleeping
			if(!target){
				sleeping = true;
				return;
			}

			var difference = (target.position - _transform.position);
			difference.y /= 6;
			var distanceSquared = difference.sqrMagnitude;

			//Trop loin, on oublie...
			if( distanceSquared &gt; _sleepDistanceSquared){
				sleeping = true;
			}
			//Assez proche pour une attaque
			else if( distanceSquared &lt; _maximumAttackEffectRangeSquared &amp;&amp; _angleToTarget &lt; 40f){
				StartCoroutine(Attack(target));
			}
			//Autrement, c'est le moment de se bouger
			else{
				//Décider la position cible
				var targetPosition = target.position + (Quaternion.AngleAxis(_attackRotation, Vector3.up) * target.forward * maximumAttackEffectRange * 0.8f);
				var basicMovement = (targetPosition - _transform.position).normalized * speed * Time.deltaTime;
				basicMovement.y = 0;
				//Mouvement seulement si en face
				_angleToTarget = Vector3.Angle(basicMovement, _transform.forward);
				if( _angleToTarget &lt; 70f)
				{
					basicMovement.y = -20 * Time.deltaTime;
					_controller.Move(basicMovement);
				}
			}
		}
	}

	void OnTriggerEnter(Collider hit) {
		if(hit.transform == _transform)
			return;

		if(hit.transform == _player){
			StartCoroutine(Attack(_player));
		}else{
			var rival = hit.transform.GetComponent&lt;EnemyMood&gt;();
			if(rival){
				if(Random.value &gt; _mood.mood/100)
					StartCoroutine("Attack",rival.transform);
			}
		}
	}

	IEnumerator Attack(Transform victim){
		sleeping = false;
		_busy = true;
		target = victim;
		_attack.enabled = true;
		_attack.time = 0;
		_attack.weight = 1;
		//Attendre la moitié de l'animation
		yield return StartCoroutine(WaitForAnimation(_attack, 0.5f));
		/Verifier si toujours proche
		if(victim &amp;&amp; (victim.position - _transform.position).sqrMagnitude &lt; _maximumAttackEffectRangeSquared){
			//Appliquer les dommages
			victim.SendMessage("TakeDamage", 1 + Random.value * 5, SendMessageOptions.DontRequireReceiver);
		}
		//Attendre la fin de l'animation
		yield return StartCoroutine(WaitForAnimation(_attack, 1f));
		_attack.weight = 0;
		_busy = false;
	}

	void TakeDamage(float amount){
		StopCoroutine("Attack");
		health -= amount;
		if(health &lt; 0)
			StartCoroutine(Die());
		else
			StartCoroutine(Hit());
	}

	IEnumerator Die(){
		_busy = true;
		_animation.Stop();
		yield return StartCoroutine(PlayAnimation(_die));
		Destroy(gameObject);
	}

	IEnumerator Hit(){
		_busy = true;
		_animation.Stop();
		yield return StartCoroutine(PlayAnimation(_hit));
		_busy = false;
	}

	public static IEnumerator WaitForAnimation(AnimationState state, float ratio){
		state.wrapMode = WrapMode.ClampForever;
		state.enabled = true;
		state.speed = state.speed == 0 ? 1 : state.speed;
		while(state.normalizedTime &lt; ratio-float.Epsilon){
			yield return null;
		}
	}

	public static IEnumerator PlayAnimation(AnimationState state){
		state.time = 0;
		state.weight = 1;
		state.speed = 1;
		state.enabled = true;
		var wait = WaitForAnimation(state, 1f);
		while(wait.MoveNext())
			yield return null;
		state.weight = 0;
	}
}</pre>
<p></div>Ok, voyons les éléments intéressants - voici ce qui est nouveau dans la fonction Start:</p>
<pre>       _mood = GetComponent&lt;EnemyMood&gt;();

		_attackDistanceSquared = attackDistance * attackDistance;
		_sleepDistanceSquared = sleepDistance * sleepDistance;
		_maximumAttackEffectRangeSquared = maximumAttackEffectRange * maximumAttackEffectRange;

		_controller = GetComponent&lt;CharacterController&gt;();

		_animation = animation;
		_attack = _animation["attack"];
		_hit = _animation["gothit"];
		_die = _animation["die"];

		_attack.layer = 5;
		_hit.layer = 5;
		_die.layer = 5;</pre>
<p>Il est clair que nous faisons un tas de cache pour des raisons de performance - aussi toutes les distances sont au carré. Ainsi, nous pouvons éviter des racines carrées lorsque nous vérifions les distances.</p>
<div class="alert blue">Calculer la distance entre deux choses utilise le théorème de Pythagore et nécessite une racine carrée. Les racines carrées sont des fonctions récursives qui sont très coûteuses. Nous pouvons éviter de calculer la racine carrée  en utilisant le carré de la distance que nous voulons vérifier</div>
<p>On place plusieurs des animations sur un layer de haut niveau de sorte qu'elles remplacent l'animation par defaut (<em>idle</em>).</p>
<p>Donc la fonction Update est assez grande - elle commence comme ceci:.</p>
<pre>                //Verifie si quelque chose d'autre controle 
		if(_busy)
			return;</pre>
<p>Pour attaquer et d'être touché, nous allons permettre à quelque chose d'autre de contrôler le personnage - quand cela arrive _busy sera vrai et l'Update sera ignoré.</p>
<div id="gt-res-content">
<div dir="ltr">Ensuite, nous avons besoin de la logique pour quand l'ennemi est endormi.</div>
</div>
<pre>                if(sleeping){
			if((_transform.position - _player.position).sqrMagnitude &lt; _attackDistanceSquared){
				sleeping = false;
				target = _player;
				//Où l'ennemi veut se placer pour attaquer
				_attackRotation = Random.Range(60,310);
			}
		}</pre>
<p><a name="enemy"></a>Quand l'ennemi est endormi, nous vérifions si le joueur est à l'intérieur de attackDistance, si il l'est - on éteint le mode sommeil (youpi!) et fixé la cible sur  le joueur. Nous allouons aussi une rotation particulière autour du joueur que nous voulons cibler (le sournois tente d'approcher par le côté ou derrière!) - Actuellement, c' est simplement stocké dans une variable, nous allons voir où elle est utilisé ensuite. C'est ce qui arrive quand l'ennemi ne dort pas:</p>
<pre>			//Si la cible est morte alors retourne en mode sleeping
			if(!target){
				sleeping = true;
				return;
			}

			var difference = (target.position - _transform.position);
			difference.y /= 6;
			var distanceSquared = difference.sqrMagnitude;

			//Trop loin, on oublie...
			if( distanceSquared &gt; _sleepDistanceSquared){
				sleeping = true;
			}
			//Assez proche pour une attaque?
			else if( distanceSquared &lt; _maximumAttackEffectRangeSquared &amp;&amp; _angleToTarget &lt; 40f){
				StartCoroutine(Attack(target));
			}
			//Autrement, temps de se la bouger
			else{
				//Decider la position cible
				var targetPosition = target.position + (Quaternion.AngleAxis(_attackRotation, Vector3.up) * target.forward * maximumAttackEffectRange * 0.8f);
				var basicMovement = (targetPosition - _transform.position).normalized * speed * Time.deltaTime;
				basicMovement.y = 0;
				//Mouvement seulemeent si en face
				_angleToTarget = Vector3.Angle(basicMovement, _transform.forward);
				if( _angleToTarget &lt; 70f){
					basicMovement.y = -20 * Time.deltaTime;
					_controller.Move(basicMovement);
				}
			}</pre>
<p>Nous mettons l'ennemi à dormir si sa cible a disparu ou qu'elle est trop loin. Ensuite, si ce n'est pas le cas, si nous sommes à distance de frappe, nous commençons une coroutine pour effectuer une attaque. Si nous ne sommes pas endormis et nous ne sommes pas assez près pour attaquer alors nous envisageons de nous de déplacer vers la cible.</p>
<p>La première partie de ce travail est d'où nous voulons défendre. Il s'agit d'une combinaison de la position de la cible, l'angle que nous avons décidé sur le moment où nous l'avons ciblé et la distance de frappe (que nous voulons être à 80%). Nous utilisons un Quaternion basé sur l'angle pour modifier un vecteur basé sur la direction vers laquelle la cible est orientée et nous utilisons 80% de la distance de frappe pour modifier cette valeur. Tout cela est appelé targetPosition. Par exemple, si l'angle nous avons pris était de 180 et la distance de frappe est de 2 alors la position de la cible serait 1,6 unité du monde directement derrière la caméra.</p>
<p>Ensuite, nous travaillons sur l'angle entre l'endroit où nous sommes et où nous voulons aller - si il ya trop d'écart on ne bouge pas encore (on laisse le script de rotation définir l'angle). Si c'était ok, alors nous nous dirigeons vers la position cible après avoir ajouté un peu de pesanteur pour maintenir l'ennemi sur le terrain. Ouf!</p>
<h2>Utiliser des coroutines pour attendre la fin d'une animation</h2>
<p>Ok, donc nous savons que si nous sommes assez proche alors une coroutine d'attaque est lancée. Ce que nous voulons faire est de mettre en pause le comportement normal,  lancer une animation d'attaque et appliquer des dommages à moitié de l'animation. C'est ainsi que nous obtenons ce qui suit:</p>
<p>D'abord - pour faire la routine de plus utile, nous réveillons toujours un ennemi quand d'attaque est appelé - c'est parce que vous pouvez également déclencher une attaque avec deux ennemies qui se rentrent dedans!</p>
<pre>	IEnumerator Attack(Transform victim){
		sleeping = false;
		_busy = true;
		target = victim;
		_attack.enabled = true;
		_attack.time = 0;
		_attack.weight = 1;
		//Attendre l amoitié de l'animation
		yield return StartCoroutine(WaitForAnimation(_attack, 0.5f));
		//Toujours assez proche?
		if(victim &amp;&amp; (victim.position - _transform.position).sqrMagnitude &lt; _maximumAttackEffectRangeSquared){
			//Appliquer les dommages
			victim.SendMessage("TakeDamage", 1 + Random.value * 5, SendMessageOptions.DontRequireReceiver);
		}
		//Attendre la fin de l'animation
		yield return StartCoroutine(WaitForAnimation(_attack, 1f));
		_attack.weight = 0;
		_busy = false;
	}</pre>
<p>En réglant  _busy = true, nous mettons l'Update en attente alors que cette routine performe. _attack est l'animation d'attaque que nous activons, définissons le début et lui donner son facteur. L'animation commence alors à jouer. Ensuite, nous commençons une autre coroutine qui permettra de surveiller l'animation, dans ce cas, elle attendre qu'elle soit passée de 50%. Nous allons voir cette routine dans un instant.</p>
<p>Lorsque l'animation est passée de 50%, nous vérifions que la victime cible n'est pas déjà morte, et qu'elle est toujours à portée et si ces conditions sont remplies, nous envoyons un message TakeDamageavec une quantité aléatoire de dégâts à infliger.</p>
<p>Nous attendons ensuite que l'animation soit terminée avant de retirer notre état busy et désactiver l'animation.</p>
<p>Donc, nous allons jeter un oeil à la coroutine WaitForAnimation:</p>
<pre>	public static IEnumerator WaitForAnimation(AnimationState state, float ratio){
		state.wrapMode = WrapMode.ClampForever;
		state.enabled = true;
		state.speed = state.speed == 0 ? 1 : state.speed;
		while(state.normalizedTime &lt; ratio-float.Epsilon){
			yield return null;
		}
	}</pre>
<p>Then the loop just waits for the .normalizedTime (the ratio of the clip) to be greater than or equal to the value we passed in (- a floating point fudge factor).</p>
<p>Comme vous pouvez le voir, c'est assez simple! Nous nous assurons d'abord que l'animation ne provoque pas  une boucle ou une réinitialisation, car cela pourrait signifier que nous avons manqué le point de fin. Nous nous assurons également qu'elle est activée et a une certaine vitesse, sinon cette routine ne finirait jamais.</p>
<p>Puis la boucle attend que .normalizedTime (le ratio du clip) soit supérieure ou égale à la valeur que nous avons passée. (- Un facteur arbitraire en float).</p>
<h2><a name="7"></a></h2>
<h2>Plus de states</h2>
<p>Donc maintenant nous avons attaqué et envoyé un message de dégâts, nous devrions examiner comment ce message est traité. Dans cette démo, le joueur est invincible (haha!), mais les ennemis peuvent infliger des dommages l'un l'autre.</p>
<p>Quand l'ennemi reçoit un message TakeDamage il doit réagir:</p>
<pre>	void TakeDamage(float amount){
		StopCoroutine("Attack");
		health -= amount;
		if(health &lt; 0)
			StartCoroutine(Die());
		else
			StartCoroutine(Hit());
	}</pre>
<p>Tout d'abord nous stoppons toutes attaques en court, puis on soustrait la santé puis nous lançons une coroutine Hit ou Die.</p>
<pre>	IEnumerator Die(){
		_busy = true;
		_animation.Stop();
		yield return StartCoroutine(PlayAnimation(_die));
		Destroy(gameObject);
	}

	IEnumerator Hit(){
		_busy = true;
		_animation.Stop();
		yield return StartCoroutine(PlayAnimation(_hit));
		_busy = false;
	}</pre>
<p>Both coroutines play an animation to completion, Die destroys the object, Hit re-enables it.</p>
<p>And that's pretty much it for this tutorial.  You should check out RotateToFaceTarget which replaces our earlier rotation script, using the target variable rather than always facing the player - this let's enemies target each other.  The only other script of interest is WalkingAnimation:</p>
<p>Les deux coroutines jouent une animation entière, Die détruit l'objet,  Hit le réactive.</p>
<p>Et c'est à peu près tout pour ce tutoriel. Vous devriez vérifier RotateToFaceTarget qui remplace notre script de rotation, en utilisant la variable cible plutôt que de toujours faire face au joueur - cela permet aux ennemis de se cibler les uns les autres. Le seul autre script d'intérêt est WalkingAnimation:</p>
<pre>using UnityEngine;
using System.Collections;

public class WalkingAnimation : MonoBehaviour {

	Transform _transform;
	Vector3 _lastPosition;
	AnimationState _walk;

	public float minimumDistance = 0.01f;

	void Start () {
		_transform = transform;
		_lastPosition = _transform.position;
		_walk = animation["walk"];
		_walk.layer = 2;
	}

	void Update () {
		var moved = (_transform.position - _lastPosition).magnitude;
		_lastPosition = _transform.position;
		if(moved &lt; minimumDistance)		{
			_walk.weight = 0;
		}else{
			_walk.weight = moved * 100;
			_walk.enabled = true;
			_walk.speed = 1;
		}
	}
}</pre>
<p>Ce script se fond dans l'animation de marche en fonction de la rapidité de l'ennemi en mouvement.</p>
<h2>Conclusion</h2>
<p>Nous espérons que vous avez trouvé ce tutoriel utile. S'il vous plaît n'hésitez pas à laisser vos commentaires - particulièrement utile serait les commentaires concernant de futures fonctionnalités que vous aimeriez voir expliquées.</p>
<p><em>Mike(whydoidoit)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/quaternion-rotation-attaque/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Interaction de scripts &#8211; GetComponent</title>
		<link>http://unitygems.com/interaction-scripts/</link>
		<comments>http://unitygems.com/interaction-scripts/#comments</comments>
		<pubDate>Wed, 28 Nov 2012 14:00:34 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[Beginner]]></category>
		<category><![CDATA[Boo]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[beginner]]></category>
		<category><![CDATA[Beginners]]></category>
		<category><![CDATA[Débutant]]></category>
		<category><![CDATA[francais]]></category>
		<category><![CDATA[GetComponent]]></category>
		<category><![CDATA[Physics]]></category>
		<category><![CDATA[Script Interaction]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[UnityScript]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1686</guid>
		<description><![CDATA[<p>Dans ce tutoriel Acceder à un script sur le même objet Comment GetComponent fonctionne? Obtenir plusieurs composants Interaction entre objets Interaction entre objets dans la hierarchie SendMessage et BroadcastMessage Fonctions Interactives Introduction Un problème récurrent quand on commence avec Unity est de savoir comment accéder aux membres d&#8217;un script à partir d&#8217;un autre script. Nombreux &#8230;<br /><a class="excerpt" href="http://unitygems.com/interaction-scripts/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Dans ce tutoriel</h2>
<ul>
<li><a href="#1">Acceder à un script sur le même objet</a></li>
<li><a href="#2">Comment GetComponent fonctionne?</a></li>
<li><a href="#3">Obtenir plusieurs composants</a></li>
<li><a href="#4">Interaction entre objets</a></li>
<li><a href="#5">Interaction entre objets dans la hierarchie</a></li>
<li><a href="#6">SendMessage et BroadcastMessage</a></li>
<li><a href="#7">Fonctions Interactives</a></li>
</ul>
<h2>Introduction</h2>
<p>Un problème récurrent quand on commence avec Unity est de savoir comment accéder aux membres d'un script à partir d'un autre script. Nombreux sont ceux qui pensent que le simple déréférencement du nom du script serait suffisant, ils réalisent rapidement qu'il ne l'est pas.</p>
<p>Durant l'élaboration d'un programme, les variables sont stockées dans la mémoire à des emplacements différents. Si un objet pouvait voir les membres d'autres objets, il y aurait alors le risque de les modifier, même si cela n'était pas voulu. Si,  deux instances d'objets contiennent le même script avec les mêmes noms de variables, le compilateur ne serait pas en mesure de dissocier les deux.</p>
<p>Pour éviter ce problème, chaque objet dans la mémoire ne peut pas voir les autres objets. Il est alors nécessaire de dire à un objet où la variable dont elle a besoin se trouve en mémoire. Le principe du pointeur a été abandonné avec C# et maintenant, nous utilisons à la place des références (qui utilisent en fait un pointeur).</p>
<p>Il ya en fait différentes façons d'accéder à des variables, certaines sont meilleurs que d'autres et certaines sont tout simplement à utiliser dans des situations particulières.</p>
<p>Pour résumer, il existe trois façons:</p>
<ol>
<li>GetComponent, la plus commune, aussi celle qui crée le plus de confusion au premier abord</li>
<li>SendMessage, qui peut sembler plus facile à saisir, mais aussi beaucoup moins efficace.</li>
<li>Les variable statiques, la plus facile à utiliser, mais aussi la plus compliquée à comprendre pleinement.</li>
</ol>
<p>Créez une nouvelle scène et ajoutez un Empty GameObject et nommez-le "ObjectA". Créez deux scripts appelés «Scripta» et «ScriptB". Ajouter les deux scripts sur ObjectA.</p>
<p>Ouvrez les deux scripts dans l'éditeur et ajoutez ces lignes:<br />
<br clear="none" /><span class="collapseomatic " id="id9545"  title="<strong>ScriptA.cs</strong>"><strong>ScriptA.cs</strong></span><div id="target-id9545" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
public class ScriptA : MonoBehaviour{
	public int varBInA;
	public int otherBInA;

	void Update(){
		if (Input.GetKeyDown(KeyCode.Space)){
			varBInA = ScriptB.GetVarB();
			otherBInA = ScriptB.varB;
			if (varBInA &gt; 0)
				ScriptB.AddVarB(10);
		}
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id4620"  title="<strong>ScriptB.cs</strong>"><strong>ScriptB.cs</strong></span><div id="target-id4620" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class ScriptB : MonoBehaviour{
	private int varB;
	void Start(){
		varB = 20;
	}

	void Update(){
		if (Input.GetKeyDown(KeyCode.P))
			print("varB in ScriptB"+varB);
	}

        public int GetVarB(){
		return varB;
	}

        public void AddVarB(int num){
		varB += num;
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id2407"  title="<strong>ScriptA.js</strong>"><strong>ScriptA.js</strong></span><div id="target-id2407" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">var varBInA:int;
var otherBInA:int;

function Update(){
	if (Input.GetKeyDown(KeyCode.Space)){
	       varBInA = ScriptB.GetVarB();
		otherBInA = ScriptB.varB;
		if (varBInA &gt; 0)
			ScriptB.AddVarB(10);
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id3628"  title="<strong>ScriptB.js</strong>"><strong>ScriptB.js</strong></span><div id="target-id3628" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">var varB:int;
functionStart(){
	varB = 20;
}

function Update(){
	if (Input.GetKeyDown(KeyCode.P))
		print("varB in ScriptB"+varB);
}

function GetVarB(){
	return varB;
}

function AddVarB(){
varB += num;
}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id1909"  title="<strong>ScriptA.boo</strong>"><strong>ScriptA.boo</strong></span><div id="target-id1909" class="collapseomatic_content "></p>
<pre class="brush: python; gutter: true; first-line: 1">import UnityEngine
import System.Collections
class ScriptA (MonoBehaviour): 
   public varBinA as int
   public otherBinA as int

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         varBinA = ScriptB.GetVarB()
         otherBinA = ScriptB.varB
         if varBinA &gt; 0:
            ScriptB.AddVarB(10)</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id4141"  title="<strong>ScriptB.boo</strong>"><strong>ScriptB.boo</strong></span><div id="target-id4141" class="collapseomatic_content "></p>
<pre class="brush: python; gutter: true; first-line: 1">import UnityEngine
class ScriptB (MonoBehaviour):
   public varB as int
   def Start ():
      varB = 20

   def Update ():
      if Input.GetKeyDown(KeyCode.P):
         Debug.Log ("varB in ScriptB $varB")

   def GetVarB () as int:
      return varB

   def AddVarB (num as int):
      varB += num</pre>
<p></div><br />
Lancer ce code retourne simplement l'erreur "An object reference is required to access non-static members".</p>
<p>Nous devons dire au Scripta où est ScriptB afin qu'il puisse accéder à ses membres. Puisque nos scripts sont sur le même objet nous avons simplement besoin de déclarer une variable de type du script que nous souhaitons  et utiliser GetComponent pour trouver le script.</p>
<h2><a name="1"></a></h2>
<h2>Acceder à un script sur le même objet</h2>
<p>Modifier ScriptA ainsi:<br />
<br clear="none" /><span class="collapseomatic " id="id4954"  title="<strong>ScriptA.cs</strong>"><strong>ScriptA.cs</strong></span><div id="target-id4954" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class ScriptA : MonoBehaviour{
	public ScriptB scriptB;
	public int varBInA;
	public int otherBInA;

	void Start(){
		scriptB = GetComponent&lt;ScriptB&gt;();
	}

	void Update(){
		if (Input.GetKeyDown(KeyCode.Space)){
			varBInA = scriptB.GetVarB();
			otherBInA = scriptB.varB;

			if (varBInA &gt; 0){
				scriptB.AddVarB(10);
				print("In ScriptA otherBInA is " + otherBInA);
			}
		}
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id1576"  title="<strong>ScriptA.js</strong>"><strong>ScriptA.js</strong></span><div id="target-id1576" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">	var scriptB: ScriptB ;
	var varBInA:int;
	varotherBInA:int;

	function Start(){
		scriptB = GetComponent(ScriptB);
	}

	function Update(){
		if (Input.GetKeyDown(KeyCode.Space)){
			varBInA = scriptB.GetVarB();
			otherBInA = scriptB.varB;

			if (varBInA &gt; 0){
				scriptB.AddVarB(10);
				print("In ScriptA otherBInA is " + otherBInA);
			}
		}
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id1718"  title="<strong>ScriptA.boo</strong>"><strong>ScriptA.boo</strong></span><div id="target-id1718" class="collapseomatic_content "></p>
<pre class="brush: python; gutter: true; first-line: 1">import UnityEngine
class ScriptA (MonoBehaviour):
   public scriptB as ScriptB 
   public varBinA as int
   public otherBinA as int

   def Start ():
      scriptB = GetComponent[of ScriptB]()

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         varBinA = scriptB.GetVarB()
         otherBinA = scriptB.varB
         if varBinA &gt; 0:
            scriptB.AddVarB(10)</pre>
<p></div></p>
<p>Avec les modifications, lancez le jeu, appuyez sur P, il devrait s'afficher 20 dans la console, appuyez sur Espace, puis à nouveau sur P, la valeur est maintenant de 30. Il était également possible d'accéder directement à varB sans passer par la fonction puisque varB est public.Notez qu'accéder à une méthode  se fait de la même manière que pour les variables.</p>
<p>Si les membres étaient privée (<em>private</em>), il ne serait pas possible d'y accéder directement. Il faudrait alors untiliser une fonction publique (encapsulation).</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/PiQ3MvuN79M?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<h2>Comment GetComponent fonctionne?</h2>
<p>Nous devons d'abord déclarer un objet du type du script que nous voulons atteindre.</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">// C# 
ScriptB script;

// UnityScript
var script:ScriptB;

// Boo
ScriptB script;</pre>
<p>Puis on utilise la fonction GetComponent comme ceci:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">// C#
script = GetComponent&lt;ScriptB&gt;();

// UnityScript
script = GetComponent(ScriptB);

// Boo
script = GetComponent[of ScriptB]()</pre>
<p>La fonction GetComponent va chercher à l'intérieur de l'objet  un composant correspondant au type que nous passons. Si aucun n'est trouvé une référence null est retourné et notre variable  script ne fera rien, elle pointe dans le vide. Si un composant de type ScriptB  est trouvé, alors l'adresse de ce composant est passé à la script variable, la variable pointe désormais vers le composant ScriptB stocké dans la mémoire. Afin d'accéder aux membres publics de ScriptB, nous avons juste besoin de déréférencer la variable  script à l'aide de l'opérateur point.</p>
<p>script.PublicMembers;</p>
<p>Les membres privés sont toujours inaccessibles.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/10/Présentation12.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-411" title="Reference" src="http://unitygems.com/wp-content/uploads/2012/10/Présentation12.png" alt="Reference" width="960" height="720" /></a></p>
<h3>Donc je peux cacher avec GetComponent?</h3>
<p>Oui, et cela est recommandé pour les variables fréquement utilisées comme la Transform.</p>
<p>Quand vous accédez une variable d'un composant "Built-in" (d'usine) comme Rigidbody, Renderer, Transform...etc, Unity permet un accès direct comme ceci:</p>
<pre>void Update(){
    transform.position.x += 10;
}</pre>
<p>Mais ce que Unity fait derrière:</p>
<pre>void Update(){
    GetComponent&lt;Transform&gt;().position.x +=10;
}</pre>
<p>GetComponent devrait être éviter dans l'update donc il est préférable de cacher le composant:<br />
<br clear="none" /><span class="collapseomatic " id="id8438"  title="<strong>C#</strong>"><strong>C#</strong></span><div id="target-id8438" class="collapseomatic_content "></p>
<pre>Transform _transform;

void Start(){
     _transform = GetComponent&lt;Transform&gt;();
}

void Update(){
     _transform.position.x = new Vector3(_transform.position.x+10,0,0);
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id9003"  title="<strong>UnityScript</strong>"><strong>UnityScript</strong></span><div id="target-id9003" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">_transform:Transform;

function Start(){
     trans = GetComponent(Transform);
}

function Update(){
     _transform.position.x +=10;
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id4260"  title="<strong>Boo</strong>"><strong>Boo</strong></span><div id="target-id4260" class="collapseomatic_content "></p>
<pre class="brush: python; gutter: true; first-line: 1">_transform as Transform

def Start():
   _transform = GetComponent[of Transform]()

def Update():
   _transform.position.x +=10</pre>
<p></div></p>
<p>This will save some computation.</p>
<h2><a name="3"></a></h2>
<h2>Obtenir plusieurs composants</h2>
<p>Que faire si notre ObjectA a plusieurs  ScriptB sur lui-même. Dupliquez le ScriptB deux fois, ObjectA en a désormais trois.</p>
<p>ScriptA devient:<br />
<br clear="none" /><span class="collapseomatic " id="id1772"  title="<strong>C#</strong>"><strong>C#</strong></span><div id="target-id1772" class="collapseomatic_content "></p>
<pre>using UnityEngine;
using System.Collections;

public class ScriptA : MonoBehaviour{
	private ScriptB [] scriptB;

	void Start(){
		scriptB = GetComponents&lt;ScriptB&gt;();
	}

	void Update(){
		if (Input.GetKeyDown(KeyCode.Space)){
			for (int i = 0; i&lt;scriptB.Length; i++)
				scriptB[i].AddVarB(i);
		}
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id7312"  title="<strong>UnityScript</strong>"><strong>UnityScript</strong></span><div id="target-id7312" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">private var scriptB:ScriptB [];

functionStart(){
	scriptB = GetComponents(ScriptB);
}

function Update(){
if (Input.GetKeyDown(KeyCode.Space)){
	for (int i = 0; i&lt;scriptB.Length; i++)
		scriptB[i].AddVarB(i);
	}
}</pre>
<p></div><br />
<br clear="none" /><span class="collapseomatic " id="id6215"  title="<strong>Boo</strong>"><strong>Boo</strong></span><div id="target-id6215" class="collapseomatic_content "></p>
<pre class="brush: python; gutter: true; first-line: 1">import UnityEngine
class ScriptA (MonoBehaviour):
   public scriptB as (ScriptB)

   def Start ():
      scriptB = GetComponents[of ScriptB]()

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         for i in range(scriptB.Length):
            scriptB[i].AddVarB(i)</pre>
<p></div></p>
<p>Lancez le jeu, appuyez sur P, la console imprime trois 20. Appuyez sur Espace et P encore, la console devrait ressembler à ceci:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/10/ScreenHunter_107-Oct.-19-10.30.jpg"><img title="Console" src="http://unitygems.com/wp-content/uploads/2012/10/ScreenHunter_107-Oct.-19-10.30-300x203.jpg" alt="Console" width="300" height="203" /></a></p>
<p>Parce que j'ai utilisé la valeur de i dans la boucle comme paramètre de la fonction, chaque script a reçu une valeur différente. A noter que pusique la boucle commence à 0, un script ne change pas.</p>
<h2><a name="4"></a></h2>
<h2>Interaction entre objets</h2>
<p>Nous pouvons également faire interagir deux objets d'une manière similaire. Créez un nouvel objet nommé "ObjectB". Retirez le composant ScriptB de ObjectA et'ajoutez le sur ObjetB.</p>
<p>Lancez le jeu, vous pouvez imprimer mais appuyer sur Espace lèvera une exception de référence null. Cela est dû au fait que le ScriptB n'est plus sur ObjectA et GetComponent n'a tout simplement pas pu le trouver. Nous devons d'abord trouver l' ObjectB avec GameObject.Find ("ObjectB").</p>
<p>Il vous suffit d'ajouter la ligne suivante dans le scriptA:</p>
<pre>// C#
void Start () {
     scriptB = GameObject.Find ("ObjectB").GetComponent&lt;ScriptB&gt;();
}

// UnityScript
function Start(){
    scriptB = GameObject.Find ("ObjectB").GetComponent(ScriptB);
}

// Boo
def Start ():
   scriptB =GameObject.Find ("ObjectB").GetComponent[of ScriptB]()</pre>
<p>GameObject.Find () trouve d'abord l'objet passé en paramètre, puis cherche le composant requis à l'intérieur de celui-ci. Il est recommandé d'effectuer ces actions dans le fonction Start ou à un moment du jeu où les retards n'affecte pas le gameplay. GameObject.Find et GetComponent sont des fonctions coûteuses car elles doivent parcourir toute la hiérarchie. Si votre scène ne comprend que 10 objets, ça passera, mais si elle contient des milliers d'objets vous verrez sûrement un mauvais effet.</p>
<h2><a name="5"></a></h2>
<h2>Interaction entre objets dans la hierarchie</h2>
<p>Faites glisser ObjectB dans ObjectA.</p>
<p>Lancez le jeu et vous verrez que cela fonctionne très bien. Pourtant, nous pouvons y arriver de meilleure manière à l'aide de commandes qui indiquent au compilateur que ObjectB est un enfant de ObjectA. Par conséquent, aucune nécessité de chercher tous les objets de la scène.</p>
<pre>// C#
void Start () {
    scriptB =_transform.Find ("ObjectB").GetComponent&lt;ScriptB&gt;();
}
// UnityScript
function Start(){
   scriptB =_transform.Find ("ObjectB").GetComponent(ScriptB);
}

// Boo
def Start ():
    scriptB =transform.Find ("ObjectB").GetComponent[of ScriptB]()</pre>
<p>Gameobject est échangé pour _transform. En effet, un objet enfant appartient à la transform deu parent donc nous limitons la recherche aux objets se trouvant dans la transform de ObjectA.</p>
<p>Encore mieux:</p>
<pre>void Start () {
     script =GetComponentInChildren&lt;ScriptB&gt;();
}
function Start(){
   script =GetComponentInChildren(ScriptB);
}
def Start():
   script = GetComponentInChildren[of ScriptB]()</pre>
<p>Note that it also works if you have children of children holding the script. Create an “ObjectC”, add ScriptB to it and add the object to ObjectB. Now A has B which has C.</p>
<p>Notez que cela fonctionne aussi si vous avez des enfants d'enfants qui contiennent le script. Créer un "ObjectC", ajoutez ScriptB dessus et ajoutez ObjectC à ObjectB. Maintenant A contient B qui contient C.</p>
<p>Changez ScriptB pour:</p>
<pre>void Update(){
    if(Input.GetKeyDown (KeyCode.P))print (gameObject.name+" "+varB);
}</pre>
<p>Lnacez le jeu, vous verrez que tous les objets sont trouvés.</p>
<p>GetComponentsInChildren fonctionnera de la même manière si chaque enfant contient plusieurs fois le script .</p>
<h2><a name="6"></a></h2>
<h2>SendMessage et BroadcastMessage</h2>
<p>Nous venons de voir différentes manières de faire interagir deux objets ou deux scripts. SendMessage et BroadcastMeassage sont deux autres possibiltés qui peuvent s'avérer plus simples mais aussi plus coûteuses. Le principe reste le même, on a une référence à un objet et on souhaite affecter un script qu'il contient.</p>
<p>Avec SendMessage, on peut appeler une fonction sur un objet sans avoir à trouver une référence au script. Vous allez me dire: "C'est quoi tout ce remue-manège si on peut faire simple?"</p>
<div class="alert red">SendMessage est une fonction extrêmement lente!</div>
<p>Et cela devrait vous paraitre logique, avec GetComponent on indique exactement où se trouve le script en mémoire. Avec SendMessage, le compilateur connait l'objet mais il devra passer par tous les scripts et toutes les fonctions jusqu'à ce qu'il trouve l'heureuse élue. Cela peut altérer votre jeu si vous l'utilisez souvent sur plusieurs objets.</p>
<p>SendMessage ne cherche que sur l'objet auquel l'appel est fait, BroadcastMeassage lance une recherche sur l'objet visé mais aussi sur tous ces enfants. La recherche sera donc encore plus longue si l'objet contient une grande hierarchie.</p>
<p>Voici un exemple tout simple en C#:</p>
<p><br clear="none" /><span class="collapseomatic " id="id8984"  title="<strong>SendMessage</strong>"><strong>SendMessage</strong></span><div id="target-id8984" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">// ObjetA  Script.cs

int argent = 100;
void FonctionA(){
    print("FonctionA dans l'objet A");
}
void RetireArgent(int montant){
    argent -=montant;
}

// ObjetB

ObjetA obj;

void Start(){
    obj = GameObject.Find("ObjetA");
}
void Update(){
    if(Input.GetKeyDown(KeyCode.Space)){
        obj.SendMessage("FonctionA");
        obj.SendMessage("RetireArgent",50);
    }
}</pre>
<p></div></p>
<p>Dans l'exemple ci-dessus, le premier appel va simplement chercher la fonction et lancer une impression sur la console. Le deuxième appel pass aussi un paramètre requit par la fonction.</p>
<p>BroadcastMessage fonctionne de la même manière.</p>
<h2><a name="7"></a></h2>
<h2>Fonctions Interactives</h2>
<p>Unity utilise de nombreuses fonctions qui font interagir deux objets ou plus. L'avantage de ces fonctions réside dans le fait qu'elles stockent de nombreuses informations sur l'autre objet.</p>
<p>Il existe deux principaux groupes:</p>
<ol>
<li>Fonctions de collision : OnCollisionXXXX/OnTriggerXXXX</li>
<li>Fonctions de la class Physics</li>
</ol>
<p>Voici une simple déclaration de collision :</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">// C#
void OnCollisionEnter(Collision other){}

//UnityScript
function OnCollisionEnter(other:Collision){}

//Boo
def OnCollisionEnter(collision as Collision):</pre>
<p>Chaque appel crée une référence à l'autre objet qui est désormais accessible dans la fonction. other dans notre example est un référence à l'autre objet. En déréférençant cette variable nous pouvons désormais accéder aux composants de l'objet avec GetComponent.</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">void OnCollisionEnter(Collision other){
   if(other.gameObject.tag == "ObjetB"){
       ScriptB script = other.GetComponent&lt;ScriptB&gt;();
       script.variable = 20;
   }
}</pre>
<p>Dans cet exemple en C#, j'accède aux données de other et vérifie si other a pour tag "ObjetB". Je sais alors que je suis en collision avec l'ObjetB et j epeux faire une requête pour le ScriptB avec GetComponent.</p>
<p>L'avantage est que vous n'avez pas à chercher l'objet avec <em>GameObject.Find();</em>, ilvous est donné par la fonction.</p>
<p>À noter que la classe COllider est un peu plus complète que la class Collsion, mais vous serez en mesure de faire les mêmes actions avec les deux classes. Il se peut que Collision nécessite une déréférenciation de plus pour accéder la même variable.</p>
<p>Les fonctions de la classe Physics ont un principe similaire. Elles utilisent une variable ou un tableau de variable pour stocker des information sur l'objet qvec lequel nous interagissons.</p>
<p>Voici par exmple un raycast:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void Update() {
        RaycastHit hit;
        if (Physics.Raycast(_transform.position, _transform.forward, out hit))
            print(hit.gameObject.name);

    }
}</pre>
<p>Une variable de type RaycastHit est déclarée et passé comme paramètre à la fonction, le mot-clé out en C# permet de modifier une structure passée comme paramètre. En utilisant hit, nous pouvons retrouver toutes sortes d''informations concernant l'objet. Dans mon exemple, j'imprime simplement le nom de l'objet.</p>
<h2>Interaction en action</h2>
<p>Afin de donner une représentation visuelle et pratique, la vidéo ci-dessous résume quelques-unes des utilisations de GetComponent (en anglais pour le moment).</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/videoseries?list=PLagU0TJRK7XBU0GBjVFwTDnpsurKmX2SB&#038;hl=en_US' frameborder='0'></iframe></span></p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/interaction-scripts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A* #1: All Journeys Start with a Single Step</title>
		<link>http://unitygems.com/astar-1-journeys-start-single-step/</link>
		<comments>http://unitygems.com/astar-1-journeys-start-single-step/#comments</comments>
		<pubDate>Tue, 27 Nov 2012 09:32:23 +0000</pubDate>
		<dc:creator>whydoidoit</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[AStar]]></category>
		<category><![CDATA[Navmesh]]></category>
		<category><![CDATA[pathfinding]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1659</guid>
		<description><![CDATA[<p>Motivation You should read this article if: You want smarter enemies (and not just ones that follow the shortest path!) You want to understand an A* Path finding algorithm implementation in Unity You&#8217;d like to learn about building a navmesh You&#8217;d like to see Linq and threading in action Resources Wikipedia Article On A* Project &#8230;<br /><a class="excerpt" href="http://unitygems.com/astar-1-journeys-start-single-step/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Motivation</h2>
<p>You should read this article if:</p>
<ul>
<li>You want smarter enemies (and not just ones that follow the shortest path!)</li>
<li>You want to understand an A* Path finding algorithm implementation in Unity</li>
<li>You'd like to learn about building a navmesh</li>
<li>You'd like to see Linq and threading in action</li>
</ul>
<h2>Resources</h2>
<ul>
<li><a href="http://en.wikipedia.org/wiki/A*_search_algorithm">Wikipedia Article On A*</a></li>
</ul>
<h2>Project Video</h2>
<p>A quick introduction to the project associated with this article.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/a2f-I0LM-ZI?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<div><span style="font-size: 14px; line-height: 21px;"><br />
</span></div>
<h2>Fundamentally Smart</h2>
<p>A* is the basic way to make you enemies smart - because it's not just about finding the shortest path between two points.</p>
<p>With A* you can:</p>
<ul>
<li>Find the path between two points</li>
<li>Based on the current threat level:
<ul>
<li>Find the shortest path</li>
<li>Find the path that avoids pinch points</li>
<li>Find the path that keeps in cover</li>
<li>Find the path that avoids where the player is looking</li>
<li>Find the best retreat from a fight</li>
<li>Find the best path to draw the player into crossfire</li>
<li>Find the best path to draw the player away from an asset</li>
</ul>
</li>
<li>Find the path that offers the most cover from a current attacker</li>
</ul>
<p>Kinda cool!  In fact A* can pretty much do anything you can think of, presuming you have the nous to writing an algorithm that weights a path position for a given outcome.  In part #2 we will look at examples of this kind of intelligence - but first you need to understand what A* is and how to implement it.</p>
<h2>A*</h2>
<p>Ok, it's got a silly name, I admit it - and it can also be quite intimidating.  You can find some great implementations of A* including Aaron Grandberg's great A* Pathfinding Project - but there's nothing quite the same as understanding it for yourself, even if you use someone else's implementation.</p>
<p>A* uses a "best-first" approach to finding a path between the start and end points - in other words - it tries to go the logically shortest way first, then backs up if it can't make it and tries other short options next if the shortest path is blocked.</p>
<p>This is how A* works:</p>
<ul>
<li>Create an <em>open set</em> of all of the nodes that haven't been considered yet and have been discovered as a part of path finding</li>
<li>Create a <em>closed set </em>of all of the nodes that have been considered</li>
<li>Add the starting position to the <em>open set</em></li>
</ul>
<p>For each <em>node</em> we need to keep two scores - the first is the <em>lowest </em><em><strong>known </strong></em>cost of getting to the node.  Later on we will use <em>cost</em> as something other than distance, but for now, imagine that is the number of world units that we travelled to reach this node (I'll show you how we calculate it next).  We call this the <em>g score</em>.</p>
<p>The second score is our best guess at how far it is from the start to the end positions via this node!   How do we guess?  Well we take the known cost of getting to this node and then we estimate the distance to the goal (in our case we will use the <em>Manhattan</em> distance) and add them together. We call this the <em>f score.</em></p>
<div class="alert blue">Manhattan distances are the distance you would have to travel in a city comprised of blocks, such that at each intersection you can only move North, South, East or West.  In such a system there are no diagonals, no short cuts in other words.  The benefit of <em>Manhattan</em> distance is that it does not involve a square root because we can just add up the difference in x and y coordinates, yet it remains a <em>reasonable</em> estimate of the distance.</div>
<p>Ok so thats the setup - next the actual algorithim:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-17.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1662" title="Untitled 17" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-17.png" alt="" width="510" height="940" /></a></p>
<p>So for the best node (lowest <em>f score</em>) in the <em>open set</em> we check if it's the goal position and return if it is -otherwise we find all of its walkable neighbours that haven't already been processed and for each one, calculate the cost of reaching that node via the one we are considering.  Then we check whether we already know of a better (less costly) way of reaching the neighbour, if we don't then we setup an open set node for the neighbour with the cost of getting to it and our estimated cost to the end position.</p>
<p>An example may help:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-12.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1663" title="Untitled 12" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-12.png" alt="" width="454" height="346" /></a></p>
<p>Her we have a starting position (in green) and a goal (in yellow).  On the first step of the algorithm we find all of the walkable neighbours and calculate a g and an f score for them.</p>
<p>The node with the lowest f score is the one indicated by the green arrow. So we consider that one next - on this step we now will have some candidates for which our g score via the current node is higher than the g score from the first test - so they won't be updated (in the graphic below they have a <em>tg</em> which is higher than the cells <em>g</em>):</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-13.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1664" title="Untitled 13" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-13.png" alt="" width="454" height="346" /></a></p>
<p>On the next step we again take the lowest scoring <em>open set</em> node (the node in red shows the only one currently in theclosed set):</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-14.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1665" title="Untitled 14" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-14.png" alt="" width="454" height="346" /></a></p>
<p>After processing that - again we take the lowest <em>f scoring</em> node:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-15.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1666" title="Untitled 15" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-15.png" alt="" width="454" height="346" /></a></p>
<p>After that, in this case it's just a straight run for the finish:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled-16.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-full wp-image-1667" title="Untitled 16" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-16.png" alt="" width="454" height="346" /></a></p>
<p><img class="alignleft" src="http://upload.wikimedia.org/wikipedia/commons/5/5d/Astar_progress_animation.gif" alt="" width="210" height="210" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Here's an example of the A* algorithm seeking a target. Red to green indicates the distance from the target - open blue nodes are the ones in the open set, the coloured ones are in the closed set.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>NavMesh</h2>
<p>So in order for that algorithm to work we actually need something to represent the walkable and unwalkable positions in a terrain - we call such things a <em>NavMesh - </em>the easiest one is a Grid.  We can create a grid map that overlays the terrain and creates a simplified map of it for our algorithm.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Screen-Shot-2012-11-27-at-08.41.24-copy.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter size-large wp-image-1668" title="Screen Shot 2012-11-27 at 08.41.24 copy" src="http://unitygems.com/wp-content/uploads/2012/11/Screen-Shot-2012-11-27-at-08.41.24-copy-1024x323.png" alt="" width="940" height="296" /></a></p>
<p>In this picture we take an example scene and overlay a grid showing, in green, the walkable areas.</p>
<p>In Unity creating one of these is surprisingly easy!  All we need is a cube to define the bounds of our map and then ray cast each cell to see if it is walkable or not.</p>
<p>First we need a way of representing a cell in the map - for now we just care about walkable/unwalkable and the height of that cell in the world:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	//Representation of a grid cell
	public class GridCell
	{
		public bool walkable;
		public float height;
	}</pre>
<p>Now we actually need a map - so clearly that should be a 2d array of these cells:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	//Width and height of the map in cells
	int width, height;
	//Active map of the world
	public GridCell[,] cells;</pre>
<p>And then to convert it from World coordinates to grid coordinates we need a size for each cell:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	//Size in world units of a cell
	public float cellSize = 0.5f;</pre>
<p>So we will now build a cube in the world, attach our script to it and use the bounds of its renderer to map where we want to put our navmesh (obviously we'd normally use a semi-transparent material!).</p>
<p style="text-align: center;"><a href="http://unitygems.com/wp-content/uploads/2012/11/Screen-Shot-2012-11-27-at-08.56.23.png" data-rel="prettyPhoto[this_page]" title=""><img class="aligncenter  wp-image-1669" title="Screen Shot 2012-11-27 at 08.56.23" src="http://unitygems.com/wp-content/uploads/2012/11/Screen-Shot-2012-11-27-at-08.56.23-1024x602.png" alt="" width="564" height="331" /></a></p>
<p>We need to work out the size of the map from our cubes bounds and the cell size and then do a couple of for next loops to actually find the terrain or another collider.  We also need a mask to indicate what colliders are walkable and which ones are not.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	//Scan the bounds of the model and create a grid
		bounds = renderer.bounds;
		//Work out the top left corner
		topLeftCorner = bounds.center - bounds.extents + new Vector3(0, bounds.size.y, 0);
		//Calculate the dimensions of the grid map
		width = Mathf.RoundToInt(bounds.size.x / cellSize);
		height = Mathf.RoundToInt(bounds.size.z / cellSize);
		//Create the grid map
		cells = new GridCell[width, height];
		//Scan for walkable terrain in each cell
		for(var x = 0; x &lt; width; x ++)
		{
			for(var y = 0; y &lt; height; y++)
			{
				//Get the position for a ray
				var currentPosition = topLeftCorner + new Vector3(x * cellSize, 0, y * cellSize);
				RaycastHit hit;
				//Create a cell for the grid
				var cell = new GridCell();
				cells[x, y] = cell;
				//Cast the ray
				if(Physics.Raycast(currentPosition, -Vector3.up, out hit, bounds.size.y))
				{
					//The height of the highest item in the cell
					cell.height = hit.point.y;
					//Test if the thing we hit was walkable
					if(((1 &lt;&lt; hit.collider.gameObject.layer) &amp; walkableLayer) != 0)
					{
						//Flag the cell as walkable
						cell.walkable = true;
					}
				}

			}
		}</pre>
<p>When that's finished we actually want to run some "post processing" because at the moment it doesn't use any kind of concept of the width of a character and we can bake standard widths into the mesh.  In the example project with this tutorial we have build a plug in system that will call specially decorated classes - passing them the grid we make and letting them modify it.</p>
<p>Using that we can define a <em>Radius Modifier</em> that looks to make unwalkable areas a bit larger:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;

[ProcessingPriority(1)]
public class RadiusModifier : BuildGraph.IProcessGrid {
	#region IProcessGrid implementation
	//Post process the grid
	public void ProcessGrid (BuildGraph builder)
	{
		//Make a list of nodes to flag as unwalkable
		//we can't immediately update them or the
		//whole thing would go horribly wrong as it
		//scanned its own output!
		var unwalkable = new List&lt;BuildGraph.GridPosition&gt;();
		//Run through the grid
		for(var x = 0; x &lt; builder.width; x ++)
		{
			for(var y = 0; y &lt; builder.height; y++)
			{
				//Get a current position
				var currentPosition = new BuildGraph.GridPosition { x = x, y = y };
				//Get all of the neighbours within 2 grid units and see if any
				//of them are not walkable
				if(builder.GetNeighbours(currentPosition, 2).Select(cell=&gt;builder.GetCell(cell)).Any(gc=&gt;!gc.walkable))
				{
					//If so add this cell to the unwalkable
					//list
					unwalkable.Add(currentPosition);
				}
			}
		}
		//Update the map
		foreach(var unwalk in unwalkable)
		{
			builder.GetCell(unwalk).walkable = false;
		}

	}
	#endregion

}</pre>
<h2>Seeking a Path</h2>
<p>Having made a reasonable implementation of a grid navmesh - all we need to do now is some pathfinding!</p>
<p>We create a seeker script that is attached to the thing that wants to follow a path:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Seeker : MonoBehaviour {

	//Target object
	public Transform target;
	//Cache to know what our
	//last path was for
	Vector3 lastDestination;

	//Route to follow
	public List&lt;Vector3&gt; route = new List&lt;Vector3&gt;();
	//Position on the route
	public int routePos;

	//Something that knows how to move
	//our character
	Movement movement;

	void Awake()
	{
		//Something that can be told where to go
		movement = GetComponent&lt;Movement&gt;();
	}

	// Update is called once per frame
	void Update () {
		//Check for a target
		if(target == null)
			return;

		//Get the position from the target
		var targetPosition = target.position;
		//Has it moved
		if(targetPosition != lastDestination)
		{
			//Update the cache
			lastDestination = targetPosition;
			//Ask the grid to build a path
			BuildGraph.instance.SeekPath(transform.position, targetPosition, (path)=&gt;{
				//This is called when we get a result
				if(path == null)
					return;
				//Update the route
				route.Clear();
				route.AddRange(path);
				routePos = 0;

			});
		}

		//Are we at the end of the route?
		if(routePos &lt; route.Count)
		{
			//Set the target to the current route position
			movement.targetPosition = route[routePos];
			//Check for the next route position
			var distance = Vector3.Distance(route[routePos], transform.position);	
			if(distance &lt; movement.speed/2)
				routePos++;
		}

	}
}</pre>
<p>This will track a scene object and try to get to it - it calls our SeekPath function, which is where the magic happens, every time the target moves.  Note that we use a callback function to update the path so we can use multiple threading.  This script interacts with a movement script which just moves towards a target position - the seeker updates that target as the enemy follows the path.</p>
<h2>A* Implementation</h2>
<p>Ok so it's time to look at the A* SeekPath function itself:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	//Find a path between two positions
	public void SeekPath(Vector3 startPosition, Vector3 endPosition, Action&lt;IEnumerable&lt;Vector3&gt;&gt; onComplete)
	{
		//Scan if we don't have a map yet
		if(cells == null)
			Scan();

		onComplete = onComplete ?? delegate {};

		//Start and end in grid coordinates
		var start = GetGridPosition(startPosition);
		var end = GetGridPosition(endPosition);

		//Run multithreaded
		Loom.RunAsync(()=&gt;{
			try
			{
				//Set of considered nodes
				var closedSet = new Dictionary&lt;GridPosition, Node&gt;();
				//Set of all nodes processed (so we can rebuild the path)
				var map = new Dictionary&lt;GridPosition, Node&gt;();
				//Set of nodes yet to be considered
				var openSet = new Dictionary&lt;GridPosition, Node&gt;();

				//Create a node for the start
				var startNode = new Node { f_score = end.Distance(start) };
				//No cost
				startNode.g_score = 0;
				//Add to the map and opensets 
				map[start] = startNode;
				openSet[start] = startNode;
				//Get the time so we can abort if it takes too long
			    var currentTime = DateTime.Now;
				//While we have nodes
				while(openSet.Count &gt; 0 )
				{
					//Check if we should abort
					if((DateTime.Now - currentTime).TotalMilliseconds &gt; maxSeekTime)
					{
						break;
					}
					//Get the best possible node
					var best = openSet.Aggregate((c,n)=&gt;c.Value.f_score &lt; n.Value.f_score ? c : n);
					//Remove it from the open set and add it to
					//the closed set
					openSet.Remove(best.Key);
					closedSet[best.Key] = best.Value;
					//Have we reached the target?
					if(best.Key == end)
					{
						//Recreate the path
						var path = new List&lt;Vector3&gt;();
						var scan = best.Value;
						//Add the actual end position
						path.Add(endPosition);
						//Scan backwards from the end of the path
						//until scan.cameFrom is 0
						while(scan != null &amp;&amp; scan.cameFrom != GridPosition.zero)
						{
							//Add the current node to the START of the path
							//thereby reversing the direction of the list
							path.Insert(0, GetWorldPosition(scan.cameFrom));
							//Get the next node
							scan = map[scan.cameFrom];
						}
						//Update the caller
						Loom.QueueOnMainThread(()=&gt;{
							onComplete(path);
						});
						return;

					}

					//Get all of the neighbours of the current cell
					//that are walkable
					foreach(var cell in GetNeighbours(best.Key).Where(c=&gt;GetCell(c).walkable))
					{
						//Have we processed this already?
						if(closedSet.ContainsKey(cell))
						{
							continue;
						}
						//Work out the cost to the neighbour via the current node
						var tentativeGScore = best.Value.g_score + GetWeightOfMovingBetween(best.Key, cell);
						Node currentNode;
						//Is the neighbour already open?
						if(!openSet.TryGetValue(cell, out currentNode))
						{
							//If not then create a node for it
							//this will have a maximum g_score
							currentNode = new Node();
							//Add it to the map and the open set
							map[cell] = currentNode;
							openSet[cell] = currentNode;
						}
						//Is the new g_score lower than the
						//current one?
						if(currentNode.g_score &gt; tentativeGScore)
						{
							//Update the openset node with this
							//new better way of getting there
							currentNode.g_score = tentativeGScore;
							currentNode.cameFrom = best.Key;
							currentNode.f_score = tentativeGScore + cell.Distance(end);
						}

					}

				}
				//Indicate failure
				Loom.QueueOnMainThread(()=&gt;{
					onComplete(null);
				});
			}
			catch(Exception e)
			{
				Debug.Log(e.ToString());
			}
		});

	}</pre>
<p>As you can see we have a special struct representing grid positions called GridPosition and we call a number of helper functions to manipulate them, but I'll leave you to dig into the code if you want to learn more about them.  Hopefully you can see how the algorithm is processing the nodes and the set.  We have chosen Dictionaries as our method of storing data due to their O(1) lookup performance - so these are very fast to look up, but our "find the node with the best f_score" is running in O(n) time so that if the routine has to back up often it might start getting expensive - but this seems the best trade off between clarity of code and performance in this case.</p>
<h2>Conclusion</h2>
<p>So a lot of theory in #1 - in #2 we will get on to the actual job of making enemies smarter and look at ways of detecting pinch points and cover - then apply that to smarter path finding.</p>
<h2>Tutorial Project</h2>
<p><a href="http://unitygems.com/Downloads/AStar_U3.unitypackage"><img class="alignright size-full wp-image-947" title="downloads" src="http://unitygems.com/wp-content/uploads/2012/10/downloads.png" alt="" width="150" height="64" /></a></p>
<div>
<p>You can download the project from <a href="http://unitygems.com/Downloads/AStar_U3.unitypackage">here</a>.  It includes some great free assets from the Asset Store <img src='http://unitygems.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>In the project there is an enemy that follows a sphere - the scene view draws a line showing the path, in the game view you can click on the ground to move the enemy there and control the camera angle with the scroll wheel and the right button.<br />
.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/astar-1-journeys-start-single-step/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Gestion de la mémoire</title>
		<link>http://unitygems.com/gestion-memoire/</link>
		<comments>http://unitygems.com/gestion-memoire/#comments</comments>
		<pubDate>Sun, 25 Nov 2012 16:52:45 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[Beginner]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Class]]></category>
		<category><![CDATA[Débutant]]></category>
		<category><![CDATA[Garbage Collection]]></category>
		<category><![CDATA[GetComponent]]></category>
		<category><![CDATA[Intermédiaire]]></category>
		<category><![CDATA[mémoire]]></category>
		<category><![CDATA[static]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1580</guid>
		<description><![CDATA[<p>Motivation: Comment .NET gère la mémoire est marqué par  de nombreuses inconnues. Pourquoi Unity me dit que mes value types ne peuvent être modifiées? Boxing une variable ne signifie pas lui en mettre plein la fiole?Non. Cet article va tenter de clarifier certains points qui nous le souhaitons éclarciront votre manière de programmer. Zones de &#8230;<br /><a class="excerpt" href="http://unitygems.com/gestion-memoire/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Motivation:</h2>
<p>Comment .NET gère la mémoire est marqué par  de nombreuses inconnues. Pourquoi Unity me dit que mes value types ne peuvent être modifiées? Boxing une variable ne signifie pas lui en mettre plein la fiole?Non.</p>
<p>Cet article va tenter de clarifier certains points qui nous le souhaitons éclarciront votre manière de programmer.</p>
<ul>
<li><a href="#memory">Zones de mémoire</a></li>
<li><a href="#valuetypes">Value Types et le Stack</a></li>
<li><a href="#reference">Reference Types et le Heap</a></li>
<li><a href="#struct">Struct vs Class</a></li>
<li><a href="#creference">Créer une Reference</a></li>
<li><a href="#staticclass">Classes Statiques</a></li>
<li><a href="#staticvariables">Variables Statiques</a></li>
<li><a href="#staticfuncs">Fonctions Statiques</a></li>
<li><a href="#heap">Heap Fragmentation, Object Pooling et Garbage Collection</a></li>
</ul>
<div><div class="alert blue">Ce tutoriel est particulièrement utile pour les programmeurs en C/C++ qui font le dèplacement vers C# pour développer avec Unity. C# manipule la mémoire differement ce qui peut paraitre confus ou magique en premier lieu aussi. Comme tous systèmes C# a ses petits défauts.</div></div>
<p>Lorsqu'on débute la programmation avec Unity et la programmation en général, nombreux sont ceux qui tombent face à l'utilisation des variables types. Pourquoi certaines variables sont modifiées et d'autres ne le sont pas, pourquoi ma variable a disparu alors que j'en ai encore besoin?</p>
<p>Une autre erreur classique est l'utilisation des variables statiques. Les nombreux tutoriels sur internet vous les font utiliser sans vraiment vous dire ce qu'elles sont et mettent simplement en avant la "facilité d'accès".</p>
<p>Le problème c'est que les variables statiques (aussi appelées variables de classe) ne sont pas un sujet facile.</p>
<p>Certains vous diront tout simplement de les éviter, clamant que ce qui peut être fait avec du statique peut aussi être fait sans. Si cela est vrai, ce n'est pas toujours la meilleure solution.<br />
<div class="alert  yellow">Avant de commencer, si vous arrivez du langage C et que vous avez peu d'expérience de la programmation orientée-objet, n'oubliez que ce que vous connaissez de la gestion de le mémoire et les mot-clés de stockage ne sont pas totalement similaire en POO. N'essayez pas de lier C avec C#. </div></p>
<p>Dans ce tutoriel, nous couvrirons les différentes zones de la mémoire, les value types et reference types, l'allocation dynamique de la mémoire et les variables statiques.</p>
<h2><a name="memory"></a></h2>
<h2>Zones de Mémoire</h2>
<p>En lançant un programme, l'OS (operating system,  Windows, Mac ou Linux) réserve une partie de la mémoire de l'ordinateur pour le programme. Avant, il y avait quatre zones principales, le call stack, le heap, les registres et la mémoire statique.</p>
<p>Les développeurs de C# ont été assez gentils de minimiser ce nombre à deux zones seulement, stack et heap. La première est ordonnée, rapide mais limitée, la seconde est aléatoire, large et ainsi plus lente.</p>
<p>Il est possible pour le programmeur de choisir quelle zone sera utilisée pour chaque variable en fonction du but et du destin de la variable.</p>
<p>Il existe trois mot-clés de stockage (C en avait un quatrième,<em> register</em>)  pour le gestion de la mémoire:</p>
<ol>
<li>auto</li>
<li>static (nous allons couvrir ces deux là)</li>
<li>extern.</li>
</ol>
<p>Il se peut que vous rencontriez <em>extern</em>, cela signifie simplement que la variable est déclarée en dehors du projet, par exemple dans un DLL écrit dans un langage différent et non .NET.</p>
<div class="alert yellow">Encore, si vous venez de C, <em>extern</em> est différent (et similaire). Cela refère à une variable qui est déclarée dans un autre fichier.</div>
<pre>extern int number;</pre>
<p>Le compilateur n'alloue aucune zone de mémoire pour <em>number</em> et attend que la variable soit trouvée ailleurs. Nous n'allons pas passé plus de temps là-dessus. Pour plus d'info <a href="http://msdn.microsoft.com/en-us/library/e59b22c5(v=vs.71).aspx"> ici</a>.</p>
<h2><a name="valuetypes"></a></h2>
<h2>Value Types et le Stack</h2>
<p><em>auto</em> signifie une variable automatique. Il se peut que vous n'ayez jamais vu ce mot auparavant puisqu'il n'est plus utilisé en C# cependant le principe existe toujours. Il fut un temps où <em>auto</em> était la variable par défaut:</p>
<pre>int variable = 10;
auto int variable = 10;</pre>
<p>Ces deux lignes ont le même effet.</p>
<p>Le principe d'une variable automatique est qu'elle est placée sur le call stack. Un stack est une pile de variables, tout comme une pile d'assiettes, vous pouvez retirer celle du dessus ou en ajouter une sur le dessus, mais  vous ne pouvez pas toucher celle du dessous. Voyez plutot:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Stack.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-427" title="Stack" alt="Stack" src="http://unitygems.com/wp-content/uploads/2012/12/Stack.png" width="658" height="330" /></a></p>
<p title="Stack"><div class="alert green">On dit d'un stack qu'il est de type LIFO (Last-In-First-Out, dernier arrivé-premier parti), ce qui arrive en dernier part en premier.</div>[/one_half_last]Pour savoir où se trouve le dessus de la pile, le programme utilise un pointeur de stack (stack pointer) qui est une variable dans le CPU (processeur) qui garde une trace de la position dans le stack représentée sur notre dessin par la flèche noire. Si nous ajoutons une variable, le pointeur est poussé vers le haut (en fait il se peut qu'il descende en fonction de votre OS) et inversement lorsqu'on retire une variable.</p>
<p>Le stack est utilisé pour les appels de fonction, si vous réfléchissez deux secondes, le programme est une fonction principale qui lance une boucle sans fin (jusqu'à la fermeture du programme...) dans laquelle les fonctions Updates sont appelées à leur tour et elles appellent d'autres fonctions. Ainsi il est logique que toutes les variables de votre programme soient automatiques si elles ne sont pas définies autrement.</p>
<p>Il se peut que vous rencontriez le concept de stack frame, une collection de variables allouées localement par la fonction en cours (et contient également l'adresse de retour qui est le point d'instruction qui sera exécutée immédiatement après le retour de la fonction). Le compilateur maintient un pointeur vers la fin du stack frame puis utilise un décalage négatif de ce pointeur pour trouver la mémoire que vos variables locales occupent. Le résultat pratique de ceci est qu'après qu'une fonction ait retourné, alors aucun espace utilisé par ses variables locales est encore utilisé ou alloué en aucune façon mais plutot sauvegardées de manière à être disponible pour le prochain l'appel de la fonction.</p>
<p>Si vous écrivez une fonction récursive (une fonction qui s'appelle elle-même) vous pouvez potentiellement manquer d'espace dans le stack. Voici un exemple de fonction recursive:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">void Fonction(int num){
   int temp;
   temp = num+1;
   Fonction(temp);
   print(temp);
}</pre>
<p>Comme vous pouvez le constater, la fonction place <em>num</em>  sur le stack puis une variable <em>temp</em> puis s'appelle et le processus se répète. Notre fonction n'a aucune "sentinelle" et va infiniment se répéter jusqu'à ce qu'un stack overflow crash le programme. Si votre programme comporte une tel bug, le compilateur va probablement lancer l'avertissement de stack overflow.</p>
<p>Le temps de vie et la portée d'une variable fonctionnent ensemble. La vie d'une variable commence avec sa déclaration jusqu'à l'accolade correspondant à l'accolade qui s'ouvre au dessus. Mmm, une clarification s'impose.</p>
<pre>void Update(){
    int number = 10;
    Fct(number);
    print(number);
} 

void Fct(int n){
    int inside=20;
    n = n + inside;
    print(n);
}</pre>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Stack2.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-428" title="Stack function" alt="Stack function" src="http://unitygems.com/wp-content/uploads/2012/12/Stack2.png" width="409" height="346" /></a></p>
<p>Update est appelée et la première instruction est une déclaration de variable. Le stack pointer est poussé vers le haut et la valeur de <em>number</em> est placée en mémoire.</p>
<p>La seconde commande est un appel de fonction. Lors d'un appel de fonction, le programme s'arrête et saute vers l'adresse de mémoire où la fonction est stockée. Certaines données sont placées sur le stack de manière à pouvoir reprendre le programme en fin de fonction. Les paramètres (s'il y en a) sont alors poussés sur le stack en créant une copie de l'original.</p>
<p>La variable <em>number</em> n'est pas poussée sur le stack pour être utilisée dans la fonction mais une nouvelle variable<em> n</em> est créée, placée sur le stack et la valeur de <em>number</em> y est placée. On dit que la variable <em>number</em> est passée par copie.</p>
<p>Nous avons alors une variable <em>n</em> dans la fonction qui a la valeur de <em>numbe</em>r mais <em>number</em> n'existe pas dans <em>Fct()</em> et de ce fait ne peut être vue ni atteinte. Dans la fonction, la variable <em>inside</em> est créée. Le stack ressemble en quelque sorte à l'image au-dessus ( largement simplifié).</p>
<p>En fin de fonction, <em>n</em> est imprimée et a la valeur 30. Toutes les variables créées dans la fonction sont détruites/perdues. Cela inclut <em>n</em> et<em> inside</em>. Bien que les variables soient toujours physiquement en mémoire, elles sont simplement ignorées par le système et finiront probablement écrasées.</p>
<p>De retour dans Update, nous imprimons la variable <em>number</em> qui n'a pas changée sa valeur de 10. Le stack pointer a perdu la location de <em>n</em> et <em>inside</em>, si nous tentons de les utiliser dans Update, le compilateur renverrait une erreur que la variable n'existe pas dans cette partie du programme (scope).</p>
<p>Nous venons de voir que la portée d'une variable automatique est définie par les { } dans laquelle elle fut déclarée. En dehors, la variable n'existe plus et n'est plus visible. Ces accolades marquent le<em> scope</em> d'une fonction, d'une commande if, une boucle,...Il est en fait possible de créer un scope de la manière suivante:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void Update(){
  int a = 10;
   {
     int b = a;
   }
   // b n'existe plus
}</pre>
<h3>Temps de vie et scope<a name="lifetime"></a></h3>
<p>Le temps de vie (lifetime) signifie le moment du programme pendant lequel la variable existe, scope definit la zone du programme où la variable est visible. Dans le cas des variables automatiques, les deux sont identiques.</p>
<p>Toutes les variables value type sont placées sur le stack, celles ci sont:</p>
<ul>
<li>int</li>
<li>unsigned</li>
<li>float</li>
<li>double</li>
<li>char</li>
<li>struct</li>
<li>bool</li>
<li>byte</li>
<li>enum</li>
<li>long</li>
<li>short</li>
</ul>
<p>Plus ou moins les variables héritées de C (excepté bool).</p>
<p>Pour une variable automatique, sa vie est prise en charge par le compilateur. La fin du scope dans lequel elle fut déclarée marque aussi la fin de  la variable comme nous l'avons vu dans l'exemple précédent. Le programmeur n'a pas à se soucier de libérer la mémoire occupée par la variable, cela est fait automatiquement.</p>
<h2><a name="reference"></a></h2>
<h2>Reference Type et le Heap</h2>
<p>Une variable <em>reference typ</em>e est un objet stocké en mémoire comme référence. Lorsqu'on crée une nouvelle instance de la classe, les données sont stockées dans la zone de mémoire appelée le heap. Une référence pointant vers ces données est placée sur le stack. Cette référence  a comme valeur l'adresse de l'objet. Pour créer une instance d'une classe, le mot-clé <strong>new</strong> est utilisé. C'est un appel à l'OS pour obtenir de l'espace de mémoire correspondant au type de l'objet et une instruction pour lancer les codes nécessaires à l'initialisation de l'objet. Voyez ci-dessous comment créer une instance d'un objet de type Dog.</p>
<pre>public class Dog{
     public string name { get; set;}
     public int age { get; set;}
     public Dog(string s, int n){
           name = s;
           age = n;
    }                          
}
public class Test : MonoBehaviour {
    Dog dog1 = new Dog("Rufus",10);
    Dog dog2 = new Dog("Brutus",8);

    void Update (){                                                  
        if(Input.GetKeyDown(KeyCode.Alpha1))
            print ("Le dog1 est nommé "+dog1.name+" et a  "+dog1.age+" ans.");
        if(Input.GetKeyDown(KeyCode.Alpha2))
             print ("Le dog2 est nommé "+dog2.name+" et a "+dog2.age+" ans.");
    }
}</pre>
<p>Nos variables <em>dog1</em> et <em>dog2</em> sont des références vers des  locations en mémoire où les données concernées sont stockées. Ces références étant placées sur le stack, elles seront détruites en fin de scope.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Diapositive8.png"><img title="Class" alt="Class" src="http://unitygems.com/wp-content/uploads/2012/12/Diapositive8-300x182.png" width="300" height="182" /></a></p>
<p>Voyons maintenant la fonction Instantiate. Imaginons une prefab nommée Enemy qui inclut un modèle 3D, des composants et des scripts.</p>
<pre>using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour{
    public GameObject enemyPrefab;

    void Update(){
        if(Input.GeyKeyDown(KeyCode.Space))
               Instantiate(enemyPrefab,new Vector3(0,0,0), Quaternion.identity);
    }
}</pre>
<p>Nous venons de créer une instance de enemyPrefab et elle se porte bien. Un problème cependant, nous n'avons aucune référence pour l'utiliser. Si nous devons appliquer des changements ou des actions à notre prefab, nous avons besoin d'une référence à cet objet.</p>
<pre>void Update(){
    if(Input.GeyKeyDown(KeyCode.Space))
       GameObject enemyRef = Instantiate(enemyPrefab, new Vector3(0,0,0), Quaternion.identity);
        enemyRef.AddComponent(Rigidbody);
        Destroy(enemyRef);
     }
}</pre>
<p>Dans cet exemple, la variable <em>enemyRef</em> est déclarée et assignée l'adresse du nouvel objet de type <em>GameObject</em>. <em>enemyRef</em> est désormais une référence à cet objet. Voyez comment il nous est possible d'ajouter un <em>component</em> (Rigidbody dans notre cas) puisque <em>enemyRef</em> sait où se trouve l'objet en mémoire. Sur la dernière ligne, l'objet est détruit, ce qui est plutot inhabituel de créer et détruire dans la foulée mais c'est juste pour l'exemple.</p>
<p>La référence est une variable automatique est par conséquent ne vit qu'entre les {} de la commande if. En dehors, la variable référence n'existe plus. Pour récuperer notre objet, nous devons le chercher ainsi:</p>
<pre>GameObject enemyRefAgain = GameObject.Find(“Enemy”);</pre>
<p>Toutes les variables reference type sont stockées dans le heap. Celles ci sont:</p>
<ul>
<li>class (classe, interface, classe abstraite, delegate)</li>
<li>object</li>
<li>string (bien qu'il n'y paraisse pas, c'est une instance de la classe <em>String</em>)</li>
</ul>
<p>Les principales différences entre une variable value type et une variable reference type sont l'addition d'une variable pour pointer vers la donnée et la zone de stockage en mémoire. Cette référence doit d'abord être accéder avant de pouvoir accéder aux données. Cela rend les classes légèrement plus lentes que les structures qui peuvent être accédées directement. L'autre différence entre <em>struct</em> et <em>class, </em>les structures ne peuvent inhériter et sont passées par copie. Cela siginifie que lorsqu'on passe une structure en tant que paramètre d'une fonction, si la structure a une taille de 50 octets, on copie 50 octets de données sur le stack, une classe copie seulement sa variable référence et on peut accéder les données via cette référence.</p>
<p>Un autre problème:</p>
<pre>using UnityEngine;
using System.Collections;

public class Memory : MonoBehaviour {
    DogC dogC1 = new DogC();
    DogC dogC2 = new DogC();
    int number1;
    int number2;

    void Update () {
        if(Input.GetKeyDown(KeyCode.Space)){
           number2=number1 = 10;
           number1 = 20;
           print (number1+" "+number2);
           dogC1.name = "Rufus";
           dogC1.age = 12;
           dogC2 = dogC1;
           dogC1.name = "Brutus";
           print (dogC1.name+" "+dogC1.age+" "+dogC2.name+" "+dogC2.age);
        }
    }
}</pre>
<p>Vous remarquerez que les deux <em>number</em> sont indépendants, quand l'un change l'autre n'en voit rien.</p>
<p>Par contre, assigner un objet à un autre crée une connection et modifier l'un modifiera l'autre.</p>
<p>La raison est simple, avec <em>dogC2 = dogC1;</em> nous assignons l'adresse de dogC1 dans la variable référence dogC2. L'adresse original de dogC2 est perdue en mémoire et modifier dogC1 ou dogC2 revient au même. Nous avons alors deux références pour la même location.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Diapositive4.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-431" title="Class reference" alt="Class reference" src="http://unitygems.com/wp-content/uploads/2012/12/Diapositive4.png" width="449" height="583" /></a></p>
<h3>Temps de vie, Scope et Garbage Collection</h3>
<p>Dans le cas d'une variable reference type, le temps de vie est un peu trouble puisque c'est le job du<em> Garbage Collector (GC) </em>de vérifier et retirer la variable si nécessaire. Du temps de C et C++, c'était le boulot du programmeur de s'assurer que les variables allouées dynamiquement soient libérées (la fonction <em>free()</em> en C, ~ et<em> delete</em> en C++).</p>
<p>En C#, le GC vérifie si la variable est encore utilisée ou accessible, si aucune référence  n'est trouvée à partir des codes, il marque l'emplacement comme libre pour être remplacé. Les programmeurs familiers des interface COM ou autre système de décompte des références trouve souvent le GC un peu étrange comme concept. Ceci parce que dans un système de décompte des références, si deux objets se réfèrent l'un l'autre (comme un parent qui a une référence à un child et ce child lui même a une référence à son parent) peut avoir comme résultat que la mémoire n'est jamais libérée. Le GC n'a pas ce genre de problème puisqu'il considére que bien que les deux se réfèrent l'un l'autre, aucun des deux n'est accessible pour le reste du programme.</p>
<div class="alert yellow">Le GC est un gros sujet et Unity a ses propres bizarreries. Si vous êtes habitué du C# classique, vous vous attendez à ce que le GC fasse les choses simplement pour les objets à court temps de vie, ce n'est pas le cas avec Unity.</p>
<p>Chaque fois qu'un bloc de mémoire se remplit, le système doit vérifier l'accessibilité de tous les objets alloués sur le heap. Cela implique que si l'objet peut être accédé à partir de codes en cours ou de codes qui peuvent être lancés  alors il est gardé, dans l'autre cas il est libéré. Un .NET GC normal utilise un principeé de <em>generation</em> qui consiste à tenter de réduire le temps de travail associé à l'accessibilité en essayant d'abord les objets récemment créés et en continuant vers les plus anciens si l'espace de mémoire vient à manquer. Simplement, un object qui vient d'être créer est placé en generation 0, si il passe le premier passage de GC alors il est poussé vers la génération 1 et si il passe la génération 1 alors il finit en génération 2 qui est la dernière. Ce principe est basé sur la probabilité qu'un objet récemment créé est plus enclin à ne plus être utilisé.</p>
<p>Il semble que Unity préfère tester tous les objets, de ce fait le GC devient une surcharge importante, bien plus importante que ce qui serait attendu avec un langage .NET.</div>
<div class="alert blue">Le test d'accessibilité crée toute la magie derrière le GC, il permet au collecteur  de déterminer si un code qui est actuellement en cours d'exécution ou qui pourrait être en cours d'exécution, parce qu'il existe une référence active vers ce code, a une référence à l'objet qui est un candidat pour le GC. Cela inclut l'utilisation des <em>closures</em> dans une fonction qui sont très compliquées, très utiles mais aussi assez lent.</div>
<div class="alert blue">Une <em>closure</em> est créé avec une référence vers des variables locales ou des paramètres dans une fonction anonyme définit à l'intérieur d'une fonction. La valeur de la variable est préservée et si la fonction anonyme est appelée encore une fois, alors la variable préserve sa valeur. Les programmeurs en C y verront une similarité avec les variables statiques dans une fonction.</p>
<pre>List&lt;Action&gt; actionsToPerformLater = new List&lt;Action&gt;();

void DisplayAMessage(string message)
{
      var t = System.DateTime.Now;
      actionsToPerformLater.Add(()=&gt;{
          Debug.Log(message + " @ " + t.ToString());
      });
}

void SomeOtherFunction()
{
      DisplayAMessage("Hello");
      DisplayAMessage("World");
      SomeFunctionThatTakesAWhile();
      DisplayAMessage("From Unity Gems");

      foreach(var a in actionsToPerformLater)
      {
           a();
      }

}</pre>
<p>Dans ce code, chaque appel à <em>DisplayAMessage</em> forme une closure entre le message passé et le temps actuel du système. Lorsque la boucle <em>foreach</em> tourne, le message de De<em>bug</em> montre que le message contient les valeurs de  <em>t</em> au moment de l'appel de la fonction. Les <em>closures</em> sont particulièrement importantes et sont plus précisement décrites <a title="Finite State Machines #2 – Delegates, Reflection &amp; Closures" href="http://unitygems.com/fsm2/">ici</a>.</div>
<div class="alert blue">Le Gc se lance quand le système considère qu'il y a un manque d'espace de mémoire pour stocker une donnée. Cela signifie qu'un objet qui n'est plus utilisé peut cependant rester en mémoire pour un moment.Il est donc pratique courante de fermer explicitement les connexions externes ou de libérer des ressources externes quand un objet n'est plus nécessaire.</p>
<p>Il n'est pas nécessaire de libérer explicitement les objets internes (classes de votre projet), mais cela devient nécessaire lorsque vous utilisez des fichiers ou autres en dehors de votre projet, y compris Streams (fichiers) et les connexions de base de données qui pourrait avoir un certain impact sur le système. Par exemple ne pas fermer un fichier peut faire échouer une action ultérieure qui accèdent à ce fichier car le fichier est toujours ouvert par un objet qui n'existe plus.</div>
<div class="alert green">Le GC est une opération coûteuse et il est donc logique de la déclencher manuellement quand il ne fait aucune différence pour le jeu - entre deux niveaux par exemple, lorsque le joueur entre dans un menu de pause ou à n'importe quel moment qui n'altererait pas le jeu pour le joueur. Vous pouvez déclencher manuellement le GC avec <em>System.GC.Collect ();</em> </div>
<p>En ce qui concerne la portée d'une variable de type référence, elle peut être consultée n'importe où dans le programme à condition d'effectuer l'action appropriée pour la trouver, à l'aide <em>GameObject.Find ()</em>, par exemple, qui renvoie une référence à l'objet dans tous les scripts. <div class="alert green"> Voir notre tutoriel <a title="Script Interaction Tutorial  – GetComponent in C#" href="http://unitygems.com/script-interaction1/">GetComponent</a> pour plus de détails sur la recherche des instances de classes au cours du jeu.</div></p>
<h2><a name="struct"></a></h2>
<h2>Struct vs Class</h2>
<p>Laquelle doit on utiliser et dans quelle situations? Nous avons découvert qu'utiliser une classe ajoute une surcharge, la référence. Si nous devions créer un millier d'objets, nous obtenons un milliers de surcharges alors que notre structure n'en a pas.</p>
<p>Voyez cet exemple:</p>
<pre>public class DogC{
    public string name { get; set;}
    public int age { get; set;}
}

public struct DogS {
    public string name;
    public int age;
}

using UnityEngine;
using System.Collections;

public class Memory : MonoBehaviour {
    DogC dogC = new DogC();
    DogS dogS = new DogS();

    void Update () {
        if(Input.GetKeyDown(KeyCode.Alpha1))
            Print (dogS);
        if(Input.GetKeyDown(KeyCode.Alpha2))
            Print (dogC);
        if(Input.GetKeyDown(KeyCode.Alpha3))
            print ("Struct: The dog's name is "+dogS.name +" and is "+dogS.age);
        if(Input.GetKeyDown(KeyCode.Alpha4))
            print ("Class: The dog's name is "+dogC.name +" and is "+dogC.age);
     }

    void Print(DogS d){
        d.age = 10;
        d.name = "Rufus";
        print ("Struct:The dog's name is "+d.name +" and is "+d.age);
     }

    void Print(DogC d){
        d.age = 10;
        d.name = "Rufus";
        print ("Class:The dog's name is "+d.name +" and is "+d.age);
    }
}</pre>
<p>Tout d'abord, vous remarquerez que la troisième entrée n'imprime pas ce qui est attendu, le nom et l'âge du chien en structure ont disparu. D'autre part, la classe conserve ses valeurs.</p>
<p>Rappelez-vous ce que nous avons dit, une structure est un value type  quand une classe est un reference type. Lorsque vous appelez la fonction avec la structure, nous passons une copie de la structure, mais la copie n'est pas l'original. Lorsque vous modifiez les données, nous  modifions la copies sur la pile. Celle-ci est perdue à la fin de la fonction (nous pouvons retourners la structure en dehors de la fonction qui est alors copiée sur une autre structure).</p>
<p>La classe est passée en utilisant une référence qui peut accéder aux données d'origine et les modifier au sein de la fonction, ces modifications demeure même lorsque la fonction est terminée puisque c'est l'original qui est modifiée.</p>
<p>Qu'est-ce que cela devrait nous faire penser? Si ma structure est vraiment grande avec par exemple 10 variables, quand elle est passée à la fonction, la pile grossit de 10 emplacements. Maintenant, si je passe un tableau de structures avec 50 d'entre elles, la pile a maintenant 500 emplacements, la pile est limitée en taille et un débordement de pile (stack overflow) pourrait arriver si la structure et le tableau sont encore plus grands.</p>
<p>En passant la référence de ma classe, je passe une seule variable. Avec 50 instances, je passe 50 variables seulement.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/12/Diapositive6.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-432" title="Struct vs Class" alt="Struct vs Class" src="http://unitygems.com/wp-content/uploads/2012/12/Diapositive6.png" width="744" height="338" /></a></p>
<p>Donc, les classes économisent de la mémoire, mais les structures sont plus rapides (sauf en cas de boxing sur lequel nous reviendrons plus tard). Donc, il s'agit de trouver un équilibre entre les deux. Envisagez d'utiliser des structures quand vous avez, par exemple de 5 à 8 variables. Au-delà, utiliser une classe.</p>
<p>Vous devez également garder à l'esprit que chaque fois que vous accédez à une variable qui est une structure (par exemple en faisant transform.position, transform est une class qui contient la structure position), vous créez une copie de cette structure sur la pile - cette copie prend du temps pour être créer.</p>
<p>Chaque fois que vous créez une classe vous allouez de la mémoire sur le heap qui va rapidement conduire à un GC  pour les variables rejetées - les structures sont toujours allouées sur la pile et donc ne causeront jamais de Garbage Collection.</p>
<p>Vous remarquerez que dans Unity, les structures sont souvent utilisés pour 3 à 4 variables comme position, color, quaternion, rotation, scale, ..., toutes sont des structures.</p>
<div class="alert green">Les objets de courte durée et souvent  alloués sont de bons candidats pour des structures parce qu'ils ne causent pas de GC. Les objets de longue durée de vie et les gros objets sont de bons candidats pour les classes parce qu'ils ne seront pas copiés à chaque fois qu'ils sont utilisés et leur longue existence ne causera pas la nécessité d'un GC régulier. Vous verrez que beaucoup de petits objets comme Vector3 et RaycastHit sont des structures dans Unity pour cette raison.</div>
<p>Un dernier point avant de passer à la suite, nous avons gardé pour la fin la cerise sur le gâteau. Il est possible de passer une structure par réf´rence pour que nous puissions modifier notre structure originales.</p>
<div class="alert red">Vous ne pouvez pas maintenir une référence à une structure une fois que la fonction qui a défini la référence a quitté. Il existe de nombreuses façons pour qu'elles causent un problème telle que l'utilisation de closures (formées par des fonctions lambda ou fonctions inline), mais ce sont des techniques très avancés.</div>
<pre>void PrintRef(ref DogS d){
    d.age = 10;
    d.name = "Rufus";
    print ("Structure:Le nom du chien est "+d.name +" et il a "+d.age+" ans.");
}</pre>
<p>On appelle la fonction ainsi:</p>
<pre>void Update(){
    PrintRef(ref dogS);
    print ("Structure:Le nom du chien est "+d.name +" et il a "+d.age+" ans.");
}</pre>
<p>Vous avez remarqué le mot clé<strong> ref</strong>, cela dit au compilateur de créer une référence à la structure, au lieu de la copier sur la pile. En dehors de la fonction, la structure a gardé les valeurs données à l'intérieur de celle-ci. Ce mot-clé peut être utilisé avec n'importe quelle value type. C# a un deuxième mot-clé similaire <strong>out. </strong>La différence entre les deux est que <em>out</em> nécessite que la variable soit modifié dans la fonction.</p>
<h2><a name="creference"></a></h2>
<h2>Créer une Référence</h2>
<p>Donc, nous venons de voir qu'il est possible de créer une référence à une variable value type. Considérons que nous voulons créer une variabe integer dans une fonction, mais nous voulons la garder pour une utilisation ultérieure. En déclarant simplement à l'intérieur de la fonction la variable automatique est perdue à la fin de la fonction.</p>
<p>Nous pouvons créer une variable allouée dynamiquement qui sera stocké dans le heap avec une référence dans notre script.</p>
<pre>using UnityEngine;
using System.Collections;

public class Test:MonoBehaviour{
    int number;

    void Update () {
        if(Input.GetKeyDown (KeyCode.C))
            CreateVariable();
        if(Input.GetKeyDown (KeyCode.Space))
            PrintVariable(number);
    }

    void CreateVariable(){
        //int number = new int();
        number = new int();
        number = 10;
        print ("In function "+number);
    }

    void PrintVariable(int n){
        print (n);
        n+=10;
    }
}</pre>
<p>Nous avons d'abord déclaré une variable <em>number</em> de type int qui est global à notre script. Nous utilisons cette variable à l'intérieur CreateVariable et lui attribue une référence à une variable integer  en utilisant new int ();</p>
<p title="Reference for automatic "><a href="http://unitygems.com/wp-content/uploads/2012/12/Heap.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-429" title="Reference for automatic " alt="Reference for automatic" src="http://unitygems.com/wp-content/uploads/2012/12/Heap.png" width="480" height="222" /></a></p>
<p title="Reference for automatic ">Pour clarifier cette situation, le mot clé new renvoie une référence à la variable qui est créé dans la section heap. Cette référence est stockée dans number qui contient maintenant l'adresse de la variable nouvellement créée. Utiliser<em> number</em> c'est utiliser indirectement la nouvelle variable.</p>
<p>Considérons la partie commenté, si nous avions fait de cette façon, nous aurions perdu notre référence à la fin de la fonction. Sur son cycle de nettoyage suivant, le garbage collector aurait trouvé notre donnée sans aucune référence et la retirerait de la mémoire. Considérez que lorsque vous déclarez une variable locale, comme nous l'avons fait ici à l'intérieur de la fonction, <em>int number;</em> aurait caché la variable global <em>int number</em>.</p>
<div class="alert blue">Lorsque vous maintenez une variable primitive, comme un integer, à l'intérieur d'une référence, le compilateur exécute une fonction appelée <em>boxing</em> qui consiste essentiellement à envelopper la variable primitive à l'intérieur d'une classe. Les variables déclarées de cette manière sont alloués sur le heap et nécessite le GC pour être libérées. Elles prennent également plus de mémoire que la valeur primitive par défaut.</div>
<p>Prenons une situation basique de boxing(emboitâge...si cela a un sens...). Lorsque vous utilisez la fonction <em>Debug.Log (objet);</em>, le paramètre est de type <em>object</em> qui signifie que tout type de variable peut être passé à la fonction. Mais en passant un integer, le compilateur va<em> boxer</em> l'integer dans un objet. Il est alors possible d'optimiser le<em> boxing</em> en anticipant le comme ceci:</p>
<div class="one_half">
<pre>void PrintingManyTimes(int n){
    object obj = n;
    for(int i = 0;i&lt;500;i++)
        Debug.Log(obj);
}</pre>
<p></div><div class="one_half last">De cette manière, le compilateur n'a pas besoin de lancer un boxing à chaque appel. C'est fait une fois pour tous les 500 appels.</div><div class="clear"></div></p>
<h2>Static</h2>
<p>Nous entrons maintenant dans la dernière partie de notre tutoriel. Encore une fois, si vous avez un passé en C, oubliez ce que vous savez à propos de l'utilisation de static.</p>
<p>Une variable statique en . NET est stockée dans une partie spéciale du heap appelée le heap à haute fréquence (<em>high frequency heap</em>).</p>
<p>Comme nous l'avons mentionné précédemment, nous rencontrons souvent des variables statiques dans des tutoriels pour débutants où seule la facilité d'utilisation est mise en avant. Le gentil tuteur ne prend souvent pas le temps de bien expliquer les avantages et les dangers des variables statiques. Nous allons essayer de clarifier ce qu'est un objet statique, comment l'utiliser, où l'utiliser et l'inverse.</p>
<h2><a name="staticclass"></a></h2>
<h2>Classes Statiques</h2>
<p>Une classe statique est une classe qui ne possède pas d'instanciation d'objet, vous ne pourrez pas créer un objet d'une classe statique.</p>
<p>En conséquence, il n'y a qu'une instanciation et elle est faite par le compilateur. Vous pourriez être confus puisque je viens de dire qu'il ne peut y avoir aucune instance de celle-ci. Le programme alloue de la mémoire dans le heap pour cet objet et ne permettra aucun instanciation par l'utilisateur.</p>
<p>Les objets statiques sont créés à leur premier appel et seront détruits à la fin du programme (ou de son crash ...).</p>
<pre>public static class GameManager{
    public static int score;  
    public static float amountOfTime;
}</pre>
<p>Notez que si la classe est statique, les membres doivent l'être aussi.</p>
<p>Vous ne pourrez pas créer d'instance de GameManager.</p>
<pre>GameManager GM = new GameManager();</pre>
<p>renverra une erreur.</p>
<p>Vous pouvez accéder les membres de la classe statique simplement comme ceci:</p>
<pre>GameManager.score = 10;</pre>
<p>Cela peut se faire n'importe où et n'importe quand dans le programme. Une classe statique et ses membres ont une portée dans chaque fichier et un temps de vie de la durée du programme.</p>
<h3>Exemple d'utilisation d'une classe statique</h3>
<p>Lors du chargement d'une nouvelle scène, toutes les variables de la scène précédente sont détruites. Si nous voulons préserver une variable comme le score, par exemple, nous pouvons utiliser:</p>
<pre>DontDestroyOnLoad(score);</pre>
<p>Une grande utilité pour la classe statique réside dans leur temps de vie. Comme elles ne meurent pas, si nous voulons que notre score survive à la nouvelle scène, nous pouvons simplement utiliser une classe statique. À la fin de notre niveau, nous passons la valeur à l'élément statique, à partir de notre nouvelle scène nous pouvons faire l'opération inverse.</p>
<pre>if(newLevel){
    GameManager.score = tempScore;
    Application.LoadLevel(nextLevel);
}</pre>
<p>Et dans le script du nouveau niveau:</p>
<pre>void Start(){
    scoreTemp = GameManager.score;
}</pre>
<p>Un petit truc pour cet usage, ne pas utiliser GameManager.score pendant le niveau mais plutot une variable "classique" et seulement en fin de niveau passer les informations vers la statique.</p>
<p>Pensez à un jeu avec 10 niveaux où vous obtenez au maximum 200pts par niveau.</p>
<p>Un joueur termine le jeu en une seule fois et obtient 2000pts.</p>
<p>Un autre joueur termine le jeu en plusieurs coups et obtient 5000pts.</p>
<p>Le second joueur n'est pas aussi bon mais obtient plus de points parce qu'il a essayé chaque niveau plusieurs fois et accumuler des points. Si nous attendons le chargement du niveau suivant pour passer les points à la variable statique, les nouvelles tentatives annulent les points accumulés durant le niveau.</p>
<p>A la sortie du jeu, les données de la classe statique peuvent être envoyé à une sauvegarde, <a title="Saving Data #1 – Remember Me?" href="http://unitygems.com/saving-data-1-remember-me/">voyez plutot ici</a>.</p>
<div class="alert blue">Les classes statiques et les variables statiques sont allouées lors de la première rencontre durant l'exécution du programme. Une classe statique n'est <em>jamais</em> créée, jusqu'à ce que vous accédiez un membre ou une fonction. </div>
<h2><a name="staticvariables"></a></h2>
<h2>Variables Statiques</h2>
<p>De nombreux débutants font cette erreur:</p>
<pre>public static int health;
void Start(){
    health=100;
}</pre>
<p>Dans un autre script, vous pourriez trouver:</p>
<pre>void OnCollisionEnter(Collision other){
    if (other.gameObject.tag == “Enemy”){
        EnemyScript.health-=10;
        if(EnemyScript.health &lt;=0)Destroy(other);
    }
}</pre>
<p>Ils essayent le jeu avec un ennemi et réussissent à le tuer. Mais ils ajoutent plus d'ennemis et se demande pourquoi tout le monde meurt subitement.</p>
<p>La raison en est simple, vous avez plusieurs instances de la classe ennemie (qui n'est pas statique), mais vous n'avez qu'une seule variable <em>health</em> pour toutes les instances. Tuer un, c'est tous les tuer!</p>
<p>En fait, une variable statique déclarée dans une classe n'appartient pas aux objets, mais à la classe elle-même. C'est pourquoi nous y accédons en utilisant le nom de la classe et pas le nom de l'instance.</p>
<p>Cela n'a pas fonctionné pour la santé de l' ennemi parce que chaque ennemi doit avoir sa propre variable <em>health</em>.</p>
<p>Une variable statique de la même façon que la classe statique est instanciée lorsque la classe qui la définit est accédée pour le première fois. Cela signifie que même si il n'y avait aucune instance de la classe dans le jeu, la variable existerait si vous avez essayé d'y accéder.</p>
<p>Considérons un compteur d'ennemi, nous voulons garder la trace de la quantité d'ennemis que nous avons dans le jeu.</p>
<pre>static var counter;

public void CreateEnemy(){
    GameObject obj=Instantiate(enemyPrefab, new Vector3(0,0,0).Quaternion.identity);

    if(obj)counter++;
}

public void DestroyEnemy(){
    Destroy(gameObject);
    counter--;
}</pre>
<p>Ce script est attaché à chaque ennemi. Ils partagent tous la même variable compteur, même si ils ont tous un script différent.</p>
<p>Grâce à cette fonction dans notre jeu nous pouvons garder une trace de notre compteur d'ennemis. Notez l'utilisation d'une variable de référence, dans le cas où  Instantiate ne réussirait pas à créer l'objet, Instantiate retournerait une référence null. Si nous augmentons notre compteur sans vérifier, si pour quelque raison une instanciation échoue, nous avons un compteur qui tourne mal. Maintenant, si nous utilisons ce compteur à la fin de notre niveau, nous pouvons lancer le nouveau niveau comme tel:</p>
<pre>if(counter&lt;=0)Application.LoadLevel(nextLevel);</pre>
<p>Sans la vérification, si nous avions un échec, après avoir tué tous les ennemis, nous aurions un compteur de 1, notre jeu a un bug.</p>
<p>Qu'en est-il de notre joueur, puis-je utiliser une variable health statique? Oui, vous pouvez utiliser une variable statique pour la santé du joueur puisqu'il n'y a qu'un seul joueur. De plus, l'accès à une variable statique est plus rapide que l'accès à une variable non-statique.</p>
<p>Lorsque vous appelez le membre d'une instance, le compilateur a besoin d'appeler une petite fonction qui vérifie l'existence de l'objet. C'est logique puisque vous ne devriez pas être en mesure de modifier une donnée qui n'existe pas. Une variable statique existera en toute circonstance. Du coup, la vérification n'est pas utile. Le gain est faible cependant.</p>
<h2><a name="staticfuncs"></a></h2>
<h2>Fonctions Statiques</h2>
<p>Une fonction statique peut être implémentée dans une classe non statique, dans ce cas, seuls les membres statiques de cette classe peuvent être consultés à l'intérieur de la fonction. Ce qui est logique puisque la fonction statique est appelée par la classe et non par une instance, il serait difficile d'essayer d'accéder à des membres qui ne sont pas sûrs d'être en vigueur.</p>
<p>D'autre part, il est possible de passer des paramètres et vous avez probablement utilisé ce genre de fonction.</p>
<pre>Vector3.Distance(vec1.vec2);
vec1.Normalize();

Application.LoadLevel (1);

if (GUI.Button(Rect(10,10,50,50),btnTexture)){}</pre>
<p>La liste pourrait s'allonger encore et encore. Notez que le deuxième exemple n'est pas une méthode statique. Elle est appelée par l'instance de vec1 de type Vector3. Les autres exemples montrent que la classe est utilisée pour appeler la fonction statique.</p>
<p>Une fonction statique tend à être plus rapide que les non-statiques pour les mêmes raisons expliquées plus tot avec les variables statiques.</p>
<div class="alert blue"> Un autre avantage des classes statiques est que leur existence est permanente et connue par le compilateur, par conséquent, elles peuvent être utilisées, en C #, afin de définir les méthodes d'extension - ce sont des méthodes qui semblent être des fonctions supplémentaires ajoutées à tout un autre type de variable. Les classes étendues de cette façon ne sont pas réellement ouvertes (leurs variables privées et protégées ne sont pas disponibles pour les méthodes d'extension), mais cela peut être une belle façon de donner de nouvelles fonctions à des objets existants qui conduisent souvent à une plus grande lisibilité des codes et une API plus simples pour les développeurs. Par exemple, vous pouvez  ajouter une nouvelle fonction pour la  Transform</p>
<p>transform.MyWeirdNewFunction(x);</p>
<p></div>
<p>Exemple de fonction d'extension:</p>
<p>Nous voulons créer une fonction pour les tableaux qui prolongeront celles qui existent déjà (OrderBy, Sort, ...), nous pouvons déclarer une fonction statique qui permettra d'étendre la liste.</p>
<pre>using UnityEngine;
using System.Collections;

public static class ExtensionTest {

	public static int BiggestOfAll(this int[] integer){
		int length = integer.Length;
		int biggest = integer[0];
		for(int i = 1;i&lt;length;i++){
			if(integer[i]&gt;biggest)biggest = integer[i];
		}
		return biggest;
	}
}</pre>
<p>Nous déclarons une fonction statique, voyez comment le paramètre passé est l'instance qui appelle la fonction. En modifiant le type du paramètre, nous pouvons travailler avec d'autres types d'objets.</p>
<p>Déclarons et remplissons un tableau:</p>
<pre>using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {

	int[] array = {1,25,12,120,12,6};

	void Start () {
		print(array.BiggestOfAll());
        }
}</pre>
<p>Alors que vous tapez le point après le nom de votre tableau, vous verrez votre nouvelle fonction apparaître dans la liste.</p>
<p>Si vous décidez de créer une fonction plus générique qui accepte n'importe quel tableau quel que soit son type, vous mettriez en place une méthode d'extension statique générique.</p>
<pre>using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public static class ExtensionTest {

	public static T TypelessBiggestOfAll&lt;T&gt;(this T[] t){
		int length = t.Length;
		var biggest = t[0];
		for(int i = 1;i&lt;length;i++){
			biggest =((Comparer&lt;T&gt;.Default.Compare(t[i], biggest)&gt;0)?t[i]:biggest);
		}
		return biggest;
	}
}</pre>
<p>Notez l'ajout de l'aide <em>System.Collections.Generic;</em>. Comme le compilateur ne sais pas quel est le type de T, on ne peut pas se contenter de comparer les valeurs avec &lt; ou &gt;. Mais nous pouvons utiliser<em> Compare &lt;T&gt;</em>. Dans l'exemple, l'opérateur ternaire est utilisé. Il tend à rendre le code un peu déroutant au début, mais  aussi à sauver quelques lignes.</p>
<div class="alert green"> L'opérateur ternaire :      <em> a ? b : c;</em></p>
<p>Si a retourne vrai, b est retourné, si a retourne faux, c est envoyé hors de la commande.</p>
<p>L'avantage par rapport à un if normal réside dans la valeur retournée par la comparaison.        <em>result = a ? b : c;</em>           result recevra la valeur b ou c en fonction de a.</div>
<p>Il est maintenant possible de déclarer différents types de tableaux et utiliser la même fonction.</p>
<pre>using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {

	int[] arrayInt = {1, 25, 12, 120, 12, 6};
	float[] arrayFl = {0.5f, 52.456f, 654.25f, 41.2f};
	double[]arrayDb = {0.1254, -15487.258, 654, 8795.25, -2};

	void Start () {
		print(arrayInt.TypelessBiggestOfAll());
		print (arrayFl.TypelessBiggestOfAll());	
		print (arrayDb.TypelessBiggestOfAll());
       }
}</pre>
<p>Cela imprime  <em>120, 654.25, 8795.25</em> .</p>
<p>De nombreux utilisateurs de Unity posent des questions sur la façon de contraindre un objet à l'intérieur d'une zone. Par exemple si vous voulez garder un objet à l'intérieur de l'écran, vous pouvez restraindre la transform de cet objet à l'aide de cette fonction:</p>
<pre>using UnityEngine;
using System.Collections;

public static class GameManager{

	public static void ClampTransform(this Transform tr,Vector3 move, Vector3 min, Vector3 max){
		Vector3 pos = tr.position + move;
		if(pos.x &lt; min.x ) pos.x = min.x;
		else if(pos.x &gt; max.x) pos.x = max.x;

		if(pos.y  &lt; min.y ) pos.y = min.y;
		else if(pos.y&gt; max.y) pos.y = max.y;

		if(pos.z &lt; min.z) pos.z = min.z;
		else if(pos.z &gt; max.z) pos.z = max.z;

		tr.position = pos;
	}
}</pre>
<p>Et voici comment l'utiliser sur n'importe quel objet:</p>
<pre>Vector3 minVector = new Vector3(-10,0,-10);
Vector3 maxVector = new Vector3(10,0,10);
transform.ClampTransform(move,minVector,maxVector);</pre>
<p>Dans cet exemple, l' objet est restreint dans un environnement 2D (y reste 0) dans un carré de 20*20  cenntré à (0,0,0).</p>
<h2><a name="heap"></a></h2>
<h2>Heap Fragmentation, Garbage Collection et Object Pooling</h2>
<p>Le heap est une grande zone de mémoire dans laquelle les données sont stockées de manière aléatoire. En fait, elle n'est pas si aléatoire, l'OS va se pencher sur la mémoire et rechercher la première zone assez grande pour accueillir les données requises. La taille et l'emplacement du heap varie en fonction de la plate-forme que vous avez sélectionné.</p>
<p>Par exemple, lorsque nous demandons un <em>integer</em>, le système d'exploitation recherche 4 octets consécutifs de mémoire libre. Le fait est que pendant que le programme s'exécute, les emplacements de mémoire sont utilisés et  libérés sans véritable logique et votre programme pourrait se retrouver avec une fragmentation du heap.</p>
<p><div class="one_half"><a href="http://unitygems.com/wp-content/uploads/2012/12/Diapositive5.png"><img title="Heap fragmentation" alt="Heap fragmentation" src="http://unitygems.com/wp-content/uploads/2012/12/Diapositive5-300x149.png" width="300" height="149" /></a></div><div class="one_half last">La photo montre un exemple de fragmentation du heap, de toute évidence celui-ci est radicale et met l'accent sur l'idée. Vous remarquerez peut-être que nous essayons d'allouer une data3 mais au state1 nous avions une datas3 qui a été détruite au state2.</div><div class="clear"></div></p>
<p>Notez qu'aucune donnée n'a été ajoutée, il ya à la fin la même quantité de données qu'au state1. Seuls les mouvements ont créé une fragmentation du heap.</p>
<div class="alert yellow">Unity utilise la mémoire managée par .NET. Dans un programme en C, la fragmentation du heap pourrait créer une situation où il serait impossible d'allouer un bloc de mémoire car aucun bloc contigu d'une taille appropriée n'a pu être trouvée, même s'il y avait effectivement assez de mémoire libre sur l'ensemble - .NET ne souffre pas de cette limitation. Si un bloc de mémoire ne peut pas être trouvé la gestion de la mémoire. NET et les GC peuvent être utilisés pour éliminer la fragmentation du heap en déplaçant les éléments. Il s'agit, bien sûr, d'une opération relativement longue qui peut entraîner des baisses de rendement dans un jeu qui exige une performance élevée et constante.</div>
<p>Une solution pour le programmeur peut être d'utiliser l'<em>object pooling</em>. Au lieu de détruire notre data3 en state1 nous la désactivons pour une utilisation ultérieure. Cela aurait évité notre fragmentation du heap.</p>
<p>Nous n'avons pas à détruire les données, nous les conservons inactives et en cas de besoin, nous les réveillons.</p>
<p>Il y a de nombreux avantages pour cette solution, tout d'abord nous évitons le cas vu plus haut d'appel du GC et de remaniement de la mémoire, d'autre part nous avons également éviter d'appeler<em> Instantiate</em> et <em>Destroy</em>, nous avons seulement besoin d'utiliser <em>gameObject.SetActive(true / false);</em></p>
<p>Enfin, puisque nous ne détruisons pas, nous n'appelons pas le garbage collector qui est une action coûteuse.</p>
<pre>ObjectScript.cs
using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {
	public GameObject prefab;
	GameObject[] objectArray = new GameObject[5];  
        public static int counter; 

         void Start(){
		for(int i = 0;i&lt;objectArray.Length;i++){
			objectArray[i] = (GameObject)Instantiate(prefab,new Vector3(0,0,0),Quaternion.identity);
			objectArray[i].SetActive(false);
		}
        }
        void Createobject(){
		if(counter &lt; objectArray.Length){    
                // iterate through array
			for(int i = 0;i&lt;objectArray.Length;i++){  
                                // Find an inactive object                                     
				if(!objectArray[i].active){    
                               // Increase the counter, activate the object, position it                                              
					counter++;					                            
					objectArray[i].SetActive(true);	           
					objectArray[i].transform.position = new Vector3(0,0,0);  
					return;
				}
			}return;
		}else return;
	}
}
void OnCollisionEnter(CollisionEnter){
    if(other.gameObject.tag=="Object"){
        other.gameobject.SetActive(false);       //Deactivate the object
        ObjectScript.counter--;                        //Decrease counter</pre>
<p>La scène n'a jamais  plus de 5 objets en même temps, quand l'un est désactivé, il peut être réactivé quand nous le voulons. Le GC n'est pas nécessaire.</p>
<p>Vous pouvez utiliser cette astuce pour vos ennemis, si vous avez une vague d'ennemis venant à vous, au lieu de détruire un ennemi tué, repositionnez-le à l'arrière, vous êtes sur le point de tuer le même gars plusieurs fois sans vous en apercevoir.</p>
<p>Idem pour vos munitions, au lieu de détruire chaque balle que vous ou les NPC tirez  (Non-Player-Character, les objets guidés par IA) , désactivez-les. Réactivez-les quand vous tirez à nouveau avec la position en face de votre arme et la vitesse adéquate.</p>
<p>Notez que<em> pooling</em> quand on parle de mémoire est un processus différent géré par le système d'exploitation qui consiste à réserver toujours la même quantité de mémoire quelle que soit la taille de l'objet. En conséquence, il n'y aura jamais de petits emplacements de mémoire discéminés en mémoire.</p>
<h3>Réutilisation des tableaux</h3>
<p>En plus de la réutilisation des objets, il est également utile d'envisager la création de zones tampons qui sont réutilisées par votre code entre les différentes demandes ou répétées dans le même appel.</p>
<pre>void Update()
{
      if(readyToFire &amp;&amp; Input.GetKeyDown(KeyCode.F))
      {
          var _cinqPlusProches = new Enemy[5];

          //Faire quelque chose pour remplir une liste d'ennemies

          TargetEnemies( _cinqPlusProches);
      }
}</pre>
<p>Dans cet exemple, nous ciblons les 5 ennemis les plus proches  et nous tirons une arme automatique dans leur direction. Le problème est que nous allouons de la mémoire chaque fois que nous appuyons sur le bouton de tir. Si, au contraire, nous avions fait un tableau avec une longue durée de vie pour les ennemis que nous pouvons utiliser n'importe où dans notre code, nous n'aurions pas  à allouer de la mémoire et donc d'éviter le ralentissement.</p>
<p>Voici un exemple simple:</p>
<pre>Enemy[] _cinqPlusProches = new Enemy[5];

void Update()
{
      if(readyToFire &amp;&amp; Input.GetKeyDown(KeyCode.F))
      {
          //Faire quelque chose pour remplir une liste d'ennemies

          TargetEnemies( _cinqPlusProches);
      }
}</pre>
<p>Mais peut-être que nous pourrions faire encore plus générale, si nous avons souvent besoin de tableaux d'ennemis:</p>
<pre>Enemy[] _enemies = new Enemy[100];

void Update()
{
      if(readyToFire &amp;&amp; Input.GetKeyDown(KeyCode.F))
      {
          //Faire quelque chose pour remplir une liste d'ennemies

          TargetEnemies(_enemies, 5);
      }
}</pre>
<p>En réécrivant notre code pour TargetEnemies, on peut effectivement utiliser un tampon à usage général pour les ennemis partout dans notre code et d'éviter des allocations inutiles.</p>
<div class="alert green">Le deuxième exemple ici est un cas assez extrême, et vous ne devriez faire cela que si vous avez vraiment d'énormes collections qui pourraient causer un problème de mémoire - en général, vous devriez toujours écrire des codes lisibles et compréhensibles plutot que de sauver quelques octets de mémoires.</div>
<h2>Conclusion</h2>
<p>Nous arrivons à la fin de notre article. Nous voila en mesure de mieux comprendre comment la mémoire de notre ordinateur fonctionne et plus particulièrement sous Unity et le .NET framework.</p>
<p>Nous avons aussi abordé comment et où utiliser des cas statiques en prenant en compte qu'ils ne fonctionnent pas pour tous les cas d'objets.</p>
<p>Voici deux vidéos qui démontrent des cas traités dans cet article <a title="Use of static variables" href="     http://youtu.be/nLO3uHGaTkw">Use of static variables</a> et <a title="Demonstration of Memory Management" href="http://youtu.be/XozFsbbFukE">Demonstration of Memory Management</a> (en anglais).</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/nLO3uHGaTkw?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/XozFsbbFukE?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/gestion-memoire/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Linq #1 &#8211; It&#8217;s Time To Think Linq</title>
		<link>http://unitygems.com/linq-1-time-linq/</link>
		<comments>http://unitygems.com/linq-1-time-linq/#comments</comments>
		<pubDate>Fri, 23 Nov 2012 23:58:07 +0000</pubDate>
		<dc:creator>whydoidoit</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Intermediate]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Arrays]]></category>
		<category><![CDATA[Collections]]></category>
		<category><![CDATA[Linq]]></category>
		<category><![CDATA[Lists]]></category>
		<category><![CDATA[Nearest Object]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1565</guid>
		<description><![CDATA[<p>Motivation You should read this article if: You&#8217;d like a way to find all of the transforms with GameObject.FindGameObjectsWithTag() rather than the game objects themselves You need to manipulate, sort and change the types of lists and arrays but always seem to write too much code You&#8217;ve heard of LINQ but don&#8217;t know how it &#8230;<br /><a class="excerpt" href="http://unitygems.com/linq-1-time-linq/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Motivation</h2>
<p>You should read this article if:</p>
<ul>
<li>You'd like a way to find all of the transforms with GameObject.FindGameObjectsWithTag() rather than the game objects themselves</li>
<li>You need to manipulate, sort and change the types of lists and arrays but always seem to write too much code</li>
<li>You've heard of LINQ but don't know how it works</li>
<li>You don't believe me when I say I can write a single line of code that returns all of the materials on the renderers on the five tagged objects nearest to a target! (or anything else seemingly as complex)</li>
</ul>
<div><span style="font-size: 14px; line-height: 21px;"><div class="alert green">While I'm setting puzzles and you are worrying about writing a single line of code to do all that - for light relief why don't you also consider this question? <em>Can you think of the English sentence which is grammatically correct and contains the word "and" five times in a row?</em>  The totally irrelevant answer is at the end (no peeking)</div></span></div>
<h2>Introduction</h2>
<p>LINQ stands for Language Integrated Native Query and in .NET it's a way of writing things that look like database queries but work on objects.  It's very powerful and, when you get your head around it, very easy to use.</p>
<div class="alert yellow">LINQ is can be slower than writing out all of the for next loops. It can be up to half as fast and so should be considered carefully in Update functions where it occurs every frame.  It's great for caching, it's great for processing.</div>
<p>In C# you can actually write things that look very like SQL statements:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">var transformsWithTag = from go in GameObject.FindGameObjectsWithTag("YourTag") 
     where Vector3.Distance(go.transform.position - transform.position) &lt; 100
     select go.transform;</pre>
<p class="brush: csharp; gutter: true; first-line: 1">But we'll be using the function based approach with is much more powerful and, I believe more readable.</p>
<h2 class="brush: csharp; gutter: true; first-line: 1">The Power Of Enumerations</h2>
<p>So Linq is a way of making an enumerator that enumerates an existing enumerable collection but changes it as it goes.  So you can use Linq on anything that is an array, a list, a dictionary - basically a collection of any kind.  Note that as a Linq function returns an enumeration - you can chain them together - and therein lies the power.</p>
<p>Linq lets you write a series of functions that manipulate the  collection. Supplying your own code in the form of anonymous functions.</p>
<p>Let's get into it.</p>
<h2>Enabling LINQ</h2>
<p>To use Linq you need to add an <em>import</em> or a <em>using</em> directive to your source code.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#
using System.Collections.Generic; //Always a good idea
using System.Linq;

//JavaScript
import System.Linq;</pre>
<p>That's it!</p>
<h2>A First Linq Statement</h2>
<p>So let's do something simple - lets make an array of all of the transforms associated with game objects returned by GameObject.FindGameObjectsWithTag.</p>
<ul>
<li>Find all the game objects</li>
<li>Select the transform from the game object</li>
<li>Turn the result into an array</li>
</ul>
<div><span style="font-size: 14px; line-height: 21px;">That looks like this:</span></div>
<div></div>
<div>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(go =&gt; go.transform)
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(function (go) go.transform)
    .ToArray();</pre>
</div>
<p>So notice how we use an anonymous function to do the selection work we want.   Select says take the current thing in the enumeration (at this point a game object), call it whatever (in our case <em>go</em>) and then return the result of some calculation (in our case get the transform) and then ToArray runs the whole job and puts the results into an array.</p>
<p>In C# we use a <em>Lambda </em>function: <em>go =&gt; go.transform</em>, and in JavaScript we use an anonymous function: <em>function(go) go.transform</em></p>
<p>We aren't limited to a single statement in that function either!  We can put { and } and type any amount of code we like... More on this later.</p>
<h2>Performing a Query</h2>
<p>Ok so the Q is Query - let's do something that asks a question.  Let's get all of the transforms for the objects within 10 world units of the current position.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(go =&gt; go.transform)
    .Where(t =&gt; Vector3.Distance(t.position - transform.position) &lt; 10
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(function (go) go.transform)
    .Where(function (t) Vector3.Distance(t.position - transform.position) &lt; 10)
    .ToArray();</pre>
<p>So we've put our <em>Where</em> function after the select - so the enumeration is already an enumeration of <em>Transforms - </em>our Where anonymous function must return <em>true</em> or <em>false</em> so we make a simple test of the distance from the transform in the enumeration to our current transform.</p>
<h2>Performing a Sort</h2>
<p>Ok, let's imagine that some of our objects will have a script attached called Danger and that this script contains a float variable with a value called <em>dangerLevel</em>.  Let's sort our list of transforms by this danger level (if it exits, otherwise let's say they really aren't dangerous at all).</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(go =&gt; go.transform)
    .Where(t =&gt; Vector3.Distance(t.position - transform.position) &lt; 10
    .OrderByDescending(t =&gt; {
       var danger = t.GetComponent&lt;Danger&gt;();
       return danger ? danger.dangerLevel : 0;
      })
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(function (go) go.transform)
    .Where(function (t) Vector3.Distance(t.position - transform.position) &lt; 10)
    .OrderByDescending(function (t) {
          var danger = t.GetComponent(Danger);
          return danger ? danger.dangerLevel : 0;
         })
    .ToArray();</pre>
<p>So we've added an OrderByDescending (sort them top to bottom).  We've also written a multi line function, because first we needed to get the component and then use one of its values.  You see how easy that was?  It's just like a normal function.</p>
<p>Right cool - but what about if we then also wanted them sorted by proximity - danger then proximity being the important factor?</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(go =&gt; go.transform)
    .Where(t =&gt; Vector3.Distance(t.position - transform.position) &lt; 10
    .OrderByDescending(t =&gt; {
       var danger = t.GetComponent&lt;Danger&gt;();
       return danger ? danger.dangerLevel : 0;
      })
    .ThenBy(t =&gt; Vector3.Distance(t.position, transform.position)
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .Select(function (go) go.transform)
    .Where(function (t) Vector3.Distance(t.position - transform.position) &lt; 10)
    .OrderByDescending(function (t) {
          var danger = t.GetComponent(Danger);
          return danger ? danger.dangerLevel : 0;
         })
    .ThenBy(function (t) Vector3.Distance(t.position, transform.position)
    .ToArray();</pre>
<p>You can chain as many ThenBy and ThenByDescending as you like (note we should have used <em>sqrMagnitude</em> for performance reasons as the order is the same, but for clarity, we'll keep it as Vector3.Distance).</p>
<h2>Drilling Down</h2>
<p>You can also use LINQ to drill into the contents of a collection which is the member of an item in the list.</p>
<p>In our previous example we were returning the <em>transform</em> of all of the items found by tag - what if for some reason we wanted all of their renderers, in them and all of their descendants in the hierarchy?  That's where <em>SelectMany</em> comes in:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .SelectMany(go =&gt; go.GetComponentsInChildren&lt;Renderer&gt;())
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .SelectMany(function (go) go.GetComponentsInChildren(Renderer))
    .ToArray();</pre>
<p>SelectMany makes the collection a concatenation of all of the collections returned by it, so after our SelectMany the array will contain all of the renderers on all of the items.</p>
<h2>Linq inside Linq</h2>
<p>Let's say that last example wasn't what we wanted - let's say we wanted the renderer on the object and only its immediate children - still simple, but we will use a Linq statement inside a Linq statement...</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .SelectMany(go =&gt; go.transform.Cast&lt;Transform&gt;()
       .Select(t=&gt;t.renderer)
       .Concat(new [] { go.renderer })
       .Where(r=&gt;r!=null)
     )
    .ToArray();

//Javascript

var transformArray = GameObject.FindGameObjectsWithTag("MyTag")
    .SelectMany(function (go) go.transform.Cast.&lt;Transform&gt;()
         .Select(function (t) t.renderer)
         .Concat([go.renderer])
         .Where(function (r) r != null)
     )
    .ToArray();</pre>
<p>So we get the <em>transform</em> and cast it to be a collection of Transforms (it's a weirdness in Unity that it isn't that by default, as it's capable of getting all of its children).  Then we select the <em>renderer</em> from each child and concatenate that enumeration with an array containing the renderer of the parent, then we only allow through the ones that aren't <em>null</em>.</p>
<p>Job done.</p>
<h2>Finding the Closest Object</h2>
<p>Ok so there are a couple of ways we could find the closest object - here's the inefficient one:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var closestGameObject = GameObject.FindGameObjectsWithTag("MyTag")
    .OrderBy(go =&gt; Vector3.Distance(go.transform.position, transform.position)
    .FirstOrDefault();

//Javascript

var closestGameObject = GameObject.FindGameObjectsWithTag("MyTag")
    .OrderBy(function (go) Vector3.Distance(go.transform.position, transform.position))
    .FirstOrDefault();</pre>
<p>So here we order the collections by the distance and we get the <em>FirstOrDefault</em> one.  <em>FirstOrDefault</em> will return <em>null</em> if there are no objects in the list - you can also use <em>First</em> but it will throw an exception if there aren't any items.</p>
<p>The problem with this is that we had to sort the list - that takes time, especially when we only want the closest object.</p>
<p>We can use the generic <em>Aggregate</em> function to mean we don't have to do that:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">var closestGameObject = GameObject.FindGameObjectsWithTag("MyTag")
   .Aggregate((current, next)=&gt; Vector3.Distance(current.transform.position, transform.position) &lt; Vector3.Distance(next.transform.position, transform.position) 
      ? current : next);

//Javascript

var closestGameObject = GameObject.FindGameObjectsWithTag("MyTag")
     .Aggregate(function(current, next) Vector3.Distance(current.transform.position, transform.position) &lt; Vector3.Distance(next.transform.position, transform.position) 
        ? current : next);</pre>
<p>So this only runs through the list once, each step it works out the closest of the two candidate items and returns that.  It only passes the list once.  In C# you can optimise this a bit using anonymous classes too (doesn't work anywhere near as well in JavaScript so I'll leave it out).</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//Optimal C#
var currentPos = transform.position;    //Cache it - it's expensive!
var closestGameObject = GameObject.FindGameObjectsWithTag("MyTag")
   .Select( go =&gt; new { go = go, position  = go.transform.position })
   .Aggregate((current, next)=&gt; 
      (current.position - currentPosition).sqrMagnitude &lt;
      (next.position - currentPosition).sqrMagnitude
      ? current : next).go;</pre>
<p>So in our first Select we just made up a new class with two members - <em>go</em> and <em>position</em> - that's what's in the enumeration now.  Then we use that cached position to work out which is closer (using the optimal sqrMagnitude method to avoid an expensive square root).  At the end we have the closest object, but it's now our anonymous class, so we convert it to a game object by taking the <em>go</em> variable.</p>
<h2>Lists and Dictionaries</h2>
<p>So we aren't limited to making arrays - we can make a list using .ToList() and we can make a Dictionary too!</p>
<p>Dictionaries clearly have a <em>key </em>so let's see how we make that...  Let's find all of the game objects in our scene with a tag and put them into a dictionary based on that tag:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var lookupByTag = GameObject.FindObjectsOfType(typeof(GameObject))
     .Cast&lt;GameObject&gt;()
     .Where(go=&gt;!string.IsNullOrEmpty(go.tag))
     .ToLookup(go =&gt; go.tag);

//JavaScript

var lookupByTag = GameObject.FindObjectsOfType(GameObject)
    .Cast.&lt;GameObject&gt;()
    .Where(function (go) go.tag != "")
    .ToLookup( function (go) go.tag );</pre>
<p>This creates a special sort of dictionary that we can access a list of game objects from with lookupByTag["SomeTag"]</p>
<p>We could create an ordinary dictionary perhaps of GameObject to distance (plug in a game object and it returns its distance from the target point).  This would be very fast if we continually needed to know that due to some calculation that ran on many game objects.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//C#

var objectToDistance = GameObject.FindObjectsOfType(typeof(GameObject))
     .Cast&lt;GameObject&gt;()
     .ToDictionary(go=&gt;go, go=&gt;Vector3.Distance(go.transform.position, transform.position));

//Get the distance of a GO later:

var distance = objectToDistance[someGameObject];</pre>
<p>Notice the first parameter in <em>ToDictionary</em> is a key and the second is what we want in the dictionary values.  So this is returning a Dictionary&lt;GameObject, float&gt;.</p>
<h2>Conclusion</h2>
<p>So hopefully this first introduction has shown you some handy tips for using Linq to get going with list manipulations.  We'll explore more next time, because more there is!</p>
<h2>Answers</h2>
<p><em>You don't believe me when I say I can write a single line of code that returns all of the materials on the renderers on the five tagged objects nearest to a target!</em></p>
<pre class="brush: csharp; gutter: true; first-line: 1">var materials = GameObject.FindGameObjectsWithTag("sometag").Select(r=&gt;r.renderer).Where(r=&gt;r!=null).OrderBy(r=&gt;(r.transform.position - transform.position).sqrMagnitude).Take(5).SelectMany(r=&gt;r.materials).ToList();

foreach(var m in materials) m.color = Color.red;</pre>
<p><em>Can you think of the English sentence which is grammatically correct and contains the word "and" five times in a row?</em></p>
<p>There is a man painting a pub sign for the "Pig and Whistle" pub.  The landlord walks outside, looks at the sign and says to the painter: "You need to leave more space between the Pig and 'and' and 'and' and Whistle."</p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/linq-1-time-linq/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Basics of AI-Character v2.0</title>
		<link>http://unitygems.com/basic-ai-character/</link>
		<comments>http://unitygems.com/basic-ai-character/#comments</comments>
		<pubDate>Thu, 22 Nov 2012 13:58:02 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[beginner]]></category>
		<category><![CDATA[Beginners]]></category>
		<category><![CDATA[Character Controller]]></category>
		<category><![CDATA[Class]]></category>
		<category><![CDATA[Finite State Machine]]></category>
		<category><![CDATA[FSM]]></category>
		<category><![CDATA[GetComponent]]></category>
		<category><![CDATA[Line of Sight]]></category>
		<category><![CDATA[Quaternions]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=659</guid>
		<description><![CDATA[<p>Starting with your character AI Motivation: You want to develop your first game, probably a zombie game or a Slender-like game (See below about this) and you are doing so. But hell on earth when you see that zombie getting through the trees and passing walls, they are zombies not ghosts. You go through your &#8230;<br /><a class="excerpt" href="http://unitygems.com/basic-ai-character/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h1><span style="font-size: 18px;">Starting with your character AI</span></h1>
<h2>Motivation:</h2>
<div class="alert green">I just updated a little the article (07th April 2013 ), at the moment the projects to download are not totally matching the article snippets.</p>
<p>Differences:</p>
<ul>
<li>There is a new PathScript Component to get the paths for our NPCs</li>
<li>The waypoint script is now using gizmos and is modified in adequation with the component above</li>
<li>NPC script has lost some lines due to the new components above, the dictionary is replaced by a list</li>
<li>delegates replaced booleans in if statement in delegate paragraph</li>
</ul>
<p>Due to the modifications, I may have left some mistakes, if so, please be kind enough to let me know.</p>
<p>Enjoy <img src='http://unitygems.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </div>
<p>You want to develop your first game, probably a zombie game or a Slender-like game (See below about this) and you are doing so. But hell on earth when you see that zombie getting through the trees and passing walls, they are zombies not ghosts. You go through your codes and the components of your zombie and everything seems fine, you even check the walls. Well, let me tell you something, everything is not fine or it would work  (Thank you Captain Obvious!!).</p>
<div class="alert green"><a title="Slender playlist" href="https://www.youtube.com/playlist?list=PLrlKq98BDhenhNh8G42dE0T-edvLvJ0ba">See here if you are after Slender style game</a></div>
<p>In this tutorial we will go through the basics of moving an NPC (Non-Player-Character) around, how to give him a little bit of reaction depending on its environment and how to implement a second FSM a little more developed than the one you may have seen in the <a title="Basic of AI – Space shooter" href="http://unitygems.com/basic-ai-space-shooter/">Space Shooter tutoria</a>l but also more accessible than the one you will see in the <a title="Finite State Machine Tutorial #1" href="http://unitygems.com/fsm1/">FSM tutorials</a>. Also you will have a little first peek at pathfinding algorithm.</p>
<ul>
<li><a href="#Start">Starting with our NPC</a></li>
<li><a href="#WP">Adding waypoints</a></li>
<li><a href="#Pattern">Adding patterns</a></li>
<li><a href="#Delegate">Introduction to delegate</a></li>
<li><a href="#Range">Come closer (checking range)</a></li>
<li><a href="#Sight">I can see you (Line of sight)</a></li>
</ul>
<h2><a name="Start"></a></h2>
<h2>Starting with our NPC</h2>
<div class="alert green">When dealing with a NPC character the best first move is to use the character controller (CC).  This will simply solve all of your problems of  NPC passing through walls.</div>
<p>You can learn the basics of CC with this video:</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/IxJ3objAfl4?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p>The CC is simply a complex component that helps in many ways to get collision detection without using a rigidbody. It is mainly composed of a capsule that wraps the player and detects and reports collision.</p>
<p>Using CC on your NPCs  and they will bump onto any colliders the world has to offer.There will be situations where CC could not be the best of solutions, for instance if you are trying to recreate a Mario Galaxy environment where gravity is constantly switched, that won't do. If you played a game like Prey (2006), the player was able to walk on the wall, CC won't do either. One major issue with CC is the fact that it does not react to physics, so you would have to do that by script. But in many cases, you are good to go with it.</p>
<p>You attach it to your NPC and first thing you do in your script is fetch the CC so that you can manipulate it. For  a tutorial on how and why fetching component, see <a title="Script Interaction – GetComponent in C#" href="http://unitygems.com/script-interaction1/">here</a>. We also make sure our object contains a CC using an attribute placed before the class.</p>
<div class="alert red">Do use the RequireComponent attribute when you have two components interacting. If for instance, script A relies on the functions or variables of  script B, do add the attribute on  script A</p>
<pre class="brush: csharp; gutter: true; first-line: 1">[RequireComponent (typeof (ScriptB))]</pre>
<p>Same if for instance, you have a script for Physics, you are likely to need the Rigidbody component.</div>
<p>Here is what you do:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

// This below is an attribute that ensures a CC is attached to the object and cannot be removed
// Try and remove the CC component from the object to see the result.
[RequireComponent (typeof (CharacterController))] 
public class AIScript : MonoBehaviour {
   CharacterController _controller;
   Transform _transform;

   void Start(){
      _controller = GetComponent&lt;CharacterController&gt;();
      _transform = GetComponent&lt;Transform&gt;();
   }
}</pre>
<p>Using our _controller variable, we are in control of the Character Controller (what an awkward sentence that is...). The second line is just a cache of the Transform component for optimization.We shall get our NPC to move.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">float speed = 5f;
float gravity = 20f;
Vector3 moveDirection;

void Update(){
    moveDirection = _transform.forward;
	moveDirection *= speed;
	moveDirection.y -= gravity;
	_controller.Move(moveDirection * Time.deltaTime);
}</pre>
<p>Hold on a second before rushing into scripting as this is not about to do much good yet. The script above is pretty much taken from the Unity CC docs, we have a moveDirection vector3 that gets the forward of the object, each member is multiplied by the speed and the y member receives the gravity so that our NPC is constantly affected by "real " gravity as it is in the update. Finally, we call the Move method from the CC class to which we pass our moveDirection vector. Time.delatTime is just there to make our game frame independent.</p>
<p>For the time being our NPC only go straight forward, if you intend to develop a not-so-fun game that will be just fine. For any other purpose,  we need to get our NPC turning around. <a title="Quaternions &amp; Rotations – C#" href="http://unitygems.com/quaternions-rotations-part-1-c/">Here</a> is the tutorial that will get you through this all so I will simply apply what is there in here:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Vector3 target;
float maxRotSpeed = 200.0f;
float minTime = 0.1f;
float velocity;

void Update () {	
//Previous moving codes	
	var newRotation = Quaternion.LookRotation(target - _transform.position).eulerAngles;
	var angles = _transform.rotation.eulerAngles;
	_transform.rotation = Quaternion.Euler(angles.x, 
		Mathf.SmoothDampAngle(angles.y, newRotation.y, ref velocity, minTime, maxRotSpeed),
	        angles.z);
}</pre>
<p>The idea is that we create a quaternion vector from the NPC to the target that we convert to euler angles, so from quaternion vector to Vector3 vector. Then we convert our current rotation to eulerAngles.  Finally, we smoothly move from our current rotation to the target rotation with SmoothDampAngle. Our x and z rotations are not changing.</p>
<p>You will still have to be patient, we are missing some details  to get our guy going. But what we have here is the basics of moving our CC. We are only missing a target. Keep in mind our guy is stupid. He does what he is told to and we are about to tell him to go there (and he will, trust me). Next part we assign a value to target so that our NPC will use it as....target.</p>
<p>To make the reading easier, I will turn the two parts (moving and rotating) we have into one Move() function.</p>
<p>Let's get our NPC to move around with a simple script. :</p>
<pre class="brush: csharp; gutter: true; first-line: 1">bool change; 
float range;
void Start () {
   range = 2f;
   target = GetTarget();
   InvokeRepeating ("NewTarget",0.01f,2.0f);
}
void Update () {		
   if(change)
       target = GetTarget ();

   if(Vector3.Distance(_transform.position,target)&gt;range){
      Move();
      animation.CrossFade("walk");
   }else animation.CrossFade ("idle");
}
Vector3 GetTarget(){
   return new Vector3(Random.Range (0,300),0,Random.Range (0,300));
}
void NewTarget(){
   int choice = Random.Range (0,3);
   switch(choice){
      case 0: 
         change = true;
         break;
      case 1: 
         change = false;
         break;
      case 2:
         target = _transform.position;
         break;
   }	
}</pre>
<p>Our AI does not think, so we need to tell it where to move. For this purpose, the function GetTarget() is used. It simply returns a Vector3 that we assign to the target variable.</p>
<p>Notice the NewTarget function called with InvokeRepeating (for explanation on Invoke functions <a title="Common Unity Gotchas" href="http://unitygems.com/mistakes1/">see here</a>) that will simply decide if we assign a new target or not. It uses a random number between 0 and 2 and uses that number in a switch to decide the behavior.</p>
<ul>
<li>0, we get a new target</li>
<li>1, we continue with the previous target</li>
<li>2, we stop and wait</li>
</ul>
<p>The movement of the NPC is based on the distance to the target. If we are not close enough (&gt;range), the NPC moves towards the target, if we are close enough, it waits. That is why on case 2, the transform.position is provided to the target, so that the NPC is close enough and wait. In the case of movement, the walking animation is played, in case of resting, the idle animation is played.</p>
<p>For this first AI our FSM looks like the picture next:</p>
<p><a href="http://unitygems.com/wp-content/uploads/2013/01/Présentation1.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-662" title="First FSM" alt="First FSM" src="http://unitygems.com/wp-content/uploads/2013/01/Présentation1.png" width="958" height="519" /></a></p>
<p>The picture tells us that the decision center (NewTarget function) defines the next action. Notice that the decision does not choose to walk, it only decides to provide a target. The Update will create the displacement using the target.</p>
<p>This kind of AI is not likely to be good enough for a “Human” NPC but is fairly good enough for any kind of animals. For instance, you could use this kind of script for a boar wandering in the forest. There is still one issue, on our terrain there is no particular environment threats. But what if there were a cliff or a lake, you do not want the NPC to get there, it would not look natural. To prevent this kind of happenings, we simply provide the NPC with a set of predefined targets.</p>
<p>Also, another issue that will come up pretty quick is the relief of your terrain. As you are assigning random values and in our case we kept y at 0, it means this algorithm is fine for flat terrain only. Simply think your relief goes at y = 10, which is just a tiny little hill, still you are too far from the point at 0, your character would never get below the range to switch target. Otherwise, you would have to increase the range but then again, that is not really good.</p>
<div class="alert green">Get the project from <a title="AICharacter1" href="http://unitygems.com/Downloads/AICharacter/AICharacter1.zip">here</a>.</div>
<h2><a name="WP"></a></h2>
<h2>Adding waypoints</h2>
<p>So the idea here is simple, we won't let our NPC go around freely. We provide a set of point that will be where the NPC goes and nowhere else. Consider a warden that walks around a building and nothing else. You place four point around the building and you let him know that his only duty is to walk from point A to B, then B to C, C to D and finally back to A and there you go again, A to B and so on. Not the best AI but we do not want smart AI yet.</p>
<p>On top of that since you are manually placing the waypoints if the relief would go up and down, you would have to place it at the level of the ground. For  the rest let the CC do its job.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2013/01/Path.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-1490" style="border: 1px solid black;" title="Path" alt="Path" src="http://unitygems.com/wp-content/uploads/2013/01/Path.png" width="862" height="392" /></a></p>
<p>On the picture above the waypoints A and B are at different y positions. The green line represent the actual path your CC will take. It just makes sense that since we are applying constant gravity , the CC just goes towards the target but follows the relief curve.</p>
<p>Let's first talk a little about the design. We could easily create an array of Transform to store our waypoints and manually assign waypoint A to 0, waypoint B to 1 and so on. Well, that doe snot sound really efficient to me. Particularly if we have hundreds of waypoints. We need to figure out a way that allows us to make our script universal, that is, for any amount of waypoint and also any waypoint grid.</p>
<p>First thing we do is define our waypoint. We need them to get an index in order to know which is first and second and so on. Well, let's add:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class WaypointScript : MonoBehaviour {

   bool used;
   public bool GetUsed(){
      return used;
   }
   public void SetUsed(bool b){
      used = b;
   }
   public float radius = 0.5f;
   void OnDrawGizmosSelected() {
        Gizmos.color = Color.red;
        Gizmos.DrawSphere(transform.position, radius);
    }
}</pre>
<p>Attach that to the waypoint prefab.When placing a waypoint on the map, if the waypoint is selected in the hierarchy that will show a little red ball. It is now easier to see where is our waypoint. I suggest you add an empty game object and add the waypoint as children. It will keep your hierarchy clean and selecting the parent object will show the whole path. Now give a tag to the waypoint and start duplicating our waypoint to create a path.The tag is the name of our path. So you can create a second different path simply giving a different tag.</p>
<p>Only little special point, make sure the next node is always the closest one, let make clarify this (if possible), the distance between two consecutive nodes should always be smaller than the distance between the node and any other. That is if you have nodes A, B, C, D and E (in order), make sure B is the closest to A, then C is the closest to B, D the closest to C and finally E does not really matter since it is the last one remaining but as it will close the path do not make it closer to A than B would be (I probably lost half of you already...). Also, make sure the waypoints are placed above ground (not too high though).</p>
<p>Now we need a component that will create the different paths and will share them with the NPCs that need them. Create a new script called "PathScript" and attach it to an empty game object that we call "PathObject".</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PathScript : MonoBehaviour {

   public GameObject[]start;
   Dictionary&lt;string,List&lt;Transform&gt;&gt;path = new Dictionary&lt;string, List&lt;Transform&gt;&gt;();

   void Awake () {
      string str = null;
      for(int i = 0;i&lt;start.Length;i++){
         int index=0;
         str = start[i].gameObject.tag;
         GameObject [] gos = GameObject.FindGameObjectsWithTag(str);

         List&lt;Transform&gt; waypoints = new List&lt;Transform&gt;();
         waypoints.Add (start[i].transform);
         start[i].gameObject.GetComponent&lt;WaypointScript&gt;().SetUsed(true);
         while(true){
            Transform closest = FindClosest(waypoints[index],gos);
            if(closest != null)
               waypoints.Add (closest);
            if(++index &gt;= gos.Length)break;
         }
         path.Add (str,waypoints);
     }	
   }

   Transform FindClosest(Transform start, GameObject[] obj){
      int layerMask = 1 &lt;&lt; 2;
      layerMask = ~layerMask;
      Transform closest = null;float distance = Mathf.Infinity;
      foreach(GameObject go in obj){
         WaypointScript sc = go.GetComponent&lt;WaypointScript&gt;();
         if(start!=go.transform &amp;&amp; !sc.GetUsed()){
            if(!Physics.Linecast (start.position,go.transform.position,layerMask)){
               float dist = (start.position - go.transform.position).magnitude;
               if(dist &lt; distance){
                  distance = dist;
                  closest = go.transform;
               }
            }
         }
      }
      if(closest != null){
         closest.gameObject.GetComponent&lt;WaypointScript&gt;().SetUsed (true);
      }
      return closest;
   }

   public List&lt;Transform&gt; GetPath(string str){
      return path[str];
   }
}</pre>
<p>This is a little bit of a first step into pathfinding. We have the Awake function that creates a public GameObject array. What you need to do is simply drag and drop the starting waypoint of your path into the slot and that is it for now actually, the rest is done for you.</p>
<p>The script gets the tag of the waypoint you gave, then find all waypoints with similar tag and place them in an array.  A list of Transform is created and the starting waypoint is added and remember the used boolean in our waypoint script, we set it to true so that we won't use that waypoint again. Then starts a loop that will take the latest node placed in the list and compare it with all other waypoints. The closest is return and placed in the list, then we start again until we have no more waypoint. The resulting list is placed in a Dictionary of string and List of Transform so that we have a way to retrieve our list with a name.</p>
<p>Pffff, next the FindClosest method: well no biggie here, simply we get our latest node from the list and we iterate through the array checking if the waypoint is not used already, if it is not hidden from the latest node (Linecast) and finally if it is the closest. We then have the GetPath method that uses the string parameter to retrieve the path from the dictionary. That simple!!!</p>
<p>Note that the FindClosest method is a simplified version of pathfinding method , greatly simplified I agree, but the idea is still there, comparing a node with other nodes and returning the closest one.</p>
<p>Now how do we provide our path to our NPCs?</p>
<p>In the code snippet below, I added a <em>public string strTag;</em>, this variable is showing in the inspector of teh NPC and allows you to provide the name of the path you want the NPC to follow. The name is actually the tag given. Remember that our path is made of waypoints and those waypoints have a common tag representing the path name. This is what you need to provide to the strTag of the NPC for it to find the path. Hopefully I made myself clear enough...</p>
<p><br clear="none" /><span class="collapseomatic " id="id179"  title="<strong>Waypoint code snippet</strong>"><strong>Waypoint code snippet</strong></span><div id="target-id179" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
//Added namespace
using System.Collections.Generic;

[RequireComponent(typeof(CharacterController))]
public class AIScript : MonoBehaviour
{
    //Cached variables
    CharacterController _controller;
    Transform _transform;

    //Movement variables
    float speed = 5f;
    float gravity = 100f;
    Vector3 moveDirection;
    float maxRotSpeed = 200.0f;
    float minTime = 0.1f;
    float velocity;
    //Added variables
    float range;
    List&lt;Transform&gt; waypoint;
    int index;
    public string strTag;

    void Start()
    {      
        _controller = GetComponent&lt;CharacterController&gt;();
        _transform = GetComponent&lt;Transform&gt;();

        index = 0;

        //Added codes
        if (string.IsNullOrEmpty(strTag))
            Debug.LogError("No waypoint tag given");
        range = 2.5f;
        waypoint = GameObject.Find("PathObject").GetComponent&lt;PathScript&gt;().GetPath(strTag);
    }

    void Update()
    {
        if ((_transform.position - waypoint[index].position).sqrMagnitude &gt; range)
        {
            Move(waypoint[index]);
            animation.CrossFade("walk");
        }
        else NextIndex();
    }

    void Move(Transform target)
    {
        // Movement
        moveDirection = _transform.forward;
        moveDirection *= speed;
        moveDirection.y -= gravity;
        _controller.Move(moveDirection * Time.deltaTime);
        //Rotation
        var newRotation = Quaternion.LookRotation(target.position - _transform.position).eulerAngles;
        var angles = _transform.rotation.eulerAngles;
        _transform.rotation = Quaternion.Euler(angles.x,
         Mathf.SmoothDampAngle(angles.y, newRotation.y, ref velocity, minTime, maxRotSpeed), angles.z);
    }

    void NextIndex()
    {
        if (++index == waypoint.Count) index = 0;
    }
}</pre>
<p></div></p>
<p>So what is new? Notice the required namespace at the top for using our List. Then we have a public string that needs to be given a value. Do that in the inspector.<em> </em></p>
<p><em>if (string.IsNullOrEmpty(strTag))Debug.LogError("No waypoint tag given"); </em>ensures a string is given. If none the game won't start.</p>
<p>We declare our  <em>List&lt;Transform&gt; waypoint ;  </em>note that it is only a reference but no memory is allocated. This way each NPC has a reference but only one path exists in memory instead of having duplicated paths for each NPC.</p>
<p>The Update has changed a little and we have a new function:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void Update()
{
    if ((_transform.position - waypoint[index].position).sqrMagnitude &gt; range)
    {
        Move(waypoint[index]);
        animation.CrossFade("walk");
    }
    else 
        NextIndex();
}
void NextIndex()
{
     if (++index == waypoint.Count) index = 0;
}</pre>
<p>So the update is not using <em>Vector3.Distance</em> anymore. We try to optimize our game so we gave up this function as it uses square root internally and square root is a little bad since it is a recursive function. Using squared magnitude we avoid the square root but we now need to keep in mind that all values will squared. So when we want to check if the distance is 2 we need to check for 4 (2*2). (Keep in mind that processors nowadays performs those actions real fast so this is tiny optimization but still it is )</p>
<p><em>NextIndex(); </em>simply increase the index until it is equal to the waypoint.Count. It is then set to 0 to avoid out of bound and close our path.</p>
<div class="alert green">Get the project <a title="AICharacter2" href="http://unitygems.com/Downloads/AICharacter/AICharacter2.zip">here</a>.</div>
<h2><a name="Pattern"></a></h2>
<h2>Adding patterns</h2>
<p>In the previous part we told our NPC to walk around and he now does. We could also tell him to do other actions in between. Instead of blindly go from A to B, then B to C (damn there he goes again...) and so on, we now tell him go from A to B but when you are there wait a while and do something (in our case he will do a victory animation), then continue. And maybe just wait a while when you reach another waypoint. Well, feel free to make him do whatever you want.</p>
<p>Actually, what the NPC will do will mainly depend on the animations you have under your sleeves. If you had a bench on the way, you could develop an animation with the NPC sitting down for a sec and continuing. You can even get him moonwalking if you fancy, again it has no limit but your imagination (and what you want your game to look like). Avoid the moonwalk tip if you plan on doing a zombie game or the next Call of Duty...</p>
<p>What we need to do is prepare some function we want to call in the appropriate moment. Let's see first our FSM.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2013/01/FSMWalk.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone  wp-image-1494" style="border: 1px solid black;" title="FSMWalk" alt="FSMWalk" src="http://unitygems.com/wp-content/uploads/2013/01/FSMWalk.png" width="729" height="484" /></a></p>
<div class="alert blue">The FSM above is based on a previous tutorial. The Rotate and Wait state is now a Victory state</div>
<p>As stated previously, nothing fancy, we are progressing slow. Our guy walks, reaches the waypoint and then depending on which waypoint he is on, we launch an action. Note that waypoints 2 and 3 will not do anything.</p>
<p>The action are a simple victory animation, you can use any animation you want instead, you can also add other states. The Wait state is just an IEnumerator function that waits 2 sec on an idle animation.</p>
<p>Now the code:</p>
<p><br clear="none" /><span class="collapseomatic " id="id5110"  title="<strong>Pattern code snippet</strong>"><strong>Pattern code snippet</strong></span><div id="target-id5110" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(CharacterController))]
public class AIScript : MonoBehaviour
{
    // Cached variables
    CharacterController _controller;
    Transform _transform;

    //Movement variables
    float speed = 5f;
    float gravity = 100f;
    Vector3 moveDirection;
    float maxRotSpeed = 200.0f;
    float minTime = 0.1f;
    float velocity;
    float range;

    //Waypoint variables
    List&lt;Transform&gt; waypoint;
    int index;
    public string strTag;

    //Added variables
    bool walking, waiting, victoring;
    bool isWaiting, isVictoring;

    void Start()
    {
        _controller = GetComponent&lt;CharacterController&gt;();
        _transform = GetComponent&lt;Transform&gt;();
        if (string.IsNullOrEmpty(strTag)) 
            Debug.LogError("No waypoint tag given");
        index = 0; 
        range = 4;

        waypoint = GameObject.Find("PathObject").GetComponent&lt;PathScript&gt;().GetPath(strTag);
        //Added codes
        walking = true; waiting = false; victoring = false;
        isWaiting = false; isVictoring = false;
        animation["victory"].wrapMode = WrapMode.Once;
    }

    void Update()
    {
        if (walking)
        {
            if (!isWaiting &amp;&amp; !isVictoring)
                Walk();
        }
        else if (victoring)
        {
            StartCoroutine(Victory());
            victoring = false;
        }
        else if (waiting)
        {
            StartCoroutine(Wait());
            waiting = false;
        }
    }

    void Walk()
    {
        if ((_transform.position - waypoint[index].position).sqrMagnitude &gt; range)
        {
            Move(waypoint[index]);
            animation.CrossFade("walk");
        }
        else
        {
            switch (index)
            {
                case 0:
                    walking = false; victoring = true;
                    isVictoring = true;
                    break;
                case 1:
                    walking = false; waiting = true;
                    isWaiting = true;
                    break;
                default:
                    NextIndex(); break;
            }
        }
    }
    void Move(Transform target)
    {
        //Movement
        moveDirection = _transform.forward;
        moveDirection *= speed;
        moveDirection.y -= gravity;
        _controller.Move(moveDirection * Time.deltaTime);
        // Rotation
        var newRotation = Quaternion.LookRotation(target.position - _transform.position).eulerAngles;
        var angles = _transform.rotation.eulerAngles;
        _transform.rotation = Quaternion.Euler(angles.x,
         Mathf.SmoothDampAngle(angles.y, newRotation.y, ref velocity, minTime, maxRotSpeed), angles.z);
    }

    void NextIndex()
    {
        if (++index == waypoint.Count) index = 0;
    }

    //Added functions
    IEnumerator Victory()
    {
        if (!animation.IsPlaying("victory")) animation.CrossFade("victory");
        yield return new WaitForSeconds(animation["victory"].length);
        walking = true; isVictoring = false;
        NextIndex();
    }

    IEnumerator Wait()
    {
        animation.CrossFade("idle");
        yield return new WaitForSeconds(2.0f);
        walking = true; isWaiting = false;
        NextIndex();
    }
}</pre>
<p></div></p>
<p>So, we have some boolean variables to check what the status of our guy is. He can be walking, waiting or victoring. The update checks the booleans and call the appropriate function. The Walk function checks which waypoint is being reached, and defines the status of each boolean according to the waypoint. The rest is simple coding you should understand.</p>
<p>You often see in games this kind of pattern, for instance the guard at the entrance will walk back and forth in front of the door but after a while will stop and look around or might do a special action which often is the trigger condition for the player to perform a special action, like shooting right in the face.</p>
<div class="alert green">Get the project<a title="AICharacter3" href="http://unitygems.com/Downloads/AICharacter/AICharacter3.zip"> here</a>.</div>
<h2><a name="Delegate"></a></h2>
<h2>Introduction to delegate</h2>
<p>Before we dive into our <a title="Finite State Machines #2 – Delegates, Reflection &amp; Closures" href="http://unitygems.com/fsm2/">FSM tutorials</a> and get scared by all those delegates and closures and decide to retire in a remote mountain lodge with no computers, I will introduce a simple example about delegates.</p>
<div class="alert green">If you have a C or C++ background, you could compare them to the function pointer or the functor from C++. Remember the:</p>
<pre class="brush: c; gutter: true; first-line: 1">void Afunction(){
    //stuff here
}

void (*fct)(int);
fct = &amp;Afunction;</pre>
<p>delegates are somehow similar but easier and typesafe.</div>
<p>We are now about to modify our code so that we can use delegate. First off we need to declare the delegate, then create an instance of the delegate and finally assign a function to it. Then at last we can use our delegate.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">delegate void DelFunc();
DelFunc delegate;
delegate = Afunction;

static void Afunction(){

}
void Update(){
   delegate();
}</pre>
<p>This is the basic declaration and that is probably all you are about to see from most internet tutorials, few or none takes the risk to show more about it, we will. You know that a static function cannot access non-static members. So how do we use that on our NPC in a way that if we have many on scene, it still works.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">float variable;
delegate void DelFunc();
DelFunc delegate;
delegate = this.Afunction; //Did you see the this pointer?

void Afunction(){
    variable = variable +10;
}</pre>
<p>Now the whole point of a delegate is to be used but also to be flexible. Our goal is to have one function to call another one from a bag of functions. See below the example:</p>
<p><br clear="none" /><span class="collapseomatic " id="id6484"  title="<strong>Delegate code snippet</strong>"><strong>Delegate code snippet</strong></span><div id="target-id6484" class="collapseomatic_content "></p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System;

public class Delegate :MonoBehaviour {
	[SerializeField]
	float pos;
	float val = 10;
	//Delegate declaration
        public delegate void DelegateFunction();
	public delegate IEnumerator DelegateEnum();
	// Delegate object
        DelegateFunction _delegate;
	DelegateEnum _delegateEnum;
	bool del;
	void Start(){
		_delegate = this.Increase;   
		_delegateEnum = null;    
		pos = 0;
		del = true;
	}
	void Update () {
        // We press Space and _delegate is called since del is true 
        // (that is why we assign a function in Start to avoid null reference)
		if(Input.GetKeyDown(KeyCode.Space)){
			if(del)_delegate(); 
			// _delegateEnum is called in a StartCoroutine
                        else StartCoroutine(_delegateEnum());  
		}
		if(Input.GetKeyDown(KeyCode.I)){
			del =true;                // we ensure del is true
			_delegate =this.Increase; // we assign a function to _delegate
		}
		if(Input.GetKeyDown(KeyCode.D)){
			del =true;
			_delegate = this.Decrease;
		}
		if(Input.GetKeyDown(KeyCode.O)){
			del =true;
			_delegate = this.Zero;
		}
		if(Input.GetKeyDown(KeyCode.W)){
			del =false;        // we ensure del is false
			_delegateEnum = this.Wait; // we assign a function to _delegateEnum
		}
		if(Input.GetKeyDown(KeyCode.A)){
			del =false;
			_delegateEnum = this.WaitAndAdd;
		}

	}
	public void Increase(){
		pos += val*Time.deltaTime; 
		print (pos);
	}
	public void Decrease(){
		 pos -= val*Time.deltaTime;
		print (pos);
	}	
	public void Zero(){
		pos = 0;
		print (pos);
	}
	public IEnumerator Wait(){
		yield return new WaitForSeconds(1.0f);
		print("Enum"+pos);
	}
	public IEnumerator WaitAndAdd(){
		print("Adding soon"+pos);
		yield return new WaitForSeconds(1.0f);
		pos+=2;
		print("Added "+pos);
	}
}</pre>
<p></div></p>
<p>Attach that script to any object of a scene and look at the console. You can also look at the Editor since pos has the [SerializeField] attribute, it makes a private variable show in the Inspector.</p>
<p>Depending on the button pressed, a function is assign to a delegate. Since the signature of a function needs to match the signature of a delegate (vice-versa), we need two delegates. We just use a boolean to decide which one is called in the update.</p>
<p>It is possible to use parameters as well, you would create a delegate with the appropriate signature for return value and parameter and pass the functions with the same signature but  I will not go into Action and Func, as it is well done in the FSM tutorials.</p>
<p>Now let's modify our AIScript with delegates. Minor modifications are needed:</p>
<p><br clear="none" /><span class="collapseomatic " id="id2716"  title="<strong>AIScript Delegate code snippet</strong>"><strong>AIScript Delegate code snippet</strong></span><div id="target-id2716" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(CharacterController))]
public class AIScript : MonoBehaviour
{
    // Cached variables
    CharacterController _controller;
    Transform _transform;

    //Movement variables
    float speed = 5f;
    float gravity = 100f;
    Vector3 moveDirection;
    float maxRotSpeed = 200.0f;
    float minTime = 0.1f;
    float velocity;
    float range;

    //Waypoint variables
    public string strTag;
    List&lt;Transform&gt; waypoint;
    int index;

    //Added variables
    delegate void DelFunc();
    delegate IEnumerator DelEnum();
    DelFunc delFunc;
    DelEnum delEnum;

    void Start()
    {
		if(string.IsNullOrEmpty(strTag))Debug.LogError("No waypoint tag given");
        index = 0;
        _controller = GetComponent&lt;CharacterController&gt;();
        _transform = GetComponent&lt;Transform&gt;();
        range = 4;
        waypoint = GameObject.Find("PathObject").GetComponent&lt;PathScript&gt;().GetPath(strTag);
        animation["victory"].wrapMode = WrapMode.Once;

        //Added codes
        delFunc = this.Walk;
        delEnum = null;
    }

    //Modified update
    void Update()
    {
        if (delFunc != null){
            delFunc();
        }else if (delEnum != null){
            StartCoroutine(delEnum());
            delEnum = null;
        }
    }

    //Modified Walk
    void Walk()
    {
        if ((_transform.position - waypoint[index].position).sqrMagnitude &gt; range)
        {
            Move(waypoint[index]);
            animation.CrossFade("walk");
        }
        else
        {
            switch (index)
            {
                case 0:
                    delFunc = null;
                    delEnum = this.Victory;
                    break;
                case 1:
                    delFunc = null;
                    delEnum = this.Wait;
                    break;
                default:
                    NextIndex(); break;
            }
        }
    }

    void Move(Transform target)
    {
        // Movement
        moveDirection = _transform.forward;
        moveDirection *= speed;
        moveDirection.y -= gravity;
        _controller.Move(moveDirection * Time.deltaTime);
        // Rotation
        var newRotation = Quaternion.LookRotation(target.position - _transform.position).eulerAngles;
        var angles = _transform.rotation.eulerAngles;
        _transform.rotation = Quaternion.Euler(angles.x,
         Mathf.SmoothDampAngle(angles.y, newRotation.y, ref velocity, minTime, maxRotSpeed), angles.z);
    }

    void NextIndex()
    {
        if (++index == waypoint.Count) index = 0;
    }

    //Modified animation functions
    IEnumerator Victory()
    {
        if (!animation.IsPlaying("victory")) animation.CrossFade("victory");
        yield return new WaitForSeconds(animation["victory"].length);
        NextIndex();
        delFunc= this.Walk;
    }
    IEnumerator Wait()
    {
        animation.CrossFade("idle");
        yield return new WaitForSeconds(2.0f);
        NextIndex();
        delFunc = this.Walk; 
    }
}</pre>
<p></div></p>
<p>Our Update is now tinier, and we lost most of our boolean checks.  One good point of a delegate is that you can set it to null, meaning it simply points nowhere. What is so good about it is that we can check for nullity and use our delegate as boolean.</p>
<pre>    if (delFunc != null){
        delFunc();
    }else if (delEnum != null){
       StartCoroutine(delEnum());
       delEnum = null;
    }</pre>
<p>The line <em>delEnum = null;</em>  is there to avoid multiple calls of the coroutine. What you need to understand is the flow of our state-machine.</p>
<pre>switch (index){
   case 0:
      delFunc = null;
      delEnum = this.Victory;
      break;
   case 1:
      delFunc = null;
      delEnum = this.Wait;
      break;
   default:
      NextIndex(); 
      break;
}</pre>
<p>The switch simply sets the <em>delFunc</em> to null and <em>delEnum</em> to the appropriate action. Now, our coroutines are running, nothing is actually happening in the Update anymore. At the end of the coroutine <em>delFunc</em> is set back to <em>this.Walk</em>.</p>
<p>Our guy is fine walking around the place but he still does not do anything with us. Next, we see how to make him interact with the player.</p>
<div class="alert green">Get the project <a title="AICharacter4" href="http://unitygems.com/Downloads/AICharacter/AICharacter4.zip">here</a>.</div>
<p>Notice that the project includes two NPCs that do independent thing. With some more code, we could also define a different order of actions but I leave this one to you. As a hint, you could create an array of string to store animation names. Each NPC could then have a different order of actions. You would then pass the content of the array as parameter of the animation calls. [/alert]</p>
<h2><a name="Range"></a></h2>
<h2>Come closer (checking range)</h2>
<p>Good, our NPC has a pattern of movement we stored and he looks more realistic than a simple movement from A to B, then B to C (now come on!!!). Still, if you add a First-Person-Controller and move around, you may have noticed that you can get close to him, even real close, he simply ignores you. It makes sense since we have not told him to do any particular action in case we would get close.</p>
<div class="alert red">If you add a FPC, remove the camera already in use. </div>
<p><div class="alert green">We need to check the range or the distance between our player and the NPC. There are two approaches to do so:</p>
<ol>
<li>Using a trigger collider</li>
<li>Using Vector3.Distance or similar approach</div></li>
</ol>
<p><strong>Trigger Collider:</strong></p>
<p>Pros:</p>
<ul>
<li>Easy to use</li>
<li>All done by the engine</li>
<li>We get a reference to the colliding object</li>
</ul>
<p>Cons:</p>
<ul>
<li>That is more the engine has to do</li>
</ul>
<p>Using a trigger collider can be simple, we attach a sphere collider, set it to IsTrigger and then we can check collision. When something enters, we verify who it is using the reference the function created and apply the action. Good point it is done by the engine, every frame it takes all colliders and checks the distance between each triangle of the collider and see if any other collider intersects or is inside.</p>
<p><strong>Distance checking:</strong></p>
<p>Pros:</p>
<ul>
<li>Easy to use and implement</li>
</ul>
<p>Cons:</p>
<ul>
<li>Depending on the function choice it can be expensive</li>
<li>We need a reference to the object</li>
</ul>
<p>Well, let's see two different cases in which one is better that the other. First, we have an enemy and we want to check collision with everything around (enemies, player and random NPCs). We cannot keep a reference of each and every one of them, on top of that, we would have to regularly call for any new object or any destroyed object. This is a case where the collider comes handy:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void OnTriggerEnter(Collider other){}</pre>
<p>I get a reference automatically when anyone collides. This way, no need for arrays or lists of references. other is my reference and after the collision, the reference is destroyed. On the other hand, a whole Collider object  is created and destroyed calling the constructor and then the garbage collector and I need to check who collides with the NPC.</p>
<p>Now if I want my enemy to interact with a single object in particular, the player for instance and it might happen for various reasons and regularly, I might get a reference to the player at start and use it all along.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Transform _player;

void Start(){
   _player = GameObject.Find("Player").GetComponent&lt;Transform&gt;();
}</pre>
<p>Now let's check if my player is in range.</p>
<p>We use the squared value (we already use it before on this tutorial) so that no square root is involved. Keep in mind that my squareRange is 100 so the actual distance is 10.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Transform _player;
Transform _transform;
float attackRange = 100f;
float closeRange = 4.0f;

void Start(){
   _transform = GetComponent&lt;Transform&gt;();
   _player = GameObject.Find("Player").GetComponent&lt;Transform&gt;();
   if(player == null)
      Debug.LogError("No player on scene");
}

function Update(){
    if(AIFunction())//Player in
}

bool AIFunction(){
    if((_transform.position - _player.position).sqrMagnitude &lt; attackRange)return true;
    else return false;
}</pre>
<p>Good, now we can just modify our function so that when in, the NPC follows us and when out, he gets back to his duty.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">    bool AIFunction(){
        if((player.position - _transform.position).sqrMagnitude &lt; attackRange){
           delFunc = this.Attack;
          return true;
       }else{
            delFunc = this.Walk;
            return false;
        }
    }</pre>
<p>We  need modify our Update as such:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">if(AIFunction()&amp;&amp; delEnum != null){
    StopAllCoroutines();
}</pre>
<p>We call <em>AIFunction</em> that returns true , note that at this point, if we are in range, we are the target already. <em>delEnum</em> is checked so that if our NPC is doing his little animation, it will stop the animation and will follow us.</p>
<p>Now we have our guy minding his own business but he does not get too kindly on folks that come around so he attacks when you get too close but if you agree to leave then he gets back to his duty. By the way, he does not attack for now, so let's do it.</p>
<p>We need an Attack function:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void Attack(){
   if((player.position - _transform.position).sqrMagnitude &gt; closeRange){
      Move(player);
      animation.CrossFade("walk");
  }else{
      print ("Slap slap!!");
   }
}</pre>
<p>And finally, we modify our AI function:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">bool AIFunction(){
   Vector3 direction = player.position - _transform.position;
   if(direction.sqrMagnitude &lt; attackRange){
      delFunc = this.Attack;
      return true;
   }else{
      delFunc = this.Walk;
      return false;
   }
}</pre>
<p>Depending on the distance we assign a different function.</p>
<p>This will do the trick but you probably noticed that whether you come from the front or behind the result is the same. Also, what if you are behind a tree or a house, checking the range, the NPC would know you are behind even though he cannot see you. Let's fix that in the next part.</p>
<h2><a name="Sight"></a></h2>
<h2>I can see you (Line of sight)</h2>
<p>In order to give some vision to our NPC we use a little vector trick. We use dot product and unit circle from trigonometry.</p>
<div class="alert green"></p>
<p style="text-align: center;">A·B = |A|·|B|cosΘ</p>
<p style="text-align: center;">A·B / |A|·|B| = cosΘ</p>
<p style="text-align: center;">arcos(A·B / |A|·|B| ) = Θ</p>
<p>angle is in radians.</div>
<p>That tells us dot product of A and B is equal to product of the magnitude of A and B multiplied by cosin of the angle. Aie. Well actually it is way more simple than it looks. But it also shows that with some manipulation we can find the angle between two vectors.Look at the picture below.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Présentation1.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-2008" alt="Présentation1" src="http://unitygems.com/wp-content/uploads/2012/11/Présentation1-300x225.png" width="300" height="225" /></a></p>
<p>What this tells us is that the NPC is at the center of the circle looking in the green vector direction. The player is the blue dot at the end of the black vector. We want to know the red angle and we can do that with the dot product.</p>
<p>Our dot product becomes <em>green·black / |green|·|black| = cosΘ </em></p>
<p>It also tells us, that if the dot product returns a positive value, my player is in front of the NPC. We are getting closer.</p>
<p>Now, green is the transform.forward of our NPC and black is (player.position - transform.position). Mmm but hold on green is a unit vector so magnitude is 1 and I can make my black vector a unit vector as well without modify its direction property. Hooray!!!</p>
<p>Why hooray, because is I use the normalized version of my black vector the <em> |green|·|black|</em> part is equal 1 and dividing by 1 is like no division so I am left with <em>transform.forward </em><em>·</em> (player.position - transform.position).normalized = cosΘ.</p>
<p>And that is it. I can use Vector3.Dot(<em>transform.forward </em><em>,</em>(player.position - transform.position).normalized)&gt;0 and if this is true my guy is in front, the NPC sees him and attack.</p>
<pre>if((player.position - _transform.position).sqrMagnitude &lt; squareRange &amp;&amp; 
      (Vector3.Dot((player.position - _transform.position).normalized, _transform.forward) &gt;0)){}</pre>
<p>We still have a problem, if we managed to get quickly behind the guy, he loses our sight.  So we need to modify our script so that when the NPC knows we are close, it will not lose sight until we get out of range. For this, I simply use a boolean.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">bool chasing;
bool AIFunction()
{
     Vector3 direction = player.position - _transform.position;
     if (direction.sqrMagnitude &lt; attackRange)
     {
         if (chasing)
         {
             delFunc = this.Attack;
             return true;
         }
         else
         {
             if (Vector3.Dot(direction.normalized, _transform.forward) &gt; 0 )
             {
                 delFunc = this.Attack;
                 dhasing = true;
                 return true;
             }
             return false;
         }
     }
     else
     {
         if(chasing)delFunc = this.Walk;
         chasing = false;
         return false;
     }
 }</pre>
<p>So we check if the player is in range AND if he is in sight. Then when he is seen, we set the boolean <em>chasing </em>to true. Next frame, it does not matter if we are behind him since he is aware of us. Only when we get far enough, then he gives up.</p>
<pre>if(chasing){
   delFunc = this.Walk;
   chasing = false;
}
return false;</pre>
<p>You might wonder about this bit above , well, we only want the NPC to get back to Walk if he has been chasing us and we got away from him. The rest of teh time we just return false.</p>
<p>Now how can we check if the NPC actually sees us. You do not want the NPC to see you if you are behind a wall. So we use <a title="Physics.Linecast" href="http://docs.unity3d.com/Documentation/ScriptReference/Physics.Linecast.html">Physics.Linecast</a>. It will cast a line (as the name says) from one position to another and report if something is in between. But first, one side note about Linecast. If we use like this:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">    if (!Physics.Linecast (_transform.position, player.position)) {
        //I see you
    }</pre>
<p>You will notice that the NPC never sees you. The function returns true if something is in-between and skips our action if so. But the problem comes from our NPC itself. _transform.position is really likely to be positioned in the middle of the models, the Linecast will then automatically considered a collision with the collider of the NPC, two solutions to that. The simple one, add an empty game object right in front of the eye of the NPC with forward matching the view and casts the line from there. Good point about it, the NPC now sees from the eye level and I like this approach more actually as it matches realism.  Or we need to tell the compiler we want to ignore collision with the NPC using Layers.</p>
<p>Click Layers in the inspector, and select Add Layer. Select the User Layer 8 and add Vision, give that layer  to our player. We need to check if the line goes from the NPC eyes to our player position but our player also has a collider.</p>
<p>So we will modify a little our linecast function:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Transform _eyes;
int layerMask = 1 &lt;&lt; 8;

void Start(){
    _eyes = transform.Find("Eyes");
    layerMask = ~layerMask;
}

void Update(){	
    Debug.DrawLine (_transform.position, _player.position, Color.yellow);
    if (!Physics.Linecast (_eyes.position, _player.position, layerMask)) {
           ("Did Hit "+hit.collider.gameObject.name);
    }
}</pre>
<p>The layer variable uses some bitwise manipulation, instead of giving a particular value to the variable, we modify it by bit so we say to move to the 8th bit and turn it to 1-&gt; 10000000. This kind of manipulation is widely used in communication and embedded-system, in game a little less...</p>
<p>The Start does another of those bitwise thingy, what we want is actually a bit like 01111111, so instead of 7 operations like the first one for each bit we can do it in two. ~ is a NOT operator just like ! but for bit, so it turns 0 into 1 and 1 into 0 and returns the invert byte (8bit). It is also called the complement. Let's not dig too much into bitwise manipulation shall we?</p>
<p>The Debug.DrawLine is just there for you to see the Linecast in the scene view. The linecast function checks every collision between our NPC and the player.If none then it means the NPC can see us.</p>
<p>So all we need here is this:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">    bool AIFunction(){
        Vector3 direction = player.position - _transform.position;
        if (direction.sqrMagnitude &lt; attackRange){
            if (chasing){
                delFunc = this.Attack;
                return true;
            } else{
                if (Vector3.Dot(direction.normalized, _transform.forward) &gt; 0 &amp;&amp;
                    !Physics.Linecast(_eyes.position, player.position, layerMask)){
                        delFunc = this.Attack;
                        chasing = true;
                        return true;
                }
                return false;
            }
        }else{
            if(chasing)delFunc = this.Walk;
            chasing = false;
            return false;
        }
    }</pre>
<p>Finally, our NPC starts to act reasonably. Last part we will look at is if our NPC is closer to a safe point, he will move there instead of attacking directly.</p>
<p>You may have notice I have added a script for the sword collision which is not a real collision. The issue being that we used an animation so collision won't do properly. A simple function will fix that problem.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class SwordScript : MonoBehaviour {

   Transform player;
   Transform _transform;
   float sqrRange = 3;

   void Start(){
      player = GameObject.Find ("Player").GetComponent&lt;Transform&gt;();
      if (player == null)
          Debug.LogError("No player on scene");
      _transform = GetComponent&lt;Transform&gt;();
   }

    void CollisionSword(){
        Vector3 direction = player.position - _transform.position;
	if (direction.sqrMagnitude &lt; sqrRange){
		if(Vector3.Dot (direction.normalized,_transform.forward) &gt; 0){
			//Add here your logic for decreasing player health
			print ("Hit");
		}
	}
    }
}</pre>
<h2><a name="Cover"></a></h2>
<p>We are using a similar approach as for the line of sight, if we are close enough and facing the player at the moment of call then we get hit. The special thing here is that I used animation event. Select the NPC, then go to window in the menu bar and open up a animation window.<br />
In the animation selection drop-down, select attackOwn (I had to create a new attack animation as imported animation are read-only). Around frame 13, you will notice a little white bar. This is an animation event. It just means at frame 13, I am calling the function that is given. By the way, you will probably see a (function not supported) message. Ignore it, it works. from what I have found, it seems only the functions attached to the first script on the object should be working. Nonetheless, it does work but give a warning.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled1.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-2009" alt="Untitled1" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled1-300x285.png" width="300" height="285" /></a><a href="http://unitygems.com/wp-content/uploads/2012/11/Untitled.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-medium wp-image-2010" alt="Untitled" src="http://unitygems.com/wp-content/uploads/2012/11/Untitled-300x132.png" width="300" height="132" /></a></p>
<p>When our guy gets close, he starts swinging and we get a message telling us we are getting hit.</p>
<p>We also add an attack function that is called when we are close enough to the player that simply launch the animation that will call the SwordCollision function.</p>
<p><br clear="none" /><span class="collapseomatic " id="id5023"  title="<strong>Final code snippet</strong>"><strong>Final code snippet</strong></span><div id="target-id5023" class="collapseomatic_content "></p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(CharacterController))]
public class AIScript : MonoBehaviour{
    #region variables
    #region cached variables
    CharacterController _controller;
    Transform _transform;
    Transform player;
    Transform _eyes;
    #endregion
    #region movement variables
    float speed = 5;
    float gravity = 100;
    Vector3 moveDirection;
    float maxRotSpeed = 200.0f;
    float minTime = 0.1f;
    float velocity;
    float range;
    float attackRange;
    #endregion
    #region waypoint variables
    int index;
    public string strTag;
    List&lt;Transform&gt; waypoint;
    #endregion
    #region delegate variable
    delegate void DelFunc();
    delegate IEnumerator DelEnum();
    DelFunc delFunc;
    DelEnum delEnum;
    #endregion
    #endregion
    bool chasing;
    bool coroutineOn;
    int layerMask = 1 &lt;&lt; 8;

    void Start(){
        _controller = GetComponent&lt;CharacterController&gt;();
        _transform = GetComponent&lt;Transform&gt;();
        _eyes = transform.Find ("Eyes");
        player = GameObject.Find("Player").GetComponent&lt;Transform&gt;();
        if (player == null)
            Debug.LogError("No player on scene");
        if (string.IsNullOrEmpty(strTag)) 
            Debug.LogError("No waypoint tag given");

        index = 0;
        range = 2.5f; attackRange = 200f;

        waypoint = GameObject.Find("PathObject").GetComponent&lt;PathScript&gt;().GetPath(strTag);
        animation["victory"].wrapMode = WrapMode.Once;

        delFunc = this.Walk;
        delEnum = null;

        chasing = false;
        layerMask = ~layerMask;
    }

    void Update()
    {
        if (AIFunction()&amp;&amp;coroutineOn) {
            StopAllCoroutines();
            coroutineOn = false;
        }

        if (delFunc != null){
            delFunc();
        }else if (delEnum != null){
               StartCoroutine(delEnum());
               delEnum = null;
        }
    }

    #region movement functions
    void Move(Transform target){
        //Movements
        moveDirection = _transform.forward;
        moveDirection *= speed;
        moveDirection.y -= gravity;
        _controller.Move(moveDirection * Time.deltaTime);
        //Rotation
        var newRotation = Quaternion.LookRotation(target.position - _transform.position).eulerAngles;
        var angles = _transform.rotation.eulerAngles;
        _transform.rotation = Quaternion.Euler(angles.x,
            Mathf.SmoothDampAngle(angles.y, newRotation.y, ref velocity, minTime, maxRotSpeed), angles.z);
    }

    void NextIndex(){
        if (++index == waypoint.Count) index = 0;
    }

    void Walk(){
        if ((_transform.position - waypoint[index].position).sqrMagnitude &gt; range) {
            Move(waypoint[index]);
            animation.CrossFade("walk");
        }
        else{
            switch (index) {
                case 0:
                    delFunc = null;
                    delEnum = this.Victory;
                    break;
                case 1:
                    delFunc = null;
                    delEnum = this.Wait;
                    break;
                default:
                    NextIndex(); break;
            }
        }
    }

    void Attack(){
        if ((_transform.position - player.position).sqrMagnitude &gt; range){
            Move(player);
            animation.CrossFade("charge");
        }else{
            animation.CrossFade("attackOwn");
        }
    }

    #endregion

    #region animation functions
    IEnumerator Victory() {
        couroutineOn = true;
        if (!animation.IsPlaying("victory")) animation.CrossFade("victory");
        yield return new WaitForSeconds(animation["victory"].length);
        NextIndex();
        delFunc = this.Walk;
        couroutineOn = false;
    }

    IEnumerator Wait(){
        couroutineOn = true;
        animation.CrossFade("idle");
        yield return new WaitForSeconds(2.0f);
        NextIndex();
        delFunc = this.Walk;
        couroutineOn = false;
    }
    #endregion

    #region AI function
    bool AIFunction(){
        Vector3 direction = player.position - _transform.position;
        if (direction.sqrMagnitude &lt; attackRange){
            if (chasing){
                delFunc = this.Attack;
                return true;
            } else{
                if (Vector3.Dot(direction.normalized, _transform.forward) &gt; 0 &amp;&amp;
                    !Physics.Linecast(_eyes.position, player.position, layerMask)){
                        delFunc = this.Attack;
                        chasing = true;
                        return true;
                }
                return false;
            }
        }else{
            if(chasing){
                delFunc = this.Walk;
                chasing = false;
            }
            return false;
        }
    }
    #endregion
}</pre>
<p></div></p>
<div class="alert green">Get the project<a title="AICharacter5" href="http://unitygems.com/Downloads/AICharacter/AICharacter5.zip"> here</a>.</div>
<h2>Conclusion</h2>
<p>You now have the basic to develop your NPC further. Hopefully that was useful and I hope it will ease a little the approach to the more advanced delegate tutorial.</p>
<p>So you learn how to get our little guy around without passing through walls and trees. He also sees you and run at you. You learn about simple delegates. Now it is your turn to get this to a higher level.</p>
<p>Hope you liked it.</p>
<p>Also, it took a little while and a lot of coffee to review all that and make it better but still, it could be that you see something wrong. Please report it so that we can make it even better. Also, if you feel some techniques should be used over the one provided, well then again, drop a comment.</p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/basic-ai-character/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Les traquenards courants avec Unity</title>
		<link>http://unitygems.com/traquenards-unity/</link>
		<comments>http://unitygems.com/traquenards-unity/#comments</comments>
		<pubDate>Thu, 22 Nov 2012 07:58:17 +0000</pubDate>
		<dc:creator>fafase</dc:creator>
				<category><![CDATA[Beginner]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[French]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[beginner]]></category>
		<category><![CDATA[Beginners]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Custom Inspector]]></category>
		<category><![CDATA[erreur]]></category>
		<category><![CDATA[francais]]></category>
		<category><![CDATA[GetComponent]]></category>
		<category><![CDATA[Gotcha]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[Quaternions]]></category>
		<category><![CDATA[Rigidbody]]></category>
		<category><![CDATA[traquenard]]></category>
		<category><![CDATA[UnityScript]]></category>
		<category><![CDATA[yield]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1476</guid>
		<description><![CDATA[<p>Cet article est la traduction de l&#8217;article &#8220;Common Gotchas&#8221; paru sur ce même site en Anglais. L&#8217;informatique est un domaine international où l&#8217;Anglais domine (le langage, pas le gars bien sur&#8230;). De ce fait, certains mots seront laissés en Anglais, pas les plus compliqués, promis. Il existe un certain nombre de &#8220;pièges&#8221; qui ont frappé presque tous &#8230;<br /><a class="excerpt" href="http://unitygems.com/traquenards-unity/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<p>Cet article est la traduction de l'article "Common Gotchas" paru sur ce même site en Anglais. L'informatique est un domaine international où l'Anglais domine (le langage, pas le gars bien sur...). De ce fait, certains mots seront laissés en Anglais, pas les plus compliqués, promis.</p>
<p>Il existe un certain nombre de "pièges" qui ont frappé presque tous les débutants de Unity. Parfois, cela est dû au fait que vous débutez la programmation en général mais c'est parfois dû au fait que Unity utilise une méthode légèrement inhabituelle d'attacher plusieurs scripts sur un objet.<br />
Cet aperçu tente de vous guider à travers ceux que nous voyons le plus souvent sur le forum de réponses Unity. Ce tutoriel s'adresse donc aux nouveaux venus, les noobs.</p>
<h2>Les Traquenards</h2>
<p><br clear="none" /><span class="collapseomatic " id="id5264"  title="Comment accéder à une variable d'un autre script ou d'un autre objet">Comment accéder à une variable d'un autre script ou d'un autre objet</span><div id="target-id5264" class="collapseomatic_content "></p>
<h2>Comment accéder à une variable d'un autre script ou d'un autre objet</h2>
<div class="alert green">Vous pouvez trouver une version plus détaillée sur ce sujet en <a title="Script Interaction in C#" href="http://unitygems.com/script-interaction-cs/">C#</a> ou en <a title="Script Interaction in UnityScript" href="http://unitygems.com/script-interaction-unityscript/">UnityScript</a> (seulement en Anglais pour le moment...)</div>
<p>Donc, vous avez préparé deux scripts et vous voulez accéder à des variables ou des méthodes d' un script à partir de l'autre, mais obtenir une référence au script ou comment obtenir la variable reste un mystère. Appelons le script qui veut accéder à la variable le <em>caller (</em>appeleur) et le script qui contient la variable ou la méthode de la<em> target </em>(cible).</p>
<div class="alert yellow">Vous pourriez être tenté de déclarer des variables comme static afin de pouvoir y accéder facilement sans avoir à réellement faire référence à l'objet sur lequel le script est placé. C'est une <strong>très mauvaise idée</strong>, sauf si vous savez ce que vous faites. Si vous êtes nouveau à la programmation, <strong>éviter le procédé static</strong> jusqu'à ce que vous le compreniez parfaitement. Les variables statiques sont des variables globales et ne devrait être utilisée que dans des scénarios rares et assez avancé. En fait, vous pouvez facilement programmer un jeu compliqué et ne jamais définir une variable comme statique.</div>
<div class="alert blue">Sur le forum de réponses Unity, on voit souvent des questions du genre - quand un de mes ennemi meurt, ils meurent tous. Ceci est normalement causée par les nouveaux développeurs (noobies) qui utilisent des variables statiques, car ils ne pouvaient se faire une idée sur comment accéder d'une autre manière à la donnée dont ils ont été besoin. Si cela s'applique à vous, lisez la suite!</div>
<p>Pour obtenir le script <em>target</em>, nous devons trouver  l'objet auquel il est attaché. Il existe cinq manières:</p>
<p>1. Le script <em>target </em>est attaché a même object que le script <em>caller</em>.</p>
<p>Dans ce cas, vous devez placer un appel à la fonction GetComponent, qui retourne une reference au script <em>target</em> attaché au même object.   GetComponent sans rien devant cherche dans l'objet.</p>
<p>Avec UnityScript, on utilise GetComponent de cette manière:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">GetComponent(ScriptTarget).uneVariable = uneValeur;</pre>
<pre class="brush: actionscript3; gutter: true; first-line: 1">GetComponent(ScriptTarget).UneMethode();</pre>
<p>Avec C#:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">GetComponent&lt;ScriptTarget&gt;().uneVariable = uneValeur;
GetComponent&lt;ScriptTarget&gt;().UneMethode();</pre>
<div class="alert yellow">Evitez d'utiliser GetComponent avec une string.  Avec un appel de GetComponent sans une string la valeur retournée est déjà du bon type et vous pouvez accéder à vos variables et méthodes. Si vous appelez GetComponent ("ScriptTarget"), vous obtiendrez votre script, mais d'un le processus est plus lent et de deux il se peut que certaines variables ne soit pas accessibles puisque le compilateur ne connait pas la nature exact du script. Sans plus d'indications, faîtes simples, pas de  guillemets. </div>
<p>2. Vous voulez accéder un script <em>target </em>script attaché à un autre objet parce que vous venez d'entrer en collision avec ce dernier, ou invoqué une trigger sur le script <em>caller.</em></p>
<p>Dans ce cas, votre méthode devrait déjà inclure une référence à l'autre objet soit en tant que Collider pour OnTriggerXXX ou en tant que Collision pour OnCollisionXXX.</p>
<p>Dans ce cas, il vous est seulement nécessaire d'appeler GetComponent sur la référence.</p>
<p>Avec UnityScript:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">function OnTriggerEnter(reference : Collider) 
{ 
      reference.GetComponent(ScriptTarget).uneVariable = uneValeur; 
}</pre>
<p>Avec C#</p>
<pre>void OnTriggerEnter(Collider reference)
{
      reference.GetComponent&lt;ScriptTarget&gt;().uneVariable = une Valeur;
}</pre>
<p>Dans une collision, vous avez juste besoin d'obtenir quelque chose qui représente l'autre objet et appeler GetComponent dessus:</p>
<pre>function OnCollisionEnter(reference : Collision)
{
       reference.collider.GetComponent(ScriptTarget).uneVariable = uneValeur;
}</pre>
<p>Avec C#:</p>
<p>Or in C#</p>
<pre>void OnCollisionEnter(Collision reference)
{
      reference.GetComponent&lt;ScriptTarget&gt;().uneVariable = uneValeur;
}</pre>
<p>If for some reason you want to set a variable on some child of the object you triggered or collided with then you can use GetComponentInChildren.</p>
<p>Si pour une quelconque raison, vous souhaitez modifer une variable se trouvant sur un child de l'objet vous venez d'entrer en collision, vous pouvez utiliser GetComponentInChildren.</p>
<div class="alert blue">GetComponentInChildren cherche aussi dans l'objet sur lequel l'appel est fait.</div>
<h3>3.  Vous avez une relation entre deux objets que vous pouvez créer en utilisant l'éditeur ou définir à l'aide de script lorsque la relation est créée</h3>
<p>Donc dans ce cas vous avez une relation entre deux objets, non pas parce qu'ils sont en train d'interagir, mais plutôt parce qu'ils ont une autre relation à long terme. Par exemple, un ennemi peut courir après le joueur, un joueur peut avoir «verrouillé» une arme sur un ennemi, ou peut-être le joueur est actuellement dans ou sur  un certain véhicule.</p>
<p>Dans ce cas, vous voulez avoir une variable dans votre script <em>caller</em> qui fait référence à votre script <em>target</em>. Le plus simple est de définir cette variable comme étant de type NomScriptTarget,cela peut aussi être un autre type de variable référence comme GameObject ou Transform.</p>
<div class="alert yellow">Soyez conscient que l'appel de GetComponent n'est pas «gratuit» en terme de performance. Si possible essayez de placer l'appel avant le début de la scène (Awake ou Start) . Par la suite la variable référence sera placé en cache ce qui optimize les appels vers les variables cibles.</div>
<p>You will assign the variable using the inspector if the relationship can be created at editing time - or if you assign it at runtime you will use either <strong>method 2</strong> (above) or <strong>method 4</strong> (below) to get the component and set up the variable.</p>
<p>Vous pouvez assigner la variable dans l'inspecteur si la relation peut être créé au moment de l'édition - ou si vous l'assignez pendant l'exécution, utilisez soit la méthode 2 (ci-dessus) ou la méthode 4 (ci-dessous) pour obtenir le composant et définir la variable.</p>
<p>Voici un exemple de création d'une relation à long terme à partir d'une trigger:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">var targetScript : TargetScript;       //Le script est directement placé dans l'emplacement de l'inspecteur 

function Update(){
     //Si nous avons une target et elle est prête à être utilisée
     if(targetScript &amp;&amp; targetScript.uneVariable &gt; 100){
         //Action
     }else{
         //Une autre action
     }
}

function OnTriggerEnter(other : Collider){
     //Vérifions si l'objet avec lequel nous entrons en collision peut être une target
     var target = other.GetComponent(ScriptTarget);
     if(target){
           //Si possible 
           targetScript = target;
     }
}</pre>
<h3>4. Vous pouvez trouver l'objet qui contient la <em>target</em>  en cherchant par nom ou tag</h3>
<div class="alert yellow"> C'est de loin le moyen le plus couteux en terme de performance. Il est hautement recommandé de faire la rechercher si possible dans Awake ou Start. Pensez que la fonction Find parcours l'ensemble de la Hierarchie, si votre scène inclut 1000 objets, cela peut prendre du temps.</div>
<p>Une fois l'objet trouvé, on retourne à la <strong>méthode 2</strong> avec GetComponent.</p>
<p>Il est possible de trouver un objet de différentes manières - avec <a href="http://docs.unity3d.com/Documentation/ScriptReference/GameObject.FindWithTag.html">GameObject.FindWithTag</a>  ou <a href="http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html">GameObject.Find</a> pour chercher l'inégralité de la scène.  Ou bien <a href="http://docs.unity3d.com/Documentation/ScriptReference/Transform.Find.html">transform.Find</a> pour chercher seulement dans la hierarchie de l'objet en question et limiter la recherche à ses children. Peu importe le processus,  la <strong>methode 2</strong> revient pour accéder au script dont vous avez besoin. Vous pouvex tout autant cacher le résultat en le storant dans une variable pour obtenir une relation à long terms et utiliser la <strong>methode 3</strong> pour manipuler l'objet.</p>
<pre>TargetScriptName targetScript;

void Start()
{
       targetScript = GameObject.Find("NomObjet").GetComponent&lt;TargetScriptName&gt;();
}

void Update()
{
      if(Vector3.Distance(targetScript.transform.position, transform.position) &lt; 10)
      {
          targetScript.uneVariable -= uneValeur;
      }
}</pre>
<h3></h3>
<h3>5. Vous avez un autre composant sur l'objet mais ce n'est pas celui avec le script que vous voulez</h3>
<p>Ceci arrive souvent quand vous traversez la hierarchie ou vous avez un autre script sur le même objet. En quelque sorte, on revient à la <strong>methode 2.</strong></p>
<p>Par exemple, vous souhaitez accéder un script contenu dans chacun des children de votre caller:</p>
<pre>for(var t : Transform in transform)
{
     target = t.GetComponent(TargetScriptName);
     target.DoSomething();
     target.someVariable = someValue;
}</pre>
<p>en C#:</p>
<pre>foreach (Transform t : in transform)
{
     target = t.GetComponent&lt;TargetScriptName&gt;();
     target.Action();
     target.uneVariable = uneValeur;
}</pre>
<p>Vous pouvez regarder la vidéo démonstrative ci-dessous (en Anglais pour le moment)</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/OaQ6E3BlFA4?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id7708"  title="Rigidbody, à quoi ça sert? ">Rigidbody, à quoi ça sert? </span><div id="target-id7708" class="collapseomatic_content "></p>
<h2>Rigidbody, à quoi ça sert?</h2>
<p>Donc vous venez de passer les 3 derniers jours sans dormir à essayer de faire en sorte que votre objet ait un semblant de réalisme. Alors vous faites la tournée des sites de physique pour comprendre les principes de gravité, friction, collision et autres. Puis vous entendez parler du Rigidbody et sentez une montée de sueur. Et là vous vous dites, "Non vas-y quoi!!!".</p>
<div class="alert green"> Le Rigidbody est un composant qui vous permet d'appliquer les principes fondamentaux de physique à votre objet sans rien faire (ou presque).</div>
<p>Maintenant comment l'utiliser? Pour cela, je vous suggère de télécharger ce<a title="AngryBird" href="http://fafase.comuf.com/Content/Project/AngryBird.zip"> projet</a> et vous pouvez trouver les explication sur cette vidéo en fr:</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/lmdYIi6jU58?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/q3lrrPDAHEU?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/nc_kXEIwD58?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id9813"  title="Comment s'assurer que les fonctions OnCollisionXXX et OnTriggerXXX sont appelées dans votre script. ">Comment s'assurer que les fonctions OnCollisionXXX et OnTriggerXXX sont appelées dans votre script. </span><div id="target-id9813" class="collapseomatic_content "></p>
<h2>Comment s'assurer que les fonctions OnCollisionXXX et OnTriggerXXX sont appelées dans votre script.</h2>
<p>Tout d'abord pour détecter une collision, les deux objets doivent avoir un composant collider attaché. Pour que OnCollisioXXX fonctionne, isTrigger ne doit pas être sélectionné, en contrepartie pour que OnTriggerXXX fonctionne, il vous faut sélectionner isTrigger. Vous devez aussi suivre les règles suivantes:</p>
<h3>L'objet qui contient le script avec OnCollisionXXX, OnTriggerXXX doit avoir un composant rigidbody attaché.</h3>
<div class="alert blue">Avec Unity, la détection des collisions fait partie du système de physique.  Si vous ne souhaitez pas appliquer de physique sur votre objet, vous pouvez sélectionner isKinematic. Ainsi, Unity détectera la collision mais n'appliquera aucune résolution ou interaction.  </div>
<h3>Au moins un des partis doit avoir un rigidbody qui ne soit pas endormi</h3>
<p>Dans un souci d'optimisation, Unity place automatiquement en sommeil les rigidbodys qui ne bougent pas. Une collision avec un autre rigidbody le réveillera, considérant que ce rigidbody n'est pas lui même endormi. Dans la cas où chaque parti est endormi, la collision est simplement ignorée.</p>
<div class="alert green">Attachez un rigidbody à chaque collider vous créez ou bougez si votre objet n'en contient pas déjà un.</div>
<h3>D'autres importantes considérations</h3>
<div class="alert yellow">Un Mesh Collider peut entrer en collision avec  un autre mesh collider si ils sont <strong>tous les deux</strong> définis comme convex. POur une collision avec un mesh concave, alors l'autre parti doit être un  collider primitif (box collider, sphere collider,...). Voir ci-dessous.</div>
<div class="alert yellow">Les mesh colliders n'ont qu'un seul coté, ils entrent en collision seulement du coté comportant la normal pointant vers l'exterieur.</div>
<div class="alert yellow">Les mesh colliders sont sujets au back face culling. Chaque polygone de votre jeu comporte une normal sur une seule face. Par souci d'optimisation, l'autre face est ignorée. Il en va de même avec les mesh colliders. Une seule face peut détecter une collision.</div>
<p>Vous pouvez construire des colliders à partor de colliders primitifs. Il est ainsi possible de reproduire des objets complexes sans pour autant puiser dans les resources. Il vous suffit d'attacher des game objects sur l'objet et attacher les colliders sur ces objets. Le composant rigidbody est attaché au parent (root). Un voiture qui devrait comporter des centaines voire des milliers de polygones peut être réduite à quatre colliders pour les roues et deux larges colliders pour les parties hautes et basses. </div></p>
<p><br clear="none" /><span class="collapseomatic " id="id6498"  title="Détecter l'Input convenablement">Détecter l'Input convenablement</span><div id="target-id6498" class="collapseomatic_content "></p>
<h2>Détecter l'Input convenablement</h2>
<p>Les débutants finissent souvent devant leur programme à se demander pourquoi la pression d'une touche est parfois non détectée. Ils ont tout bien fait en suivant la documentation à la lettre (du moins c'est ce qu'ils croient) mais ils ont le sentiment que certaines fois rien ne se passe. La plupart du temps, ce genre de problème survient lors du dévelopement de la partie physique du jeu via l'Input. Puisque la physique se passe dans la FixedUpdate, il serait logique que l'INput en rapport avec la physique y soit aussi. Beh non...</p>
<p>La fonction Update est dépendante de la machine sur laquelle le programme fonctionne. Cela signifie donc que chaque ordinateur peut avoir un FPS (Frame Per Second, combien de fois chaque script est pris en charge par seconde) différent en fonction du processeur et des différents programmes qui tournent.</p>
<p>La fonction FixedUpdate est définie par l'utilisateur. Il vous est possible de modifer sa valeur via le Physics Manager sur le menu, Edit-&gt;Project Settings-&gt;Physics. La valeur par défaut est 0.02 qui représente 50fps. Une valeur plus petite demandera au système de tourner plus vite. Notez que la valeur est une requête mais peut ne pas être garantis si vous demandez une valeur que le processeur ne peut fournir.</p>
<p>Update et FixedUpdate tourne indépendamment, cela signifie que pour une Update, on peut avoir une, plusieurs ou aucune FixedUpdate. Si votre ordinateur tourne à 100fps mais FixedUpdate est définie à 50fps, pour deux Updates, on a seulement une FixedUpdate.</p>
<p><a href="http://unitygems.com/wp-content/uploads/2012/10/Présentation13.png" data-rel="prettyPhoto[this_page]" title=""><img class="alignnone size-full wp-image-479" style="border: 1px solid black;" title="InputFixed" src="http://unitygems.com/wp-content/uploads/2012/10/Présentation13.png" alt="InputFixed" width="960" height="720" /></a></p>
<p>Voici ce qu'il ne fait pas faire:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;

public class Test:MonoBehaviour{
    void FixedUpdate(){
        if(Input.GetKeyDown(KeyCode.Space)){
           //Action
        }
    }
}</pre>
<p>Ce que vous devez faire:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;

public class Test:MonoBehaviour{
    bool action = false;
    void Update(){
         if(Input.GetKeyDown(KeyCode.Space)){
             action = true;
         }
    }
    void FixedUpdate(){
       if(action){
           //Action
           action = false;
        }
    }
}</pre>
<p>L'Input dans l'Update est détectée chaque frame ce qui garantit qu'aucune Input ne peut être ignorée. Une variable globale est modifiée pour indiquer à la FixedUpdate qu'une Input a été détectée. FixedUpdate utilise cette variable et la définit à nouveau comme false de manière à ce que l'action ne se répète pas indéfiniment.</p>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id1293"  title="Action dans le futur">Action dans le futur</span><div id="target-id1293" class="collapseomatic_content "></p>
<h2>Action dans le futur</h2>
<p>Les coroutines sont un sujet particulièrement pointilleux pour faire que quelque chose arrive plus tard. Il est préférable de les oublier pour le moment surtout si vous débutez avec Unity. Voyons plutôt ce que nous pouvons faire</p>
<p>Juste pour le principe, voici un minuteur (timer) par code:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">float timer;
int attente;

void Update(){
    timer += Time.deltaTime;
    if(timer &gt; attente){
        //Action
       timer = 0;
    }
}</pre>
<p>La variable timer croît chaque frame en ajoutant deltaTime (le temps écoulé depuis le dernier frame). La variable est comparée cahque frame avec attente. Quand timer devient plus grand que attente, la déclaration est vraie, l'action est lancée et timer est remis à zéro. Cerner le timer avec un boolean permet de lancer le timer sous une certaine condition:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;
public class Test:MonoBehaviour{
    float timer;       
    int attente;
    bool inside;

    void Start(){
        timer = 0.0;
        attente = 2;
        inside = false;
    }

    void Update(){
        if(inside){
            timer += Time.deltaTime;
            if(timer &gt; attente){
                //Action
               timer = 0;
           }
       }
    }

    void OnTriggerEnter(Collider other){
        if (other.gameObject.tag=="Joueur")inside = true;
    }
   void OnTriggerExit(Collider other){
        if (other.gameObject.tag =="Joueur"){
            inside=false;
            timer = 0;
        }
   }
}</pre>
<p>L'exemple ci-dessus montre comment créer un minuteur pour lancer une action tant que le joueur reste dans la zone trigger. Par exemple, si le joueur marche sur du feu, si nous blessons le joueur à chaque frame, il va vite se retrouver à 0. Avec un minuteur, on peut le blesser chaque x secondes.</p>
<p>Cependant, Unity offre de meilleures solutio.</p>
<h3>Limiter le temps de vie d'un object</h3>
<p>Si vous souhaitez qu'un object n'apparaisse que pour une période déterminée de quelques secondes, vous pouvez le detruire dans la fonction Start. Destroy prend un second paramètre qui correspond à la durée de vie avant la mort définitive (...).</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void Start()
{
       //Détruire l'objet après 5 secondes
       Destroy(gameObject, 5);
}</pre>
<p>Il est ainsi possible de garder un objet pour une durée déterminée avant de la faire disparaître:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">int vie = 10;

void Update(){
       if(vie &lt;= 0)
            //Détruire l'objet après 2 secondes
            Destroy(gameObject, 2);
}</pre>
<p>Une fois l'objet mort par le manque de vie (oh la la...), il meurt une deuxième fois après 2 secondes. Ce procédé est souvent utilisé, un personnage est tué mais son corps reste sur le sol pour une durée.</p>
<h3>Retarder une action</h3>
<p>Vous voulez qu'une action se fasse et une autre action d'attendre un certain temps avant de se faire, la première étant décisive. UnityScript et C# offrent des méthodes différentes pour le même résultat. dans les examples ci-dessous, la variable check est nécessaire pour entrer dans la commande. En entrant, check devient false, après 2 secondes elle redevient true.</p>
<p>UnityScript:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">#pragma strict
var check :boolean =true;
var i:int =0;

function Update () {
    if(Input.GetKeyDown(KeyCode.A)&amp;&amp;check){
        check = false;
        print("Dedans" + i++);
        WaitForIt();
    }
}
function WaitForIt(){
    yield WaitForSeconds(2.0f);
    check=true;
}</pre>
<p>C#:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">using UnityEngine;
using System.Collections;

public class Wait : MonoBehaviour {
    public bool check =true;
    int i =0;

    void Update () {
        if(Input.GetKeyDown(KeyCode.A)&amp;&amp;check){
            check = false;
            print("Inside" + i++);
            StartCoroutine(WaitForIt());
        }
    }
    IEnumerator WaitForIt(){
        yield return new WaitForSeconds(2.0f);
        check=true;
    }
}</pre>
<p>Notez le type que renvoie la fonction, IEnumerator Ce type est utilisé pour toutes les fonctions qui sont mise en attente par le système. dans notre cas WaitForIt est lancée une première fois, yield return WaitForSeconds(2.0f); est retournée. Le système met la fonction dans une liste. Au frame suivant, le système soustarait le temps écoulé depuis le dernier frame et verifie si le temps correspondant au paramètre s'est écoulé depuis le premier appel. Et ainsi de suite.Notez aussi la manière d'appeler une coroutine en C#, Unity nécessite l'utilisation de StartCoroutine(Fonction());.</p>
<p>Si vous lancez ces deux scripts, vous verrez que vous pouvez appuyer sur A et la console imprime, il vous faudra attendre 2 secondes avant que l'action ne puisse se répéter.</p>
<h3>Faire quelque chose dans quelques secondes</h3>
<p>Si vous voulez que quelque chose se fasse quelques secondes après une autre, vous pouvez simplement utiliser Invoke. Vous déclarez la fonction vous souhaitez utiliser et vous l'invoquez ainsi Invoke("NomFonction",retardEnSeconde); Dans l'exemple ci-dessous, la fonction TurnMeBlue est appelée après 2 secondes.</p>
<p>UnityScript:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">function Start(){
      //Change l'object en bleu dans 2 sec
      Invoke("TurnMeBlue", 2);
}

void TurnMeBlue(){
       renderer.material.color = Color.blue;
}</pre>
<p>Vous pouvez même faire plusieurs invocations:</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">var startPosition : Vector3;
var health = 100.0;
var respawning = false;

function Start(){
    startPosition = transform.position;
}

//Repositione l'objet
function Respawn(){
      transform.position = startPosition;
      health = 100;
      renderer.enabled = true;
      respawning = false;
}

//Cacher le personnage
function Hide(){
     renderer.enabled = false;
     transform.position = new Vector3(1000,1000,1000);
}

function Update(){
    if(health &lt; 0 &amp;&amp; !respawning){
         respawning = true;
         animation.Play("die");
         Invoke("Hide", 3);
         Invoke("Respawn", 10);
    }
}</pre>
<p>Ce script utilise Invoke pour appeler une animatin de mort et ensuite replace le personnage. Quand la vie descend en dessous de 0, l'animation "die" est jouée. Le modèle est caché (et retiré du champs) 3 secondes aprés et réapparait après 10 secondes.</p>
<h3>Faire une action régulièrement</h3>
<p>Au lieu de déclarer une fonction et la placer dans une boucle avec un minuteur, on peut simplement utiliser la focntion InvokeRepeating("NomFonction", retardPremierAppel,frequenceAppelSuivant);</p>
<p>Il est possible d'annuler la répétition avec CancelInvoke("NomeFonction"); pour annuler un appel en particulier ou sans paramètre pour annuler tous les appels.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">float sante = 100f;

void Start()
{
    InvokeRepeating("Soigne", 2, 2);
}

void Soigne()
{
    sante = Mathf.Clamp(health + 1, 0, 100);
}</pre>
<div class="alert red">Au moment de l'écriture de cet article, InvokeRepeating comporte un bug mineur. Il est tentant de placer 0 comme second paramètre pour lancer le premier appel desuite. Or, cette situation lancera deux appels de la même fonction lors du premier appel. Pour y remédier, il vous suffit de passer une valeur minime.</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">InvokeRepeating("Fonction",0,001f,2.0f);</pre>
<p></div>
<h3>Quand utiliser une coroutine</h3>
<p>Une coroutine peut s'avérer utile lorsque vous avez besoin de lancer une action qui devrait être placée dans l'Update mais vous ne le voulez pas pour simplifier la chose.</p>
<div class="alert yellow"> Soyez conscient que lancer plusieurs coroutines depuis l'Update peut altérer la même variable depuis différentes sources. Debugging devient alors fastidieux...</div>
<p>Par example, il se pourrait que vous vouliez changer la rotation d'un objet dans une fonction, dela peut se faire avec une coroutine. Dans l'example suuivant, l'appel de TourneToi change la rotation de l'objet avec un angle sur une période de temps.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">function OnMouseUp()
{
     TournToi(Vector3(0,90,0),2);
}

function TourneToi(angle : Vector3, time : float)
{
     var maRotation = transform.rotation;
     var targetAngle = currentRotation.eulerAngles + angle;
     var targetRotation = Quaternion.Euler(targetAngle);
     var t = 0;
     while(t &lt; 1)
     {
          transform.rotation = Quaternion.Slerp(maRotation, targetRotation, t);
          t += Time.deltaTime / time;
          yield null;
     } 
     transform.rotation = targetRotation;
}</pre>
<p>Avec UnityScript, une fonction devient une coroutine en ajoutant le mot-clé yield. Malheureux, jamais ôh grand jamais de faire ça dans l'Update.</p>
<p>La vidéo ci-dessous montre ce qui vient d'être expliqué par l'exemple. Malheureusement, c'est encore en Anglais.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='940' height='559' src='http://www.youtube.com/embed/JmlCm67o6DI?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id7090"  title="Comment utiliser Vector3.Lerp">Comment utiliser Vector3.Lerp</span><div id="target-id7090" class="collapseomatic_content "></p>
<h2>Comment utiliser Vector3.Lerp</h2>
<p>Vous avez défini votre ligne de code mais pour une quelconque rien ne se passe ou tout se passe mais pas comme vous le dîtes (à voix haute) à l'ordinateur. Lerp qui signifie Linear Interpolation ou interpolation linéaire. On change une valeur entre une valuer de départ et une valeur cible par un ratio.</p>
<pre class="brush: actionscript3; gutter: true; first-line: 1">transform.position = Vector3.Lerp(depart, cible, ratio);</pre>
<p>Le ratio représente le pourcentage de déplacement entre les deux valeurs.<br />
Si le ratio est 0, alors rien ne bouge, si 1 depart devient cible.</p>
<p>Si vous souhaitez déplacer unobjet entre deux points en t secondes, il vous faut enregistrer la position de départ et croitre le ratio (généralement par un facteur Time.deltaTime/nombreDeSecondes) et l'objet atteindra la destination quand ratio est égal à 1.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Vector3 _depart;
Vector3 _target;
float _t;

void Update()
{
     transform.position = Vector3.Lerp(_depart, _target, _t);
     _t += Time.deltaTime/2; //Take 2 seconds
}

public void SetTargetPosition(Vector3 newTargetPosition)
{
    _depart = transform.position;
    _target = newTargetPosition;
    _t = 0;
}</pre>
<p>Si vous souhaitez un effet plus délicat (car vous l'êtes) depuis le point où se trouve l'objet vers la cible, pour ce cas vous passez la position actuelle à Lerp.</p>
<p>Vous prenez <em>depart</em> (probablement transform.position) et vous regardez vers <em>target</em>. Puis vous bougez l'objet par le ratio. Avec ratio = 1, le mouvement est 100% de la distance. Avec ratio = 0.5 le mouvement représente 50% de la distance entre les deux points.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">void Update(){
    transform.position = Vector3.Lerp(transform.position, target.position, Time.deltaTime);
    }</pre>
<p>Si 10 m sépare transform(0) et target(10) et deltaTime est 0.2 (20%) alors (deltaTime a peu de chance d'être 0.2 mais pour l'exemple il le sera):</p>
<ol>
<li>20% de target-transform (10-0) = 2m donc transform = 2</li>
<li>20% de target-transform (10-2) = 1.6m donc transform = 3.6</li>
<li>20% de target-transform (10-3.6) = 1.28m donc transform = 4.88</li>
<li>Et ainsi de suite</li>
</ol>
<p>Notez que l'objet n'atteind jamais sa cible mais s'en approche sans jamais la toucher similaire à la limite en algèbre.  Il est possible de stopper la focntion en ajoutant une condition. Lerp est utilisé quand vous souhaitez déplacer un objet progressivement, cela peut être une porte qui glisse lentement pour s'ouvrir ou encore la caméra sur un 3rdPersonController utilise ce procédé pour ne pas bouger de manière top abrupte.</p>
<div class="alert red">Certains exemples de la documentation (s'ils n'ont pas été changés depuis) utilisent Time.time comme ratio. C'est en quelque sorte un peu faux. L'interpolation n'arriverait que dans la première seconde de la scène. Le ration doit avoir comme valeur 0 &lt;  ratio&lt; 1.</div>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id2978"  title="Stocker une liste d'objets qui peut grandir">Stocker une liste d'objets qui peut grandir</span><div id="target-id2978" class="collapseomatic_content "></p>
<h3>Stocker une liste d'objets qui peut grandir</h3>
<div class="alert red">N'utilisez pas Array, ArrayList et HashTable - toujours utiliser une des collections génériques de .NET ou les tableaux "Built-in". Les collections vieilles versions inpliquent beaucoup plus de codes pour obtenir l'objet souhaité. Les collections génériques retirent ce problème mais peuvent aussi contenir toutes sortes d'objets.</div>
<div class="alert green">Les tableaux Built-in comme int[100], sont les collections les plus rapides et les plus efficaces, cependant leur taille est fixe. Ils sont parfaits si la taille du tableau n'a pas besoin d'être modifiée.</div>
<p>En C# il vous faut ajouter en haut de page:</p>
<div>
<div id="highlighter_795023">
<pre class="brush: csharp; gutter: true; first-line: 1">using System.Collections.Generic;</pre>
</div>
</div>
<p>UnityScript n'a besoin de rien.</p>
<p>Au lieu d'utliser Array ou ArraList, utiliser les List génériques. Avec les Lists, vous pouvez ajouter ou retirer des objets pendant l'execution, Lists continennent de nombreuses fonctions pour faciliter leur utilisation, telles que Sort pour arranger l'ordre. Elles peuvent aussi être changée en tableau si nécessaire.</p>
<div class="alert blue">Vous pouvez vous réferer à la documentation .NET pour <a href="http://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.90%29.aspx">List</a> et <a href="http://msdn.microsoft.com/en-us/library/xfhwa508%28v=vs.90%29.aspx">Dictionary</a> sur MSDN.  Quelques exmples en C# et UnityScript sont démontrés ci-dessous</div>
<p>Travailler avec une liste:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//Definir une liste avec UniyScript
var myList = new List.&lt;int&gt;();
var anotherList = new List.&lt;SomeClass&gt;();

//Definir une liste avec C#
List&lt;int&gt; myList = new List&lt;int&gt;();
List&lt;SomeClass&gt; anotherList = new List&lt;SomeClass&gt;();

//Ajouter un élément à une liste
myList.Add(someValue);

//Ajouter de multiples éléments à la liste
myList.AddRange(someListOrArrayOfValues);

//Vider la liste
myList.Clear();

//Insérer dasn une liste
myList.Insert(1, someValue);

//Insérer de multiples éléments
myList.InsertRange(1, someListOrArrayOfValues);

//Retirer un élément en particulier
myList.Remove(someValue);

//Retirer à un index
myList.RemoveAt(1);

//Trouver l'index d'un élément
var index = myList.IndexOf(someValue);

//Trouver l'index d'un éleément avec une fonction en UnityScript
var index = anotherList.FindIndex(function(entry) entry.someValue == something);

//Faire un tableau avec une liste
var myArray = myList.ToArray();

//Trouver l'index d'un objet avec une fonction en C#
var index = anotherList.FindIndex((entry) =&gt; entry.someValue == something)

//Taille de la liste (nombre d'éléments)
var itemCount = myList.Count</pre>
<p>Les dictionnaires sont les tableaux associatifs génériques de .NET:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">//Définir un dictionnaire de string pour integer en UnityScript
var myDic = new Dictionary.&lt;String, int&gt;();

//Définir un dictionnaire de GameObject pour classe in UnityScript
var anotherDic = new Dictionary.&lt;GameObject, SomeClass&gt;();

//String pour int den C#
Dictionary&lt;string, int&gt; myDic = new Dictionary&lt;string, int&gt;();

//GameObejct pour classe en C#
Dictionary&lt;GameObject, SomeClass&gt; anotherDic = new Dictionary&lt;GameObject, SomeClass&gt;();

//Ajouter un élément
myDic["Something"] = someIntValue;

//Obtenir une valeur
var someValue = myDic["Something"];

//Obtenir une valeur complexe et modifier ses attributs
anotherDic[gameObject].someProperty = someValue;

//Vérifier si une valeur existe
if(myDic.ContainsKey("Something")) { }

//Retirer un élément
myDic.Remove("Something');

//Iteration de chaque clé en UnityScript
for(var key : String in myDic.Keys) { }

//Iteration de chaque valeur en C#
foreach(int value in myDic.Values) { }

//Vider le dictionnaire
myDic.Clear();

//Nombre de valeurs
var count = myDic.Count;</pre>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id2146"  title="Comment bouger un rigidbody">Comment bouger un rigidbody</span><div id="target-id2146" class="collapseomatic_content "></p>
<p>La physique est votre ami, elle vous fera beaucoup de bien alors il vous faut bien en prendre soin!</p>
<div class="alert green">Si vous utilisez le systême de physique de Unity, il est recommandé d'utiliser AddForce ou les fonctions similaires pour déplacer le rigidbody si il ne sont pas désignés comme isKinematic</div>
<div class="alert 5">Si vous déplacez les rigidbody vous même, vous devez le faire dans la FixedUpdate, cependant il vous tout de mëme vous attendre á des surprises tel que des forces étonnament grandes ou petites appliqués à des objets. Vous ne pouvez pas utiliser Input dans la FixedUpdate. Jetez un oeil à la partie sur Détecter l'Input convenablement sur cette même page.</div>
<div class="alert yellow">Ne changez pas la gravité ou timeScale, si un objet semble bouger trop vite outrop lentement, c'est surement un problème de taille ou de distance par rapport à la caméra. Si vous essayez de modifier la gravité de gérer le problème, vous ferez surement face à d'autres problèmes ulterieurement. Si vous débutez, changez plutot la taille (scale) et les proportions</div>
<div class="alert green "> Utilisez une taille réaliste pour vos objets, pensez que 1 unités dans Unity représente 1m. Ce n'est pas un règle juste une convention mais respectez la.  Une personne fait 1.7 m, une voiture fait  3.5 m de long etc etc. Chaque objet avec la bonne taille, la caméra placée convenablement et vous serez surement déjà à moitié fixé.  Si vous avez un doute, il vous suffit de vous réferer au monde réel.</p>
<p>Si votre balle semble tomber trop vite, a-t-elle la taille d'un berlon (ou une bille)? Essaeyez de faire tomber un berlon sur votre table, vous verrez que ça va vite. Pour un effet plus "flottant", il vous faut une balle bien plus grosse et lus loin de la caméra.</div>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id6593"  title="Le Character Controller, à quoi donc que ça sert? ">Le Character Controller, à quoi donc que ça sert? </span><div id="target-id6593" class="collapseomatic_content "></p>
<h2>Le Character Controller, à quoi donc que ça sert?</h2>
<p>Le Character Controller peut être utilisé pour le joueur et les NPC (personnages IA). Le bon point c'est que le CC prend en charge des mesures et des logiques qui seraient compliquées de coder soi-même. Par exemple, bouger sur une plate-forme ou entrer en collision avec l'environement et les autres personnages.</p>
<div class="alert yellow">Oubliez le CC si vous voulez appliquer des contraintes physiques à votre personnage. Privilégiez un script personnalisé. avec un rigidbody.</div>
<p>De nombreaux jeux, n'utilisent pas le CC, alors assurez-vous que ce soit bien ce dont vous avez besoin et si vous d´cidez de l'utiliser, réservez le pour les objets qui en ont besoin (Pas de CC pour une voiture par exemple).</p>
<div class="alert blue">Le CC peut interagir avec les éléments de l'environement, comme les pousser hors de votre chemin. Il vous faudra faire cela par script et le résultat n'est pas garantit de paraître réalistique puisque il y a "conflit" avec le système de Physique. <a href="http://docs.unity3d.com/Documentation/ScriptReference/CharacterController.OnControllerColliderHit.html">Voyez cet exemple</a>.</div>
<div class="alert yellow">CC n'a pas de rigidbody par défaut et donc OnCollisionXXXX et OnTriggerXXXX ne fonctioneront pas par défaut. Il vous faut ajouter un rigidbody kinematic ou utliser <a href="http://docs.unity3d.com/Documentation/ScriptReference/CharacterController.OnControllerColliderHit.html">OnControllerColliderHit</a>.</div>
<div class="alert yellow">Toujours utiliser les fonctions  SimpleMove ou Move pour déplacer un objet avec un CC. Ne pas changer la position directement.</div>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id9649"  title="Vous pensez programmez en Java ou Javascript">Vous pensez programmez en Java ou Javascript</span><div id="target-id9649" class="collapseomatic_content "></p>
<h2>Vous pensez programmez en Java ou Javascript</h2>
<div class="alert red">Dans le but de légèrement faire oublier la confusion, le terme UnityScript a été utilisé sur cette page.</p>
<p>Tout d'abord, Unity dit utiliser Javascript. Javascript n'est pas Java et ne partage que peu ou pas de fonctionalités.Au départ, Javascript (la langage browser) se nommait LiveScript. Java était (et est encore) populaire à cette époque, alors il fut renommé JavaScript  </div>
<div class="alert green">Si vous êtes familier avec Java, C# partage plus de fonctionalités que UnityScript. Il existe de nombreux tutoriels pour transiter de Java vers C#, C# sur Unity est C#. C'est donc tout à fait applicable au Unity C#.</div>
<div class="alert yellow ">Unity JavaScript n'est pas JavaScript pour internet. De nombreaux utlisateurs (nous)  le nomme Unity Script pour marquer la différence.  JavaScript/UnityScript sur Unityest un langage .NETplus proche d' Action Script que JavaScript.  Certaines particularités de JavaScript peuvent se retrouver sur UnityScript, mais de nombreuses manquent. Par exemple, UnityScript utilise l'héritage classique alors que Javascript utilise l'héritage prototype, il n'est pas possible d'ajouter des fonctions à un objet après compilation avec UnityScript et ça continue comme ça pour un moment.</div>
<div class="alert red">Quoi qu'il advienne, jamais ôh grand jamais un tutoriel de Javascript internet vous permettra de programmer sur Unity. Cela ne ferait qu'amplifier la confusion. Faîtes comme moi, utilisez le terme UnityScript pour que les nouveaux venus ne fassent pas l'erreur.</div>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id1690"  title="La coroutine ne semble pas s'arrêter après le yield ou wait">La coroutine ne semble pas s'arrêter après le yield ou wait</span><div id="target-id1690" class="collapseomatic_content "></p>
<h2>La coroutine ne semble pas s'arrêter après le yield ou wait</h2>
<p>Cela arrive souvent lorsque vous desactiver le script qui contient la coroutine ou détruit l'objet qui contenait le script qui contenait la coroutine. SOuvent, lorsque un objet meurt, on lance une coroutine ou appelle Invoke pour que quelque chose se fasse après l'animation de mort, une mise à jour des scores ou quelconque autre processus de retard.</p>
<div class="alert yellow">Une coroutine executera toujours la partie se trouvant avant le yield. Si le script est désactivé ou détruit alors le reste de la fonciton ne sera jamais executée.</div>
<div class="alert yellow">Si vous utilisez WaitForSeconds, Time.timeScale ne peut pas être 0 sinon rien ne bouge. WaitForSeconds utilise l'horloge du jeu qui est régit par timeScale. Si timeScale est 0, tout s'arrête.</div>
<div class="alert green">Les coroutines s'executent sur l'objet qui contient l'appel de  StartCoroutine (pour C#). Donc si vous faites l'appel depuis un autre objet, il est logique de faire l'appel de StartCoroutine sur cet objet. Un exemple va clarifier: <em>otherScript.StartCoroutine(otherScript.SomeFunction());</em></div>
<p>Pas bien:</p>
<pre>void Update() {
    if(health &lt; 0) {
           StartCoroutine(Die());
           Destroy(gameObject); //ou enabled = false;
    }
}

IEnumerator Die() {
       animation.Play("wobble");
       yield return new WaitForSeconds(3);
       //Cela n'arrivera jamais
       animation.Play("meurir");
}</pre>
<p>Bien:</p>
<pre>bool estMort;
void Update() {
     if(estMort) return;
     if(health &lt; 0) {
         StartCoroutine(Meurt());
     }
}

IEnumerator Meurt() {
      estMort = true;
      animation.Play("wobble");
      yield return new WaitForSeconds(3);
      animation.Play("meurir");
      yield return new WaitForSeconds(3);
      Destroy(gameObject);
}</pre>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id1213"  title="Accéder un script en C# avec UnityScript et inverse">Accéder un script en C# avec UnityScript et inverse</span><div id="target-id1213" class="collapseomatic_content "></p>
<h2>Accéder un script en C# avec UnityScript et inverse</h2>
<div class="alert yellow"> L'accession ne peut se faire que dans un seul sens depuis l'un vers l'autre mais pas dans l'autre sens (l'autre ne peut pas voir l'un). Deux classes écrites en différents langages ne pourront jamais se voir dans les deux sens.</div>
<div class="alert green">Choisissez un langage pour votre programme. SI vous utilisez un script d'un tierce parti, le lagage a peu d'importance tant que vous faites le nécessaire. Il vous suffit de placer le script dans un fichier qui est compilé en premier - Standard Asset, Pro Standard Asset ou Plugins, alors il vous est possible d'accéder à ces fichiers à partir de classes stockées dans un fichier compilé ulterieurement. </div>
<p>UnityScript et C# ne sont pas compilés avec le même assembleur, c'est pourquoi il n'est pas possible de simplement accéder un fichier via un autre puisque les deux langages ne se comprennent pas. Un script placé dans Plugins, Standard Asset ou Pro Standard Asset est compilé en premier en IL (Intermediate Language). IL est le langage assembleur de .NET. De nombreux langages peuvent utiliser .NET et se mêler parce qu'en bout de chaîne, tout le monde se retrouve convertit en un langage commun. Une fois les scripts compilés, les autre scripts placés dans d'autres fichiers peuvent y accéder.</p>
<p>Ainsi, un script en C# peut accéder un script en UnityScript si ce dernier est placé dans un des fichiers Standard Asset, Pro Standard Asset ou Plugins (ou n'importe quel fichier sous leur hiérarchie).  Et ce la fonctionne aussi dans l'autre sens.</p>
<p>Gardez tête qu'un script en UnityScript placé dans un de ces fichiers spéciaux ne pourra voir un script en C# où qu'il soit et vice-versa. La hiérarchie fait que si un script est placé dans un fichier spécial, il peut voir les autres scripts de même langage placés en dessous (compilés ultérieurement) mais ne peut voir aucun script de l'autre langage. Par logique, on retombe dans le même problême de départ. C'est pour cela qu'il vous faut éviter autant que faire se peut (rooh le langage!!) de mélanger les langages et essayer de tout faire en un seul (autant que faire se peut).</p>
<div class="alert blue">Unity propose une bonne documentation sur l'ordre de compilation des scripts <a href="http://docs.unity3d.com/Documentation/ScriptReference/index.Script_compilation_28Advanced29.html">ici</a>.</div>
<p></div></p>
<p><br clear="none" /><span class="collapseomatic " id="id2056"  title="Modifier la rotation d'un objet avec Quaternion">Modifier la rotation d'un objet avec Quaternion</span><div id="target-id2056" class="collapseomatic_content "></p>
<div>
<div>
<h2>Modifier la rotation d'un objet avec Quaternion</h2>
<div class="alert red"> Les paramètres x, y, z et w d'un quaternion n'ont rien à voir avec les valeurs qui sont affichées dans l'inspecteur pour la rotation de l'objet. Un quaternion n'est pas stocké en degrés mais en sinus et cosinus d'angles. La rotation en degrés est stockée dans la variable .eulerAngles de la rotation.</p>
<p>Évitez (ne faites pas) de modifer x, y, z, et w d'un quaternion sauf dans le cas peu probable où vous savez exactement ce que vous faites. Si vous souhaitez modifer une rotation par degrés, utilisez .eulerAngles. </div>
<p>Si vous souhaitez en savoir plus sur les quaternions, tout d'abord bonne chance, c'est un sujet lourd qui laisse nombre de programmeurs sur le carreau. Vous pouvez toujours en savoir un peu plus en lisant <a title="Quaternions &amp; Rotations Part 1 – C#" href="../quaternions-rotations-part-1-c/">ce tutoriel</a>.</p>
<p>Voici comment définir une rotation avec un ensemble d'angles:</p>
<pre>transform.rotation.eulerAngles = new Vector3(100,0,100);</pre>
<p></div></p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/traquenards-unity/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Weak Associations &#8211; Leak Free Extension Properties</title>
		<link>http://unitygems.com/weak-associations-leak-free-extension-properties/</link>
		<comments>http://unitygems.com/weak-associations-leak-free-extension-properties/#comments</comments>
		<pubDate>Sat, 17 Nov 2012 02:31:54 +0000</pubDate>
		<dc:creator>whydoidoit</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[AnimationState]]></category>
		<category><![CDATA[Extension Properties]]></category>
		<category><![CDATA[RPC]]></category>
		<category><![CDATA[Serialization]]></category>
		<category><![CDATA[WeakReferece]]></category>
		<category><![CDATA[WeakTable]]></category>

		<guid isPermaLink="false">http://unitygems.com/?p=1458</guid>
		<description><![CDATA[<p>Motivation You should read this article if: You&#8217;d like to send AnimationStates over the network (including mixing transforms) You&#8217;d like to know how to imbue any object with new properties without leaking memory You&#8217;d like to learn more about garbage collection and weak references Introduction One of the perennial problems with Unity is that the &#8230;<br /><a class="excerpt" href="http://unitygems.com/weak-associations-leak-free-extension-properties/">Read More</a></p>
]]></description>
				<content:encoded><![CDATA[<h2>Motivation</h2>
<p>You should read this article if:</p>
<ul>
<li>You'd like to send AnimationStates over the network (including mixing transforms)</li>
<li>You'd like to know how to imbue any object with new properties without leaking memory</li>
<li>You'd like to learn more about garbage collection and weak references</li>
</ul>
<h2>Introduction</h2>
<p>One of the perennial problems with Unity is that the back end is C++ and our coding interface is .NET.  The guys have done a great job but there are places where you just can't get to the values you need.  One classic example is Mixing Transforms that you add to animations to make them only play on part of the character.  You can add them and you can remove them, but only if you know what they are. In many circumstances you can find yourself adding mixing transforms in one piece of code and then needing to know what they are, perhaps to send them via an RPC call or to remove them, in a different function.</p>
<p>You could jump through hoops trying to solve that problem - having to store and manage a lot of new variables and classes to keep track of the information - and who knows when that object will be destroyed?  How will you free your memory? Will you lock the object forever and leak?  Quite possibly.</p>
<div class="alert green">This article covers the creation of a method of associating a class with any other object and to have that class only live while the object itself is alive.  It's very easy to use:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">public class Extra
{
    public int anyVariablesYouLike;
}

...

anyObject.Get&lt;Extra&gt;().anyVariablesYouLike = 1;</pre>
<p class="brush: csharp; gutter: true; first-line: 1"> </div>
<h2>A First Association - Animation Mixing</h2>
<p>Ok so lets have a look at a basic way we could associate data with the <em>AnimationState</em> we want to mix - we could build a little helper class that allowed us to key objects off other objects:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">public static class Extensions
{
    //Dictionary to hold our extensions
    static Dictionary&lt;object, Dictionary&lt;Type, object&gt;&gt; _extensions = new Dictionary&lt;object, Dictionary&lt;Type, object&gt;&gt;();

    //Get an associated extension class
    public static T Get&lt;T&gt;(this object o) where T : class, new()
    {
         //Do we have this object yet?
         if(!_extensions.ContainsKey(o))
         {
             //If not then add it
             _extensions[o] = new Dictionary&lt;Type, object&gt;();
         }
         //Do we have this associate type yet?
         if(!_extensions[o].ContainsKey(typeof(T)))
         {
             //If not create a new one
             _extensions[o][typeof(T)] = new T();
         }
         //Return the associate
         return _extensions[o][typeof(T)];

    }
}</pre>
<p class="brush: csharp; gutter: true; first-line: 1">Ok so with that class we can do <em>anyObject.Get&lt;AnyClass&gt;()</em> and it will give us an instance of that class!  The Dictionaries are giving us O(1) lookup so it should be very fast.  So we want to associate transforms with animations states, let's make up a class to do that.  We will use the names of the transforms so that we can find them on another computer if we send them via RPC.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">	public class Mixing
	{
		public List&lt;string&gt; transforms = new List&lt;string&gt;();
	}</pre>
<p class="brush: csharp; gutter: true; first-line: 1"> Now lets add something to that class, using our Get&lt;T&gt; helper function.</p>
<pre class="brush: csharp; gutter: true; first-line: 1">Transform spine2;

public void SwingSword()
{
    var state = animation["swingSword"];
    //We'd probably only do this if we were 
    //walking - but for ease I'm leaving out
    //any testing for that
    state.AddMixingTransform(spine2);
    //Get a Mixing instance for this animation state and add the
    //name of our new transform
    state.Get&lt;Mixing&gt;().transforms.Add(spine2.name);
    state.enabled = true;
    state.weight = 1;
}</pre>
<p class="brush: csharp; gutter: true; first-line: 1">Ok so that will associate our Mixing class with this particular animation  - let's look at how we might send AnimationStates by RPC to another player.</p>
<p class="brush: csharp; gutter: true; first-line: 1">We need a class suitable for RPC transmission that represents the AnimationState:</p>
<pre class="brush: csharp; gutter: true; first-line: 1;collapse:1;title:'StoredAnimationState class for RPC';toolbar:1">using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

/// &lt;summary&gt;
/// Stores the animation state for a character
/// &lt;/summary&gt;
public class StoredAnimationState
{
    /// &lt;summary&gt;
    /// The name of the animatoin
    /// &lt;/summary&gt;
    public string name;
    /// &lt;summary&gt;
    /// Is the animation enabled
    /// &lt;/summary&gt;
    public bool enabled;
    /// &lt;summary&gt;
    /// The current speed of the animation
    /// &lt;/summary&gt;
    public float speed;
    /// &lt;summary&gt;
    /// The current progress through the animation
    /// &lt;/summary&gt;
    public float time;
    /// &lt;summary&gt;
    /// The current weight of the animation
    /// &lt;/summary&gt;
    public float weight;
    /// &lt;summary&gt;
    /// The current blend mode of the animation
    /// &lt;/summary&gt;
    public AnimationBlendMode blendMode;
    /// &lt;summary&gt;
    /// The current layer of the animation
    /// &lt;/summary&gt;
    public int layer;
    /// &lt;summary&gt;
    /// The current wrap mode of the animation
    /// &lt;/summary&gt;
    public WrapMode wrapMode;
    /// &lt;summary&gt;
    /// The list of current mixing transforms for the animation
    /// &lt;/summary&gt;
    public List&lt;string&gt; mixingTransforms = new List&lt;string&gt;();

    public override int GetHashCode()
    {
        return name.GetHashCode() ^ weight.GetHashCode();
    }

    public override bool Equals (object obj)
    {
        if(!(obj is StoredAnimationState))
            return false;
        var other = (StoredAnimationState) obj;
        return name == other.name &amp;&amp; enabled == other.enabled &amp;&amp;
               Math.Abs(speed - other.speed) &lt; Single.Epsilon &amp;&amp; Math.Abs(weight - other.weight) &lt; Single.Epsilon &amp;&amp;
               blendMode == other.blendMode &amp;&amp; 
               layer == other.layer &amp;&amp;
               wrapMode == other.wrapMode &amp;&amp;
               mixingTransforms.Count == other.mixingTransforms.Count;

    }

    public StoredAnimationState()
    {
    }

    //Configure from an animation	
    public StoredAnimationState(AnimationState state)
    {
        name = state.name;
        enabled = state.enabled;
        speed = state.speed;
        time = state.time;
        weight = state.weight;
        blendMode = state.blendMode;
        layer = state.layer;
        wrapMode = state.wrapMode;
        mixingTransforms = state.Get&lt;Mixing&gt;().transforms;
    }

    /// &lt;summary&gt;
    /// Configure an existing animation state from the information in this transfer class
    /// &lt;/summary&gt;
    /// &lt;param name="animation"&gt;&lt;/param&gt;
    public void Set(Animation animation)
    {
        var anim = animation[name];
        //Do our mixing transform match?
        //First check if we have the same number, if they match then check
        //the names
        if(anim.Get&lt;Mixing&gt;().transforms.Count != mixingTransforms.Count || !anim.Get&lt;Mixing&gt;().transforms.All(mixingTransforms.Contains))
        {
            //Remove all of the existing mixings
            foreach(var m in anim.Get&lt;Mixing&gt;().transforms)
            {
                anim.RemoveMixingTransform(animation.transform.Find(m));
            }
            //Update the list
            anim.Get&lt;Mixing&gt;().transforms = mixingTransforms;
            //Apply the new mixings
            foreach(var m in mixingTransforms)
            {
                anim.AddMixingTransform(animation.transform.Find(m), true);
            }

        }
        //Apply other variables
        anim.enabled = enabled;
        anim.weight = weight;
        anim.speed = speed;
        if(Mathf.Abs(anim.time - time) &gt; 1)
            anim.time = time;
        anim.blendMode = blendMode;
        anim.layer = layer;
        anim.wrapMode = wrapMode;
    }

    /// &lt;summary&gt;
    /// Class to transfer a list of animation states
    /// &lt;/summary&gt;
    public class AnimationTransfer
    {
        /// &lt;summary&gt;
        /// The animation state to be transferred
        /// &lt;/summary&gt;
        public List&lt;StoredAnimation&gt; StoredAnimations;
        /// &lt;summary&gt;
        /// The representation of an animation state
        /// &lt;/summary&gt;
        public class StoredAnimation
        {
            /// &lt;summary&gt;
            /// The name of the animation
            /// &lt;/summary&gt;
            public string name;
            /// &lt;summary&gt;
            /// The data for the stored state of the animation
            /// &lt;/summary&gt;
            public StoredAnimationState data;
        }
    }
}</pre>
<p class="brush: csharp; gutter: true; first-line: 1">Ok, so that's quite a lot of code - we've basically made a class that can represent an animation state, suitable for serialization.  It also knows how to apply itself back onto an animation.</p>
<p class="brush: csharp; gutter: true; first-line: 1">Let's look at how we could send that to the other players:</p>
<pre class="brush: csharp; gutter: true; first-line: 1">public void SendAnimations()
{
      //Create a transfer structure
      var transfer = new StoredAnimationState.AnimationTransfer();
      //Create the list of stored animations
      transfer.StoredAnimations = 
         //All of the states in the current list
         animation.Cast&lt;AnimationState&gt;()
            //Only when enabled
            .Where(state=&gt;state.enabled)
            //Create a stored animation
            .Select(state=&gt;new StoredAnimationState.AnimationTransfer.StoredAnimation
                   { 
                        //Animation name
                        name = state.name, 
                        //Animation data
                        data = new StoredAnimationState(state) 
                   })
            .ToList();   
       //Serialize the data
       var m = new MemoryStream();
       var b = new BinaryFormatter();
       b.Serialize(transfer, m);
       //Send it
       networkView.RPC("ReceiveAnimations", RPCMode.Others, m.ToArray());

}

[RPC]
void ReceiveAnimations(byte[] data)
{
     //Get the transfer structure
     var m = new MemoryStream(data);
     var b = new BinaryFormatter();
     var transfer = (StoredAnimationState.AnimationTransfer)b.Deserialize(m);
     //Disable all animations (they will be re-enabled
     //if required)
     foreach(var state in animation.Cast&lt;AnimationState&gt;())
        state.enabled = false;
     //Set up all of the animations from the
     //transfer
     foreach(var state in transfer.StoredAnimations)
         state.data.Set(animation);
}</pre>
<h2 class="brush: csharp; gutter: true; first-line: 1">It Leaks Like a Sieve!!!</h2>
<p>Yep, sorry to tell you - but without forcibly removing things from our <em>_extensions</em> Dictionary this code is sinking fast.  When you destroy the game objects, the memory won't be freed because we're holding on to those AnimationStates as keys in our Dictionary - if it happens a lot there will be vast memory usage.</p>
<h2>Ye of Little Faith</h2>
<p>I'm hoping that you don't think I've lead you down the garden path for no reason?  There is a way around this problem - but it's going to get techy.</p>
<p>What we need is to free our Mixing (or other extensions) when the <em>AnimationState </em>(or whatever the key is) is destroyed.  Of course they aren't getting destroyed because we're holding on to them.</p>
<h2>Weak References</h2>
<p>What we need to do first is to hold a weak reference to the <em>AnimationState </em>rather than a strong one.  .NET has the <em>WeakReference</em> type built in - so we can manage that.  Now two weak references to the same object are not going to have the same <em>hash code</em> - so we can't use them as the key in a Dictionary!  That's ok - all objects in .NET have a <em>GetHashCode</em> call that we can use to find out what it would be for our real key and use that instead.  It's an <em>int</em> by the way.</p>
<p>Genericising everthing we come up with a <em>WeakTable&lt;T&gt; </em>class that associates our objects.  We'll see this in a minute, for the moment we also need to remove our associates when the original key is garbage collected.</p>
<p>Its kind of hard to figure out when the Garbage Collector has run - but we can actually find out by creating some objects that have no references to them, and see when they are collected - using their <em>finalization</em> methods!  We borrow this from Jeff Richter:</p>
<pre class="brush: csharp; gutter: true; first-line: 1;collapse:1;toolbar:1;title:'Garbage Collection Notification Class'">//The following class is from:
//Jeff Richter - http://www.wintellect.com/CS/blogs/jeffreyr/archive/2009/12/22/receiving-notifications-garbage-collections-occur.aspx
public static class GCNotification {
   private static Action&lt;Int32&gt; s_gcDone = null; // The event’s field
   public static event Action&lt;Int32&gt; GCDone {
      add {
         // If there were no registered delegates before, start reporting notifications now 
         if (s_gcDone == null) { new GenObject(0); new GenObject(2); }
         s_gcDone += value;
      }
      remove { s_gcDone -= value; }
   }
   private sealed class GenObject {
      private Int32 m_generation;
      public GenObject(Int32 generation) { m_generation = generation; }
      ~GenObject() { // This is the Finalize method
         // If this object is in the generation we want (or higher), 
         // notify the delegates that a GC just completed
         if (GC.GetGeneration(this) &gt;= m_generation) {
	        //Thread safe get of the s_gcDone delegate - will not be interrupted
            Action&lt;Int32&gt; temp = Interlocked.CompareExchange(ref s_gcDone, null, null);
			//Fire the event
            if (temp != null) temp(m_generation);
         }
         // Keep reporting notifications if there is at least one delegate
         // registered, the AppDomain isn't unloading, and the process 
         // isn’t shutting down
         if ((s_gcDone != null) &amp;&amp; 
            !AppDomain.CurrentDomain.IsFinalizingForUnload() &amp;&amp; 
            !Environment.HasShutdownStarted) {
            // For Gen 0, create a new object; for Gen 2, resurrect the
            // object &amp; let the GC call Finalize again the next time Gen 2 is GC'd
            if (m_generation == 0) new GenObject(0);
            else GC.ReRegisterForFinalize(this);
         } else { /* Let the objects go away */ }
      }
   }
}</pre>
<p>This class creates a couple of objects with no references, waits for them to be <em>finalized</em> by the Garbage Collector and when that happens it fires a <em>GCDone</em> event.  We can use this event as a cue to decide to check whether our weak references are still valid, the ones that aren't need to have their associated objects removed...</p>
<p>The final <em>WeakTable&lt;T&gt;</em> and static extension method <em>Get&lt;T&gt;</em> look like this:</p>
<pre class="brush: csharp; gutter: true; first-line: 1;collapse:1;title:'Complete WeakTable&lt;T&gt;';toolbar:1">using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Threading;

/// &lt;summary&gt;
/// Weak entry for the table
/// &lt;/summary&gt;
class WeakEntry 
{
	/// &lt;summary&gt;
	/// The weak reference to the collectable object
	/// &lt;/summary&gt;
	public WeakReference weakReference;
	/// &lt;summary&gt;
	/// The associated object with the reference
	/// &lt;/summary&gt;
	public object associate;
}

/// &lt;summary&gt;
/// A weak table for a particular type of associated class
/// &lt;/summary&gt;
public class WeakTable&lt;T&gt; : IDisposable where T : class, new()
{

	//When finished we can dispose of the notification
	public void Dispose()
	{
		GCNotification.GCDone -= Collected;
	}

	/// &lt;summary&gt;
	/// The references held by the table
	/// &lt;/summary&gt;
	Dictionary&lt;int, List&lt;WeakEntry&gt;&gt; references = new Dictionary&lt;int, List&lt;WeakEntry&gt;&gt;();

	/// &lt;summary&gt;
	/// Gets an associated object give an index of another object
	/// &lt;/summary&gt;
	/// &lt;param name='index'&gt;
	/// The object to use as an index
	/// &lt;/param&gt;
	public T this[object index]
	{
		get
		{
			//Get the hash code of the indexed object
			var hash = index.GetHashCode();
			List&lt;WeakEntry&gt; entries;
			//Try to get a reference to it
			if(!references.TryGetValue(hash, out entries))
			{
				//If we failed then create a new entry
				references[hash] = entries = new List&lt;WeakEntry&gt;();
			}
			//Try to get an associated object of the right type for this
			//indexer/make sure it is still alive
			var item = entries.FirstOrDefault(e=&gt;e.weakReference.IsAlive &amp;&amp; e.weakReference.Target == index);
			//Check if we got one
			if(item == null) 
			{
				//If we didn't then create a new one
				entries.Add(item = new WeakEntry { weakReference = new WeakReference(index), associate = new T() });
			}
			//Return the associated object
			return (T)item.associate;
		}

	}

	/// &lt;summary&gt;
	/// Get an associate given an indexing object
	/// &lt;/summary&gt;
	/// &lt;param name='index'&gt;
	/// The object to find the associate for
	/// &lt;/param&gt;
	/// &lt;typeparam name='T2'&gt;
	/// The type of associate to find
	/// &lt;/typeparam&gt;
	public T2 Get&lt;T2&gt;(object index) where T2 : T, new()
	{
		//Get the hash code of the indexing object
		var hash = index.GetHashCode();
		List&lt;WeakEntry&gt; entries;
		//See if we have a reference already
		if(!references.TryGetValue(hash, out entries))
		{	
			//If not the create the reference list
			references[hash] = entries = new List&lt;WeakEntry&gt;();
		}
		//See if we have an object of the correct type and that the
		//reference is still alive
		var item = entries.FirstOrDefault(e=&gt;e.weakReference.IsAlive &amp;&amp; e.weakReference.Target == index &amp;&amp; e.associate is T2);
		if(item == null) 
		{
			//If not create one
			entries.Add(item = new WeakEntry { weakReference = new WeakReference(index), associate = new T2() });
		}
		//Return the associate
		return (T2)item.associate;
	}

	public WeakTable() 
	{
		//Setup garbage collection notification
		GCNotification.GCDone += Collected;
	}

	/// &lt;summary&gt;
	/// Called when the garbage has been collected
	/// &lt;/summary&gt;
	/// &lt;param name='generation'&gt;
	/// The generation that was collected
	/// &lt;/param&gt;
	void Collected(int generation)
	{
		//Remove the references which are no longer alive

		//Scan each reference list
		foreach(var p in references)
		{
			//Scan each item in the references and remove
			//items that are missing
			removeEntries.Clear();
			foreach(var r in p.Value.Where(r=&gt;!r.weakReference.IsAlive))
				removeEntries.Add(r);
			foreach(var entry in removeEntries)
			{
				if(entry.associate is IDisposable)
					(entry.associate as IDisposable).Dispose();                      
				p.Value.Remove(entry);
			}
		}
	}

	List&lt;WeakEntry&gt; removeEntries = new List&lt;WeakEntry&gt;();

}

/// &lt;summary&gt;
/// Extension class to support getting weak tables easily
/// &lt;/summary&gt;
public static class Extension
{
	static Dictionary&lt;Type, WeakTable&lt;object&gt;&gt; extensions = new Dictionary&lt;Type, WeakTable&lt;object&gt;&gt;();

	/// &lt;summary&gt;
	/// Get an associate for a particular object
	/// &lt;/summary&gt;
	/// &lt;param name='reference'&gt;
	/// The object whose associate should be found
	/// &lt;/param&gt;
	/// &lt;param name='create'&gt;
	/// Whether the associate should be created (defaults true)
	/// &lt;/param&gt;
	/// &lt;typeparam name='T'&gt;
	/// The type of associate
	/// &lt;/typeparam&gt;
	public static T Get&lt;T&gt;(this object reference, bool create = true) where T : class, new()
	{
		WeakTable&lt;object&gt; references;
		//Try to get a weaktable for the reference object
		if(!extensions.TryGetValue(reference.GetType(), out references))
		{
			//Verify that we should be creating it if missing
			if(!create)
				return null;
			//Create a new table
			extensions[reference.GetType()] = references = new WeakTable&lt;object&gt;();
		}
		//Get the associate from the table
		return (T)references.Get&lt;T&gt;(reference);
	}

}

//The following class is from:
//Jeff Richter - http://www.wintellect.com/CS/blogs/jeffreyr/archive/2009/12/22/receiving-notifications-garbage-collections-occur.aspx
public static class GCNotification {
   private static Action&lt;Int32&gt; s_gcDone = null; // The event’s field
   public static event Action&lt;Int32&gt; GCDone {
      add {
         // If there were no registered delegates before, start reporting notifications now 
         if (s_gcDone == null) { new GenObject(0); new GenObject(2); }
         s_gcDone += value;
      }
      remove { s_gcDone -= value; }
   }
   private sealed class GenObject {
      private Int32 m_generation;
      public GenObject(Int32 generation) { m_generation = generation; }
      ~GenObject() { // This is the Finalize method
         // If this object is in the generation we want (or higher), 
         // notify the delegates that a GC just completed
         if (GC.GetGeneration(this) &gt;= m_generation) {
			//Thread safe get of the s_gcDone delegate - will not be interrupted
            Action&lt;Int32&gt; temp = Interlocked.CompareExchange(ref s_gcDone, null, null);
			//Fire the event
            if (temp != null) temp(m_generation);
         }
         // Keep reporting notifications if there is at least one delegate
         // registered, the AppDomain isn't unloading, and the process 
         // isn’t shutting down
         if ((s_gcDone != null) &amp;&amp; 
            !AppDomain.CurrentDomain.IsFinalizingForUnload() &amp;&amp; 
            !Environment.HasShutdownStarted) {
            // For Gen 0, create a new object; for Gen 2, resurrect the
            // object &amp; let the GC call Finalize again the next time Gen 2 is GC'd
            if (m_generation == 0) new GenObject(0);
            else GC.ReRegisterForFinalize(this);
         } else { /* Let the objects go away */ }
      }
   }
}</pre>
<p class="brush: csharp; gutter: true; first-line: 1">Just note that we have had to switch around our Dictionary definition to use the type of the reference first, that's so we can get a WeakTable that knows about those references.</p>
<p class="brush: csharp; gutter: true; first-line: 1">When we are finished with the associated classes we call <em>IDisposable.Dispose </em>on them in case they want to know that they are finished with.</p>
<h2 class="brush: csharp; gutter: true; first-line: 1">Conclusion</h2>
<p>This has been a pretty techy article, hopefully it makes some sense!  You should be able to see how associating a class of our own devising with something we don't control the lifetime of (like an <em>AnimationState</em>) is a powerful technique. <em><strong>Enjoy!</strong></em></p>
]]></content:encoded>
			<wfw:commentRss>http://unitygems.com/weak-associations-leak-free-extension-properties/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 1.695 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2013-05-26 08:35:36 -->
