vendredi 18 mai 2012

Attention au thread dans Unity 3D.

Hier, j'ai passé une partie de la journée à chercher une faute dans un de mes codes. Le message d'erreur était le suivant: get_transform can only be called from the main thread. Constructors and field initializers will be executed from the loading thread when loading a scene. Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function. Après bien des recherches et des modifications inutiles, j'ai trouvé le coupable: System.Timers. Voici un code bien simple qui reproduit l'erreur ci-dessus:
using UnityEngine;
using System.Collections;
using System.Timers;

public class DemoTimer : MonoBehaviour
{
 private Timer _timer;
 
 void Start ()
 {
  this._timer = new Timer( 5 );
  this._timer.Elapsed += new ElapsedEventHandler( OnTimeEvent);
  this._timer.Start();
 }
 
 void OnTimeEvent( object sender, ElapsedEventArgs e )
 {
  //L'erreur se produit ici.
  this.transform.position = new Vector3(0,0,0); 
 }
  
}
Pourquoi ce code est fautif? Voici la raison. Unity utilise un seul thread. Un thread (http://fr.wikipedia.org/wiki/Thread_%28informatique%29) est un processus indépendant. Le timer crée un nouveau thread. Lorsque l'intervalle de temps est écoulé, la fonction OnTimeEvent est appelée dans le thread du timer. L'object this est créé dans le thread d'Unity. Lorsque j'écris
this.transform.position = new Vector3(0,0,0);
je tente d'accéder à un object qui vie dans un autre thread. Le thread timer ne sait pas quoi faire avec l'object this et me retourne une erreur. En règle générale, il est préférable de ne pas utiliser de thread avec Unity. L'engin de jeu Unity n'est pas thread safe. L'alternative à System.Timers dans Unity est d'utiliser une coroutine comme suit:
public class DemoTimer : MonoBehaviour
{
 void Start ()
 {
  StartCoroutine(this.OnTimeEvent()); 
 }
 
 IEnumerator OnTimeEvent()
 {
     yield return new WaitForSeconds(1);
  
  Debug.Log("Tic");
  this.transform.position = new Vector3(0,0,0);
 }
}

2 commentaires: