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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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
- Serializzazione Multi-livello. Oggetti complessi custom.
- Oauth 2.0 e Save Cloud - Parte 1: La teoria
- Oauth 2.0 e Save Cloud - Parte 2: Google Drive - Autenticazione, Upload, Download

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 3 Aug 2018, 10:52
 
Lief
messaggio23 Apr 2018, 08:19
Messaggio #2





Gruppo: Gamer
Messaggi: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 290
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.607
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: 952
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 952
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 290
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 290
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
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?
 
Lief
messaggio6 Jul 2018, 13:07
Messaggio #20





Gruppo: Gamer
Messaggi: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
SO Altro




Prendendo spunto da una risposta che ho dato su stackoverflow (downvotata ma corretta, come dimostra il fatto che è stata accettata dall'utente):
https://stackoverflow.com/questions/5119350...193771#51193771

Nella mia risposta trovate il metodo per serializzare un oggetto contenente una lista di oggetti che a loro volta contengono 2 array.
Ovviamente è solo un esempio, potete personalizzarlo come volete per usare il limitatissimo serializzatore json di unity per fare oggetti complessi (esempio, al posto di un dizionario (Dictionary, l'equivalente delle HashMap in Java) non supportato potete utilizzare una List di Oggetti contenenti due campi key value).

Alla prossima

PS. È quasi due mesi che non aggiorno il topic. Ma c'è poco da fare, fin quando non mi vengono in mente nuove idee aggiornare è inutile.

Messaggio modificato da Lief il 6 Jul 2018, 14:10
 
Lief
messaggio12 Jul 2018, 15:11
Messaggio #21





Gruppo: Gamer
Messaggi: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
SO Altro




Quante volte avete pensato:
- Ma quanto sono comodi i salvataggi su cloud?

Cambi PC e tutto quel che devi pare è sincronizzare il salvataggio e continuare la partita.
Succede un disastro e non devi ricominciare la partita.

Eppure i salvataggi su cloud hanno anche loro dei problemi:
- Sono legati alla piattaforma. Il che significa che se hai lo stesso gioco su PC e su smartphone (anche se i salvataggi sarebbero in teoria compatibili) non c'è modo di passare i salvataggi da un gioco all'altro (al massimo si può fare manualmente... ma non su iOS e non sempre su Android senza root).
- Per usufruirne è necessario installare un client in grado di supportarli. Se si gioca su gog senza gog galaxy si perdono i salvataggi su cloud. Se si gioca su steam senza steam (pochi giochi lo permettono ma ci sono) niente salvataggi su cloud.


Un utente con un minimo di esperienza può creare un sistema alternativo per tutti i giochi su PC. Con delle cartelle simboliche e dei servizi cloud tipo dropbox, collegando i salvataggi alla cartella di sincronizzazione e riuscendo così a risolvere il problema del client obbligatorio...
Ma rimane comunque il primo problema.
Inoltre è una rottura settare il tutto.
Senza contare che ci costringe ad installare le varie app di sincronizzazione (app che potrebbero non servirci in linea di massima, se solitamente usiamo il browser e non teniamo cartelle sincronizzate).

Eppure settare un sistema simile in-game non è impossibile e da modo ai nostri utenti di potersi semplicemente loggare al loro account personale per sincronizzare i propri salvataggi su qualsiasi piattaforma.

O meglio... sarebbe così se parlassimo di qualche anno fa. Oggi i sistemi di autenticazione Oauth 2.0 sono molto complessi e non ci consentono di rendere l'operazione un semplice "metti il tuo utente e password qui che io mando tutto con una post".

Tuttavia il sistema non è così complesso come potrebbe sembrare in un primo momento e le API messe a disposizione ci permettono di semplificare molto il sistema.

Visto che è un sistema complesso che varia da piattaforma a piattaforma ho deciso di dividere questo post in diverse parti, questa prima parte sarà dedicata ad un riassunto dei passaggi necessari per la nostra applicazione in Unity3d.

Passaggi:

1. Creazione di un'app autorizzata a fare le chiamate. Le chiamate alle API di default vengono respinte dai siti moderni questo per evitare abusi e attacchi (in questo modo chi riceve le chiamate può identificare chi le fa, e bloccare chi abusa).
Solitamente basta iscriversi al sito cloud prescelto e andare nella sezione API/sviluppo per poter creare un'app autorizzata.
Riceveremo così un client id e un secret id.
2. Fare la chiamata per la prima autorizzazione. Questa chiamata di solito viene fatta solo una volta. Consiste in realtà nell'aprire un link (quindi non è una vera chiamata alle API). Questo link (passano i dati client id e secret id) permetterà all'utente di autenticarsi sul proprio browser (lasciando quindi la nostra app). Una volta finita l'autorizzazione ci restituirà un token temporaneo dalla breve durata.
Ma come ce lo restituisce?
Se parlassimo di un'app web ce lo restituirebbe con un semplicissimo redirect... Sfortunatamente con i giochi Unity3d questo non si può fare perché la nostra app ovviamente non è un sito web.
Si può però sfruttare un redirect su un nostro server (che cattura il token e lo passa alla nostra app magari scrivendo su un file leggibile dalla nostra app) oppure con altri due metodi che non richiedono alcun server... un semplice copia/incolla senza redirect (dopo il login viene mostrato un codice all'utente che viene invitato a copiarlo all'interno dell'applicazione) o un redirect su localhost (che però la nostra app deve ascoltare).
Ovviamente il metodo più semplice da implementare (in mancanza di API già scritte) è quello del copia/incolla, almeno per i giochi in Unity3d.
3. Ottenuto il token temporaneo è tempo di fare la nostra prima vera e propria chiamata alle API. Solitamente una post con il token ottenuto. Al suo posto otterremo un token duraturo che identifica la nostra applicazione come loggata.
Possiamo leggere il token nel body di risposta o negli header dipende dal sito.
4. Trasformiamo il nostro file di salvataggio in un array di byte (byte[]) e lo mandiamo con una post insieme al token ottenuto in precedenza (cosa mettere nel body e cosa negli header dipende dal sito, solitamente però nel body si mette l'array di byte che rappresenta il nostro file, nell'header il nostro codice di autorizzazione).
Solitamente la risposta è successo o fallimento, quel che troviamo nel body e nell'header varia da sito a sito, solitamente però è qui che troviamo tutte le informazioni per ritrovare il file in caso di update o download.
5. L'update serve per aggiornare il nostro file di salvataggio. A seconda del sito può essere uguale alla create (con una post con overwrite come header) o ci può essere un id (ricevuto durante la create). È sempre una post che restituisce la stessa response della create (solitamente). Ovviamente, come per la create va mandato anche il token.
6. Download. Solitamente si fa con una get o con una post. Si passa l'indirizzo e, negli header o nel body, il token.
Il nostro file viene restituito come un array di byte che può essere convertito nel formato originario e poi salvato su disco (viene restituito quasi sempre nel body).

Ricapitolando:
- Apro link, utente si logga, copia il codice (o avviene tutto in automatico)
- Scambio il token temporaneo per uno di lunga durata.
- Post per creare il file su cloud con token (invio un byte[]).
- Post per update (a volte coincide con create con parametro di sovrascrittura)
- Get o Post per download con token (restituisce il body con la il file in byte[]).

Esistono eccezioni a questo flow (esempio Mega, che ha le sue API non compatibili con Unity3d), sfortunatamente nessuno supporta ufficialmente Unity3d.

Esistono però delle semplici API per Dropbox.
Un pacchetto open source molto comodo per Google Drive (non ufficiale ma molto simile ad un pacchetto ufficiale).
Dei siti che non richiedono alcuna autenticazione e che restituiscono un url (ovviamente i salvataggi degli utenti non contengono dati personali quindi non necessitano necessariamente di essere segreti. Altrettanto ovviamente sarà l'utente a scegliere tra Google Drive e Dropbox o i siti senza autenticazione). Con tali siti può bastare la Post/Put e la Get.

La prossima volta vedremo i dettagli implementativi per il pacchetto di Google Drive (il più semplice).

Alla prossima.
 
Lief
messaggio18 Jul 2018, 14:16
Messaggio #22





Gruppo: Gamer
Messaggi: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
SO Altro




Piccola aggiunta al mio post precedente.
1. Ascoltare la risposta su localhost è molto più semplice di quel che pensavo. Ho letto il codice sorgente del pacchetto per Google Drive e l'ho implementato per Dropbox (che però non può ascoltare su una porta qualsiasi di localhost, quindi è necessario registrare un range di porte da controllare manualmente).
Il metodo è migliore del copia/incolla perché non richiede all'utente di fare azioni innaturali (a parte "tornare all'app" che però è decisamente più semplice di copiare/incollare un codice alfanumerico). Oltretutto il metodo copia/incolla è segnato come deprecato da parte di google, il che significa che anche dropbox potrebbe rimuoverlo in futuro (anche se al momento su dropbox non è segnato come deprecato).
2. Le API di Mega sono ora compatibili con Unity3d (dalla versione 2018.2 in poi). Quindi vedremo anche il metodo per fare upload e download da Mega (con 3 servizi autenticati direi che siamo davvero a buon punto).
3. Su Android localhost va sostituito con 127.0.0.1 ossia l'ip del localhost... su iOS ovviamente è il contrario, non funziona 127.0.0.1 ma funziona il localhost.

Messaggio modificato da Lief il 22 Jul 2018, 07:15
 
Lief
messaggio3 Aug 2018, 10:51
Messaggio #23





Gruppo: Gamer
Messaggi: 333
Iscritto il: 29 November 16
Utente Nr.: 21.351
BGE Deus Ex 1
Playing Fallout New Vegas
SO Altro




Google Drive.

Per google drive esiste fortunatamente qualcuno che ha già fatto la maggior parte del lavoro per noi.
Basta scaricare il pacchetto da qui:
https://github.com/Elringus/UnityGoogleDrive

e seguire le istruzioni per il setup.

Il bello di questo pacchetto è che, qualsiasi chiamata faremo da ora in avanti, ci presenterà, se necessario, l'autenticazione.
Il che significa che non dobbiamo implementare l'accesso (neanche la parte per ascoltare la risposta su localhost).

Ma come utilizzare l'API per fare l'upload di un file si salvataggio e farne successivamente il download?

Upload:
si divide in:
-creazione
-aggiorrnamento

private IEnumerator UploadFileToCloud(){
byte[] myData = System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(Application.persistentDataPa
th + "/" + "uploadtry.json"));
var file = new UnityGoogleDrive.Data.File() { Name = "uploadtry.json", Content = myData };
var request = GoogleDriveFiles.Create(file);
yield return request.Send();
Debug.Log(request.ResponseData.Id);
}

Il metodo sopra vi permetterà di fare l'upload di un file nel persistentDataPath nella root di google drive.
request.ResponseData.Id è l'id del vostro file. Salvandolo potrete fare il download e l'aggiornamento del file.

var request = GoogleDriveFiles.Update(request.ResponseData.Id, file);
var request = GoogleDriveFiles.Download(request.ResponseData.Id);

Debug.Log(System.Text.Encoding.UTF8.GetString(request.ResponseData.Content));

dove request.ResponseData.Content è il contenuto del file.

Ma come recuperare un file senza sapere l'id, e come creare una cartella?

Lo vedremo molto presto.
Alla prossima
 

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: 16th October 2018 - 05:01