vendredi 21 décembre 2012

Lister tous les component d'un objet


//Lister les components d'un objet
GameObject g = GameObject.Find("myObj");
Component[] objs = g.GetComponents(typeof(Component));
for (int i = 0; i < objs.Length; ++i)
{
Debug.Log(i+"-----"+objs[i]);
}


vendredi 14 décembre 2012

Floor & Object picking


Routine de picking au sol simple et pratique:

static Plane floor = new Plane(Vector3.up, Vector3.zero);
static public bool TouchFloorPick(Vector2 touchPos, out Vector3 hitPoint)
{
float dist = 5000f;
Ray ray = mCam.ScreenPointToRay(new Vector3(touchPos.x, touchPos.y, 0));
float enter = 0.0f;
floor.Raycast(ray, out enter);
if (enter > 0.0f && enter <= dist)
{
hitPoint = ray.GetPoint(enter);
return true;
}
hitPoint = Vector3.zero;
return false;
}




Routine de picking sur object:


static public bool TouchObjectPick(Vector2 touchPos, out RaycastHit hit)
{
RaycastHit[] hits;
float dist = 50000f;

Ray ray = mCam.ScreenPointToRay(new Vector3(touchPos.x, touchPos.y, 0));
hits = Physics.RaycastAll(ray.origin, ray.direction, dist);
if (hits.Length>0)
{
hit = hits[0];
return true;
}
hit = new RaycastHit();
return false;
}

mercredi 5 décembre 2012

Acceder aux Settings iOS d'une application via Unity

On peut sous xCode ajouter des settings à une application qui seront accessibles dans le panel Settings du device.
Ca peut etre un moyen interessant pour permettre à l'utilisateur de configurer ou regler l'application sans prevoir un menu specifique dans celle-ci.

Pour avoir un panneau de Settings associée à l'application:
Sous Xcode "New File..."->"Resource/Settings Bundle"
Ca rajoute un fichier Settings.Bundle dans le projet.
Editer le fichier Root.plist qui s'y trouve.
Rajouter un TextFiled dans la section "Preference Items", donnez lui un identifier (exemple MyVar).
Ensuite dans unity vous pouvez acceder à ce parametre simplement avec les PlayerPrefs ainsi:
PlayerPrefs.GetString("MyVar")

Notez qu'il semble tout de meme qu'il faille aller modifier la valeur de ce textfield sur le device afin que ca soit pris en compte par Unity, mais cela ne pose pas trop de problemes si on utilise une valeur par defaut.

Maintenant il faudrait utiliser le systeme de PostProcessBuildPlayer dans Unity afin que de lui meme il insere ce fichier Settings.Bundle dans le projet xCode lors de la compilation.
Si je me penche la dessus je mettrais le code de ce PostProcessBuildPlayer.

lundi 5 mars 2012

Trouver une methode par son nom (Reflection C#)

Grace à la lib Reflection de .Net il est possible de retrouver une methode par son nom et de l'appeller.

Les lib à utiliser:
using System;
using System.Reflection;

Stocker la classe:
Type maClasse = typeof(MyClass);

Avoir le nom de la classe:
maClasse.Name;

Retrouver toutes les methodes de la classe (ici on ne cherche que les methodes static public):
MethodInfo[] myArrayMethodInfo = maClasse.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
for (int i=0; i< myArrayMethodInfo.Length; i++)
Debug.Log(""+myArrayMethodInfo[i].Name);

Retrouver une methode par son nom et l'executer (ici la fonction est censée renvoyer une string):
MethodInfo method = maClasse.GetMethod("GetName");
if (method!=null) Debug.Log(method.Invoke(null, null).ToString());

Retrouver le nom de la fonction en cours d'execution:
object method = System.Reflection.MethodBase.GetCurrentMethod();
Debug.Log(method.ToString());


On peut faire pas mal d'autres choses tres interessantes avec cette lib.



lundi 20 février 2012

Comprendre les ratios iPhone/iPad

C'est un peu hors sujet, mais voici juste un petit schéma pour comprendre la problématique des ratios entre iPhone et iPad lorsqu'on souhaite designer une UI compatible avec ces 2 devices.

Dans le 1er cas on design l'UI au format iPad (1024*768) et on l'adapte ensuite à l'iphone.
Dans le 2eme cas on design l'UI au format iPhone (960*640) et on l'adapte ensuite à l'ipad.




Les callback (delegate) en C#

C'est assez simple.
On declare un type delegate ainsi (ici le callback aura 2 parametres):
public delegate void CommandCallbackType(int a, float b);

On a quelque part une fonction (ici statique mais pas obligatoire) de prototype identique.
public static void OnCommand(int a, float b)
{
...traitements...
}

On stocke notre callbak ainsi:
public CommandCallbackType mCallback = new CommandCallbackType(OnCommand);

On peut ensuite appeller le callback de cette maniere:
mCallback (1, 2.5f);

vendredi 17 février 2012

Lancer plusieurs instances d'Unity en meme temps

Quand on essai d'ouvrir Unity plus d'une fois celui-ci refuse de le faire.
La raison est simple, il ne veut pas que l'on puisse ouvrir plus d'une fois le même projet.
Malheureusement des qu'on lance Unity il essaye d'ouvrir par defaut le dernier projet utilisé.


La solution consiste tout simplement à spécifier à Unity quel projet charger, cela se fait grace aux parametres de ligne de commandes d'Unity.
Sous Windows il faut dupliquer le raccourcit Unity et modifier la commande ainsi:
"C:\Program Files (x86)\Unity\Editor\Unity.exe" -projectPath "D:\Dev\MonProjet"






Pour info, les parametres de ligne de commande d'unity:
http://unity3d.com/support/documentation/Manual/Command%20Line%20Arguments.html

samedi 14 janvier 2012

GUI Multi-Resolution & Bandes noires

Voici une technique que l'on peut utiliser afin de fabriquer une GUI qui soit valide quelque soit la résolution et le ratio, ce qui permet de faire des applications compatibles web/ios/android sans avoir trop à gerer les différences de ratio entre toutes les résolutions possibles (surtout pour Android).

Tout d'abord il faut choisir une resolution "idéale" dans laquelle il faut designer toute la gui (prendre de preference la résolution la plus élevée parmis toutes celles que vous souhaitez supporter).
Pour l'exemple 1024*768

On va utiliser une classe qui va tracer des bandes noires sur les cotés Gauche/Droite ou Haut/Bas en fonction du ratio courant et qui va seter la matrice de GUI (GUI.matrix) afin que celle ci s'adapte à la résolution courante.

On va utiliser une classe "cGUIRatio" (voir le code plus bas).
Dans un callback OnGUI() on va appeller notre fonction cGUIRatio.DrawBandesNoires().
Toute la gui tracée apres cet appel sera redimentionnée et replacée en fonction de la résolution.
Notons que tous les elements de gui doivent etres positionnés comme si vous etiez dans la resolution native (1024*768 pour notre exemple).


void OnGUI()
{
cGUIRatio.DrawBandesNoires();
.... le reste de la gui...
}



Voila la classe cGUIRatio:


using UnityEngine;
using System.Collections;

public class cGUIRatio
{
//Resolution native de la gui
const int WIDTH = 1024;
const int HEIGHT = 768;

//-----------------------------------------
//
//-----------------------------------------
public static void DrawBandesNoires()
{
Texture2D white = Resources.Load("Textures/white") as Texture2D; //texture blanche 8*8 dans "Resources/Textures"
float sw = Screen.width;
float sh = Screen.height;
float refw = WIDTH;
float refh = HEIGHT;
float rCurrentRatio = sw / sh;
float guiScale;
if (rCurrentRatio > (refw/refh))
{
//Bandes Droite/Gauche guiScale = sh / refh;
}
else
{
//Bandes Haut/Bas
guiScale = sw / refw;
}
float cw = refw * guiScale;
float ch = refh * guiScale;
Vector3 v = new Vector3((sw - cw) / 2, (sh - ch) / 2, 0);

GUI.matrix = Matrix4x4.identity;
if (v.x > 0)
{
//Bandes sur les cotés
GUI.color = Color.black;
GUI.DrawTexture(new Rect(0, 0, v.x, Screen.height), white);
GUI.DrawTexture(new Rect(Screen.width - v.x, 0, v.x, Screen.height), white);
}
if (v.y > 0)
{
//Bandes Haut et Bas
GUI.color = Color.black;
GUI.DrawTexture(new Rect(0, 0, Screen.width, v.y), white);
GUI.DrawTexture(new Rect(0, Screen.height - v.y, Screen.width, v.y), white);
}
GUI.color = Color.white;

//Setup matrix for next gui draw
Vector3 translation = new Vector3(v.x,v.y,0);
GUI.matrix = Matrix4x4.TRS(translation, Quaternion.identity, Vector3.one*guiScale);
}
}



vendredi 13 janvier 2012

Augmented Reality SDKs

Pas spécifiquement de l'Unity mais peut etre utile tout de meme.
http://www.icg.tugraz.at/Members/gerhard/augmented-reality-sdks

Serialisation XML

.Net permet de faire de la sérialisation XML sur n'importe quelle classe.
Exemple la classe Settings:

using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;

public class Settings
{
public int val0; //Ce membre sera serialisé car il est public
private int val1; //Ce membre ne sera pas sérialisé car il est private

 public List<MyObjectDesc> MyObjectList; //Les listes sont supportées


public Settings()
{
}
public Settings(int v0, int v1)
{
val0 = v0;
val1 = v1;
}
}

Voici le code pour la serialiser:
public static Settings mSettings = new Settings(0,1);
...

TextWriter writer = new StreamWriter(Application.persistentDataPath+"/mySettings.xml");
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, mSettings);
writer.Close();


Voici le code pour la deserialiser:
TextReader reader = new StreamReader(Application.persistentDataPath+"/mySettings.xml");
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
mSettings = (Settings)serializer.Deserialize(reader);
reader.Close();

Une variante lorsqu'on recupere le fichier xml dans les resources:

TextAsset GameAsset = Resources.Load(filename, typeof(TextAsset)) as TextAsset;
TextReader reader = new StringReader(GameAsset.text);
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
Settings mSettings = ( Settings )serializer.Deserialize(reader) as Settings;
reader.Close();


On a le possibilisté d'influer sur le format du xml.
Pour spécifier le root dans le xml (par defaut il prend le nom de la classe):
[XmlRoot("RootSettings")] public class Settings
....

Pour ignorer un membre public:
[XmlIgnore] public int val0;

Pour faire en sorte que le membre soit stocké en tant que parametre et non de node:
[XmlAttribute("myParam")] public int val0;


Pour specifier le nom du node:
[XmlElement(ElementName="marker")] public List<cPlane> marker;

--------------------
Plus d'information sur les methodes de load de data xml dans Unity:
http://www.mindthecube.com/blog/2009/11/reading-text-data-into-a-unity-game


Cacher un GameObject de la Hierarchiy


Pour cacher un GameObject de la Hierarchy:

GameObject mDumy = new GameObject("Dumy");
mDumy.hideFlags = HideFlags.HideInHierarchy;

jeudi 12 janvier 2012

Interpreter du JSON

Voici une lib tres pratique pour interpreter du JSON
Fonctionne sur toutes les plateformes.

https://bitbucket.org/darktable/jsonfx-for-unity3d/downloads

Cast int, float, string

Pas forcement simple a trouver comme information dans la doc, voici comment caster des string en int ou float.
C'est tout simple en fait:

string str = "128";
int vali = int.Parse(str);
float valf = float.Parse(str);
string str2 = vali.ToString()+","+valf.ToString()+" ou "+vali+","+valf;

Note: il y a également les fonctions de type  int.TryParse(...)

Lecture/Ecriture de fichiers

Classique, quelques lignes pour lire ou ecrire des fichiers.


using System.IO;

//Lecture
FileStream f = File.OpenRead(filename);
byte[] bt = new byte[f.Length];
f.Read(bt, 0, (int)f.Length);
f.Close();

//Ecriture
byte[] bt = ...
FileStream f = File.Create(Application.persistentDataPath+"/myFile.dat");
f.Write(bt, 0, bt.Length);
f.Close();


Au passage, pour savoir si un fichier existe:
if (File.Exist(filename)) ...

Lecture ecriture de textes:
http://www.csharphelp.com/2005/12/simple-text-file-operations-in-c/

Hastable

Avec les listes ArrayList les Hastable font partie des moyens de stockage qui peuvent etre tres pratiques.
Les hastable permettent d'associer une Key et une Value et de pouvoir ainsi retrouver une Value à partir de sa Key sans avoir à parser toute la liste et sans avoir à implementer une recherche dichotomique.
Tout ca est fait pour vous.

Creation:
Hastable mHastable = new Hastable();

Ajout:
if (!mHastable.ContainsKey("myKey"))
  mHastable.Add("myKey",myObject);

Acces direct à l'objet (ici une texture) en connaissant sa key:
if (mHastable.ContainsKey("myKey"))
  Texture2D tex = mHastable["myKey"] as Texture2D;

Nombre d'éléments:
mHastable.Count;

Tout effacer:
mHastable.Clear();

Parcours de toute la liste:
int i=0;
foreach (DictionaryEntry de in mHashtable)
{
Texture2D tex = de.Value as Texture2D;
Debug.Log(i+"  "+tex.name+"\n"+i+"  "+de.Key);
i++;
}

Qualcomm/Vuforia - Réalité Augmentée dans Unity iOS/Android

Fonctionant pour iOS et Android cette lib gratuite (pour l'instant) pour faire de la RA sur mobile est tres performante et facile d'utilisation.
Capable de detecter des plan comme des boites, partiellements cachés.
Notons tout de meme que le systeme pour fabriquer les tags est un systeme online et il faut donc imperativement passé par leur outil en ligne pour les génerer (un moyen de garder la main sur l'utilisation de la techno qui pourrait un jour devenir payante).

Pour l'avoir utilisé dans une application iPad2, c'est vraiment tres bien.

https://ar.qualcomm.at/qdevnet/sdk/ios

DrawLine dans la fenetre Game

Unity fournit une fonction Debug.DrawLine(...) tres pratique qui permet de tracer des lignes de couleur dans la fenetre Scene pour faire du debugage, mais ces lignes n'apparaissent pas dans la fenetre Game et on ne peut donc pas s'en servir pour autre chose que du debug.
Il y a pourtant un moyen de tracer des lignes dans Game (sans a voir a fabriquer de mesh pour cela), le voici.

Le tracé doit se faire dans le callback OnPostRender().
De ce fait ce code doit se trouver dans une classe de type MonoBehavior attachée à un objet de la scene.


static public Material lineMaterial;

void OnPostRender()
{
CreateLineMaterial();
lineMaterial.SetPass(0);
GL.Begin(GL.LINES);
Color col = Color.red;
GL.Color(col);
Vector3 v0 = new Vector3(0,0,0);
Vector3 v1 = new Vector3(10,10,10);
GL.Vertex3(v0.x, v0.y, v0.z);
GL.Vertex3(v1.x, v1.y, v1.z);
Debug.DrawLine(v0,v1,col); //Pour avoir le tracé aussi dans Scene
GL.End();
}


static public void CreateLineMaterial()
{
if( !lineMaterial )
{
lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" +
"SubShader { Pass { " +
"    Blend SrcAlpha OneMinusSrcAlpha " +
"    ZWrite Off Cull Off Fog { Mode Off } " +
"    BindChannels {" +
"      Bind \"vertex\", vertex Bind \"color\", color }" +
"} } }" );
lineMaterial.hideFlags = HideFlags.HideAndDontSave;
lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
}
}

Barre de progression GUI

Toute petite classe pour afficher des barres de progression dans la GUI.
Pour faire des barre simplistes de ce style la (pas tres jolie, a vocation de debug):

C'est une classe statique qu'il faut donc appeller cGUIProgressBar.DrawGUI(...)
Ca utilise la GUI, il faut donc imperativement appeller cette fonction à partir des acallback unity OnGUI().

using UnityEngine;
using System.Collections;


public class cGUIProgressBar
{
private static Texture2D mWhiteTex;
private static GUIStyle mStyle;


//----------------------------------------
// A appeller dans un callback unity OnGUI()
//----------------------------------------
public static void DrawGUI(int x, int y, int count, int total, string prefix, int width)
{
if (mWhiteTex==null) mWhiteTex = Resources.Load("Textures/white") as Texture2D; //Texture 8*8 (ou autre) toute blanche à placer dans Resources/Textures
if (mStyle==null)
{
mStyle = new GUIStyle();
mStyle.alignment = TextAnchor.MiddleCenter;
mStyle.font = Resources.Load("Font/FontProgressBar") as Font; //Font Arial size 13 à placer dans Resources/Font
mStyle.fontStyle = FontStyle.Bold;
}
GUI.color = Color.black;
GUI.DrawTexture(new Rect(x, y, width+2, 18), mWhiteTex);
GUI.color = new Color(0.8f,0,0);
GUI.DrawTexture(new Rect(x+1,y+1,width,16), mWhiteTex);
GUI.color = Color.white;
float val = 1;
if (total!=0) val = ((count)/(float)total);
GUI.DrawTexture(new Rect(x+1, y+1, val*width, 16), mWhiteTex);
GUI.color = Color.black;
GUI.Label(new Rect(x, y, width+2, 18), prefix+" "+((int)(val*100))+"% ("+count+"/"+total+")", mStyle);
GUI.color = Color.white;
}
}

Les directives de compilation Unity

Grace aux directives de compilation d'unity on peut prévoir tel ou tel code et ca peut etre extremement pratique.

UNITY_EDITORDefine for calling Unity Editor scripts from your game code.
UNITY_STANDALONE_OSXPlatform define for compiling/executing code specifically for Mac OS (This includes Universal, PPC and Intel architectures).
UNITY_DASHBOARD_WIDGETPlatform define when creating code for Mac OS dashboard widgets.
UNITY_STANDALONE_WINUse this when you want to compile/execute code for Windows stand alone applications.
UNITY_WEBPLAYERPlatform define for web player content (this includes Windows and Mac Web player executables).
UNITY_WIIPlatform define for compiling/executing code for the Wii console.
UNITY_IPHONEPlatform define for compiling/executing code for the iPhone platform.
UNITY_ANDROIDPlatform define for the Android platform.
UNITY_PS3Platform define for running Play Station 3 code.
UNITY_XBOX360Platform define for executing XBbox 360 code.

    #if UNITY_EDITOR
      Debug.Log("Unity Editor");
    #endif
    #if UNITY_IPHONE
      Debug.Log("Iphone");
    #endif
    #if UNITY_STANDALONE_OSX
Debug.Log("Stand Alone OSX");
    #endif
    #if UNITY_STANDALONE_WIN
      Debug.Log("Stand Alone Windows");
    #endif


Elles sont toutes la: http://unity3d.com/support/documentation/Manual/Platform%20Dependent%20Compilation.html

Modification du logo de Load du WebPlayer

http://unity3d.com/support/documentation/Manual/Customizing%20the%20Unity%20Web%20Player%20loading%20screen.html

Les Thread en Unity

Dans unity pour faire accomplir une operation en tache de fond on peut utiliser le fameux Yield. Mais on peut aussi utiliser des thread classiques qui restent d'ailleurs beaucoup plus simples à utiliser.
using System; using System.Threading;
... Thread myThread = new Thread(new ThreadStart(ThreadLoop)); myThread.Start(); ... ... public static void ThreadLoop() { while (Thread.CurrentThread.IsAlive) { Thread.Sleep(500); // Attente de 500 ms Debug.Log("Je travaille..."); } }
http://emerica.developpez.com/csharp/threads/

Editeur de Shader Unity Strumpy



Quitter l'application en script


Pour quitter en script l'application unity: Application.Quit();
Ca n'a de sens évidement que dans un cadre d'application standalone.