Benvenuto Visitatore(Log In|Registrati)

 
Reply to this topicStart new topic
> Unity tips, il topic dove si postano risoluzioni a problemi quotidiani
Lief
messaggio17 Apr 2018, 12:04
Messaggio #1





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Come forse qualcuno di voi saprà da un po' di tempo mi occupo dello sviluppo di giochi in Unity a livello personale (ma a livello professionale sono comunque Web Developer back e front end) e mi capita spesso di scontrarmi con problematiche di vario genere che possono far perdere giornate intere ma che non sempre hanno soluzioni realmente complesse.

Questo topic vuole semplicemente essere un elenco di suggerimenti aperto a tutti.
Io in particolare posterò suggerimenti relativi a Unity di tanto in tanto quando penserò che vale la pena farlo.

Elenco tips:
- Remap Input Personalizzato
- Virtual Joystick
- FPS Constructor by Leonardo Boselli
- Serializzazione, Traduzione, Salvataggio Dati
- Drag&Drop
- Muovere un Oggetto con un Click
- Hack & Slash RPG da zero BurgZergArcade
- Mischiare una lista di oggetti non iterabili
- Collider e Trigger, tutti i segreti
- Tocchiamo il terreno? Raycast camera, come sparare raggi in tutte le direzioni

Come primo tips voglio iniziare con il problema che mi sono ritrovato ad affrontare più recentemente, problema che in un prossimo futuro non sarà più rilevante: il Remap dell'input in Unity a runtime.

Avete presente il menù per cambiare i comandi da usare nel gioco (esempio per cambiare il comando per saltare da Spazio ad un qualsiasi altro bottone)?
È una classica opzione che viene data ai giocatori PC (mentre è spesso assente su console) ed è anche una delle più grandi limitazioni del sistema di input attuale di Unity. Unity infatti permette il remap dell'Input solo prima di avviare il gioco in una schermata completamente separata dal gioco tipica dei videogiochi Unity.

Come risolvere il problema?
- Usare il nuovo Input System, che però è ancora in una fase di sviluppo molto embrionale, richiede una versione di Unity diversa da quella di default, è soggetto a bug e cambiamenti. In futuro ovviamente questa sarà la migliore opzione disponibile e il tutto sarà decisamente più semplice.
- Comprare sull'assets store o scaricare su git uno dei tanti sistemi di Input alternativi. Sono sistemi che però richiedono l'import di molto codice che spesso non ci interessa e che va mantenuto ad ogni aggiornamento di Unity, il che può essere giustificato ma è comunque qualcosa che è meglio evitare se si è in grado di farlo.
- Creare il nostro personalissimo sistema di Input.

Se avete deciso di usare il terzo sistema vi posso dare una mano.
Prima di tutto bisogna dire che rimappare semplicemente i tasti è decisamente semplice, vi basterà creare una mappa chiave, valore impostando la chiave a stringaNomeInput (esempio "Salto"), il valore al KeyCode a cui lo volete associare (esempio KeyCode.Space)... A quel punto fate due metodi un getter e un setter e, durante lo Start, settate tutti i valori.
Per ricavare l'input vi basterà sostituire nel codice i vostri vecchi:
if(Input.GetButtonDown("Salto"))

con

if(Input.GetKeyDown(VostraClasseInput.GetInput("Salto")))

se prima Input dipendeva da un sistema settato nell'InputManager di Unity, ora dipenderà dal vostro sistema che restituirà un KeyCode nella mappa a seconda della chiave passata e il tutto verrà letto con l'Input.GetKey GetKeyDown GetKeyUp del sistema di default di Unity.

Nel vostro menù di remap vi basterà richiamare il
VostraClasseInput.SetInput("Salto", key) (dove key è il KeyCode rilevato)
per cambiare il valore nella mappa e far rispondere il GetKeyDown ad un altro pulsante.

Principale problema:
Gli Axis non hanno KeyCode quindi come fare a rilevare il float relativo al movimento?

Per quanto riguarda la tastiera è sufficiente aggirare il problema:

float avanti = 0f;

if(Input.GetKey(VostraClasseInput.GetInput("Avanti")))
avanti = 1f;
else if(Input.GetKey(VostraClasseInput.GetInput("Indietro")))
avanti = -1f;
else
avanti = 0f;

Leggendo il float avanti possiamo sapere se l'utente sta premendo il pulsante per andare avanti, quello per andare indietro oppure non si sta muovendo.

Ovviamente il codice si può abbellire, ad esempio si può aggiungere un sistema per incrementare la variabile "avanti" da 0 ad 1 non in maniera istantanea:
avanti = avanti < 1f ? avanti + Mathf.Lerp(0, 1, Time.deltaTime * 5) : 1f;

il codice sopra significa: finché la variabile "avanti" è minore di 1 incrementa avanti da 0 a 1 in base al tempo moltiplicato per 5 (il che significa che potete variare questo tempo per rendere il tutto più lento o più veloce), in caso contrario (quando la variabile raggiunge 1) vogliamo che non venga più incrementata.

Tutto questo però è ok su tastiera, se volessimo usare un gamepad inizierebbero i problemi. I joystick infatti hanno un KeyCode variabile rilevabile solo quando si preme il joystick, non quando si stanno usando gli axis.
Inoltre, il sistema che abbiamo usato prima non ha senso per un joystick (visto che un joystick può rilevare valori intermedi tra 0 e 1 che possono venir utilizzati).

Cosa fare quindi?

L'idea è simile a quella usata in precedenza: usare il vecchio sistema di Input a nostro vantaggio. Questa volta l'idea è creare nel vecchio sistema di Input tutti gli Axis che siamo certi di voler utilizzare (esempio VerticalWindows, VerticalMac, VerticalLinux, VerticalIOS, VerticalAndroid) e settare quali assi dovranno leggere, di base tutti i joystick leggono un asse verticale e uno orizzontale (X e Y) per il joystick di sinistra, mentre la cosa varia per il joystick di destra e il d-pad a seconda della piattaforma (esempio su windows il joystick di destra è sugli assi 4 e 5, mentre su mac sono gli assi 3 e 4).

Nella nostra classe di input bisognerà aggiungere una mappa chiave valore stringa-stringa, la chiave sarà come richiameremo la lettura dell'asse nella get, mentre il valore sarà il reale nome del joystick settato nel vecchio InputManager.
Esempio

Nell'Input Manager abbiamo dato il nome "Vertical" e "Horizontal" agli assi X e Y, "RightVertical" e "RightHorizontal" agli assi 4 e 5.

Nella nostra mappa dovremo mappare questi assi in un modo simile a questo:
VostraClasseInput.SetJoypad("JoyVertical", "Vertical");
VostraClasseInput.SetJoypad("JoyHorizontal", "Horizontal");
VostraClasseInput.SetJoypad("JoyVertical2", "RightVertical");
VostraClasseInput.SetJoypad("JoyHorizontal2", "RightHorizontal");

Ovviamente se volessimo rimappare il tutto in modo da invertire ciò che vogliamo fare con joystick sinistro e destro, nel nostro sistema di remap, al passo di rilevare il joystick utilizzato (cosa che richiederebbe l'associazione di un keycode che varia da piattaforma a piattaforma e non sempre è disponibile (ad esempio non lo è sul dpad)) ci conviene settare il tutto dando semplicemente all'utente la possibilità di cambiare joystick di movimento /camera (esempi) con joystick sinistra, destra o dpad in un sistema di selezione.
VostraClasseInput.SetJoypad("JoyVertical", "RightVertical");
VostraClasseInput.SetJoypad("JoyHorizontal", "RightHorizontal");
VostraClasseInput.SetJoypad("JoyVertical2", "Vertical");
VostraClasseInput.SetJoypad("JoyHorizontal2", "Horizontal");


Per richiamare il tutto invece ci basta il sistema usato per i bottini con la sola differenza che ci serve Input.GetAxis al posto di GetKey.

Ovviamente sarebbe molto più semplice se unity fosse in grado di fare setaxis e setbutton e magari anche di rilevare l'axis usato ma sfortunatamente al momento non pare sia possibile (lo sarà con il prossimo sistema di input), ovviamente se avete idee per migliorare il mio tip scrivetele pure e spero che anche altri vorranno condividere i propri.

Al prossimo tip

Messaggio modificato da Lief il 22 May 2018, 19:28
 
Lief
messaggio23 Apr 2018, 08:19
Messaggio #2





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Oggi vi lascio con un video (non mio) relativo ai comandi touch screen. A dirla tutta ho fatto qualche modifica a questo codice ma solo per renderlo più legato all'interfaccia Unity3d, zucchero sintattico insomma, il core è rimasto questo:


Penso che sia il modo migliore per creare un virtual joystick abbastanza professionale.
 
utdefault
messaggio23 Apr 2018, 22:29
Messaggio #3



Gruppo icone

Gruppo: OldGamer
Messaggi: 250
Iscritto il: 28 December 13
Utente Nr.: 20.235
SO Altro




Grazie per le tips.
Per chi non conosce l'engine, tornano utili.

Il video postato non si vede. Se puoi ripostarlo, please, aggiungici anche il link originale; così da poterlo aprire esternamente se l'embedded non funzionasse ancora. ;>

In ultimo, una domanda su Unity: come gestisce le traduzioni? -- Cioè, se fa qualcosa di simile ad Ags oppure se va gestito da code.
 
Gwenelan
messaggio24 Apr 2018, 01:59
Messaggio #4



Gruppo icone

Gruppo: SMod
Messaggi: 13.276
Iscritto il: 8 October 12
Utente Nr.: 19.580
BGE Planescape: Torment
SO Windows7




Corretto io l'embedded blush.gif! Va messo solo il codice del video, non tutto il link blush.gif.


--------------------
Conformati.

What can change the nature of a man?
*My Youtube Channel*

La vita è dura e grama - e poi si muore.

Chi è intelligente per definizione non può avere qualcosa di negativo da dire contro lo studio e contro il buon senso.
- Duca


Tutti hanno opinioni: io le ho, tu le hai. E fin da quando abbiamo aperto gli occhi ci hanno detto che abbiamo diritto di avere nostre opinioni. Be’, è una stronzata, naturalmente. Non abbiamo diritto di avere opinioni, abbiamo diritto di avere opinioni informate. Senza studio, senza basi, senza comprensione, un’opinione non vale niente.
È solo un farfugliamento. È come una scoreggia nella galleria del vento, gente.

 
Leonardo Boselli
messaggio24 Apr 2018, 13:24
Messaggio #5



Gruppo icone

Gruppo: Oldgame Editor
Messaggi: 940
Iscritto il: 18 December 13
Da: Imperia
Utente Nr.: 20.217
BGE WarCraft III
Playing L4 M4TR1C3
SO Altro




Bello questo thread! Con l'input ho smanettato poco, ma proverò di certo a seguire i consigli dei post qui sopra.

Quando mi diletto con Unity, mi diverto a mettere assieme un po' di assets gratuiti per saggiarne le potenzialità e vedere l'effetto che fanno tutti assieme.
Un asset gratuito che ho trovato interessante è "FPS constructor". Un po' datato, ma ancora funzionale (e funzionante!)
Naturalmente non ho perso l'occasione per pubblicare un video-tutorial dove inizio ad abbozzare un FPS grazie a questo tool.

Ed ecco il risultato:




--------------------
Mille e Una Avventura Canale YouTube di Narrativa Interattiva e altro ------ Twitch.tv / LeoBos67 Gameplay Live di Narrativa Interattiva ------ YouDev.it Game Development

 
Lief
messaggio24 Apr 2018, 16:53
Messaggio #6





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




@Gwenelan grazie per aver corretto.


CITAZIONE (utdefault @ 23 Apr 2018, 23:29) *
In ultimo, una domanda su Unity: come gestisce le traduzioni? -- Cioè, se fa qualcosa di simile ad Ags oppure se va gestito da code.

Le traduzioni vanno gestite via codice, al momento non mi pare esista un metodo ufficiale per farlo da interfaccia (Ags non lo conosco ma immagino, da quel che scrivi, che abbia un sistema particolare per gestirle).

Detto questo gestirle da codice non è poi così complesso come si potrebbe pensare... Ti do un indizio (ora non ho tempo di scrivere un tip completo, lo farò la prossima volta):
file json contenenti le stringhe di gioco caricati a seconda della lingua (magari con un nome diverso) e serializzati in array di stringhe in C#.

Una volta capita la serializzazione in Unity è decisamente solo una questione di scrivere 2 righe di codice molto molto semplici per caricare il file della lingua che ci interessa. I menù che ho creato usano proprio questo sistema e, dopo aver provato alcune alternative (tipo il sistema di PlayerPref) penso sia il sistema più semplice. Oltretutto è un sistema che (una volta capito) è applicabile anche per il salvataggio e il caricamento dei salvataggi e dei dialoghi in-game (insomma è decisamente molto flessibile).

Aggiungo... json e non xml perché alla fin fine son tutte stringhe, il controllo dei tipi non è decisamente la priorità ed è decisamente più semplice serializzare e deserializzare in json.

@Leonardo Boselli
Penso che sia un ottimo modo per iniziare. Copiare le soluzioni altrui e farle proprie è sempre stato il modo migliore per imparare a programmare. L'unica cosa che, personalmente, cerco di non fare, è integrare soluzioni complete senza reimplementarle e senza guardare il codice. Si rischia di finire con un progetto non aggiornabile, dipendente da un codice che non si capisce.
Non ho ancora visto il video (lo guarderò stasera) quindi non so come hai sfruttato quell'asset, ho voluto solo dire la mia sugli assets in generale (insomma sono un'ottima cosa, ma bisogna sfruttarli per imparare).

PS. Io ho iniziato con i tutotial di Burgzerg Arcade. In particolare quelli dell'RPG che però sono fatti per Unity3d 3 (quindi sono molto obsoleti ora).

Edit. Ok ho visto il video. Come scritto personalmente non userei assets come fps constructor senza analizzarli pezzo per pezzo. Infatti, a meno che non si voglia implementare tutto esattamente nello stesso modo, diventa poi difficile uscire dagli schemi preimpostati (esempio... Se volessi una camera in terza persona dovrei trovare una camera in terza persona compatibile con quel framework) e, come ho già scritto, se unity si aggiorna e rende incompatibile qualcosa poi è necessario aspettare l'aggiornamento di fps constructor per aggiornare unity. In alcuni casi non c'è scelta (esempio se si implementa le api di Dropbox non si può fare nulla), ma in casi come questo si può fare a meno.
È però un'ottima scelta studiare il codice di fps constructor e simili (spesso gli assets sono anche open source anche se non sempre la licenza e free software).
Per quanto riguarda gli assets grafici, al contrario, visto che non sono un grafico penso sia giusto usare placeholder. E voglio anche suggerire un software chiamato make human che è decisamente comodo, gratuito e può aiutare ad avere assets originali e standard per l'uso in unity. Anche il sito di mixamo è ottimo e fornisce tantissime animazioni gratuite oltre a vari modelli (notare che visto che lo scheletro fatto con make human è standard per unity si possono usare le animazioni di mixamo).

Messaggio modificato da Lief il 24 Apr 2018, 17:26
 
Leonardo Boselli
messaggio24 Apr 2018, 18:01
Messaggio #7



Gruppo icone

Gruppo: Oldgame Editor
Messaggi: 940
Iscritto il: 18 December 13
Da: Imperia
Utente Nr.: 20.217
BGE WarCraft III
Playing L4 M4TR1C3
SO Altro




CITAZIONE (Lief @ 24 Apr 2018, 17:53) *
Edit. Ok ho visto il video. Come scritto personalmente non userei assets come fps constructor senza analizzarli pezzo per pezzo. Infatti, a meno che non si voglia implementare tutto esattamente nello stesso modo, diventa poi difficile uscire dagli schemi preimpostati (esempio... Se volessi una camera in terza persona dovrei trovare una camera in terza persona compatibile con quel framework) e, come ho già scritto, se unity si aggiorna e rende incompatibile qualcosa poi è necessario aspettare l'aggiornamento di fps constructor per aggiornare unity. In alcuni casi non c'è scelta (esempio se si implementa le api di Dropbox non si può fare nulla), ma in casi come questo si può fare a meno.
È però un'ottima scelta studiare il codice di fps constructor e simili (spesso gli assets sono anche open source anche se non sempre la licenza e free software).

Sono d'accordo. Comunque mi stupisco di quanto siano fatti bene certi assets gratuiti di Unity e di come si riescano a integrare gli uni con gli altri (pur essendo sviluppati da programmatori diversi).
Per esempio, ho provato la versione gratuita di "MS Vehicle System" (un sistema per il controllo di veicoli a quattro ruote con un sistema di visuali integrato e quant'altro) e l'ho inserito nella scena del video precedente.
Mi ha stupito riuscire a passare dalla visuale dell'FPS a quella del veicolo e viceversa senza alcun codice "glue". Quando poi si spara contro il veicolo, si sente il rumore di vetri infranti blush.gif



CITAZIONE (Lief @ 24 Apr 2018, 17:53) *
E voglio anche suggerire un software chiamato make human che è decisamente comodo, gratuito e può aiutare ad avere assets originali e standard per l'uso in unity. Anche il sito di mixamo è ottimo e fornisce tantissime animazioni gratuite oltre a vari modelli (notare che visto che lo scheletro fatto con make human è standard per unity si possono usare le animazioni di mixamo).

Make Human è davvero fantastico. L'ho provato tempo fa e immagino che sia stato ancora migliorato. Mi hai fatto venire voglia di riprovarlo!


--------------------
Mille e Una Avventura Canale YouTube di Narrativa Interattiva e altro ------ Twitch.tv / LeoBos67 Gameplay Live di Narrativa Interattiva ------ YouDev.it Game Development

 
Lief
messaggio24 Apr 2018, 19:00
Messaggio #8





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Si, l'assets store di Unity è uno dei suoi punti forti. Sapere di poter avere a disposizione una quantità infinita di assets ben fatti significa non doversi preoccupare di fare ciò che non si è in grado di fare e concentrarsi sul proprio campo (esempio, io programmatore posso concentrarmi sul codice, un artista del 3d può concentrarsi sui propri modelli ecc...).

Ma passiamo al tip. Come detto qualche ora fa e richiesto da utdefault vediamo come si possono gestire le traduzioni (e più in generale il salvataggio dei dati). Ovviamente questa è solo una delle tante soluzioni possibili... vi invito a fare prove e a darmi anche dei suggerimenti (scrivendo ovviamente dei tip per tutti qui).

Partiamo dalla base: la serializzazione in Unity.
Si parte dal classico POJO (come lo chiamano i programmatori Java), POCO (come lo chiamano i programmatori C, C++, C#)... In pratica un semplicissimo oggetto con campi e getter/setter.

Si crea una classe in Unity, si elimina ": MonoBehaviour" (MOLTO IMPORTANTE), si crea un campo pubblico o SerializeField (MOLTO IMPORTANTE, pur avendo già i getter/setters. SerializeField è l'idea migliore visto che in questo modo la nostra variabile non risulterà accessibile direttamente ma solo attraverso getter e setters):

//un array di stringhe
[SerializeField] string[] menu;

//costruttore vuoto
public ConfirmMenuArrayString() {
}

//costruttore con parametri
public ConfirmMenuArrayString(string[] menu) {
this.menu = menu;
}

//getter/setter
public string[] Menu {
get {
return menu;
}
set {
menu = value;
}
}

e fin qui è una cavolata.

Ora che abbiamo il nostro oggetto dobbiamo renderlo serializzabile, sopra il public class ConfirmMenuArrayString { dobbiamo quindi scrivere
[System.Serializable]

Infine aggiungiamo i metodi per serializzare
//prende in ingresso la stringa json, restituisce l'oggetto
public static ConfirmMenuArrayString SaveFromString(string jsonString) {
return JsonUtility.FromJson<ConfirmMenuArrayString>(jsonString);
}
//fa il contrario, dall'oggetto restituisce la stringa json
public string SaveToString() {
return JsonUtility.ToJson(this);
}


Abbiamo la nostra classe di serializzazione che può prendere un qualsiasi file di testo contenente:
{"menu":["stringa 1", "stringa 2", "stringa 3"]}

e trasformarlo in un array di stringhe di lunghezza arbitraria. Ovviamente la classe di prima si può modificare per salvare singoli campi (al posto che un array), ognuno con il proprio identificativo
{"campo1":"valore campo 1", "campo2":"valore campo 2"}
E i tipi dei campi non devono essere necessariamente stringhe, ma restiamo sul semplice.

Ora dobbiamo utilizzare questa classe per cambiare lingua.
Primo step creare due file json:
Menu_Italian.json
Menu_English.json

contenenti entrambi:
{"menu":["stringa 1", "stringa 2", "stringa 3"]}

uno in inglese:
{"menu":["string 1", "string 2", "string 3"]}
l'altro in italiano.

Notare che menu (essendo il campo, quindi la nostra chiave, non deve venir tradotta... solo i valori (le stringhe) vengono tradotte).

Ma dove mettiamo questi file?
La cartella migliore è senza alcun dubbio Application.streamingAssetsPath che è una cartella diversa a seconda della piattaforma scelta. è inoltre buona norma mettere tutto dentro una nostra cartella:
Application.streamingAssetsPath + "/menu"

E se volessimo esporre il file all'utente?
In quel caso la cartella migliore è Application.persistentDataPath... e se vogliamo fare in modo che un file già presente nel nostro gioco venga esposto lì il modo migliore è farne una semplice copia.

A questo punto abbiamo i file, come decidere quale leggere?
Beh è decisamente semplice, dobbiamo leggere il file in questo path:
Application.streamingAssetsPath + "/menu/Menu_" + language + ".json"

dove language è la stringa che rappresenta la nostra lingua (e che può essere ad esempio la lingua del sistema dell'utente Application.systemLanguage).

letto il file (ad esempio con uno StreamReader)
e messo dentro una variabile di tipo stringa possiamo passare tale variabile al metodo SaveToString che abbiamo creato precedentemente:
ConfirmMenuArrayString.SaveFromString (jsontext);

(è un metodo statico quindi lo richiamiamo con il nome della classe)

se poi richiamiamo ConfirmMenuArrayString.SaveFromString (jsontext).Menu ci verrà direttamente restituito l'array di stringhe che ci serve.

A quel punto ci basta ciclare sull'array e settare tutti i Text component di Unity che ci interessa modificare con le nostre scritte.

Basterà così cambiare la variabile language per cambiare lingua (ovviamente se il tutto viene eseguito nel metodo Start solo all'avvio la lingua potrà essere modificata).

Messaggio modificato da Lief il 13 May 2018, 18:53
 
utdefault
messaggio25 Apr 2018, 11:36
Messaggio #9



Gruppo icone

Gruppo: OldGamer
Messaggi: 250
Iscritto il: 28 December 13
Utente Nr.: 20.235
SO Altro




Ok, ora tutto più chiaro.
Grazie, Lief.

Casomai, con l'aggiunta di nuovi post argomentativi, ogni messaggio potrebbe essere indicizzato in apertura di discussione. Così da poterli subito richiamare all'occorrenza. :>

Piacevole anche l'immersione nel video di Constructor.
Grazie a Leo per il play. Per ora, visto anche quello sui veicoli. ;>
 
Lief
messaggio25 Apr 2018, 13:58
Messaggio #10





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




CITAZIONE (utdefault @ 25 Apr 2018, 12:36) *
Casomai, con l'aggiunta di nuovi post argomentativi, ogni messaggio potrebbe essere indicizzato in apertura di discussione. Così da poterli subito richiamare all'occorrenza. :>

L'idea è buona, però ci vorrebbe un post sopra il mio primo post (mettere tutto in un post unico è un po' confusionario). Inoltre penso sia bello che tutti possano dare suggerimenti quindi se si indicizzano è bene che chi posta un tip dica esplicitamente che è un tip a inizio del suo post (in modo che l'indicizzazione sia più semplice).
 
Lief
messaggio28 Apr 2018, 19:47
Messaggio #11





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




In questi giorni sarò impegnato nel creare un piccolo giochino di carte come prova/colloquio per una software house (chissà magari è la volta buona che riesco ad entrare nel settore giusto, al posto di fare solo webapp). Non è detto che riuscirò a finirlo perché ho un tempo limite di 4 giorni al posto dei 7 dati (visto che 3 giorni lavoro a tempo pieno e la sera dubito di riuscire ad andare molto avanti), ma ovviamente che io riesca o no a passare, il risultato sarà comunque un piccolo gioco (se non finito quasi) e un po' di esperienza che mi tornerà utile anche in futuro.... e ovviamente qualche tip per tutti.

Quello di oggi è il Drag & Drop. Farlo non è stato particolarmente difficile visto che avevo già creato un virtual joystick per il mio videogioco principale, ma mi sono comunque chiarito parecchi dubbi con questo semplice video tutorial che consiglio a tutti (nota bene, questo è il primo di 3 video, gli altri li trovate via youtube):


A questo tutorial voglio solo aggiungere un suggerimento: se volete poter trascinare più di una carta alla volta (o solo una), perché ad esempio avete una pila di carte (esempio: K, Q, J, 10) vi basterà aggiungere un Vertical/Horizontal Layout Group a ciascuna carta.
In questa maniera le carte stesse diverranno potenziali "host" dove posizionare le carte...
Piccolo esempio, volendo fare una pila verticale si potrebbe far sì che ogni carta abbia un vertical layout group con top = X (X = numero che ci convince di più... con top positivo le carte figlie della prima appariranno sovrapposte). Iterando su questo concetto è possibile avere tante carte tutte trascinabili in cui quelle sotto trascineranno anche quelle sopra ma non viceversa.
Ricordarsi inoltre che se abbiamo iterato su questo concetto il parent del parent non sarà più il nostro panel, di conseguenza conviene settarsi un Transform del nostro Panel principale nel codice (per evitare di settarla con una variabile pubblica, si potrebbe ad esempio usare GameObject.FindGameObjectWithTag("Panel").transform; nello Start).

Altra cosa, nel video viene menzionato il fatto che si può usare il component event trigger per richiamare i metodi drag, drop ecc....
Quel che non viene detto è il fatto che richiamandoli in quel modo non c'è possibilità (che io sappia) di accedere al PointerEventData (che è l'oggetto che ci da accesso alla posizione).
Il mio suggerimento è di implementare solo IBeginDragHandler e il metodo public void OnBeginDrag(PointerEventData myPed) avendo una variabile private PointerEventData ped; e settandola nell'OnBeginDrag ped = myPed;
Tutti gli altri metodi potranno così accedere al PointerEventData che avete settato, e potrete settare tutti gli altri metodi direttamente nell'Event Trigger di Unity.

Per oggi direi che è tutto, spero di poter postare altri tip interessanti in questi giorni.
 
Lief
messaggio29 Apr 2018, 12:01
Messaggio #12





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Salve a tutti. Oggi vi porto un tip davvero carino... e semplice da utilizzare.
Nel mio primo tip vi ho detto che con questo codice
"avanti = avanti < 1f ? avanti + Mathf.Lerp(0, 1, Time.deltaTime * 5) : 1f;"
era possibile (nell'Update) fare in modo che la variabile "avanti" andasse da 0 a 1 in maniera non istantanea.
Il controllo fatto era però costante "if(Input.GetKey(VostraClasseInput.GetInput("Avanti")))" (che nell'Update viene eseguito ogni frame) infatti il codice serviva a far muovere il personaggio finché il pulsante "Avanti" veniva premuto.

Ma cosa succede se vogliamo muovere un immagine in una determinata posizione dopo aver premuto un pulsante (quindi senza tenerlo premuto), in maniera non istantanea?

La soluzione, anche se differente, è altrettanto semplice:
nel vostro metodo OnPointerDown settate a true una variabile booleana precedentemente settata a false

Nell'Update

if(vostraVariabileBooleana){
variabileDaModificare = Mathf.MoveTowards(variabileDaModificare, 0, Time.deltaTime * 5f);
if(variabileDaModificare == 0)
vostraVariabileBooleana = false;
}

il che significa che finché la vostra variabile è true la variabileDaModificare (che potrebbe essere la posizione x nello spazio di gioco del vostro oggetto da muovere) si muoverà dalla sua posizione corrente verso 0 (e qui potete ovviamente cambiare 0 con la vostra destinazione) in base al tempo * 5f.
quando avete raggiunto la destinazione settate la vostra variabile a false in modo da evitare che venga eseguito codice inutilmente (che potrebbe anche avere effetti non previsti).

Ovviamente per fare animazioni di questo genere si può usare anche il tool "Animation" messo a disposizione da Unity3d, ma se, come me, siete programmatori questo metodo vi sembrerà molto più controllabile.

Al prossimo tip.

PS. Ho aggiunto un indice che cercherò di tenere aggiornato.

Messaggio modificato da Lief il 29 Apr 2018, 12:06
 
utdefault
messaggio29 Apr 2018, 23:11
Messaggio #13



Gruppo icone

Gruppo: OldGamer
Messaggi: 250
Iscritto il: 28 December 13
Utente Nr.: 20.235
SO Altro




CITAZIONE (Lief @ 25 Apr 2018, 14:58) *
CITAZIONE (utdefault @ 25 Apr 2018, 12:36) *
Casomai, con l'aggiunta di nuovi post argomentativi, ogni messaggio potrebbe essere indicizzato in apertura di discussione. Così da poterli subito richiamare all'occorrenza. :>
L'idea è buona, però ci vorrebbe un post sopra il mio primo post (mettere tutto in un post unico è un po' confusionario). Inoltre penso sia bello che tutti possano dare suggerimenti quindi se si indicizzano è bene che chi posta un tip dica esplicitamente che è un tip a inizio del suo post (in modo che l'indicizzazione sia più semplice).

CITAZIONE (Lief @ 25 Apr 2018, 14:58) *
PS. Ho aggiunto un indice che cercherò di tenere aggiornato.
Era proprio questa l'intenzione proposta.
Ben fatto! ;>

Aiuterai di sicuro chi vuol visualizzare subito l'argomento di proprio interesse.
E soprattutto a non far perdere i tips nei meandri del topic. :>

Ciao,
ai tuoi prossimi suggerimenti.

p.s.:
in futuro, che ne diresti di realizzare una sorta di guida/manuale?
 
Lief
messaggio29 Apr 2018, 23:50
Messaggio #14





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




CITAZIONE (utdefault @ 30 Apr 2018, 00:11) *
Era proprio questa l'intenzione proposta.
p.s.:
in futuro, che ne diresti di realizzare una sorta di guida/manuale?

In futuro vorrei fare una serie di video-tutorial sulla creazione del videogioco principale che sto creando (sto facendo dei backup fin dalla versione 0.01 regolarmente, quindi potrei ripercorrere passo passo la creazione dall'inizio alla fine)... quel che mi manca al momento è solo il tempo, il lavoro mi toglie la maggior parte del tempo libero e il poco che rimane va diviso tra un sacco di cose: studio (visto che devo ancora finire l'università), casa, cibo, sonno, progetto in unity, un minimo di svago ecc.... Con gli anni qualcosina dovrei finirla (studio e il progetto come minimo) e a quel punto potrò dedicare un po' di tempo anche a creare i video-tutorial (come parte della pubblicazione/pubblicità del gioco appena fatto). Ma nel frattempo qualche piccolo ritaglio di 10-15 minuti lo posso anche trovare per scrivere qualche suggerimento qua e la (in realtà lo facevo anche prima di aprire questo topic... non in maniera specifica su Unity3d, ma piuttosto sulla programmazione in generale).

Messaggio modificato da Lief il 29 Apr 2018, 23:51
 
Lief
messaggio30 Apr 2018, 09:59
Messaggio #15





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Per il tip di oggi (visto che non ho fatto nulla di particolarmente interessante con Unity3d a parte andare avanti con quel che già sapevo) voglio darvi il canale youtube del mio "maestro", ossia colui i cui video mi hanno insegnato più di qualsiasi altra scuola:
https://www.youtube.com/user/BurgZergArcade/

Sfortunatamente non è più molto attivo, ma tra gli ultimi video troviamo anche un interessante reboot della serie con cui ho iniziato (Hack & Slash RPG) (ovviamente io ho visto la serie originale).

Non voglio postare necessariamente tips tutti i giorni, ma questo canale volevo postarlo da quando ho iniziato e oggi sembra un giorno come un altro per farlo.
 
Lief
messaggio4 May 2018, 09:12
Messaggio #16





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Il tip di oggi non è necessariamente legato a Unity, è più che altro di programmazione.
Qual'è il modo più semplice per "mischiare" una lista di oggetti non iterabili?

System.Random rnd = new System.Random();

List<Oggetto> list = oggetto.OrderBy(a => rng.Next());

(nota bene, in Unity è necessario specificare System visto che la classe UnityEngine contiene una classe Random).
 
Lief
messaggio13 May 2018, 17:09
Messaggio #17





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Un modo molto semplice per rilevare le collisioni in Unity è usare i metodi:
OnCollisionEnter
OnCollisionExit

Se però si vuole rilevare l'entrata in uno spazio (senza andare "contro" un oggetto solido) si può anche creare un Trigger e usare i metodi:
OnTriggerEnter
OnTriggerStay
OnTriggerExit

come parametro in questi metodi è possibile passare
(Collider nomeVariabile)

in questo modo sarà possibile:
- capire il gameObject, il tag dell'oggetto con cui entriamo in contatto: nomeVariabile.gameObject.tag... e tutte le altre informazioni utili


trucco per evitare di dover controllare più volte il tag e di dover settare più volte le nostre variabili relative all'oggetto è settare tutto nell'Enter in variabili di classe per poi utilizzarle anche negli altri metodi.

È molto importante ricordare che tali metodi sono molto costosi e di usarli quindi con parsimonia.
Evitare di usare tali metodi per, ad esempio, controllare se siamo a terra o in aria con il nostro personaggio... perché controllare ogni frame questo tipo di informazione tramite un collider è troppo costoso... molto meglio utilizzare un Raycast della camera.

Già ma come?
Lo vedremo nel prossimo tip.
 
Lief
messaggio13 May 2018, 18:55
Messaggio #18





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Ho corretto un piccolo "bug" nel tip della Serializzazione dei dati.
Si passa da una variabile public ad una variabile privata o SerializeField, la motivazione è spiegata nel tip.
 
Lief
messaggio22 May 2018, 19:27
Messaggio #19





Gruppo: Gamer
Messaggi: 299
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing System Shock 2
SO Altro




Ci eravamo lasciati con una domanda: Come controllare se siamo attualmente toccando il terreno, senza usare un collider troppo costoso in termini computazionali?
La risposta è, come anticipato, un raycast della camera.
Ma cos'è esattamente un raycast?
La risposta è decisamente semplice, il raycast è un raggio (se preferite una linea retta) sparata dalla camera di gioco. Parte da dove vogliamo noi, arriva dove vogliamo noi.

Ecco un codice d'esempio:
bool GroundCheck () {
//questo è il "collider" del raycast... se il raggio colpisce qualcosa ritorna un RaycastHit
RaycastHit hit;
//tolleranza minima per il Capsule Collider. Se il nostro personaggio usa un capsule collider per decidere le collisioni dobbiamo mettere una minima tolleranza, altrimenti basta un terreno leggermente più inclinato non avere un controllo corretto
distance = 0.3f;
//se il raggio proiettato ritorna un hit, con tolleranza distance in posizione transform.position(che è la posizione del nostro personaggio) + Vector3.up*0.1f (origine... ossia il punto da cui parte il raggio che è i nostri piedi in questo caso), Vector3.down (direzione verso il basso). In pratica abbiamo un raggio che parte dai piedi e si muove verso il basso per 0.1f e se colpisce qualcosa con una tolleranza di 0.3f ritorna true (ossia siamo a terra)
if (Physics.Raycast (transform.position + (Vector3.up * 0.1f), Vector3.down, out hit, distance)) {
return true;
}
}

Ma se ci trovassimo nella condizione di dover verificare se stiamo toccando una parete (anche in aria), come fare?
Beh, non è poi così complesso... dovremmo semplicemente sparare dei raggi anche avanti, indietro a destra e a sinistra...
il che significherà
transform.position + (Vector3.forward * 0.1f), Vector3.forward
per avanti
e così via per tutti gli altri.
Ovviamente si può rendere questo controllo ancora più preciso sparando quanti raggi si vuole in diverse direzioni.

Semplice vero?
 

Reply to this topicStart new topic
1 utenti stanno leggendo questa discussione (1 visitatori e 0 utenti anonimi)
0 utenti:

 

Modalità di visualizzazione: Normale · Passa a: Lineare · Passa a: Outline


Versione Lo-Fi Oggi è il: 23rd June 2018 - 13:13