Hachaisse le site

19 décembre 2013

Tutorial pour Unity 3D (4)

Classé dans : Article, Informatique, Tutoriel — admin @ 12 h 07 min

Troisième partie du tutorial : http://raphp.fr/blog/?p=312

Création du noyau du jeu

Notre jeu de carte démarre correctement, mais avant de tourner les cartes, il faudrait déjà avoir les bonnes cartes dans nos paquets !

Il nous faut donc ajouter une simulation de jeu de carte. J’ai écrit rapidement une simulation de paquet, de mélange et de donne de cartes.

Sûrement pas le plus élaboré mais c’est suffisant.

Nous allons créer 2 scripts c# :

Card.cs

public class Card {

public enum CardType

{

Heart = 1,

Spade = 2,

Diamond = 3,

Club = 4

}

public Card(CardType ct, int v )

{

Type = ct;

Value = v;

}

public CardType Type;

public int Value;

}

CardsGame.cs

public class CardsGame {

// Heart, Club, Spade, Diamond

protected Card[]Sorted = new Card[52];

ArrayList MixedCards = new ArrayList();

ArrayList Trash = new ArrayList();

public CardsGame () {

int iSorted = 0;

for( int c = 1; c <= 4; c++)

{

Card.CardType cardtype = (Card.CardType)c;

for(int i = 1; i <= 13; i++ )

{

Sorted[iSorted++] = new Card(cardtype, i);

}

}

}

public void FirstMix()

{

//Card[]Mixed = new Card[52];

System.Random r = new System.Random(new System.Random().Next(0,5000));

ArrayList al = new ArrayList();

MixedCards = new ArrayList();

Trash = new ArrayList();

for(int i = 0; i < 52; i++ )

al.Add(Sorted[i]);

Debug.Log(« Nombre de carte à mélanger :  » + al.Count);

//int iMixed = 0;

while(al.Count > 0)

{

int random = r.Next(0,al.Count-1);

Debug.Log(« random :  » + random);

Card find = (Card)al[random];

Debug.Log(« Carte :  » + find.Type +  » –  » + find.Value);

MixedCards.Add(al[random]);

al.RemoveAt(random);

}

}

public void Mix()

{

Debug.Log(« Tri des cartes »);

if(Trash.Count > 0 && MixedCards.Count > 0)

{

while(MixedCards.Count > 0 )

{

Trash.Add(MixedCards[0]);

MixedCards.RemoveAt(0);

}

}else{

Debug.Log(« Pas de poubelle, on recupere les cartes tries »);

Trash = new ArrayList();

for(int i = 0; i < 52; i++ )

{

//Debug.Log(Sorted[i].Value);

Trash.Add(Sorted[i]);

//Card c = (Trash[i] as Card);

//Debug.LogError(« Carte dans la poubelle a la position  » + i +  » :  » + c.Value);

}

}

//Card[]Mixed = new Card[52];

System.Random r = new System.Random(new System.Random().Next(0,5000));

ArrayList al = new ArrayList();

MixedCards = new ArrayList();

//Trash = new ArrayList();

for(int i = 0; i < 52; i++ )

{

Card c = (Trash[i] as Card);

if( c == null )

{

Debug.LogError(« Pas de carte dans la poubelle a la position  » + i);

}

Debug.Log( c.Value);

al.Add(Trash[i]);

}

Debug.Log(« Nombre de carte à mélanger :  » + al.Count);

//int iMixed = 0;

while(al.Count > 0)

{

int random = r.Next(0,al.Count-1);

Debug.Log(« random :  » + random);

Card find = (Card)al[random];

Debug.Log(« Carte :  » + find.Type +  » –  » + find.Value);

MixedCards.Add(al[random]);

al.RemoveAt(random);

}

}

public Card NextCard()

{

Card c = null;

if( MixedCards.Count > 0 )

{

c = (Card)MixedCards[0];

MixedCards.RemoveAt(0);

}

return c;

}

public void AddTrash(Card c)

{

Trash.Add(c);

}

}

Pour notre jeu de bataille, chaque joueur doit garder la carte plutôt que la remettre dans le paquet d’origine alors on ajoute cette classe :

PlayerCards.cs

public class PlayerCards

{

public ArrayList Pack

{

get;

private set;

}

public ArrayList Win

{

get;

private set;

}

public PlayerCards()

{

Pack = new ArrayList();

Win = new ArrayList();

}

public void AddPack(Card c)

{

Pack.Add(c);

}

public void AddWin(Card c)

{

Win.Add(c);

}

public Card GetCard()

{

Card c = null;

if( Pack.Count > 0 )

{

c = (Card)Pack[0];

Pack.RemoveAt(0);

}

return c;

}

public void MixWinToPack()

{

if( Pack.Count > 0 )

{

Debug.Log(« Impossible de remettre dans le paquet tant qu’il y a encore des cartes à jouer »);

return;

}

//Card[]Mixed = new Card[52];

System.Random r = new System.Random(new System.Random().Next(0,5000));

ArrayList al = new ArrayList();

Debug.Log(« Nombre de carte à mélanger :  » + Win.Count);

while(Win.Count > 0)

{

int random = r.Next(0,Win.Count-1);

Debug.Log(« random :  » + random);

Card find = (Card)Win[random];

Debug.Log(« Carte :  » + find.Type +  » –  » + find.Value);

Pack.Add(al[random]);

Win.RemoveAt(random);

}

}

}

Celle-ci pourra simuler le paquet de cartes à jouer et la pile de cartes gagnées contre l’adversaire.

Ensuite on se servira de notre script de GUI comme noyau.

On ajoute le membre suivant pour gérer un paquet de carte :

CardsGame mCardsPack;

Et pour gérer les cartes des joueurs :

PlayerCards Player1_Cards;

PlayerCards Player2_Cards;

On complète la méthode Start qui va initialiser les listes.

void Start () {

Debug.Log(« MyGUI – Start »);

Player1_Cards = new PlayerCards();

Player2_Cards = new PlayerCards();

Player1_3DCardsWin = new ArrayList();

Player2_3DCardsWin = new ArrayList();

Player1_3DCardsPack = new ArrayList();

Player2_3DCardsPack = new ArrayList();

}

Maintenant on ajoute la méthode de départ d’un jeu :

void NewGame()

{

mCardsPack = new CardsGame();

mCardsPack.FirstMix();

Player1_Cards = new PlayerCards();

Player2_Cards = new PlayerCards();

for(int i = 0; i < 26 ; i++)

{

Card c1 = mCardsPack.NextCard();

Player1_Cards.AddPack(c1);

Card c2 = mCardsPack.NextCard();

Player2_Cards.AddPack(c2);

}

RedrawCards(1);

RedrawCards(2);

}

La simulation de la donne : dans une bataille on distribue une carte chacun jusqu’à la fin des 52 cartes.

Ensuite on crée une pile de carte pour chaque joueur.

Ainsi que la méthode qui permet de créer les cartes dans la scène :

void RedrawCards(int player)

{

if( player == 1 )

{

for(int i = 0; i < Player1_3DCardsPack.Count; i++ )

Destroy((GameObject)Player1_3DCardsPack[i]);

Player1_3DCardsPack.Clear();

for(int i = 0; i < Player1_3DCardsWin.Count; i++ )

Destroy((GameObject)Player1_3DCardsWin[i]);

Player1_3DCardsWin.Clear();

for(int i = 0; i < Player1_Cards.Pack.Count; i++ )

Add3DCard(PlayerOne, ref Player1_3DCardsPack, -0.1f, « PlayerOne_Pack » + i);

for(int i = 0; i < Player1_Cards.Win.Count; i++ )

Add3DCard(PlayerOne, ref Player1_3DCardsWin, -0.3f, « PlayerOne_Win » + Player1_3DCardsWin.Count, « PlayerOneWin »);

}

if( player == 2 )

{

for(int i = 0; i < Player2_3DCardsPack.Count; i++ )

Destroy((GameObject)Player2_3DCardsPack[i]);

Player2_3DCardsPack.Clear();

for(int i = 0; i < Player2_3DCardsWin.Count; i++ )

Destroy((GameObject)Player2_3DCardsWin[i]);

Player2_3DCardsWin.Clear();

for(int i = 0; i < Player2_Cards.Pack.Count; i++ )

Add3DCard(PlayerTwo, ref Player2_3DCardsPack, +0.1f, « PlayerTwo_Pack » + i);

for(int i = 0; i < Player2_Cards.Win.Count; i++ )

Add3DCard(PlayerTwo, ref Player2_3DCardsWin, +0.3f, « PlayerTwo_Win » + Player2_3DCardsWin.Count, « PlayerTwoWin »);

}

}

Et on complète notre bouton démarrer avec la donne :

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Démarrer une partie ») )

{

mMenuStep = MenuStep.InGame;

mGameStep = GameStep.PlayerOneBeforeTurn;

PlayerOne.transform.rotation = Quaternion.Euler(0,0,0) ;                                                PlayerTwo.transform.rotation = Quaternion.Euler(0,0,0);

NewGame();

}

Nos joueurs ont désormais leurs paquets de cartes et une pile de cartes gagnantes.

Remarquons que je n’ai pas changé le tag du paquet, le 5ème paramètre n’est pas présent, il prend donc la valeur définie par défaut dans la méthode, c’est-à-dire « », et donc ne change pas le tag de l’objet.

Alors si on clique sur le paquet, on aura le même effet que celui de cliquer sur la carte visible. Mais pas sur le paquet de victoire.

Pour retirer la carte du paquet lorsqu’on prend une carte, j’ai modifié la méthode OnClick :

case « PlayerOneCard »:

if( playerturn==1 )

{

Debug.Log(« Click : PlayerOneCard! »);

OnClickCard(1);

PlayerOne.renderer.enabled = true;

}

Break ;

case « PlayerTwoCard »:

if( playerturn==2 )

{

Debug.Log(« Click : PlayerTwoCard! »);

OnClickCard(2);

PlayerTwo.renderer.enabled = true;

}

break;

Et en ajoutant :

void OnClickCard(int player)

{

if( player==1 )

{

mGameStep = GameStep.PlayerOneTurning;

Remove3DCard(ref Player1_3DCardsPack);

}

if( player==2 )

{

mGameStep = GameStep.PlayerTwoTurning;

Remove3DCard(ref Player2_3DCardsPack);

}

}

Cependant, les cartes ne représentent toujours pas les vraies cartes !

Alors on va affecter la texture de la bonne carte lorsqu’on tourne notre carte.

J’ajoute les membres suivant pour connaître la carte jouée actuellement de chaque côté :

Card Player1_CurrentCard, Player2_CurrentCard;

Je modifie de suite ma méthode OnClickCard :

void OnClickCard(int player)

{

if( player==1 )

{

mGameStep = GameStep.PlayerOneTurning;

Remove3DCard(ref Player1_3DCardsPack);
Player1_CurrentCard= Player1_Cards.GetCard();

UpdateCurrentCard(PlayerOne, Player1_CurrentCard);

}

if( player==2 )

{

mGameStep = GameStep.PlayerTwoTurning;

Remove3DCard(ref Player2_3DCardsPack);
Player2_CurrentCard= Player2_Cards.GetCard();

UpdateCurrentCard(PlayerTwo, Player2_CurrentCard);

}

}

Et j’ajoute celle-ci :

void UpdateCurrentCard(GameObject go, Card c)

{

string resource = «  »;

Debug.Log(c.Type +  » –  » + c.Value);

string val = c.Value.ToString();

if( c.Value == 1 )

val = « A »;

else if( c.Value == 11 )

val = « J »;

else if( c.Value == 12 )

val = « Q »;

else if( c.Value == 13 )

val = « K »;

else

{

}

switch( c.Type )

{

case Card.CardType.Club:

resource = val + « c »;

break;

case Card.CardType.Diamond:

resource = val + « d »;

break;

case Card.CardType.Heart:

resource = val + « h »;

break;

case Card.CardType.Spade:

resource = val + « s »;

break;

}

if( !string.IsNullOrEmpty(resource) )

{

Debug.Log(« Chargement texture :  » + resource);

Object res = Resources.Load(resource);

if( res != null )

{

Debug.Log(« Recuperation texture :  » + resource);

Material newMat = Resources.Load(resource, typeof(Material)) as Material;

if( newMat != null )

{

Debug.Log(« Attribution texture :  » + resource);

go.renderer.material = newMat;

}else{

Debug.LogError(« Impossible de retrouver la ressources :  » + resource);

}

}

else{

Debug.LogError(« Impossible de retrouver la ressources :  » + resource);

}

}

}

Alors attention, j’ai dû copier intégralement le répertoire des matériaux des cartes dans un autre répertoire « Assets\ Resources\ »

Donc tous les matériaux présent dans les sous-répertoires « Assets\BGA\Poker Pack\Models\Card\Materials\ » sont copiés dans le même sous-répertoire « Assets\ Resources\ »

Si je fais ceci, c’est que la fonction = Resources.Load() recherche par défaut dans ce répertoire.

Donc ici

Material newMat = Resources.Load(« 2c », typeof(Material)) as Material;

Ira charger le matériau « Assets\Ressources\2c.mat »

On a plus qu’à changer l’apparence d’un objet en passant par son renderer :

go.renderer.material = newMat;

Maintenant notre jeu ressemble à ceci lorsque l’on tourne nos cartes :

La finalisation du jeu

Je ne vais pas détailler la suite du code, il n’y a plus rien qui ne concerne Unity3D.

Il suffit de modifier le code pour gérer la reprise du paquet gagnant pour le remettre dans le paquet de jeu, de gérer la victoire, je rappelle que mon objet Player1_CurrentCard est de type Card, il suffit de tester le .Value pour connaître la puissance de la carte (transformer le 1 (as) en 14 (pour être plus fort que le roi 13).

Ne vous en faites pas, voici un ZIP contenant le projet complet pour vous aider ;)

media.visyr.ch/Unity3D/Tuto01/Tuto01HSVersion.zip

Et je rappelle l’exemple en live :

http://media.visyr.ch/Unity3D/Tuto01/

Par contre, par respect envers le créateur des modèles de cartes à 2$, je ne vous fournis pas les objets. Du moins pas totalement. Même si c’est libre commercialement, je ne suis pas sûr que cela soit autorisé de donner les objets eux-mêmes.

Je ne vous laisse que les cœurs copiés en carreaux, piques et trèfles. Donc vous aurez 4 x 2 de cœurs, 4 x 3 de cœurs et ainsi de suite.

Si vous souhaitez vraiment terminer le jeu, achetez ses modèles ou créez les. Personnellement un petit don de 2$ ne fait de mal à personne.

Je termine donc ce chapitre sur la création d’un .exe ou une application Android :

Donc sur un build « executable », dans PlayerSettings nous avons ce genre d’info :

J’ai choisi une icône présente dans le projet, à vous de mettre la vôtre.

J’ai mis mon nom de société et mon nom de produit.

Vous pouvez définir la résolution par défaut, plein écran ou non.

Il y a des détails impossibles à modifier à moins d’être en pro, comme la gestion de directx11 par exemple.

Pour un .exe, c’est assez simple.

Pour une version Android, il faut faire attention.

Techniquement, avant de vous lancer dans une app Android, vous devez vérifier la version qui vous intéresse !

En fait la technologie pour Android a évolué et continuera dans ce sens.

Cela devient trop technique pour moi, mais certains téléphones/tablettes ne sont compatibles qu’avec une technologie ArmV6 ou ArmVX, ma tablette Asus tf201 est en ArmV7 par exemple.

Ici Unity3D v4.0 et plus ne supporte que la techno ArmV7 !

Donc tout va bien pour moi.

Mais si je devais ou voulais commercialement être ouvert à tout je devrais faire du ArmV6 également, et autre.

Or… Il faut utiliser Unity3D 3.0 et plus. Heureusement la licence est compatible peu importe la version du logiciel.

Donc il faudra jongler sur deux (ou plus) installations différentes et copier le projet de l’un vers l’autre. Vous ne devriez pas rencontrer de gros problème de compatibilité, sauf si vous utilisez mecanim par exemple… Uniquement sur v4.

L’angoisse hein ?

Bref, il faut être prudent sur notre demande ou notre objectif.

Donc le playersettings de l’Android ressemble lui à ceci :

Le début est pareil, mais dans Other Settings, ça deviens « sympa ».

Comme Android est avant tout du Java, il répond à certaines normes de celui-ci.

Il faut mettre le package de java. Com.Company…

Chaque projet java est défini de la sorte. Donc on y met en général le site web privé ou pro en inversé.

Dans mon cas je mettrais ch.visyr.battlecard. Je n’ai pas testé, mais sauf erreur en java c’est minuscule. Donc je vous recommande d’éviter la majuscule comme le montre l’exemple.

Ensuite l’API, lié à la version d’Android.  Exemple Ice Cream Sandwich est la version Android 4.0 API Level 14 et plus.

Donc là encore ne vous limitez pas à une partie seulement, si vous pouvez mettre le moins c’est mieux. Mais c’est vous qui savez quelle version vous arrivez à supporter et voulez supporter.

Le device Filter, donc ici uniquement la v7 alors qu’en v3 on a le choix.

Après il y a des choix sur l’installation, préférence pour carte sd externe ou interne, les types de droits requis pour le web, etc.

Donc voilà, vous pouvez compiler votre jeu très facilement, il suffit de faire attention à l’objectif et les produits qui le supporterons.

Dans mon cas d’application professionnelle, le téléphone d’un collègue m’oblige à utiliser la version 3.5.7 pour compiler. Mais aucun problème de compatibilité,  normal, c’est pratiquement que du Gui et de l’accès Web pour interroger un webservice. Qui fera l’objet je pense d’un prochain tutorial.

Je n’ai pas de Mac pour tester une compilation Mac, et je m’en excuse. Mais un mec dont son passe-temps était de faire du directx en c# sur visual studio et qui vous ferait un tuto pour un Mac… Soyons d’accord. C’est n’importe quoi.

Pour discuter de l’article, c’est ici : http://raphp.fr/fofo/viewtopic.php?f=2&t=2339

6 septembre 2013

Tutorial pour Unity 3D (3)

Classé dans : Article, Informatique — Mots-clefs :, , — admin @ 19 h 43 min

Seconde partie du tutorial : http://raphp.fr/blog/?p=227

Démarrage de la partie

Nous avons la base du jeu, le menu et les cartes.

Cependant elles sont visibles dès le début du jeu. Hors nous ne devons afficher que le menu. Nous allons donc les masquer quand c’est inutile et ainsi gérer le fait de tourner la carte par codage. On ajoute dans la classe MyGUI 2 liens (2 membres publics) pour recevoir 2 objets de la scène :

public GameObject PlayerOne, PlayerTwo;

Le public permettra d’avoir 2 GameObject disponible dans l’Inspector qu’on peut affecter :

Ici on déplace l’objet 3D de la carte PlayerOne depuis « Hierarchy » vers le lien « Player One » du script et pareillement avec le 2è.

Maintenant notre script peut utiliser nos 2 objets.

Il est possible de chercher l’objet sans avoir du drag&drop :

Depuis les boutons à droite :

On affiche la liste des objets disponibles :

Avec un filtre de recherche, cela peut faire gagner du temps si on a une « hierarchy » remplie d’objets.

Avant de continuer je vais vous conseiller de « Tager » vos objets.

Vous comprendrez pourquoi dans le prochain chapitre.

Pour ajouter un tag :

Ou depuis le menu « Edit -> Projects Settings -> Tags »

Ajouter ensuite les 2 tags suivants :

Ensuite on sélectionne la carte 1 et on lui affecte le bon tag :

Pareillement avec la deuxième.

Maintenant on va se concentrer sur le code presque jusqu’à la fin du tutoriel.

On retourne donc compléter la classe :

case MenuStep.Start:

PlayerOne.renderer.enabled = false;

PlayerTwo.renderer.enabled = false;

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Démarrer une partie ») )

{

mMenuStep = MenuStep.InGame;

}

Si on lance le jeu, nous avons donc notre menu sans nos cartes.

Le Renderer constitue le « rendu » de l’objet. En fait c’est l’état de sortie visible de notre objet, il suffit de le désactiver pour que le moteur 3D ne l’affiche plus.

Remarque :

Si on ajoute dans le MenuStep.Start :

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Démarrer une partie ») )

{

mMenuStep = MenuStep.InGame;

PlayerOne.renderer.enabled = true;

PlayerTwo.renderer.enabled = true;

}

Nous pourrions afficher nos cartes une fois le menu « Démarrer » cliqué. Mais nous n’allons pas le gérer dans OnGUI() donc on le garde de côté.

Avant cela, on ajoute de nouveau une gestion d’étape dans le jeu:

public class MyGUI : MonoBehaviour {

public enum MenuStep

{

Start,

VideoSettings,

InGame,

MenuInGame,

Player1Win,

Player2Win

}

public enum GameStep

{

PlayerOneBeforeTurn,

PlayerOneTurning,

PlayerOneAfterTurn,

PlayerTwoBeforeTurn,

PlayerTwoTurning,

PlayerTwoAfterTurn

}

protected MenuStep mMenuStep = MenuStep.Start;

protected GameStep mGameStep = GameStep. PlayerOneBeforeTurn;

[…]

On complète de nouveau notre start :

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Démarrer une partie ») )

{

mMenuStep = MenuStep.InGame;

mGameStep = GameStep. PlayerOneBeforeTurn;

PlayerOne.transform.rotation = Quaternion.Euler(0,0,0);

PlayerTwo.transform.rotation = Quaternion.Euler(0,0,0);

}

Attention, ici ce ne sont pas des angles en ° car c’est un Quaternion, nous devons indiquer ici la position par rapport au « monde », donc l’état d’origine de la carte était bien 0.

Je le montre juste pour exemple, personnellement je préfère utiliser la fonction Rotate qui permet de faire la rotation de l’angle voulu.

Nous aurions pu écrire :

PlayerOne.transform.Rotate(new Vector3(0,180,0));

PlayerTwo.transform.Rotate(new Vector3(0,180,0));

Alors attention, n’oubliez pas que nous somme dans la fonction OnGUI !

Celle-ci s’exécute en boucle à chaque frame du jeu !

Donc si on fait un code de ce genre :

void OnGUI()

{

PlayerOne.transform.Rotate(new Vector3(0,1,0));

}

La carte tourne à l’infini.

Il existe également plusieurs méthodes, celle-ci sert à modifier l’objet sous tous les angles.

Mais dans notre cas nous n’avions besoin que du y, et ainsi écrire :

.Rotate(Vector3.up * 180);

Nous pouvons aussi gérer le temps écoulé entre les frames (pratique si ça ram) Ce qui n’est pas utile dans notre cas mais si vous souhaiter tourner un objet indéfiniment :

.Rotate(Vector3.right * Time.deltaTime);

Notre jeu démarre à présent proprement.

Création de l’interface du jeu

Maintenant nos joueurs doivent pouvoir donner leurs cartes !

Il y a plusieurs méthodes.

J’aime bien l’idée de cliquer sur chacune des cartes pour les révéler une par une, un peu comme dans la vrai vie ou l’autre joueur peut faire durer le suspens.

Mais on fera également un bouton pour retourner les deux d’un coup plus tard.

De plus, la première méthode est aussi une bonne solution pour apprendre à cliquer sur un objet visible sans tester sa position.

Nous avons juste besoin des tags indiqués précédemment sur nos objets pour distinguer notre clique sur l’objet. Il y a plusieurs solutions, je l’admets, mais on fait simple.

void OnClick(int playerturn)

{

if (Input.GetMouseButtonDown(0))

{

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

RaycastHit hit;

if(Physics.Raycast(ray, out hit, 10f))

{

switch( hit.collider.gameObject.tag )

{

case « PlayerOneCard »:

if( playerturn==1 )

mGameStep = GameStep.PlayerOneTurning;

break;

case « PlayerTwoCard »:

if( playerturn==2 )

mGameStep = GameStep.PlayerTwoTurning;

break;

}

}else{

}

}

}

Donc ScreenPointToRay permet de lancer un « rayon » où on clique avec le mousePosition.

Ensuite on se sert du Physics.Raycast pour vérifier ce que l’on croise en objet « physique », cela ne marche pas si l’objet n’est pas considéré comme « solide ».

On a en 3ème paramètre la distance de colision, ici 10 c’est bien plus loin qu’il n’en faut vu que nos cartes ne sont même pas à 1 de distance de la camera.

Donc on détecte le clique sur la carte 1 ou 2 et on modifie l’état du jeu pour lancer la découverte de la carte.

On ajoute le membre suivant pour garder quelques secondes à l’écran le résultat des 2 cartes retournées.

protected float mSeconds = 0;

On utilisera enfin la méthode Update. Je rappelle que OnGUI est fait pour l’interface alors que Update gère les objets, soit c’est plus fluide, soit le traitement est mieux réalisé.

void Update () {

switch( mMenuStep )

{

case MenuStep.InGame:

PlayerOne.renderer.enabled = true;

PlayerTwo.renderer.enabled = true;

switch( mGameStep )

{

case GameStep.PlayerOneBeforeTurn:

OnClick(1);

break;

case GameStep.PlayerOneTurning:

PlayerOne.transform.Rotate(Vector3.up * 5);

if(  Mathf.Round(PlayerOne.transform.rotation.eulerAngles.y) == 180 )

mGameStep = GameStep.PlayerOneAfterTurn;

break;

case GameStep.PlayerOneAfterTurn:

mGameStep = GameStep.PlayerTwoBeforeTurn;

break;

case GameStep.PlayerTwoBeforeTurn:

OnClick(2);

break;

case GameStep.PlayerTwoTurning:

PlayerTwo.transform.Rotate(Vector3.up * 5);

if(  Mathf.Round(PlayerTwo.transform.rotation.eulerAngles.y) == 180 )

{

mGameStep = GameStep.PlayerTwoAfterTurn;

mSeconds = 0;

}

break;

case GameStep.PlayerTwoAfterTurn:

// Resultat

//

mSeconds += Time.deltaTime;

if( mSeconds > 1 )

{

mSeconds = 0 ;

mGameStep = GameStep.PlayerOneBeforeTurn;

PlayerOne.transform.rotation = Quaternion.Euler(0,0,0);

PlayerTwo.transform.rotation = Quaternion.Euler(0,0,0);

}

break;

}

break;

}

}

Nous avons donc nos cartes qui se tournent après un clic dessus.

Lors du prochain chapitre nous étudierons le noyau du jeu, c’est-à-dire la vraie distribution de carte et le résultat de victoire entre les 2 cartes. Faut admettre que le noyau du jeu n’est que du c# pur et dur.

C’est pourquoi on va d’abord préparer un système de paquet de cartes qui nous permet de manipuler un peu Unity3D.

On se contentera de donner automatiquement les 2 cartes au joueur 1 sans encore tester le résultat de victoire.

Il nous faut déjà une liste pour contenir tous les objets 3D. Important, car on souhaitera les effacer donc on doit mémoriser tous les objets quelque part.

Remarque : Techniquement, il est possible de retrouver un objet par son nom.

Nous avons donc pour le joueur 1 et 2, une pile de cartes de départ et une 2ème pour celles qu’on gagne.

ArrayList Player1_3DCardsWin, Player1_3DCardsPack;

ArrayList Player2_3DCardsWin, Player2_3DCardsPack;

On instancie nos listes :

void Start () {

Debug.Log(« MyGUI – Start »);

Player1_3DCardsWin = new ArrayList();

Player2_3DCardsWin = new ArrayList();

Player1_3DCardsPack = new ArrayList();

Player2_3DCardsPack = new ArrayList();

}

Dans la fonction de résultat on modifie le code suivant :

if( mSeconds > 1 )

{

mSeconds = 0 ;

Add3DCard(PlayerOne, ref Player1_3DCardsWin, -0.3f, « PlayerOne_Win » + Player1_3DCardsWin.Count, « PlayerOneWin »);

Add3DCard(PlayerOne, ref Player1_3DCardsWin, -0.3f, « PlayerOne_Win » + Player1_3DCardsWin.Count, « PlayerOneWin »);

mGameStep = GameStep.PlayerOneBeforeTurn;

PlayerOne.transform.rotation = new Quaternion(0,0,0,0);

PlayerTwo.transform.rotation = new Quaternion(0,0,0,0);

}

On va donc faire en sorte de tourner la carte tant qu’elle n’est pas complètement retournée à 180° donc face visible à la caméra.

Et aussi dire au jeu lorsque les 2 cartes sont révélées que le joueur 1 gagne les 2 cartes dans sa pile de victoire.

La méthode pour gérer la création d’un objet 3D en live :

void Add3DCard(GameObject original, ref ArrayList list, float posx, string name, string tag = «  »)

{

GameObject newcard = (GameObject) Instantiate(original);

if( !string.IsNullOrEmpty(tag ))

newcard.tag = tag;

newcard.name = name;

newcard.renderer.enabled = true;

newcard.transform.position = new Vector3(original.transform.position.x + posx,-0.5f +(float)(0.002* list.Count),original.transform.position.z);

newcard.transform.Rotate(new Vector3(90,0,0));

list.Add(newcard);

}

Avec l’instantiate on crée un GameObject avec l’aide d’un objet prédéfini, il est possible d’utiliser une ressource mais dans notre cas on fera une copie d’un objet déjà présent dans la scène.

Comme elles seront retournés, on se moque de la face visible qui correspond ou non.

On la déplace vers le bas de l’écran et on la tourne pour faire une belle pile face caché.

On utilise le nombre de cartes déjà présentes pour calculer la position en y pour simuler une pile qui s’agrandit.

Maintenant quand on retourne les deux cartes, le joueur 1 gagne les deux cartes dans sa pile.

Et tout cela sans utiliser l’interface graphique d’Unity3D.

Je lui donne un nouveau TAG, car sinon un clique sur la pile des victoires fera le même code que la carte principale et retournera la carte. Il prend donc par défaut le tag de l’objet copié, ce qu’il est important de noter.

Je lui donne un nom différent pour le retrouver plus facilement sur la scène, ou si je recherche par nom un objet.

Remarque : quand on lance la lecture du jeu, lorsque l’on crée un objet, on le retrouve dans l’onglet « Hierarchy » ainsi que la scène. Mais ils disparaissent une fois la lecture terminée.

J’ai également crée les deux méthodes suivantes pour me permettre d’effacer les cartes 3D que l’on utilisera plus tard :

void Remove3DCard(ref ArrayList list)

{

if( list != null )

{

if( list.Count>= 1 )

{

Destroy((GameObject)list[list.Count-1]);

list.RemoveAt(list.Count-1);

}

}

}

void RemoveAll3DCards(ref ArrayList list)

{

for(int i = 0; i < list.Count; i++ )

{

GameObject go = (GameObject)list[i];

Destroy(go);

}

list.Clear();

}

Il suffit d’avoir l’objet et d’utiliser Destroy. Tout simplement.

Pour discuter de l’article, c’est ici : http://raphp.fr/fofo/viewtopic.php?f=2&t=2339

11 juin 2013

Tutorial pour Unity 3D (2)

Classé dans : Article, Informatique — Mots-clefs :, , — admin @ 13 h 31 min

Première partie du tutorial : http://raphp.fr/blog/?p=167

Création d’un simple Menu fonctionnel

public enum MenuStep

{

Start,

VideoSettings,

InGame,

MenuInGame,

Player1Win,

Player2Win

}

protected MenuStep mMenuStep = MenuStep.Start;

void Start () {

Debug.Log(« MyGUI – Start »);

}

void Update () {

}

void OnGUI()

{

float MenuY = 10, MenuHeight=  30, MenuBlank = 5, MenuWidth = 200;

switch(mMenuStep)

{

case MenuStep.Start:

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Démarrer une partie ») )

{

mMenuStep = MenuStep.InGame;

}

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Configuration vidéos ») )

{

mMenuStep = MenuStep.VideoSettings;

}

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Quitter le jeu ») )

{

Application.Quit();

}

break;

case MenuStep.VideoSettings:

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Fullscreen ») )

{

Screen.fullScreen = !Screen.fullScreen;

}

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Retour ») )

{

mMenuStep = MenuStep.Start;

}

break;

case MenuStep.InGame:

break;

case MenuStep.MenuInGame:

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Retour ») )

{

mMenuStep = MenuStep.InGame;

}

if( GUI.Button(new Rect(10f,MenuY += MenuHeight + MenuBlank,MenuWidth,MenuHeight), « Quitter la partie ») )

{

mMenuStep = MenuStep.Start;

}

break;

case MenuStep.Player1Win:

break;

}

}

On peut lancer play de suite, mais comme j’utilise 2 notions tel que le Screen.Fullscreen et le Application.Quit(), je vous montre de suite l’étape de sortie d’un projet car ces 2 options n’effectuent rien en mode lecture (debug) d’Unity3D.

Nous analyserons dans un autre chapitre les différentes options de sortie de projet, pour PC ou Android.

Mais pour l’instant on se contente d’une sortie simple.

Depuis le menu File -> Build settings…

Nous retrouvons les options de sortie : Windows ou Mac, ou Android et iPhone disponible selon la licence.

Il est important de noter qu’une fois un type de projet choisi, avec le player settings, l’Inspector vous donne différentes informations importantes. Modifiable selon les besoins.

Ensuite une fois choisi le chemin de sortie, vous pouvez exécuter le projet.

Comme je n’ai rien modifié dans les options de base on retrouve au démarrage ceci :

Ensuite notre application avec un menu des plus simples !

Le menu Démarrer une partie qui lance le jeu, c’est-à-dire un joli fond bleu inutile.

Le menu Configurations vidéos vous permet de passer en plein écran et inversement.

Et Quitter le jeu vous permet de … bah vous avez compris.

En fait, comme certains vont peut-être comprendre, techniquement il est possible de faire une application « Software » sans jeux 3D ou autre pour Android et iPhone rien qu’en manipulant le GUI.

Dans mon domaine professionnel c’est ce qu’on va faire. Nous avons un vrai projet en c# que nous souhaitons faire en version Web, Android et iPhone.

Problème : chaque outil demandant en général un langage différent, le support de différents outils et surtout le recodage de certaines classes sont une perte de temps et un support fastidieux.

Grâce à ça, il est possible de faire une app simple et d’avoir un minimum de support pour un petit logiciel de saisie simple.

Après rien n’empêche d’ajouter un petit côté graphique sympa même pour une app bureautique.

Ou même de reconvertir la boite en société de jeux vidéos. ;)

Mais revenons à notre jeu.

Création des objets 3D

Pour être honnête, j’aurais pu vous faire un topo sur la modélisation d’objet sur 3D max ou autre, j’ai touché un tout petit peu et faire des cartes n’aurais pas été un problème. Mais c’est vite long et chiant pour quelqu’un comme moi qui ne suis pas graphiste.

Trouver les images pour les matériaux (texture des objets) et faire un mapping proprement, …

Ou alors on peut même trouver les objets directement sur le net. C’est tout à fait faisable.

Techniquement, j’estime que mon temps coûterait plus cher qu’il ne faudrait et que je pourrais rentabiliser cela autrement.

Donc voilà, je me suis servi de l’Asset Store d’Unity3D ! En principe, sauf contre-indication, tout est utilisable même commercialement.

J’ai fait une recherche simple avec « Cards » et voilà en deux secondes ce que l’on trouve :

Bingo !

Pour la modique somme de 2$ je peux trouver mon bonheur, j’ai gagné un max de temps.

Alors bien sûr il ne faut pas succomber à chaque tentation de gagner un peu de temps ! Mais il suffit d’un minimum de réflexion pour comprendre que 2$ pour des heures de boulot c’est rentable.

Pour être sûr de son coup on va analyser le packaging !

On clique sur le moins cher et on obtient les détails, commentaires du créateur, date, etc.

On peut également consulter les objets en dessous en cliquant sur les objets .fbx (les objets 3D de base) ou .prefab (les objets préfabriqué que l’on étudiera plus tard).

Au lieu d’avoir « import » vous trouverez « Buy » mais j’ai un peu d’avance et je l’ai donc déjà acheté.

Par la suite, vous pouvez l’importer depuis toutes les installations Unity3D loggées à votre nom. En gros si vous avez 2 pc, vous n’avez pas à transférer les packages, il suffira de retélécharger depuis votre compte dans l’asset store.

Donc il vous propose de l’importer dès l’achat (mastercard, paypal etc.)

Vous pouvez retrouver les objets avec le bouton en haut à gauche (juste à côté de la maison).

Il est important de vérifier de temps en temps les packages achetés, ils sont souvent mis à jours par l’éditeur et il faut re-télécharger la dernière version.

Une petite phrase vous l’indique à côté du bouton import qui se transforme en bouton update si c’est le cas.

Exemple :

Donc nous lançons l’import :

Il est possible de ne prendre qu’une partie du package, par exemple, je n’ai besoin que des cartes de cœur, je peux choisir chaque objet (en n’oubliant pas les matériaux/textures) et ne pas prendre d’autres en les décochant. Pratique pour gagner de la place.

Ici dans ce package, il y a une table de poker, totalement inutile et qu’on pourrait ignorer.

C’est assez important si on souhaite une application pas trop volumineuse.

La taille d’une app Android est limitée par exemple. Il faudrait faire un système de téléchargement de ressources et s’arranger pour que notre jeu n’ait pas besoin des objets directement.

Par programmation on peut chercher une ressource par son chemin, mais il faudra alors le placer soi-même sur la scène aux bonnes coordonnées.

Pour l’instant on se contente d’un jeu de carte pc alors on ne se souciera pas de cela.

Dans mon projet j’obtiens ceci :

La scene01 c’est ma sauvegarde de notre scène que je n’ai pas précisé durant l’explication.

Si vous avez bien suivi, vous avez noté mon explication sur les besoins de sauvegardes fréquentes et il faudra l’assumer de vous-même !

Autrement vous le payerez cher !

Il y a dans ce package la scène de l’éditeur pour exemple. Ce n’est pas toujours le cas, mais c’est une chose que j’apprécie dans l’asset store, c’est souvent assez complet.

Retournons donc à notre création de jeu.

Il y a le répertoire Models qui représente l’objet 3D de base. C’est-à-dire une carte totalement blanche.

Il y a le répertoire prefabs, c’est ce qu’on appelle un objet préfabriqué et destiné à un certain usage. Dans notre exemple ça sera les 52 cartes avec chacune leur texture définie.

Si on sélectionne un prefabs/cards/hearts/2c je me retrouve avec l’aperçu de la carte 2 de coeur :

On y constate qu’il s’agit bien d’un objet 3D (mesh).

Les options de rendu de l’objet, ombre etc.

L’animation de l’objet, ici il n’y en a pas, mais souvent un personnage aura des animations de bases comme « idle » (l’attente), « Walk » pour marcher, etc.

Et on pourrait choisir l’animation par défaut à exécuter en boucle ou non.

Ici il n’y en a pas, et comme ma carte ne contient pas de sous objet « Bones » (Squelette), il ne lui serait pas possible d’affecter une animation par le Mecanim, donc si on souhaite l’animer, ça sera avec des options de base, comme la rotation, la translation, etc.

On trouve aussi la texture utilisée, modifiable mais inutile, c’est un prefab prévu pour cette texture.

Donc on va juste glisser l’objet « 2h » sur la scène et la placer un peu.

Alors j’ai de suite repositionné depuis l’Inspector la carte en x :-0.2,y :0,z :0

Une rotation en x de 180 sinon elle n’était pas dans le bon sens. Et j’ai déplacé ma caméra en : x :0,y :0,z :-1.

Car sinon c’était trop loin et c’était invisible.

Nous avons l’aperçu dans la fenêtre game (aperçu réel en jeu).

Et nous voilà donc avec un premier objet sur notre scène (Sauvegardez… un petit ctrl-s n’a jamais tué quelqu’un ! C’était mon dernier avertissement !).

Maintenant on peut ajouter une 2ème carte et les séparer dans chacun des écrans pour simuler la carte retourné de chaque joueur. (la 2è carte en 0.2,0,0)

Et on les renomme PlayerOne et PlayerTwo.

Troisième partie du tutorial : http://raphp.fr/blog/?p=312

Pour discuter de l’article, c’est ici : http://raphp.fr/fofo/viewtopic.php?f=2&t=2339

28 mai 2013

Tutorial pour Unity 3D (1)

Classé dans : Article, Informatique — Mots-clefs :, , — admin @ 19 h 52 min

Introduction

Qu’est-ce qu’un jeu vidéo ?

Nan mais si vous avez besoin de le savoir, c’est que vous sortez trop souvent de votre grotte. Et je ne vois pas l’intérêt de vous parler. Vous auriez mieux fait de finaliser l’objectif ultime de l’être humain : se sédentariser suffisamment pour ne plus avoir besoin de sortir de chez soi.

Qu’est-ce qu’Unity3D ?

Ça c’est une question intéressante !

C’est un logiciel qui vous place dans un écosystème de développement de jeux.

-        Il est composé d’un moteur 3D pour vous permettre d’y mettre différents objets 2D/3D.

-        D’une gestion d’animation pour vous permettre de donner vie à vos objets.

-        Mais aussi le processus de traitement, qui permet de programmer les actions de vos objets.

-        Sans oublier le gestionnaire de ressources (L’Asset Store) qui permet d’utiliser ou d’acheter des composants pour votre jeu (images, modèles 3D, musiques et même des bouts de code).

Le principal atout de cet environnement, c’est qu’il est conçu pour le multiplateforme, pour le développement sur Mac ou PC. Mais aussi en sortie finale. Il est possible avec le même jeu d’en faire :

-        un pour le web (flash ou webplayer qui  vous permet de jouer depuis n’importe quel browser)

-         un pour ordinateur avec un .exe habituel

-        Mais aussi une application iPhone ou Android.

Sans rien toucher ! Tout est dans le même langage (le c# !), donc plus besoin d’apprendre différents langages par système (comme le java pour Android habituellement).

Remarquons qu’il est possible d’exporter le projet Unity3D en version java pour Eclipse et de pouvoir le modifier par la suite.

Mais j’ignore si cela est possible dans le sens inverse.

On se demandera pour qui est conçu ce petit bijou ?

Et bien à « tout le monde » !

Que cela soit pour des entreprises ou personnellement. Pourquoi ? Et bien c’est simple, il est « gratuit » pour la plupart des fonctionnalités. (IPhone et Android nécessite au minimum 400$ chacun pour la version de base).

Autrement la sortie en Webplayer ou Windows ou Mac est gratuite, la seule vraie contrainte étant le logo Unity3D qui est obligatoire au démarrage du jeu. Ce n’est franchement pas grand-chose !

Ensuite si vous en avez vraiment besoin de manière un peu plus pro, il coûte « seulement » 1500$ (on ajoute 1500$ pour chaque option comme iPhone ou Android, cependant si vous avez pris la version 400$ avec la version gratuite d’Unity3D, seul le complément sera demandé).

Alors, attention ! Il y a eu en avril 2012 une promotion exceptionnelle qui offrait la version Android et iPhone gratuitement, 800$ d’économie, j’ai regretté de l’avoir loupé.

J’ignore si cela peut se reproduire mais cela vaut le coup de vérifier de temps en temps en cas de besoin.

Le logiciel en action.

Installation

On télécharge simplement le logiciel depuis le site officiel (http://Unity3D.com/unity/download/)

Ne vous en faites pas, il ne fait même pas 700mo !

Disponible pour PC ou Mac, attention, cela influe sur la sortie de projet, seul un dev sur Mac permet de faire un jeu Mac et seul un dev sur PC permet de faire un jeu pour PC.

Présentation

Voici la bête :

Il est possible de configurer sa présentation soi-même ou d’en choisir une prédéfinie dans la liste en haut à droite de l’écran.

Exemple en « 4 split »

Les onglets :

Scene : vue 3D de votre scène, pour l’instant  rien de visible car il n’y a que la caméra de base. Mais c’est ici qu’on place nos objets 3D.

Game : L’aperçu en temps réel de votre jeu. Permet de lancer le jeu en « debuggage » et de voir tout ce qui se passe.

Projects : liste des fichiers que votre jeu utilise ou peut utiliser en cours de route.

Si on copie un fichier dans le répertoire Assets de votre projet, il s’importe automatiquement dans le logiciel.

Plus il  y a de fichiers, plus l’application sera grosse !

Hierarchy : liste des objets sur la scène.

Inspector : propriétés d’un fichier ou d’un objet sélectionné.

Il y a d’autres onglets qu’on affiche ou non selon les besoins. Exemples.

L’Asset Store :

C’est ici qu’on retrouve la liste des ressources (image, objet 3D, sons, code source pour des scripts, etc) gratuites ou non.

Il y a des promotions spéciales, comme actuellement le mixamo store à 50%. C’est une liste d’animation pour tout type de jeux disponible pour 1 an. C’est intéressant mais cela coûte quand même 750$ par an. Il vaut mieux être sûr de ce dont on a besoin et d’être vraiment dispo pour en profiter à fond.

J’ai récemment vu que « régulièrement » du mardi  au mercredi il y a plusieurs choses en promo également.

C’est souvent intéressant vu certains objets !

L’onglet Animation :

Permet de gérer les animations basiques.

Exemple, on clique sur la frame 0, on place un objet, on demande l’enregistrement et on va à la frame 10 et on déplace l’objet.

Celui-ci durant la lecture fera le mouvement du point A au point B. il gère lui-même « le virage » de la course si ce n’est pas une ligne droite.

Mecanim/Animator : le nouvel outil d’animation d’Unity3D v4 que l’on verra plus tard.

Explication rapide : dans l’ancienne version, il fallait ajouter une animation à un objet avec l’aide d’un outil 3D et cela rendait l’animation disponible pour cet objet uniquement. Maintenant, une animation prévue pour un « squelette » 3D sera disponible pour tous les objets du même type.

Exemple : si j’ai une animation de marche à pied pour un être humain, il sera disponible pour un autre. Mais pas pour un chien. Car le squelette interne de l’objet ne sera pas défini de la même manière.

Création d’un jeu animé.

La seule notion requise ici est la connaissance de c# !

Sauf erreur on peut faire la même chose en javascript, mais il faudra recoder de la bonne manière.

Pour bien comprendre le logiciel, le mieux est de suivre un exemple.

Tout d’abord, il faut partir sur une idée simple, ce qui est souvent difficile. Personnellement je vois toujours un truc trop compliqué et je m’emmêle les pinceaux et le projet finit par partir en vrille et disparaître.

Donc on va oublier Skyrim, WoW ou autre jeux de suite !

Mais ne soyez pas déçus ! Nous allons faire un jeu de stratégie, d’action et de suspense. Un jeu qui demande de l’adresse et du doigté.

Un formidable jeu de bataille.

Nan nan, pas un jeu de bataille navale ! Juste une bataille de carte…

Comme je disais, faut vraiment faire simple mais rien que cet exemple nous montrera la notion d’objet 3D, de scripts d’animation pour animer un petit peu les cartes avec du code, de notion de caméra, de GUI (L’interface utilisateur comme le menu)…

Etc.

Je vous recommande de partir sur un simple jeu de carte (As, Roi, Dame, etc) pour vous faire la main et avoir un aperçu global d’un projet complet, des interactions des scripts…

Voici le résultat que l’on peut obtenir assez facilement :

http://media.visyr.ch/Unity3D/Tuto01/

Création du projet :

Si vous venez de lancer le projet, sauvegardez-le directement dans un répertoire, ici Tuto01.

Ne jamais oublier de sauvegarder avec un bon CTRL+S (ou le menu) ! L’exécution du projet en « debug » ne sauvegarde pas. Les habitués seront perturbés, mais faut être au courant. J’ai déjà perdu des heures de boulot en plantant pendant l’exécution du projet.

Même la sauvegarde d’un script depuis mono ne sauvegarde pas la scène en cours d’Unity3D.

Création d’un script et du GUI :

L’interface utilisateur sera basique mais il est possible de le perfectionner avec des scripts et des ressources sur l’Asset Store.

Création du premier script c# :

Qu’on nommera MyGUI. Attention, contrairement à Visual Studio, Unity3D n’accepte pas qu’une classe ne porte pas le même nom que son fichier. Sûrement une contrainte lié à Java ou Mono derrière.

Ne pas nommer son fichier GUI, car GUI est un mot clé d’Unity3D et on risque de le « surcharger » et le GUI standard ne serait plus disponible.

Quand on lance le fichier (par double clic par exemple) on tombe directement sur Mono qui permet de dev  du c# sur des systèmes différents.

C’est nettement moins bien que Visual Studio selon moi, mais l’essentiel est présent.

Pour l’instant on se contentera d’un simple affichage de texte pour vérifier l’exécution du script.

void Start () {

Debug.Log(« MyGUI – Start »);

}

Si vous lancez le projet depuis Unity3D avec l’aide du bouton play, il ne se passera rien et votre fenêtre Game n’affichera rien d’autre que votre fond bleu.

Votre script doit être lié à un élément du jeu.

Dans le menu GameObject on peut créer différent objets :

Mais pour l’instant on se contentera de créer un objet « vide » avec le « Create Empty »

Ça sera un objet transparent qui servira de noyau.

Remarque : on aurait très bien pu affecter le script à la caméra déjà existante.

On retrouve donc l’objet que je renomme Core dans l’onglet Hierarchy :

Si on regarde dans l’Inspector on retrouve ceci :

Sa position dans la scène, sa taille etc.

Ici cela a peu d’importance car il est invisible.

On peut lui ajouter des options avec AddComponent ou juste glisser un composant de notre projet comme notre script dans la fenêtre Inspector.

D’où l’intérêt de bien faire son interface !

Sur un seul écran je suis généralement comme ça :

J’ai une vision de ma scène, de l’affichage en temps réel et des 3 onglets principaux.

Je drag&drop (je glisse l’objet d’un point à l’autre) le script MyGUI à l’Inspector :

On retrouve mon script comme prévu dans l’Inspector, on y trouvera aussi toutes variables déclarées « public » pour les modifier depuis Unity3D plutôt que dans Mono.

Si je lance la lecture on retrouve ceci :

Rien !

Normal : nous n’avons pas d’objet autre qu’une caméra et un objet invisible, mais en dessous on trouve la fenêtre de debuggage avec mon texte !

Si on clique dessus cela nous ouvre l’onglet de la console :

En général je garde cette fenêtre pour l’afficher à côté de la fenêtre Game.

Donc bien entendu, la méthode Start ne s’exécute qu’une seule fois et n’est jamais rappelée.

Maintenant nous pouvons créer notre GUI !

Nous retournons dans notre code et ajoutons ceci :

void OnGUI()

{

if( GUI.Button(new Rect(10f,10f,100f,30f), « Test ») )

{

Debug.Log(« Test »);

}

}

La méthode OnGUI est appelée à chaque frame pour afficher uniquement des objets de type GUI.

Si on souhaite faire quelque chose avec un objet 3D ou autre, on fera le code dans Update() qui est appelé également à chaque frame.

En comparaison d’un bouton standard du c#, il n’y a pas d’event pour l’appui. On ne peut même pas tester si le curseur survole le bouton. Il faudra le faire soi-même en testant la position de souris.

Il faut pour ce genre d’option passer par un autre principe que l’on ne verra pas ici. Je ferai peut-être un prochain tuto dessus.

On va se contenter d’une simple condition test s’il est cliqué.

De plus, contrairement à une application logicielle, un moteur 3D fonctionne différemment. L’affichage « s’efface » continuellement et réactualise tous les objets présents (visible ou non), donc c’est dans l’OnGUI qu’on créera le bouton pour qu’il soit toujours présent, et non pas dans le Start.

Il faudra donc penser à une condition pour masquer le menu par la suite.

Seul les plus traditionnels (pour ne pas dire vieux de la vieille) dans mon genre ont l’habitude de ça car c’est ainsi que fonctionnait DirectX en C et on devait coder nous-même l’effacement et le ré affichage.

Maintenant nous avons un simple bouton qui sera visible à la position inscrite si on lance play.

Lorsque l’on clique dessus, le texte « Test » s’ajoute dans la console.

Seconde partie du tutorial : http://raphp.fr/blog/?p=227

Pour discuter de l’article, c’est ici : http://raphp.fr/fofo/viewtopic.php?f=2&t=2339

Propulsé par WordPress