dimecres, 11 de juny de 2014

TDDs a Unity(IV)

I per últim, ara que les obligacions familiars m'han donat un respir (tinc al menut dormint al meu costat), li posarem una interfície gràfica al nostre joc. Com ja sabeu he triat Unity 3D, per què m'encanta, i accepta el meu llenguatge de programació preferit (C#) per a l'scripting. El primer que he fet és crear uns apassionants gràfics amb el meu supertalent i el... mspaint!!! Per no avorrir-vos, vos pose un exemple:











Com podreu suposar, he creat una imatge per cada "vida", com el típic joc del penjat, així només s'ha de carregar en cada moment la imatge corresponent al nombre de vides (es podria fer més difícil, composant, animant... però el disseny no m'agrada, és molt avorrit i tediós i valdria més l'esperat que l'escurada).

Ara vos pose els objectes que he posat:



Si mirem la imatge tenim:
  • 1 Sprite, Vides que es on anem posant la imatge del penjat segons les vides
  • 5 3DText (TextMesh):
  1. Paraula: La paraula que hem d'encertar, les lletres que encara no hem encertat apareixeran amb un _
  2. LletresOK i LletresOK: una etiqueta indicant que davall està la llista de lletres encertades/fallades
  3. LletresOKText i LletresKOText: la llista de lletres encertades i fallades
  • La càmera
  • Un objecte (buid) GameController on he assignat l'script de control de joc (podria estar en la càmera, però no m'agrada barrejar coses)






Ara anem al codi de l'script assignat a gamecontroller, primer definim les variables que anem a gastar:

                private string Word;
private string LettersOK;
private string LettersKO;
private int Lifes;
private HangMan hang;
private TextMesh WordCompletedText;
private TextMesh LletresOKText;
private TextMesh LletresKOText;
private SpriteRenderer SpR;
public Sprite[] Vides;





La variable Sprite serà pública per que així podrem definir-la amb les imatges des de unity sense tocar una línia de codi, ja que les variables públiques apareixen a l'inspector de l'objecte a Unity.
Continuem, a l'start, és a dir a la creació simplement creem l'objecte del joc hang:
                void Start ()
{
hang = new HangMan ("hola");
}
Faltaria també posar el wordextractor, però per a este exemple no l'hem gastat, per simplificar. I ara el controlador que estarà en la funció OnGUI, tindrà 4 blocs:
  1. Assignació de variables
  2. Mostrar les variables
  3. Comprovar guanyat/perdut i mostrar missatge
  4. Comprovar si s'apreta una tecla i executar l'intent d'endivinar

void OnGUI ()
{
//BLOC1
Word = hang.GetWordCompleted ();
Lifes = hang.lifes;
LettersOK = hang.LettersOK;
LettersKO = hang.LettersTried;
WordCompletedText = (TextMesh)GameObject.FindWithTag ("WordCompleted").GetComponent (typeof(TextMesh));
LletresOKText = (TextMesh)GameObject.FindWithTag ("LletresOK").GetComponent (typeof(TextMesh));
LletresKOText = (TextMesh)GameObject.FindWithTag ("LletresKO").GetComponent (typeof(TextMesh));
//BLOC2
LletresOKText.text = LettersOK;
LletresKOText.text = LettersKO;
WordCompletedText.text = Word;
SpR = (SpriteRenderer)GameObject.FindWithTag ("Vides").GetComponent (typeof(SpriteRenderer));
SpR.sprite = Vides [Lifes];
//BLOC3
if (Lifes == 0) {
print ("you die");
}
if (hang.WordCompleted ()) {
print ("you win");
}
//BLOC4
if (Input.anyKeyDown) {
Event e = Event.current;
if (e.isKey) {
if (e.keyCode >= KeyCode.A && e.keyCode <= KeyCode.Z) {
hang.GuessLetter (e.keyCode.ToString ().ToLower () [0]);
}
}
}
}

L'única cosa que pot ser siga complicada és esta línia:
SpR.sprite = Vides [Lifes]; 
Com al vector d'sprites Vides tenim totes les imatges corresponents al penjat (sense cap part del cos a tot el cos una a una, en total 7: res, cap, tronc, braç esquerre,braç dret, peu esquerre, peu dret), li assignarem el corresponent a les vides que tinga. SpR és l'objecte sprite "Vides" que podem veure a la captura de pantalla de l'entorn Unity que he posat adés.
En breu posaré el projecte per a baixar, i podreu veure la versió web a:
http://hangman.vicentfernandez.cat (Encara no disponible)

dilluns, 9 de juny de 2014

TDDs a Unity(III)

Bo, seguint amb el joc del penjat, ara necessitarem alguna font de dades de les paraules. La forma més fàcil que he pensat és llegir d'un arxiu que continga un text (aleatori, lliure...) i extraiga una paraula, és a dir,

  • Indique l'arxiu
  • demane una paraula entre min i max lletres (ens permetrà configurar nivell de dificultat)
  • si després d'un determinat nombre d'intents no la trobe retorne "fail" (alguna cosa debia de fer)

Per tant només he trobat dos TDDs reals (altres com arxiu no existent... no els he contemplat, la veritat):

  • TestFailWord()
  • TestWordBetwenLimits()

Analitzem el codi del primer test:

 [TestMethod]
        public void TestFailWord()
        {
            WordExtractorClass W = new WordExtractorClass(@"C:\Users\Vicent\Desktop\prova.txt", 100,200);
            W.getNewWord();
            Assert.AreEqual(W.CurrentWord, "fail");
        }

Demanem de l'arxiu una paraula entre 100 i 200 lletres (suposem que no existeix) i comprovem que la paraula siga el cas d'error

Vegem el segon:

[TestMethod]
        public void TestWordBetwenLimits()
        {
            WordExtractorClass W = new WordExtractorClass(@"C:\Users\Vicent\Desktop\prova.txt", 6, 10);
            W.getNewWord();
            string _w = W.CurrentWord;
            Assert.IsTrue(_w.Length >= 6);
            Assert.IsTrue(_w.Length <= 10);
            Assert.AreNotEqual(_w, "fail");
        }
Igual que l'anterior però ara la demanem entre 6 i 10 (per exemple). Comprovem que estiga entre els límits i que la paraula no siga "fail". L'última comprovació és per què en algun test vaig posar límits entre 2 i 6, i tornava "fail" que si que acomplia eixos requisits però era debut error del programa.


Si ens fixem ja tenim el joc en c#. Ara només necessitem una interfície. Es pot programar en mode consola, en unity, XNA, DirectX... el que siga, podem empotrar-ho on vullgam que el que és el joc, ja està creat.

dissabte, 7 de juny de 2014

TDDs a Unity (II)

Bo, doncs com ja comentava intentarem crear un joc simple del penjat. Les regles són simple:

  1. Es tria una paraula
  2. Es tenen 6 vides (cap, braços, cos, cames)
  3. La paraula ix inicialment substituida cada lletra per un caràcter '_'
  4. Es pot elegir entre resodre i endivinar una lletra
  • Si resols i encertes guanyes
  • Si resols i no encertes perds una vida
  • Si endivines una lletra se substituix el caràcter '_' per la lletra corresponent en la posició pertinent
  • Si no encertes la lletra perds una vida


Comencem a programar ;) Obrim el Visual Studio i creem un projecte C# (per exemple de consola). Si no elegixes un projecte buid com jo, a l'intentar fer els tests, et dona un error que no troba cap main, te tocarà crear un nou arxiu.cs, i posar-li una funció main dummy:


 class Program
    {
        static void Main(string[] args)
        {
        }
    }

Afegim a la solució un projecte nou de test (ja ho vaig explicar a un altre post) i automàticament ens crea un test d'unitat, jo vaig pensar en aquestos tests:

  • public void GuessWordOK()
  • public void GuessWordFail()
  • public void LetterFail()
  • public void LetterOK()
  • public void WordCompleted()
  • public void WordNotCompleted()
  • public void YourDead()
  • public void CantGuessWordWhenDead()
  • public void CantGuessLetterWhenDead()
  • public void IndexIsGuessed() (Este crec que no faria falta )
  • public void GetLetterAtIndex() (Este crec que tampoc faria falta)
  • public void GetWordCompleted() 


No vaig a copiar i pegar totes les funcions per no avorrir (potser puge el codi el github), mirem per exemple la primera i la última:

 [TestMethod]
        public void GuessWordOK(){
            Tests.HangMan Hang = new Tests.HangMan("hola");
            bool res1 = Hang.DoTry("hola");
            Assert.IsTrue(res1);
        }
Creem la classe penjat (el joc), i intentem endevinar la paraula.
[TestMethod]
        public void GetWordCompleted()
        {
            HangMan Hang = new HangMan("hola");
            Hang.GuessLetter('o');
            Hang.GuessLetter('l');
            Hang.GuessLetter('z');
            Assert.AreEqual("_ol_", Hang.GetWordCompleted());
        }
Creem la classe joc i després de 3 intents (dos encertats i un fallit) comprovem que les lletres encertades estan actives i les que no amb un '_'

TDDs a Unity

Sí ja sé que feia molt de temps que no escrivia al bloc, no és que ho tinga abandonat, però acabe de ser pare, i l'embaraç i la meua xiqueta i el treball han segut prou durets últimament. A banda, duc aprenent a gastar Unity3D estos temps, la veritat és que estic enamorat del seu sistema, i a més em permet gastar el meu actual llenguatge preferit: C#.
Unity no és un entorn de desenvolupament, si no un entorn per a la creació de videojocs. Només es gasten llenguatges de programació per al comportament (scripting). Per a això és gasta un editor extern (ve per defecte el Monodevelop, però vaig aconseguir una vegada posar el Visual Studio.). Una de les primere limitacions que veig com a programador, és què Unity3d no està pensat en ells. Per tant no hi ha moltes opcions. Per exemple no he trobat cap eina per a realitzar els TDDs. Pot ser amb un plugin del Monodevelop, però vaig idear no pedre el temps. En un minijoc que estic realitzant ara (dels meus projectes mitjanets ja parlaré en un altre post) vaig pensar aïllar tot el que siga programació i fer-ho amb el Visual Studio amb nunit. Programes totes les classes que necessites (ja vaig parlar a un post anterior) i després inclous els arxius C# al teu projecte Unity. Simplement necessitaràs "programar" la classe de gestió dels objectes i les classes que deriven de MonoBehaviour, però deurien de ser les mínimes. Per exemple, si vullguerem fer un enemic, podriem programar l'atac, els atributs, l'AI... sense capturar update,OnGUI... i després afegir-lo... Estic parlant de C#, si gastem Javascript res ens impedix gastar jasmine, per exemple...