sabato 20 febbraio 2016

Riprodurre un video

Ciao ragazzi, eccomi qui con un tutorial dopo un pò di mesi.
Come ho spiegato nel precedente articolo, l'unico modo in cui per ora posso continuare a parlare del funzionamento di AGS è il blog.

Come avete letto dal titolo oggi si parla di come riprodurre video in AGS, una domanda che mi è stata posta molte volte.

In AGS esistono due funzioni adatte allo scopo: PlayVideo e PlayFlic.

PlayVideo serve per riprodurre file in diversi formati video (spiegherò quali nell'aritcolo), mentre PlayFlic per le animazioni Flic (formato .FLC) .

Premetto che sulle animazioni Flic non ho trovato molto, non sono abbastanza documentato, pertanto non so dirvi come possono essere create.
So che si tratta di un tipo di animazione obsoleto e utilizzato nelle avventure grafiche con Colour Depth a 8-bit, quindi molto datate. In questo tipo di giochi infatti PlayVideo non funziona.

Qualche riga sul funzionamento di PlayFlic verrà comunque spesa a fine articolo.

PlayVideo


I giochi con Colour Depth 16/32-bit possono utilizzare la funzione PlayVideo.
Vediamola nel dettaglio:

PlayVideo (string filename, VideoSkipStyle, int flags)

Questa funzione prende in input 3 parametri:
  • filename: una stringa, ovvero il nome del file da riprodurre (ad esempio "stanzarossa.avi");
  • VideoSkipStyle: una costante che ci verrà suggerita dall'editor e che rappresenta la modalità con cui al giocatore è permesso (o non permesso) di saltare il video;
  • flags: un numero intero per specificare alcuni aspetti della riproduzione del video (proporzioni e audio);

Filename


Esso altro non è che il nome del file compresa la sua estensione.
I file video devono essere inseriti nella cartella Compiled che trovate all'interno della cartella principale del gioco.

Va bene anche creare una o più sottocartelle dentro Compiled, ma, dovrete specificarla/le nel filename affinchè AGS lo possa trovare e riprodurre (ad esempio "introduzione/stanzarossa.avi" nel caso "introduzione" sia una sottocartella di Compiled).

I formati video supportati da AGS sono: AVI, MPG, OGG Theora o qualsiasi altro tipo di file supportato dal Media Player del vostro pc (su quest'ultimo punto non sono sicurissimo, ma così ho interpretato quello che l'help dinamico dice di PlayVideo).

Per quanto riguarda la compilazione del gioco (ovvero quando con F7 create l'eseguibile del vostro gioco finito), bisogna distinguere tra due tipi di formati video: gli OGG Theora e tutti gli altri tipi.

Per gli OGG Theora, AGS ha un supporto incorporato, quindi qualunque giocatore sarà in grado di vedere un video in questo formato.
I video OGG Theora sono inoltre integrati nel file EXE del gioco nel momento in cui il gioco viene compilato (accertatevi che il file abbia un estensione .OGV e sia posizionato nella cartella principale del progetto, non in Compiled).

Il secondo tipo di file che AGS può riprodurre è un qualsiasi formato supportato da Windows Media Player.
La lista include i formati AVI, MPG ed altri. Comunque, per fare in modo che questi tipi di formati vengano riprodotti, dovrete avere i codec video installati.
Per esempio, se create un video con codifica XVid, il player dovrà disporre del codec XVid installato.

A tal proposito, se già non ce l'avete, consiglio di scaricare e installare K-Lite Code Pack, pacchetto contenente codec video e audio per la riproduzione di tutti i formati video.

Attenzione però, questo tipo di video non può essere incluso nell'EXE del gioco, per cui dovrete darli al giocatore insieme all'eseguibile.

Questo significa che il giocatore avrà sia l'eseguibile che i video. Anche in questo caso, la struttura delle cartelle deve permettere ad AGS di trovare i file video che richiamate dal codice.

Ricapitolando: i video OGG Theora bisogna inserirli nella cartella principale del gioco (dove c'è anche il file .agf, non in Compiled) ed essi verranno incorporati nell'exe per cui anche a gioco compilato non avremo bisogno di una cartella apposita per i video che l'exe dovrà andare a caricare.

Gli altri formati invece devono essere inseriti in Compiled e non verranno incorporati nel gioco. Pertanto dovranno essere inseriti in una cartella apposita a gioco compilato e l'utente potrà anche aprirli volendo.

VideoSkipStyle


VideoSkipStyle definisce come il giocatore può saltare il video:
  • eVideoSkipNotAllowed: il giocatore non può saltare il video;
  • eVideoSkipEscKey: il giocatore può premere ESC per saltare il video;
  • eVideoSkipAnyKey: il giocatore può premere qualsiasi tasto per saltare il video;
  • eVideoSkipAnyKeyOrMouse: il giocatore può premere qualsiasi tasto o cliccare col mouse per saltare il video;

Flags


VideoSkipStyle definisce come il giocatore può saltare il video:
  • 0: the il video verrà riprodotto alle dimensioni originali, con audio AVI;
  • 1: il video verrà teso in altezza e larghezza a schermo intero, con le appropriate bande nere per mantenere le proporzioni e audio AVI;
  • 10: dimensioni originali, l'audio del gioco continuerà a venire riprodotto (audio AVI muto);
  • 11: teso in altezza e larghezza a schermo intero, l'audio del gioco continuerà a venire riprodotto (audio AVI muto);
Vediamo un esempio di come utilizzare questa funzione:

function room_Load()
{
  PlayVideo("stanzarossa.avi", eVideoSkipAnyKey, 0);
}


In questo caso, prima del caricamento della stanza verrà riprodotto il video chiamato "stanzarossa.avi". Il giocatore potrà saltarlo premendo un tasto qualsiasi della tastiera e verrà riprodotto alle dimensioni originali, con audio AVI;

Per comodità e ordine, nel prossimo esempio, invece di mettere il file del video semplicemente in Compiled, ho creato una cartella dentro Compiled chiamata "video".


function room_Load()
{
  PlayVideo("video/stanzarossa.avi", eVideoSkipAnyKey, 0);
}


Questo semplicemente per sottolineare che dentro Compiled possiamo creare più sottocartelle al fine di organizzare meglio il progetto.

Pensate se nel vostro gioco ci fossero decine di filmati, che guazzabuglio si verrebbe a creare considerando che in Compiled non ci sono solo i video.

Ecco un esempio di come può essere utilizzato un video.

Il codice è:

// room script file

function room_Load()
{
  PlayVideo("video/stanzarossa.avi", eVideoSkipAnyKey, 0);
}

function room_AfterFadeIn()
{
  aIce_Flow.Play();
  cEgo.Walk(200, 356, eBlock, eWalkableAreas);
}


In questo caso mi sono divertito a ricreare quell'effetto di filmato che si fonde con la grafica in-game visibile in alcuni titoli che utilizzano sfondi pre-renderizzati.

Prima del caricamento della stanza viene eseguito un filmato con l'audio (l'audio è del video, non è un file audio caricato in AGS).
Dopodichè viene caricata la stanza, che ha come sfondo l'ultimo frame del video cosicchè non si nota il passaggio dal video alla stanza.

AGS di default, carica la stanza con un effetto fade in. Se fosse stato così anche nel mio esempio, dopo il video avremmo visto il fade in della stanza, il che avrebbe rovinato l'effetto di continuità dal video al gioco.

Per togliere l'effetto fade in andate in General Settings, poi nella lista di opzioni, nella sezione Visual (verso la fine dell'elenco), cambiate l'opzione "Default transition when changing rooms" da "FadeOutAndIn" a "Instant".

Dopo il caricamento della stanza verrà riprodotta una traccia audio (questa volta caricata in AGS) e il nostro personaggio farà il suo ingresso nella stanza.

Ecco il risultato.



PlayFlic


Di questa funzione mi limiterò a riportarvi la traduzione direttamente dall'help dinamico.

PlayFlic (int flic_number, int options)

Riproduce un'animazione FLI o FLC. AGS cercherà un file nominato FLICx.FLC e FLICxFLI (dove x sta per il parametro flic_number) e se ne trova uno, lo riprodurrà.

 Il parametro options ha i seguenti significati:
  • 0: il giocatore non può saltare l'animaizone;
  • 1: il giocatore può premere ESC per saltare l'animazione;
  • 2: il giocatore può premere qualsiasi pulsante o cliccare col mouse per saltare il video;
  • +10 (es.10,11,12): non tendere in altezza e lunghezza, non ripeodurre a schermo intero, riproduci semplicemente alle dimensioni del file flc;
  • +100 non pulire lo schermo prima della riproduzione;
Il gioco andrà in pausa mentre l'animazione viene riprodotta.

Esempio:

PlayFlic(2, 1);

Riprodurrà il file flic2 e il giocatore sarà in grado di saltare l'animazione premendo ESC.

Ragazzi, anche per questa volta è tutto. Ci vedremo in futuro, purtroppo non so quando... il periodo è un pò così. Comunque sia, alla prossima!

sabato 2 gennaio 2016

Un procione in letargo.

Buon anno ragazzi, è da tanto tempo che non ci si sente.

Negli ultimi mesi sono scomparso dalla circolazione, mi scuso con coloro che attendevano nuovi video su AGS.

Il fatto è che in questo ultimo periodo le ore da dedicare al canale si sono ridotte drasticamente e, quando questo succede si vorrebbe utilizzare le ore rimanenti nel migliore dei modi per se stessi.
Mi dispiace dire che sempre più spesso dedicarmi al canale sta diventando un lavoro, un compito, ed è dura destinare le ore di svago ad una cosa che si sente più come un dovere più che un piacere.

Non voglio annoiarvi con tutto il procedimento che uso per girare un video del canale, ma vorrei soltanto sottolineare che è non è una cosa veloce, richiede ore e non si fa in un pomeriggio.
Potreste pensare che sia troppo pignolo, troppe complicazioni per girare un benedetto video da 20 - 30 minuti... Invece è proprio per velocizzare il tutto che prima di mettermi di fronte al microfono, preparo con cura ogni puntata.

Al contrario, le prime le giravo senza scaletta, senza provare prima quello che vi avrei spiegato e quindi via di errori, imprevisti, tagli, parti in mezzo al video che venivano ri-girate, montaggio lunghissimo, durata del video maggiore ma puntata più dipersiva nei contenuti.

Insomma, gli errori che scaturivano dalla scarsa organizzazione rendevano la realizzazione di un video ancor più lunga di quanto lo sia ora, diminuendo anche la qualità del video stesso.

Certamente, il procedimento che uso tutt'ora ha abbassato il numero di ore per creare un video, ma è anche vero che le ore sono ancora troppe per essere qualcosa di piacevole (o almeno non pesante) da fare.

Tra le cose che ho in mente c'è quella di scrivere o su questo blog o farne uno nuovo in Wordpress con un dominio mio.

Fare puntate in forma scritta è certamente più semplice che fare dei video, anche se il video ha il pregio di mostrare quello che viene spiegato in tempo reale, ma dovevo trovare un compromesso.

Dopo questo articolo pubblicherò in forma scritta quello che doveva essere un video (in cantiere da più di due mesi!) sul riprodurre video in AGS, argomento sul quale mi sono arrivare diverse email.

Dopo l'articolo sul riprodurre video vedrò cosa fare (blog o non blog, e il canale?), ma non so dirvi quando avrete una risposta precisa sul futuro dei tutorial di AGS (al momento sono confuso anch'io), scusate.

Non so in quanti leggeranno questo post, ma mi premeva dare una spiegazione un pò più dettagliata a chi mi segue sulla mia assenza da youtube.

Per ora, ci vediamo al prossimo articolo.
Un abbraccio e felice anno nuovo!

mercoledì 8 aprile 2015

Enigma a codice in AGS

Ciao ragazzi,

nel video relativo al ciclo while promisi una puntata su come creare un enigma a codice. Purtroppo però nelle ultime settimane non ho avuto modo di registrarlo.
Avevo però il tutorial pronto da tempo e mi dispiaceva farvi attendere oltre, quindi alla fine ho deciso di farlo in forma scritta così da non dover ancora aspettare il momento giusto per registrare.

Non appena avrò il tempo per farlo, caricherò comnque una versione video di questo tutorial sul canale youtube.

Prima di cominciare, breve premessa per le parti di codice che vedrete.
Le righe in neretto rappresenteranno le nuove righe di codice aggiunte rispetto allo script mostrato in precedenza.

function room_RepExec()

 
}

function room_RepExec()

  if(enigmaRisolto == true)
  {
    Display("Bravo!");
    Display("Bravissimo!");
    Display("Sei un genio!");
    Display("Ma come hai fatto?!");
    Display("Ok basta, non fa ridere...");
  }
}

I tre puntini invece indicheranno che in quel punto è presente del codice che però per quell'esempio non è importante mostrare ancora, questo per non rendere troppo lunghi gli esempi di codice.

function room_RepExec()

  if(enigmaRisolto == true)
  {
    ... //I Display dell'esempio precedente
    
    cEgo.ChangeRoom(2); //Nuova riga di codice
  }
}

Alla fine dell'articolo troverete comunque tutti gli script completi.
Bene ragazzi, cominciamo!

Innanzi tutto, apriamo il nostro progetto in AGS. Può essere un gioco nuovo o esistente nel caso vogliate inserire in esso l'enigma.

Il mio progetto prevede una sola stanza con una porta chiusa elettronicamente. A destra della porta c'è un tastierino numerico sul quale digitare un codice per sbloccarla.
Eccola qua:


Sul tastierino è posto un Hotspot chiamato hTastiera (blu) e sulla porta un altro chiamato hPorta (verde).


Ok, preparata la stanza cominciamo col creare la GUI che rappresenta il tastierino numerico. La chiamerò gTastiera.

Questa GUI contiene i seguenti elementi:

  • lTastiera: una Label per visualizzare il codice man mano che viene digitato dall'utente;
  • bNum0...bNum9: nove pulsanti per i numeri da 0 a 9;
  • bBackSp: un tasto per cancellare una cifra alla volta il codice partendo da destra, esattaamente come il tasto Backspace della tastiera del nostro pc.
  • bEsci: un pulsante per uscire dall'enigma;

Questa GUI contiene il minimo indispensabile per permettere all'utente di provare a risolvere l'enigma e uscire da esso nel caso avesse ancora bisogno di cercare ulteriori elementi per risolverlo.

Impostiamo la proprietà Visibility come Normal, initially off dato che all'inizio del gioco questa GUI non deve essere visibile.


Ora iniziamo a dare vita all'enigma scrivendo il codice per l'Hotspot del tastierino e per gli elementi della GUI.

Dato che questa GUI comparirà quando l'utente interagisce sul tastierino di fianco alla porta, entriamo nell'evento Interact hotspot di hTastiera e inseriamo il codice per rendere visibile gTastiera.

function hTastiera_Interact()
{

  gTastiera.Visible = true;
}

Ok, il tastierino compare, ma ovviamente se proviamo a premere un qualsiasi pulsante nulla accade. Ce ne occuperemo dopo.

Ora è venuto il momento di capire come, dal lato della programmazione, determinare la risoluzione dell'enigma.
La soluzione più semplice (che come accade spesso in programmazione non è comunque l'unica) è quella di confrontare il codice inserito dall'utente con un codice scelto da noi.

Se i due codici combaciano, l'enigma è risolto, la GUI scompare da sola e la porta si sblocca.
Altrimenti non succede nulla, la GUI rimarrà visibile dandoci la possibilità di provare altri codici o di uscire per cercare ulteriori indizi su come risolvere l'enigma.

Per operare questo confronto ci serviremo di due variabili: codiceUtente che conterrà il codice inserito dall'utente, e codiceEnigma conterrà il codice da noi scelto e che l'utente dovrà digitare per andare avanti nel gioco.
Entrambe le variabili saranno di tipo String e saranno globali poichè necessiteranno di essere lette e scritte anche fuori dalla Room.

Potreste chiedervi come mai due variabili che contengono numeri vengano dichiarate String invece che int. Il perchè è presto detto: sebbene entrambe le variabili contengono numeri, con questi numeri non abbiamo bisogno di compiere alcuna operazione aritmetica, avremo invece bisogno di trattarle come "parole".

Potrete infatti utilizzare il metedo che sto per spiegarvi anche per enigmi di codici alfabetici e alfanumerici in quanto in tutti i casi il codice sarà comunque una stringa, un parola.
Inoltre, dichiarare queste variabili come stringhe ci permettarà di utilizzare alcune funzioni che si adattano perfettamente al nostro scopo.

Andiamo quindi in Global variables e creiamo le due variabili. Per creare una variabile globale basterà cliccare sulla tabella (vuota, se il gioco è nuovo) delle variabli globali e selezionare Add new variable....

La prima variabile avrà come nome codiceUtente, sarà di tipo String e non avrà alcun valore predefinito, sarà vuota poichè popolata mano a mano che il giocatore digita il codice.



La seconda variabile avrà come nome codiceEnigma, anch'essa di tipo String e avrà come valore predefino un codice numerico di quattro cifre, nel mio caso 7514.




Volendo, potreste anche avere un codice più corto o più lungo di quattro cifre. Tuttavia per ora sarebbe meglio che vi atteniate al mio esempio. Una volta capito il meccanismo, poi, potrete modificare i miei script per adattarli al vostro enigma.



Bene, ora è venuto il momento di rendere funzionali i tasti numerici di gTastiera.
Ogni tasto permetterà l'inserimento di una cifra che andrà a comporre il codice di quattro cifre.

Quando un tasto numerico verrà premuto, la cifra corrispondente verrà visulaizzata in lTastiera, che fungerà da display del nostro tastierino numerico.

Facciamo quindi doppio click sul tasto numero del numero 1 (bNum1) per entrare nel suo evento OnClick.

function bNum1_OnClick(GUIControl *control, MouseButton button)
{

}

Riepilogando, abbiamo la variabile codiceUtente che conterrà il codice inserito dal giocatore, variabile che verrà popolata man mano che l'utente digita il codice.
Ad ogni pressione di un tasto numerico, dunque, viene aggiunta una cifra a codiceUtente.

Le stringhe in AGS dispongono di una funzione che fa proprio al caso nostro, trattasi della funzione Append.

Per aggiungere quindi la cifra corrispondente al numero del tasto scriviamo:

function bNum1_OnClick(GUIControl *control, MouseButton button)
{

  codiceUtente = codiceUtente.Append("1");
}

Ovvero, codiceUtente viene impostata come codiceUtente con l'aggiunta del numero 1.
Se bNum1 sarà premuto per immettere la prima cifra del codice, codiceUtente (che in quel caso sarà vuota), diventerà 1.
Se bNum1 sarà premuto per immettere la terza cifra del codice (avendo precedentemente premuto bNum0 e bNum6), codiceUtente diventerà 061.

Quindi Append aggiunge una cifra in coda a quelle precedenti.

Ok, ora la variabile codiceUtente comincia ad essere popolata una cifra per volta, ma come visualizzare questo codice in tempo reale man mano che viene digitato?

Basterà impostare la proprietà Text di lTastiera come uguale a codiceUtente.

function bNum1_OnClick(GUIControl *control, MouseButton button)
{

  codiceUtente = codiceUtente.Append("1");
  lTastiera.Text = codiceUtente;
}

Facciamo lo stesso per tutti gli altri tasti numerici cambiando soltanto la stringa tra le parentesi della funzione Append in modo che rispecchi il numero sul tasto premuto.
So che è un pò tedioso ripetere le stesse righe di codice per altre nove volte, ma per ora non ho trovato soluzione migliore.

Bene, i tasti numerici ora funzionano e  possiamo vedere le cifre comparire sul display del nostro tastierino.


Veniamo al tasto bBackSp. Per cancellare una cifra per volta partendo da destra ci avvarremo di una funzione simile ad Append chiamata Truncate.
Truncate chiede come argomento un numero intero che rappresenta la lunghezza della stringa una volta operata la troncatura.
Ad esempio il codice:

String colore = "Verde Smeraldo";
colore.Truncate(3);
Display("%s", colore);

ci farà vedere a video la stringa "Ver", ovvero le prime 3 lettere della stringa "Verde Smeraldo".
La stringa colore è stata quindi troncata eliminando i caratteri dal quarto in giù.

Entriamo quindi nell'evento OnClick di bBackSp.

function bBackSp_OnClick(GUIControl *control, MouseButton button)
{
 
}

E inseriamo:

function bBackSp_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Truncate(codiceUtente.Length - 1);
  lTastiera.Text = codiceUtente;

}

Quando il giocatore preme bBackSp codiceUtente viene troncato lasciando un numero di caratteri uguale alla lunghezza di codiceUtente meno 1:

codiceUtente.Length - 1

Se codiceUtente in quel momento è lungo 4 (ad esempio, 0567), premendo bBackSp esso viene troncato in modo da lasciare solo le prime 3 cifre (4 - 1 = 3, ovvero 056) e così via se bBackSp viene premuto più volte.
Dopodichè mostriamo sul display del nostro tastierino il codice troncato aggiornando la proprietà Text di lTastiera.

Ok, tutto bello ma... ci sono dei bug!
Il codice di sicurezza è composto da 4 cifre, ma nulla vieta al giocatore di immetterne di più, anche 1000!



Inoltre, il giocatore può premere quante volte vuole il tasto Backspace anche quando si sono già cancellate tutte le cifre del codice, cosa che porta a un errore in AGS, in quanto la funzione Truncate non può troncare una stringa che è già di per sè lunga zero cifre.


Dobbiamo quindi disabilitare i tasti numerici quando la lunghezza del codice digitato (codiceUtente) arriva a 4 cifre e abilitare il tasto Backspace solo se codiceUtente è di almeno una cifra.

Dato che questo controllo deve essere operato in tempo reale - ovvero AGS deve costantemente tenere d'occhio la lunghezza di codiceUtente per capire se abilitare o disabilitare i tasti - questo controllo deve avvenire nell'evento Repeatedly execute della stanza in cui si trova l'enigma.

Andiamo quindi in Repeatedly execute della stanza.

function room_RepExec()
{


}

Cominciamo con il tasto bBackSp. Come detto poco fa, questo tasto deve essere abilitato solo se il codice digitato è di almeno una cifra. Il che tradotto in codice è:

function room_RepExec()

  if(codiceUtente.Length > 0)
  {
    bBackSp.Enabled = true;
  }
  else
  {
    bBackSp.Enabled = false;
  }
}

Come ricorderete, codiceUtente.Length altro non è che la lunghezza in caratteri del codice immesso dal giocatore.
Adesso quando il codice digitato è di 0 cifre il tasto Backspace verrà disabilitato, cosa che riconosceremo dal fatto che il tasto sarà di un grigio più chiaro.

Backspace abilitato

Backspace disabilitato

Ora veniamo ai tasti numerici. Anche qui, ricordando quando detto prima, se la lunghezza del codice arriva a 4 cifre, questi tasti verranno disabilitati. In altre parole i tasti devono essere abilitati solo se la lunghezza di codiceUtente è inferiore a 4.

Il che in codice diventa:

function room_RepExec()

  ...

  if(codiceUtente.Length < 4)
  {
    //Abilito i tasti
  }
  else
  {
    //Disabilito i tasti
  }

}

Ho omesso di proposito il codice per abilitare e disabilitare i tasti perchè devo fare una premessa.
I tasti, come avete visto con bBackSp si abilitano e disabilitano mediante la proprietà Enabled.
bBackSp è un tasto solo, quindi sia per abilitarlo che per disabilitarlo ce la siamo cavati con una riga di codice.

La faccenda è diversa se dobbiamo abilitare o disabilitare dieci tasti numerici. Dovremmo scrivere dieci righe sia per abilitarli tutti che viceversa.

function room_RepExec()

  ...

  if(codiceUtente.Length < 4)
  {
    bNum0.Enabled = true;
    bNum1.Enabled = true;
    bNum2.Enabled = true;
    bNum3.Enabled = true;
    bNum4.Enabled = true;
    bNum5.Enabled = true;
    bNum6.Enabled = true;
    bNum7.Enabled = true;
    bNum8.Enabled = true;
    bNum9.Enabled = true;
  }
  else
  {
    bNum0.Enabled = false;
    bNum1.Enabled = false;
    bNum2.Enabled = false;
    bNum3.Enabled = false;
    bNum4.Enabled = false;
    bNum5.Enabled = false;
    bNum6.Enabled = false;
    bNum7.Enabled = false;
    bNum8.Enabled = false;
    bNum9.Enabled = false;
  }


È leggitimo procedere in questo modo e non c'è nulla di sbagliato, ma c'è un modo per accorciare notevolmente il codice.

Vi ricordate gli array e il ciclo while? Ecco una situazione in cui possiamo utilizzarli.

Tutti i controlli inseriti in una determinata GUI possono essere richiamati sia nel modo classico, ovvero scrivendo il loro nome (bNum5, bEsci, lTastiera e così via), sia richiamando l'array Controls abbinato a quella GUI.

Nel nostro caso, i controlli della GUI gTastiera possono essere raggiunti attraverso l'array Controls di gTastiera, richiamabile scrivendo gTastiera.Controls.

In questo array ogni cella è occupata da un controllo della GUI. L'indirizzo a cui e situato ogni controllo è dato dalla proprietà ID del controllo stesso.

Ad esempio, bNum7 ha un ID pari a 6. Quindi nella cella numero 6 dell'array Controls di gTastiera troviamo bNum7.
In codice potremmo dire che in gTastiera.Controls[6] troviamo bNum7.


Gli ID vengono dati in base all'ordine in cui i controlli vengono da noi inseriti nella GUI e partono da 0, per cui se avrò inserito per primo bNum1 e poi bNum2, essi avranno rispettivamente come ID 0 e 1.

Nel mio caso i tasti numerici sono stati i primi elementi ad essere inseriti nella GUI dunque nell'array Controls occupano le celle da 0 a 9.

Il ciclo while per abilitarli e disabilitarli a questo punto dovrebbe apparirvi sensato:

function room_RepExec()

  ...

  if(codiceUtente.Length < 4)
  {
    int i = 0;

    while(i <= 9)
    {
      gTastiera.Controls[i].Enabled = true;
      i++;

    }
  }
  else
  {   

    int i = 0;
    while(i <= 9)
    {
      gTastiera.Controls[i].Enabled = false;
      i++;

    }
  }
}

La variabile i inizializzata a 0 e incrementata a ogni giro del ciclo permette di riferirci giro dopo giro ad una cella specifica dell'array.

Adesso i tasti del tastierino numerico si bloccheranno quando il codice digitato arriva a una lunghezza di 4 cifre.

Tasti numerici abilitati

Raggiunte 4 cifre: tasti numerici disabilitati
Bug risolti!

Occupiamoci del tasto Esci che ci farà uscire dall'enigma, rimuovendo la GUI dallo schermo.
Entriamo nell'evento OnClick di bEsci e inseriamo gTastiera.Visible = false.

function bEsci_OnClick(GUIControl *control, MouseButton button)
{
  gTastiera.Visible = false;
}

La GUI verrà così rimossa dallo schermo. C'è però un piccolo bug.
Mettiamo che, tentando di risolvere l'enigma immetta un paio di cifre. Poi, non riuscendo a risolverlo, esca dalla GUI senza cancellare alcuna cifra.
Poco dopo voglio provare nuovamente a risolverlo e interagisco di nuovo con il tastierino di fianco alla porta richiamando così la GUI.
Noterete che le cifre immesse dall'ultimo tentativo sono ancora lì, sulla Label della GUI.
Questo perchè precedentemente avevamo impostato lTasitera in modo che mostrasse il valore di codiceUtente.

Al nuovo richiamo di gTastiera, la Label lTastiera continuerà giustamente a mostrare il valore di codiceUtente che è quello da noi assegnatoli nel tentativo precedente di risolvere l'enigma.

Quindi, una volta premuto bEsci dobbiamo, oltre a rimuovere la GUI, svuotare la variabile codiceUtente e aggiornare la proprietà Text di lTastiera in modo che rispecchi il valore aggiornato di codiceUtente, ovvero vuoto.

function bEsci_OnClick(GUIControl *control, MouseButton button)
{
  gTastiera.Visible = false;
  codiceUtente = "";
  lTastiera.Text = codiceUtente;

}

Ad ogni nuovo tentativo di risolvere l'enigma, lTastiera sarà pulita.

Ora, occupiamoci di confrontare il codice immesso dal giocatore con quello da noi scelto per determinare la risoluzione dell'enigma.
A tal proposito possiamo sfruttare l'if che abilita e disabilita i tasti numerici scritto in precedenza.

Se vi ricordate, i tasti numerici vengono disabilitati quando codiceUtente raggiunge i 4 caratteri di lunghezza e questo è anche il momento migliore per confrontare il codice immesso dal giocatore con quello che abbiamo scelto noi.

Annidiamo in questo braccio dell'if il seguente if:

function room_RepExec()

  ...

  if(codiceUtente.Length < 4)
  {
    ...
  }
  else
  {   

    int i = 0;
    while(i <= 9)
    {
      gTastiera.Controls[i].Enabled = false;
      i++;

    }
    
     if(codiceUtente == codiceEnigma)
     {
       Display("Porta sbloccata");         
       codiceUtente = "";
       gTastiera.Visible = false;
     }

  }
}

Con questo if chiediamo se il codice immesso dall'utente è lo stesso scelto da noi programmatori per l'enigma.
Se la risposta è si, ovvero se la condizione risulta true mostreremo la scritta "Porta sbloccata", svuoteremo la variablie codiceUtente e faremo scomparire la GUI del tastierino.


Svuotare la variabile codiceUtente, anche se a prima vista non si direbbe, è molto importante. Perchè? Perchè se non lo facessimo essa continuerebbe sia ad avere una lunghezza uguale a 4 - facendoci così entrare nell'else del if - sia ad essere uguale a codiceEnigma, facendoci entrare addirittura nell'if annidato ed eseguendo le righe al suo interno.
Cosa che causerebbe il continuo riproponimento della scritta "Porta sbloccata" nel mio caso.

C'è un ultimo aspetto da prendere in considerazione.

Anche dopo la risoluzione dell'enigma, qualora il giocatore cliccasse sull'Hotspot del tastierino, la GUI gTatstiera comparirebbe nuovamente, cosa che non ci serve più ora che l'enigma è stato risolto.

Per risolvere questo problema basterà creare una variabile booleana che nel mio casao sarà enigmaRisolto e che avrà il valore iniziale di false dato che l'enigma all'inizio del gioco non è risolto.
Quando l'utente clicca sull'Hotspot del tastierino verrà eseguito un if che controllerà il valore di enigmaRisolto.
Se essa è true, ovvero l'enigma è già stato risolto, faremo dire a Ego la frase: <<Ho già sbloccato la porta!>>. Se invece è false mostreremo la GUI dando la possibilità all'utente di rsolvere l'enigma.

Non è necessario dichiararla globale, in quanto essa verrà solamente utilizzata nella Room dove si trova anche l'enigma.

Dichiariamo quindi questa variabile alla prima riga della pagina degli script della Room in modo da renderla accessibile a tutti gli eventi della pagina.

bool enigmaRisolto = false;

Ora facciamola entrare in azione. Il suo valore cambierà in true nel momento in cui l'enigma sarà risolto.
Andiamo allora nell'if che confronta codiceUtente con codiceEnigma e iseriamo il cambio di valore di enigmaRisolto.

function room_RepExec()

  ...

  if(codiceUtente.Length < 4)
  {
    ...
  }
  else
  {   

    int i = 0;
    while(i <= 9)
    {
      gTastiera.Controls[i].Enabled = false;
      i++;

    }
    
     if(codiceUtente == codiceEnigma)
     {
       Display("Porta sbloccata");

       enigmaRisolto = true;         
       codiceUtente = "";
       gTastiera.Visible = false;
     }

  }
}

Inseriamo infine un if che controlla il valore di questa variabile all'interno dell'evento Interact di hTastiera per dare o meno l'accesso all'enigma come spiegato in precedenza.

function hTastiera_Interact()
{

  if(enigmaRsolto == false)
  {   
    gTastiera.Visible = true;
  }
  else
  {
    cEgo.Say("Ho già risolto l'enigma!");
  }
}

Possiamo anche sfruttare engimaRisolto con l'Hotspot sulla porta blindata (hPorta) per permettere o meno il cambio di stanza.
Con un if possiamo controllare il valore di questa variabile. Se è false Ego dirà: <<La porta sembra bloccata elettronicamente.>>, viceversa andremo avanti col gioco (ad esempio un cambio di stanza o l'inizio di una cutscene).

function hPorta_Interact()
{
  if(enigmaRisolto == false)
  {
    cEgo.Say("La porta sembra bloccata elettronicamente.");
  }
  else
  {
    cEgo.ChangeRoom(2);
  }
}

Bene ragazzi, il succo del tutorial è questo, spero vi sia piaciuto e che vi sia stato utile.
Da qui in poi potrete modificare, espandere e rendere anche più complesso l'enigma.

Come già detto più volte, potete anche utilizzare questo metodo per un codice alfabetico o alfanumerico.
Basterà scegliere un valore diverso per codiceEnigma, creare una GUI con tasti sia numerici che alfabetici e adattare l'if e i cicli while che controllano l'abilitazione/disabilitazione dei tasti, nonchè quello che confronta codiceUtente con codiceEnigma.

Ecco gli script completi.

Script della stanza:

bool enigmaRisolto = false;

function hTastiera_Interact()
{
  if(enigmaRisolto == false)
  {
    gTastiera.Visible = true;
  }
  else
  {
    cEgo.Say("Ho gia' risolto l'enigma!");
  }
}

function hPorta_Interact()
{
  if(enigmaRisolto == false)
  {
    cEgo.Say("La porta sembra bloccata elettronicamente.");
  }
  else
  {
   cEgo.ChangeRoom(2);
  }
}

function room_RepExec()
{
  if(codiceUtente.Length > 0)
  {
    bBackSp.Enabled = true;
  }
  else
  {
    bBackSp.Enabled = false;
  }

  if(codiceUtente.Length < 4)
  {
    int i = 0;
    while(i <= 9)
    { 
      gTastiera.Controls[i].Enabled = true;
      i++;
    }
  }
  else
  {
    int i = 0;
    while(i <= 9)
    {
      gTastiera.Controls[i].Enabled = false;
      i++;
    }
   
    if(codiceUtente == codiceEnigma)
    {
      Display("Porta sbloccata");
      enigmaRisolto = true;
      codiceUtente = "";
      gTastiera.Visible = false;
    }
  } 
}

Script della GUI:

function bNum1_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("1");
  lTastiera.Text = codiceUtente;
}

function bNum2_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("2");
  lTastiera.Text = codiceUtente;
}

function bNum3_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("3");
  lTastiera.Text = codiceUtente;
}

function bNum4_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("4");
  lTastiera.Text = codiceUtente;
}

function bNum5_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("5");
  lTastiera.Text = codiceUtente;
}

function bNum6_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("6");
  lTastiera.Text = codiceUtente;
}

function bNum7_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("7");
  lTastiera.Text = codiceUtente;
}

function bNum8_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("8");
  lTastiera.Text = codiceUtente;
}

function bNum9_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("9");
  lTastiera.Text = codiceUtente;
}

function bNum0_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Append("0");
  lTastiera.Text = codiceUtente;
}

function bBackSp_OnClick(GUIControl *control, MouseButton button)
{
  codiceUtente = codiceUtente.Truncate(codiceUtente.Length - 1);
  lTastiera.Text = codiceUtente;
}

function bEsci_OnClick(GUIControl *control, MouseButton button)
{
  gTastiera.Visible = false;
  codiceUtente = "";
  lTastiera.Text = codiceUtente;
}

Se avete domande scrivetemi sotto questo articolo, sotto il video da cui questo articolo è linkato o al mio indirizzo email: triventrive@gmail.com.
Vi ringrazio per essere arrivati fin qui e non mi dilungo oltre.

A presto!

domenica 29 dicembre 2013

Le Conversazioni in Adventure Game Studio

Ben tronati cari utenti, è da un pò di giorni che devo fare un video sui dialoghi in AGS, arogmento di cui io stesso, lo ammetto, sapevo poco.

Dopo aver appreso le regole per scrivere un dialogo in AGS grazie a questo, questo, questo e questo video di densming ho pensato di fare finalmente questo benedetto video.
Però, ecco che una serie di problemi si presenta: come faccio a scrivere un dialogo che racchiuda tutti i concetti che voglio spiegare, un esempio "maestro"? E come spiegare questi concetti in modo succinto senza ingarbugliarmi, rendendo tutto ben chiaro anche a coloro che guardano il video?

Così ho deciso, per risparmiare a voi ulteriori attese e spiegazioni prolisse, e a me pomeriggi persi a imprecare contro il microfono cercando di dare ad una frase il senso voluto, di racchiudere (come ho già fatto con gli articoli su Blender) la teoria in un post scritto e di usare i video per gli esempi pratici.

E quale miglior spiegazione teorica di quella che potete trovare nel manuale integrato in AGS?
Per questo ho deciso di tradurre in italiano la parte relativa a questo argomento. In - praticamente - una pagina trovate tutte le regole per scrivere i vostri dialoghi e far reagire il gioco secondo i dettami che avete stabilito.
Se avessi dovuto fare un video con quello che trovate in questa pagina, probabilmente sarebbe durato un'ora circa.

Dopo questo articolo, farò sì anche dei video, ma essi saranno di esempi pratici, scevri da tutta la teoria che avrebbe fatto inevitabilmente lievitare la durata di essi.

La pagina è pressochè formattata nello stesso modo di quella che trovate nel manuale, anche se in un paio di occasioni ho aggiunto una breve nota laddove la traduzione dall'inglese all'italiano lasciava spazio a fraintendimenti.
Per scaricarla, cliccate sul link alla fine dell'articolo.
Il suo scopo è quello di essere propedeutica per i prossimi video.

Le Conversazioni in Adventure Game Studio

lunedì 11 febbraio 2013

Make Human: un programma utilissimo.

Bentornati, in questo articolo vorrei parlarvi di Make Human un programma Open Source gratuito che ci permette di creare modelli 3D di corpi umani altamente personalizzati.

Premetto che lo conosco piuttosto superficialmente in quanto lo uso principalmente per creare modelli a cui "scatterò" delle foto delle quali mi servirò per modellare i miei personaggi. Pertanto non esplorerò tutte le sue funzioni.

Ma è bene che ve lo introduca perchè ci sarà utile nei prossimi articoli dedicati alla modellazione e animazione del personaggio per il gioco Adventure Game Studio.

Make Human si può scaricare dal sito ufficiale alla pagina release.


Nella pagina sono presenti le versioni per diversi sistemi operativi. Avendo Windows, utilizzerò la vesione per questo sistema operativo.


La cosa interessante, è che (come potete vedere andando alla pagina Make Human Mesh License) le Mesh create con questo programma hanno un licenza Creative Commons CC0. Possono quindi, tra le altre cose, essere utilizzate per progetti commerciali e non, senza chiedere il permesso all'autore del programma.


Si tratta insomma della licenza più libera che ci sia.
Vi invito comunque a dare un'occhiata alla pagina in questione per maggiori informazioni.

Una volta scaricato e installato Make Human, avviamolo.

Ecco che vediamo un modello standard.

Col Tasto Destro del mouse possiamo ruotare a piacimento il modello, scorrendo la rotella, o tenendola premuta e muovendo il mouse avanti e indietro possiamo zoomare nelle due direzioni, mentre con il Tasto Sinistro sposteremo il modello lungo la finestra.

Il modello, per ora ha tutti i valori impostati a metà.


In esso è al 50% maschio e 50% femmina, avrà un'età media, sarà di altezza media, ecc...

Agendo sui vari parametri ci sarà possibile decidere appunto:

- il sesso;
- l'età;
- il tono muscolare;
- il peso;
- l'altezza;
- L'etina (possiamo anche mescolare le etnie in diverse misure).



Nella scheda Torso potremo agire sul busto.


Anche qui le possibilità sono varie. Ad esempio scorrendo veso destra o sinistra il quadrato di ciascuna opzione possiamo decidere:


- lo spessore del busto;
- la sua larghezza;
- la sua ampiezza in altezza (per utilizzare una terminologia alla Blender, quanto esso è scalato lungo l'asse Z).
- quanto è spostato verso destra o sinistra;
- quanto è spostato verso l'alto o verso il basso;
- quanto è spostato in avanti o indietro.


Nella finestra a Category a destra, potremo apportare modifiche anche ai fianchi (Hip) al bacino (Pelvistone), allo stomaco (Stomach) e al fondoschiena (Buttocks).


Nella scheda Face, come potete immaginare modificheremo il viso.


Potremo modificare la forma di esso, anche mischiando più forme insieme in diverse percentuali.

Inoltre, sempre spostandoci nella finestra Category avremo addirittra la facoltà di cambiare ogni minimo connotato del viso nei modi più disparati. Modi che ci verranno mostrati nella finetra a sinistra.

Quest'ultima cambierà ogni volta che selezioniamo il connotato da modificare.


In Arms and Legs potremo modificare in svariati modi anche mani, piedi, braccia e gambe.


Capite quindi quante opzioni ci siano e quanto sia personalizzabile ogni modello.

E non è finita qui, ce ne sono altre che putroppo non conosco molto e che se elencate farebbero di questo articolo un lungo manuale del programma!

Per citarne alcune, si va dal colore della pelle, alle espressioni facciali, più qualche capigliatura, vestito e altro ancora.
Alcune di queste le potete trovare nella cartella superiore Library, sottoscheda Expressions per quanto riguarda le espressioni facciali.


Comunque, una volta deciso come dev'essere il nostro modello, potremo anche importarlo in Blender, completo di una struttura (chiamata anche "Armatura" o in inglese "Rig") sulla quale possiamo agire per fargli assumere diverse posizioni.

Per esportarlo, spostiamoci nella cartella superiore Files e nella sottoscheda Export.


Nella tabella Format selezioniamo Blender Exchange (mhx), lasciamo tutto com'è, diamo un nome al modello e clicchiamo su Export.


Una finesta ci avviserà che il modello è stato salvato all'interno della cartella Documenti/makehuman/exports.

Ora apriamo Blender e dal menù a tendina in basso a sinistra, invece che 3D View selezioniamo User Preferences.


Dopodichè entriamo nella scheda Addons e nel campo di ricerca a sinistra digitiamo "makehuman" (anche solo "make" andrà bene) per cercare e attivare l'Addon che ci permetterà di importare i modelli creati con Make Human.


Attiviamo l'Addon spuntando la casella.


Ora ritorniamo nelle 3D View selezionandola dallo stesso menù a tendina dal quale prima abbiamo selezionato User Preferences e cancelliamo il Cubo.

Clicchiamo su File, Import, MakeHuman(.mhx).


Selezioniamo il modello da caricare e infine clicchiamo su Import MHX.


Ecco che il modello verrà caricato in tutta la sue imponenza (in effetti è bello alto!) completo di un utilissima Armatura per metterlo in varie posizioni e animarlo (vicino alla faccia c'è n'è anche una per i muscoli del volto).


Ora il modello (o meglio l'Armatura) è in Pose Mode, modalità particolare delle Armature che ci permette di muovere la struttura e vederne gli effetti sul modello.

Ad esempio, se selezioniamo la parte del'Armatura dedicata alla coscia sinistra (parte colorata di giallo)...


... e andiamo in vista ortogonale laterale destra, premendo R potremo ruotare la coscia. Di conseguenza verranno anche ruotati il polpaccio e il piede.


Potremo agire in questo modo con tutte le altre parti del corpo.


Abbiamo insomma un modello completamente snodabile che possiamo utilizzare in tantissimi modi.

Ad esempio, possiamo animarlo facendolo camminare (cosa che spiegherò nella prossima serie di video), salvare poi i vari frame della camminata e usarli come riferimento in Gimp, disegnandoci sopra (con un livello trasparente) il personaggio, frame per frame, per poi importare questi ultimi in Adventure Game Studio.

Oppure, dato che Make Human ci permette anche di vestire il nostro personaggio e, con un Addon per Blender chiamato Make Clothes di salvare gli abiti, potremo anche vestirlo, importarlo in Blender, animarlo, salvare i frame e importarli direttamente in AGS. Il tutto senza dover modellare di persona il personaggio.

Ora, purtroppo non conosco bene il discorso vesititi in Make Human, ma in rete ci sono tutte le spiegazioni.

Come ho detto all'inizio, questo programma lo uso più che altro per creare i cosiddetti Model Sheet (purtroppo non ho trovato un corrispettivo nella nostra lingua) con modelli "nudi".

I Model Sheet non sono altro che immagini con il modello ripeso da diverse angolazioni che poi verranno utilizzate come riferimento per modellare il personaggio vero e proprio.

Questo è un Model Sheet molto semplice fatto con un modello di Make Human:


Come vedete, una volta renderizzato, noteremo che il modello fatto con Make Human è anche già fornito di textures.

Bene spero che questo articolo vi abbia fornito qualche spunto per la soluzione al problema del disegno dei frame di animazione del personaggio.

Se non lo avesse fatto, non preoccupatevi, nei prossimi video (preferisco mostrarlo in video che in forma scritta, altrimenti verrebbero articoli troppo lunghi) illustrerò il procedimento che uso per modellare un personaggio, applicargli un'Armatura fornitaci da Blender, animarlo e salvare i frame di animazione da importare in AGS.

Alla prossima!

venerdì 18 gennaio 2013

Costruzione di una stanza per AGS 6: Colori, Textures, Luci e Rendering.

Come anticipato, in questa puntata daremo colore alla stanza, sistemeremo le luci e la renderizzermo.

Cominciamo a colorare il tavolo. Prima di scegliere che colore usare, è utile chiedersi quanti ne servono per un dato oggetto.

Per il tavolo ne basta uno, un marroncino legno.

Spostiamoci quindi nel pannello Materials.



Premiamo quindi sul "+" per aggiungere uno slot Materiale (vuota).



Premiamo ora il tasto New per aggiungere un nuovo Materiale all'interno dello slot, nel nostro caso sarà un semplice colore.



Clicchiamo sulla casella bianca e scegliamo un marroncino.






La barra verticale a destra della tavolozza, quella che va dal bianco al nero, serve a rendere i colori più chiari o più scuri.

Man mano che cambiamo colore, vediamo che anche il tavolo si colora in tempo reale.

Possiamo nominare anche il colore volendo, chiamandolo con la parte dell'oggetto colorata da esso.
Per nominarlo andiamo sul pannello Material e nel campo adibito al nome rinominiamo il Materiale.
Dato che il tavolo è tutto marroncino, lo chiamorò semplicemente Tavolo.



Il Tavolo è sistemato.

Ora vediamo come coportarci con un oggetto composto da più colori, ad esempio l'Armadio.

Per lavorare senza l'intralcio degli altri elementi, possiamo nascondere tutti gli oggetti tranne l'Armadio.

Per farlo, selezioniamo l'Armadio.


Premiamo Ctrl + I (di Invert) per invertire la selezione. Se prima era solo selezionato l'Armadio, ora sono selezionati tutti gli oggetti tanne quest'ultimo.


Premiamo H (di Hide) per nascondere gli oggetti selezionati. Non preoccupatevi, non sono cancellati.


Prima di cominciare, una piccola nota. Non so se sia anche il vostro caso, ma ho scoperto che il mio Armadio presenta una coppia duplicata di maniglie.

Ve lo dico perchè se avete seguito anche i tutorial precedenti, potrebbe risultare così anche a voi.

La copia non è visibile poichè situata nello stesso punto della copia originale.

Per evitare sgradite sorprese in fase di colorazione (cioè di avere due coppie di maniglie colorate in modo diverso e sovrapposte) selezioniamo le due maniglie e cancelliamole.

Per farlo, selezioniamo una faccia di una maniglia.


Col cursore sulla maniglia premiamo L


Tenendo premuto Shift selezioniamo una faccia dell'altra maniglia.


Nuovamente, col cursore sulla maniglia premiamo L. Tutte e due le maniglie sono selezionate.


A questo punto trasliamo le maniglie selezionate, lungo l'asse Y. In effetti vediamo che ne esiste già un altro paio.


Cancelliamo quindi la copia selezionata lasciandone così solo una coppia.



Per l'Armadio servono tre colori. Una per le ante, una per le maniglie ed un altro per il resto del mobile.

Premiamo quindi 3 volte il "+" per creare 3 slot.

Dato che il Tavolo era di un solo colore, lo abbiamo colorato da Object Mode. Lo abbiamo quindi colorato nella sua "interezza".

Per l'Armadio, invece, dovremo spostarci in Edit Mode per selezionare le parti dell'oggetto che devono essere colorate con uno specifico colore.

Andiamo quindi in Edit Mode.


Cominciamo a colorare le ante. Selezioniamo le facce corrispondenti alle ante.


Clicchiamo sul primo slot, su New e scegliamo un blu abbastanza scuro.


L'Armadio si colororerà interamente di blu perchè per ora è l'unico Material presente per questo oggetto.

Nominiamo il colore in Ante e premiamo il tasto Assign per assegnare il colore alle facce selezionate.


Selezioniamo adesso tutto, tranne le ante con Ctrl + I.


Clicchiamo sul secondo dei 3 slot, su New e selezioniamo un marroncino chiaro.


Nomniamo il colore con RestoMobile e infine clicchiamo su Assign. Ora il marroncino colorerà tutto l'Armadio tranne le due facce della selezione precedente.

Premiamo A per deselezionare tutto.



Ora dedichiamoci alle maniglie.

Selezioniamo una faccia di una di esse, poi come visto prima precedente, facendo attenzione ad avere il cursore sulla maniglia, premiamo L per selezionare tutte le facce collegate alla faccia selezionata.



Come prima, diamo un colore alle facce selezionate, in questo caso un grigio chiaro.
Chiamiamolo Maniglie e premiamo Assign per assegnare il colore.


Per l'altra maniglia, sarà sufficiente selezionarla interamente e assegnare lo stesso colore dell'altra maniglia selezionandolo dall'elenco degli slot Materiali.



Andiamo in Object Mode per vedere l'oggetto senza vertici, spigoli o facce evidenziate .


E anche l'Armadio è colorato.

Per rendere di nuovo il resto della stanza visibile, basterà premere Alt + H.

Renderizziamo e vediamo come sta venendo.


Come avete visto è semplice, basterà di volta in volta decidere il numero di colori di cui è composto un oggetto e colorare le parti di questo con le diverse tinte.

Ripetiamo questo procedimento per tutti gli altri oggetti tranne il Monitor, la Tastiera e il Case.


LE TEXTURES

Ho lasciato il Monitor, la Tastiera e il Case da parte perchè per essi useremo delle texures.

Le textures, molto semplicemente sono delle immagini 2D applicatealle facce di un modello 3D.

Sono molto ultili quando non vale la pena modellare nei minimi particolari una Mesh.

Ad esempio, le piccole rughe su un volto oppure un poster su una parete, sono rese semplicemente con delle textures.

Anche i tasti di una tastiera, possono essere resi con una textures.

C'è da dire che è utile usarle solo se il vostro gioco prevede delle inquadrature ravvicinate di un dato oggetto.
Mentre se la visuale sarà sempre la classica vista frontale ad una certa distanza, non vale la pena utilizzarle, i particolari non si noterebbero.

Per fare le textures ci serviremo di un programma di disegno 2D, io userò Gimp, anch'esso gratuito.

Ora vediamo un esempio pratico con il Monitor.
Nascondiamo gli altri elementi per poterci lavorare meglio.


I Monitor, solitamente hanno dei piccoli pulsanti, un led, il marchio e talvolta delle casse incorporate.
Per questi elementi useremo una texture che interesserà la cornice del Monitor.


Dividiamo lo schermo in 2 cosicchè in una metà di esso possiamo gestire la texture.

Clicchiamo col Tasto Sinistro del Mouse sul mezzo triangolino rigato e trasciniamolo verso destra.



Vedremo che lo schermo verrà tagliato in due verticalmente.



Dopodichè clicchiamo sull'icona della 3D View, nella prima metà dello schermo. Si aprirà un menù a tendina.

Selezioniamo UV/Image Editor




Ora selezioniamo la cornice del Monitor (senza selezionare anche le facce interne di essa, quelle che ne definiscono lo spessore) e posizioniamoci in vista frontale ortogonale.


Premiamo U e dal menù che appare selezioniamo Project From View.


Abbiamo appena creato un riferimento (o Layout) per disegnare la texture. Riferimento che apriremo in Gimp.

Project from View crea un Layout prendendo come riferimento le facce selezionate così come le vediamo dalla nostra visuale (in questo caso frontale ortogonale).


Questo metodo non funzionerebbe ad esempio con la faccia superiore della tastiera (per fare la texture dei tasti), poichè dalla vista frontale ortogonale, tale faccia si vedrebbe schiacciata.


Per chiarire l'esempio, ecco cosa otterremmo con Project From View se la nostra visuale (attenzione non la telecamera) fosse spostata in altro a destra.


Ritornando a noi, per esportare il riferimento, clicchiamo su UV's, Export UV Layout.


Nominiamolo (io lo chiamerò monitorUV) e scegliamo una destinazione dove salvarlo.
Dopodichè clicchiamo Export UV Layout


DISEGNARE LA TEXUTURE IN GIMP

Apriamo con Gimp il Layout appena salvato.


Ora, ricordiamoci che il Layout è solo di riferimento, non dobbiamo disegnarci sopra.
Creiamo un Nuovo Livello in Gimp completamente bianco cliccando su Livello, Nuovo Livello.


Clicchiamo su Bianco e premiamo Ok.


Il livello è stato creato, ma come vediamo dalla finestra dei Livelli, il Livello Bianco è sovrapposto al livello del Layout.


Clicchiamo sul Livello Layout e trasciniamolo sopra il Livello Bianco.


Ora possiamo disegnare la texture.

Assicuriamoci di essere sul Livello Bianco selezionandolo dal menù dei Livelli.


Per la cornce del Monitor userò un grigio scuro. Con il secchiello coloriamo l'intero Livello di grigio.


Ora disegnamo tutti i piccoli particolari come i tasti, il led, la marca e le casse, usando il riferimento e facendo attenzione a disegnare sempre sul livello grigio.

Una cosa del genere, molto semplice.


Ora clicchiamo sull'occhio in corrispondenza del Livello con il Layout per renderlo invisibile.

Rimarrà solo la texture più la scritta SUNNY (chi sa che monitor!) che essendo una scritta è trattata anch'essa come un Livello.



Esportiamo la texture andando su File, Esporta. Scegliamo come al solito come chiamarla e dove salvarla. Io la chiamerò monitorTex.png e la salverò nella stessa cartella di monitorUV.png.

Clicchiamo su Esporta e nuovamente su Esporta.



E la Texture è pronta.


Ritorniamo in Blender.

Nella schermata di sinistra (quella dedicata a UV/Image Editor), clicchiamo Image e Open Image.



Premiamo Open Image.


Ecco che la Texture è apparsa sotto il Layout.

In pratica, il Layout serve per dire a Blender di posizionare una data porzione di Texture su una determinata faccia.



Per applicare la Texture alle facce, dobbiamo crearle un Materiale dedicato.

Andiamo quindi di nuovo nel pannello Material e premiamo New o il tasto "+" per aggiungere un Materiale.


Entriamo ora nel pannello delle Textures e clicchiamo su New.


Apriamo il menù a tendina Type e al posto di Clouds selezioniamo Image or Movie.



Clicchiamo su Open e selezioniamo la Texture.



Clicchiamo infine su Open Image per aprire la Texture.

Scorriamo un pò in basso nella sezione Mapping e dal menù a tendina Coordinates invece di Generate, scegliamo UV.

Quest'ultima opzione serve per dire al programma di riferirsi al Layout per il giusto posizionamento della Texture.



Per verificare che tutto sia andato a buon fine, andiamo in Object Mode e premiamo Alt + H per far riapparire gli altri oggetti.

Dopodichè selezioniamo la Telecamera, entriamoci dentro e trasliamola fino a quando non ci siamo avvicinati abbastanza al Monitor.


Lanciamo quindi un rendering.


Una volta verificato ciò, premiamo Esc per uscire e ricordiamoci di annullare gli spostamenti della Telecamera con Ctrl + Z in modo da riposizionarla al posto giusto.

Nominiamo il Material, Cornice.

Ora che la texture è stata posizionata vorrei fare alcuni esempi per chiarire il ruolo del Layout.

Se spostassi il Layout a sinistra, ecco come Blender renderizzerebbe la Texture sul Monitor.



Se lo ruotassi invece...



Mentre se la ingrandissi, ecco che essendo il Layout di dimensioni maggiori, la Texture risulterebbe più piccola sul Monitor.

Inoltre vediamo che se il Layout esce fuori dalla Texture (perchè troppo grande in questo caso) si comporta come se la Texture ricominciasse oltre il bordo superiore di questa, come se la Texture si ripetesse.




Ora possiamo riportare lo schermo ad un sola finestra.

Posizioniamo il cursore sulla riga che separa le due aree, clicchiamo col Tasto Destro del Mouse e selezioniamo Join Area.


Posizioniamoci col mouse sulla parte sinistra dello schermo così da portare la parte destra a larghezza intera.



Per la restante colorazione del Monitor basterà procedere come per l'Armadio, ovvero creando tanti materiali quanti sono i colori di cui è composto l'oggetto, lasciando però da parte le faccie già colorate con la Texture.

In poche parole, potremmo dire che le Textures sono anch'esse dei Materials così come i semplici colori che abbiamo visto fin'ora. Solo che invece di colorare semplicemente una o più facce, applicano un'immagine.

Per la texture della parte frontale del Case possiamo fare come per il Monitor, utilizzando sempre Project From View in vista frontale ortogonale, colorando poi con semplici Materials le restanti facce.


Per la Tastiera, invece, potremmo usare sempre Project From View essendo però questa volta in visuale dall'alto ortogonale.
Ecco il risultato della Texture applicata.

Forse i tasti era meglio estruderli... :D


Questo è uno dei molteplici modi in Blender per applicare una Texture. Gli esempi visti erano molto semplici poichè si trattava di una Texture da applicare su superfici piatte.

Per gli oggetti più sinuosi e rotondeggianti le cose sono un pò più complesse.

Se l'argomento vi interessa, vi consiglio di cercare su Google o Youtube: Blender UV Mapping.
Ci sono tantissimi tuorial in rete sull'argomento tra cui due video in italiano del caro RedBaron85.

Link primo video: https://www.youtube.com/watch?v=LjrBMxtJPss

Link secondo video: https://www.youtube.com/watch?v=xacxR4tixLg

Passiamo ora all'illuminazione della scena.

ILLUMINAZIONE DELLA SCENA

Illuminiamo ora la scena in modo da renderla più pulita e luminosa.

Vi consiglio di giocare con le varie fonti di luci e i loro parametri per ottenere l'effetto desiderato.
Qui mostrerò un'illuminazione "standard" di una stanza che ho ottenuto modificando alcuni parametri.

Andiamo nel pannello World e togliamo la spunta a Environment Lightning.


Se renderizzassimo la scena ora, sarebbe completamente buia, perchè la luce ambientale non c'è più e la fonte luminasa Lamp è "fuori" dalla Stanza.

Le parteti della Stanza impediscono alla luce di illuminare l'interno di essa.

Sposteremo quindi la lampada Lamp in corrispondenza pressappoco del Lampadario.
Per farlo, assicuriamoci di avere il cursore 3D al centro della scena premendo Shift + C.
Poi selezioniamo la fonte Lamp, premiamo Shift + S e scegliamo Selection to Cursor.


Trasliamo lingo l'asse Z la fonte vicino alla lampadina del Lampadario.


Proviamo a renderizzare.


Le ombre sono troppo scure. Per ammorbidirle e schiarirle, andiamo nella sezione dedicata ad esse all'interno del pannello delle fonti luminose.


Innanzi tutto schiariamole agendo sulla casella dei colori.


Provaiamo a renderizzare.


Va già meglio. Come risultato è già accettabile, ma volendo possiamo anche ammorbidire le ombre per renderle meno nette.

Concentriamoci quindi sui parametri Samples e Soft Size.


Soft Size determina quanto è ampia la zona dedicata al passaggio dalla zona d'ombra a quella di non ombra.

Così com'è impostato Soft Size cioè a 0.100 il passaggio è netto e quasi per niente sfumato.

Impostiamolo a 0.500 e renderizziamo.


Non è cambiato nulla vero? Questo perchè Soft Size lavora insieme a Samples.
Senza un valore di Samples maggiore di 1, Soft Size è come se non ci fosse.

Samples definisce la pulizia della sfumatura data da Soft Size. A 1 non sortisce pressochè nessun effetto, proviamo a 2.


Così è troppo granulosa, proviamo con un valore tra 5 e 10.


Così direi che va bene. Le ombre ci sono e sono sufficentemete sfumate.

Per capire meglio la relazione tra Samples e Soft Size vi consiglio di dare un'occhiata anche solo alle immagini comparative dell'articolo qui linkato:

http://wiki.blender.org/index.php/Doc:2.4/Manual/Lighting/Shadows/Raytraced_Properties

Ultimi accrogimenti. Il muro riflette fin troppo la luce, è troppo lucido.

Per diminuire o azzerare la lucidità del Materiale di cui è colorato il muro, selezioniamo l'oggetto Pareti, andiamo nel pannello Materials e selezioniamo il Materiale che vogliamo opacizzare.


Andiamo in Specular e impostiamo il valore Intensity a 0. Vedoiamo gli effetti di questo cambiamento anche sulla sfera di riferimento.


Renderizziamo. Il riflesso è scomparso dalla parete.


Come ultima cosa, sistemiamo quelle zone troppo scure sopra il Lampadario e dietro la Sedia.


In questo caso ci può ritornare utile un pò di Luce Ambientale, cioè di Environment Lighting.

Rispuntiamola e impostimola il valore Energy con un valore basso, come 0.300.
Renderizziamo per vedere i risultati.



La stanza è finita!

O almeno, secondo me è soddisfacente...

Consiglio una bella spulciata in rete per capire meglio come usare questi parametri (cosa che farebbe bene anche a me), perchè sono molti, ma più ne conosciamo, più possiamo dare l'atmosfera voluta ad una stanza.

Il vantaggio ora è che se non volete utilizzare la visuale che ho usato in questo tutorial, basta ruotare e/o traslare la telecamerta a piacimento per inquadrare e renderizzare la scena dal punto di vistoa desiderarto.

Date anche uno sguardo alle proprietà della Telecamera e diversii tipi di "Lens" (Lenti) se vi interessa.


Per esportare la stanza basta semplicemente renderizzarla, cliccare su Image e su Save a Copy o Save As Image (non so quale sia la differenza).



Questa è stata la sesta e ultima puntata, spero di essere stato abbastanza esauriente.

So che sembra una cosa lunga e complessa costruire una stanza, ma vi assicuro che quando ci prendete la mano, una scena come questa si completa nel giro di un paio di ore.

Detto questo, ditemi se preferite che continui con i tutorial in Blender e la modellazione e animazione del personaggio, o è meglio ritornare un pò ad Adventure Game Studio.