Nel tutorial precedente abbiamo equipaggiato il gioco con una semplice interfaccia utente e abbiamo implementato la logica necessaria a salvare i risultati del gioco in locale. Cosa succederebbe se potessimo salvare gli stessi risultati nel cloud? Banalmente abiliteremmo i nostri utenti a sfidare il resto del mondo.
Questa sezione servirà proprio a questo. Creeremo un plugin utilizzando Visual Studio 2013 che collegherà il nostro gioco a Windows Azure. Poi creermo un nuovo Mobile Serivce in Windows Azure che sarà disponibile in tutto il mondo e permetterà a chiunque di competere con tutti i possibili giocatori.
Impareremo come creare un servizio, come stabilire una connessione con esso e come definirne il comportamento.
Vedremo anche come creare creare un plugin Unity e come modificare gli script lato server del nostro servizio. Alla fine portemo utilizzare Windows Azure per salvare i dati di qualunque gioco realizziamo.
Registriamo il nostro servizio (Windows Azure Mobile Service)
Un Mobile Service di Windows Azure è praticamente gratis se le nostre applicazioni non richiedono molto traffico (fino a 10 servizi al mese). Se abbiamo bisogno di ulteriori servizi o di aggiungere potenza o spazio per lo storage per giochi di particolare successo, possiamo scalare finché vogliamo. Si possono anche utilizzare uno o due servizi per gioco.
Per saperne di più sui costi dei servizi WAMS (Windows Azure Mobile Services) possiamo riferirci al sito ufficiale.
Login o registrazione
Per prima cosa dobbiamo ottenere un account per Windows Azure (se non ne abbiamo già uno). Per farlo basta andare sul sito ufficiale e creare il nostro nuovo account. Possiamo stare tranquilli per la nostra carta di credito. Saremo noi ad abilitare eventuali pagamenti. Se utilizziamo più di quanto è concesso gratuitamente, il servizio semplicemente si bloccherà.
Creare il Mobile Service
Una volta registrati Windows Azure ci darà il benvenuto, con un'interfaccia semplice e pulita.
Vogliamo creare un nuovo "Servizio Mobile", quindi clicchiamo sulla tab Servizi Mobili
e creiamo un nuovo servizio cliccando su "CREA NUOVO SERVIZIO MOBILE
", oppure utilizzando il grosso bottone in basso "+ Nuovo
".
Ora dobbiamo creare un URL per raggiungere il servizio: tipicamente utilizziamo il nome della nostra app, ma possiamo scegliere quel che vogliamo (l'importante è che sia unico). Per essere sicuri di ricordarci che il servizio l'abbiamo creato per il nostro gioco possiamo mettere il nome del gioco oppure dare un nome significativo come "spacescore" e aggiungerci un qualche numero se troviamo che il nome è già occupato.
Avremo bisogno anche di creare un nuovo database o utilizzarne uno che abbiamo già. Dovremo indicare quale delle nostre sottoscrizioni vogliamo utilizzare (ammesso che ne abbiamo più di una) e l'area geografica in cui dovrà essere hostato il nostro servizio. Per il linguaggio di progammazione scegliamo JavaScript (anche se adesso sono disponibili anche linguaggi come C#) e andiamo avanti.
Ora è il momento di specificare alcuni dettagli sul database che utilizziamo per il servizio.
Compiliamo tutti i campi e spuntiamo l'icona in basso a destra per iniziare a creare il servizio.
Il sistema ci riporta alla pagina principale del portale dove vedremo che il nostro servizio sarà creato.
Una volta passato sullo stato di pronto, potrebbe passare circa un minuto, avremo a disposizione il nostro servizio.
Configurare il servizio
Ora dobbiamo sistemare le impostazioni del servizio e assicurarci che tutto funzioni. Clicchiamo sul nome del servizio nella finestra principale per raggiungere le impostazioni e ci si presenta una pagina di avvio veloce:
Nel menu in alto c'è una nuvola con un fulmine che porta alla pagina di avvio veloce che abbiamo davanti. Poi c'è un pannello (DASHBOARD
) per le statistiche, il link (DATI
) per accedere alla gestione delle tabelle del servizio ed altro.
Creare una tabella dati (data table)
A questo punto creiamo la tabella che ospiterà i dati che saranno utilizzati dal nostro servizio. Clicchiamo il link DATI
del menu.
Quindi clicchiamo su "aggiungi una tabella".
Chiamiamo la tabella "Leaderboard" e premiamo OK. In pochi secondi la tabella sarà pronta. Clicchiamoci su per scendere nei dettagli. A questo punto la tabella risulta vuota.
Clicchiamo ora sul link "COLONNE
" del menu e vediamo che la nuova tabella contiene la colonna chiamata "id" indicizzata, il ché significa che non dovremo impostarla noi dal nostro servizio.
Congratulazioni! Il servizio sta girando, con tanto di tabella, ma attenzione: adesso le impostazioni prevedono la possibilità di aggiungere nuove colonne in base a ciò che inseriremo da codice. Il ché va bene in fase di sviluppo dell'app ma una volta pubblicato conviene inibire questa funzione per motivi di sicurezza.
Creare il plugin Unity
I Mobile Services di Windows Azure non sono supportati nativamente da Unity, quindi dovremo scrivere un plugin per farli comunicare. Per farlo dobbiamo sempre utilizzare Visual Studio 2013.
Se non abbiamo installato Visual Studio 2013 sulla nostra macchina possiamo scaricare una delle versioni di prova (Ultimate, Professional, etc.) oppure le versioni Express, che sono gratuite. Per gli studenti, grazie a programmi come DreamSpark c'è la possibilità di accedere a licenze gratuite anche delle versioni a pagamento.
Creare una soluzione plugin in VS2013
Apriamo quindi Visual Studio 2013 e creiamo una nuova soluzione cliccando su File > Nuovo > Progetto
.
Cerchiamo la tab Altri tipi di progetto > Soluzioni di Visual Studio
e selezioniamo la Selezione Vuota
e la chiamiamo "Plugin.MobileServices"
Ora vediamo come Unity lavora con i plugin di Windows e Windows Phone. Unity funziona in questo modo. Ogni plugin che vogliamo includere nel nostro Unity game project deve essere copiato nella cartella Assets/Plugin. Quando esportiamo un gioco questi plugin seguono il progetto.
In alcuni casi come questo però, il codice che scriviamo non è proprio supportato dall'editor di Unity.
Ciò significa che dovremo "ingannare" il processo di esportazione creando due plugin: uno "fasullo" che contenga le stesse funzioni di quello vero (per non incorrere in errori in fase di build su Unity) e poi il plugin vero e proprio che conterrà le funzionalità giuste e che copieremo nella soluzione in Visual Studio una volta effettuata l'esportazione.
Gli sviluppatori di Unity hanno reso questo processo semplice: quando esportiamo per Windows 8 (Windows Store App) Unity cerca i plugin nella cartella Assets/Plugins
e li copia. Quindi cerca una sottocartella chiamata "Metro" (per Windows 8, mentre sarà "WP8" per Windows Phone) e copierà i plugin che trova al suo interno sovrascrivendo quelli con lo stesso nome.
In altre parole dobbiamo creare due plugin con lo stesso nome, uno per ingannare l'editor e l'altro che contenga le reali funzionalità per la connessione al cloud.
Le funzioni della DLL fasulla (fatta per l'editor) saranno visibili quando programmiamo i nostri giochi in Unity. Ciò significa che funzioni e parametri dovranno corrispondere esattamente con quelle della DLL reale.
Creare il plugin fasullo (fake editor plugin)
Iniziamo creando il plugin fasullo. In Visual Studio 2013 clicchiamo col tasto destro sulla soluzione e aggiungiamo un nuovo progetto:
Ora cerchiamo Visual C# (il linguaggio con il quale creeremo il plugin) e scegliamo il .NET Framework 3.5 sul menu in alto, poi selezioniamo "Libreria di classi", chiamiamo il progetto "Editor" e clicchiamo OK.
Una volta aggiunto il progetto alla nostra soluzione, rinominiamo il file Class1.cs
(F2 o cliccando col tasto destro) e lo chiamiamo "Connector.cs".
Clicchiamo ora su Connector.cs per modificarne il codice. Per prima cosa cambiamo il namespace, da Editor
a Plugin.MobileServices
.
Quindi è il momento di aggiungere qualche funzionalità. Noi vogliamo semplicemente poter fare due cose:
- inserire nuove entry nel nostro servizio;
- scaricare i risultati migliori dal servizio.
Ecco le due funzioni:
public void Insert(int score) { }
public void GetScore() { }
Inoltre ci serve un intero che tenga traccia del miglior punteggio disponibile.
Aggiungiamo tutto al codice del plugin:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
}
}
}
Per simulare il plugin che prende i dati dal cloud possiamo fissare il valore di BestScore
a 1000
, giusto per vedere qualche dato mentre lavoriamo nell'editor di Unity.
namespace Plugin.MobileServices
{
public class Connector
{
//...
public void GetScore()
{
BestScore = 1000;
}
}
}
... E per quanto riguarda la DLL fasulla, questo è tutto. Praticamente non fa nulla se non rendere disponibili le funzioni nell'editor di Unity e permetterci di continuare a testare il gioco e di esportarlo.
Creare il plugin effettivo
È il momento di creare il vero plugin. Clicchiamo con destro sulla soluzione principale e aggiungiamo un nuovo progetto. Stavolta selezioniamo la categoria Windows Store (sempre sotto Visual C#) e il .NET Framework 4.5. Poi utilizziamo il template Class Library (poiché stiamo creando una DLL per Windows Store) e diamo al progetto il nome di "WindowsStore". Infine clicchiamo OK.
Di nuovo cambiamo il nome del il file "Class1.cs" in "Connector.cs" e apriamo il file per implementare le stesse funzioni che abbiamo aggiunto nella DLL fasulla (assicuriamoci anche di modificare anche qui il namespace).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
}
Ora dobbiamo connettere a questo oggetto il servizio che abbiamo nel cloud.
Aggiungere Windows Azure Mobile Services al nostro progetto
Per fare questo dobbiamo installare i pacchetti Windows Azure Mobile Services sul nostro progetto. Per farlo ci serviamo di NuGet: clicchiamo sul progetto WindowsStore
col tasto destro e selezioniamo "Gestisci pacchetti NuGet"
Questo è un serivzio che permette di aggiungere librerie e pacchetti ai nostri progetti in modo molto semplice. Inseriamo "Windows Azure" nella casella di ricerca:
Tra i molti risultati che appariranno, cerchiamo Windows Azure Mobile Services e clicchiamo su "Installa". Avvieremo così il download e l'installazione del pacchetto Windows Azure Mobile Services all'interno del progetto. Una volta fatto, esso sarà visibile nella cartella Riferimenti
del progetto:
Aggiungere la logica
Ora possiamo utilizzare il nuovo pacchetto per connettere il gioco al nostro servizio e inserire nel cloud nuovi elementi per i punteggi. Dovremo anche accertarci che la nostre tabella contenga le colonne giuste.
Un record nella tabella Leaderboard
consistedi un id e del punteggio effettuato, possiamo definire questa semplice struttura implementando una classe in Connector.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
}
Questa classe deve avere lo stesso nome della tabella che abbiamo creato nel servizio. I campi id e score sono entrambi interi.
Ora dobbiamo aggiungere una variabile che servirà a collegare questo plugin con il mobile service. Per impostarla correttamente torniamo ancora al portal Windows azure e apriamo di nuovo la pagina di avvio veloce del servizio.
Qui in basso clicchiamo su "connetti un'app di Windows Store esistente".
Il passo 1 contiene informazioni molto importanti sul servizio: l'URL e il token di autenticazione con cui solo possiamo connetterci al servizio (da non diffondere).
Ora questa è proprio la variabile che dobbiamo aggiungere al nostro script per connetterci al servizio, quindi clicchiamo il bottone "copia" in alto a destra nel box oppure selezioniamo e copiamo il testo come facciamo di solito e incolliamolo nel nostro Connector.cs
.
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://spacescore.azure-mobile.net/",
"<Qui la chiave segreta>");
public int BestScore = 0;
// ...
Inoltre dobbiamo aggiungere una espressione using
per utilizzare i riferimenti alla libreria Windows Azure Mobile Services, altrimenti il compilatore non capirà cos'è un MobileServicesClient
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices; // aggiunto il namespace
namespace Plugin.MobileServices
{
//...
Ciò che faremo ora è creare un nuovo elemento di tipo Leaderboard, inserire dei dati e inviarlo alla tabella del nostro servizio.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://spacescore.azure-mobile.net/",
"<codice segreto>");
public int BestScore = 0;
public async void Insert(int score)
{
Leaderboard entry = new Leaderboard { Score = score };
await MobileService.GetTable<Leaderboard>().InsertAsync(entry);
}
public void GetScore()
{
BestScore = 1000;
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
}
Fatto questo dovremmo essere in grado di inviare dati alla tabella Leaderboard del nostro servizio. Aggiungiamo tutto ciò a Unity e proviamo!
Aggiungere plugin al gioco in Unity
Vediamo ora come aggiungere i plugin a Unity e rendere le funzionalità disponibili per i nostri giochi. La prima cosa che dovremmo fare è compilare la soluzione dei plugin per ottenere le DLL che ci servono.
Clicchiamo col tasto destro sul progetto Plugin.MobileServices e clicchiamo su Compila Soluzione:
Ora troviamo la carella della soluzione sul file system e copiamo la DLL del plugin Editor, che preleviamo da Plugin.MobileServices\Editor\bin\Debug
.
Il file sarà Editor.dll
, lo copiamo e, sempre da file system ci spostiamo sul progetto Unity, dove creiamo una nuova cartella "Plugins" sotto la cartella "Assets". Qui incolliamo la dll.
Ora dobbiamo prendere la DLL "reale", quindi torniamo alla directory del Plugin ("Plugin.MobileServices\WindowsStore\bin\Debug
") e qui rinominiamo il file WindowsStore.dll
in Editor.dll
, quindi copiamo TUTTI i file .dll di questa cartella inserirli nel progetto Unity.
Ora torniamo nella cartella Assets/Plugins/
del nostro progetto Unity e creiamo una sottocartella "Metro" dove incolliamo tutti i file .dll selezionati.
Ora quando lavoreremo nell'editor di Unity, creando script e altro, troveremo le funzionalità di Editor.dll collocate nella cartella Plugins. Quando esportiamo il nostro progetto come app Windows Store, i file DLL che della cartella Plugins saranno copiati e sostituiti, se necessario, da quelli che si trovano nella cartella "Metro". In questo modo il file Editor.dll "fasullo" sarà sostituito da quello reale.
Aggiungere i nostri risultati al servizio cloud
Lanciamo Unity e apriamo il progetto che abbiamo lasciato nella lezione precedente (in allegato a questa lezione) e apriamo la scena Game Over.
Qui clicchiamo sul GameObject Main Camera
nel pannello Hierarchy e apriamo lo script GameOverController
(che troviamo anche nel pannello Inspector) con un doppio click. Lo script appare così:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour
{
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt("CurrentScore", 0);
int _highscore = PlayerPrefs.GetInt("HighScore", 0);
if (_score > _highscore)
PlayerPrefs.SetInt("HighScore", _score);
}
void Start()
{
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = "Score: " + PlayerPrefs.GetInt("CurrentScore", 0);
highScoreText.text = "Highscore: " + PlayerPrefs.GetInt("HighScore", 0);
PlayerPrefs.Save();
}
void Update()
{
gameOverTimer -= Time.deltaTime;
if (gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
Ciò che faremo è modificare la funzione CheckHighScore()
perché essa carichi il punteggio nel cloud (ma solo se è il massimo punteggio anche in locale, per evitare sprechi).
public class GameOverController : MonoBehaviour
{
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt("CurrentScore", 0);
int _highscore = PlayerPrefs.GetInt("HighScore", 0);
if (_score > _highscore)
{
PlayerPrefs.SetInt("HighScore", _score);
connector.Insert(_score);
}
}
// ...
Quando il gioco passa alla scena Game Over, comincia col verificare se abbiamo un nuovo punteggio record. In caso affermativo lo memorizza nel PlayerPrefs locale e lo inserisce anche nel cloud utilizzando il plugin.
Prima di provarlo dobbiamo essere certi che all'applicazione Windows Store sia permesso di accedere a internet. Andiamo su Unity e poi su File > Build Settings
, e poi su player settings.
Nel pannello Inspector cerchiamo in basso, tra i Publishing Settings
la capability InternetClient e la spuntiamo:
Ora esportiamo il gioco come app Windows Store, apriamolo come soluzione in Visual Studio 2013 e mandiamolo in esecuzione col tasto Play (dobbiamo essere su una macchina Windows 8.1).
Ora non ci resta che giocare, fare un buon punteggio e verificare che sia stato registrato nella tabella Leaderboard in Windows Azure:
Ottenere i risultati salvati nel cloud
Per finire possiamo utilizzare quanto visto per ottenere gli high score dal cloud e mostrarli in una terza label su Unity.
Aggiungere una nuova label è molto semplice a questo punto: andiamo sul GameObject GUI nella scena di Game Over e dal pannello Hierarchy duplichiamo il GameObject che utilizziamo per l'high score. Lo rinominiamo "OnlineLeaderText" e lo spostiamo per non far sovrapporre i testi a (0.5, 0.9, 0)
Ora, nello script GameOverController, aggiungiamo una variabile public per ottenere un riferimento all'elemento della GUI:
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
public GUIText onlineLeaderText; // aggiunta variabile public
// ...
Torniamo su Unity e trasciniamo il Gui Text sulla variabile nello script della Maing camera. Se necessario ricolleghiamo anche l'high score.
Impostare il testo per il punteggio online
È il momento di modificare ancora lo script. Dobbiamo interrogare il servizio e impostare il testo del punteggio migliore che ricaviamo dal plugin:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour
{
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
public GUIText onlineLeaderText;
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt("CurrentScore", 0);
int _highscore = PlayerPrefs.GetInt("HighScore", 0);
if (_score > _highscore)
{
PlayerPrefs.SetInt("HighScore", _score);
connector.Insert(_score);
}
}
void Start()
{
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = "Score: " + PlayerPrefs.GetInt("CurrentScore", 0);
highScoreText.text = "Highscore: " + PlayerPrefs.GetInt("HighScore", 0);
PlayerPrefs.Save();
}
void Update()
{
gameOverTimer -= Time.deltaTime;
if (gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
Tutto ciò di cui abbiamo bisogno è di verificare l'aggiornamento del punteggio online ad ogni fotogramma (poiché connect.GetScore()
è async
e dovrebbe impiegare un po' di tempo prima di essere pronto).
Quando lo script parte controlliamo l'high score, lo carichiamo se abbiamo un nuovo valore e scarichiamo il miglior punteggio online.
Modificare il plugin per scaricare i dati
Apriamo il file Connector.cs
nel progetto del plugin WindowsStore e apportiamo le seguenti modifiche:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceCollection<Leaderboard, Leaderboard> Items = null;
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://spacescore.azure-mobile.net/",
"<codice segreto>");
public int BestScore = 0;
public async void Insert(int score)
{
Leaderboard entry = new Leaderboard { Score = score };
await MobileService.GetTable<Leaderboard>().InsertAsync(entry);
}
public async void GetScore()
{
Items = await MobileService.GetTable<Leaderboard>().ToCollectionAsync();
if (Items != null)
{
if (Items.Count > 0)
{
BestScore = Items[0].Score;
}
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
}
Non abbiamo fatto altro che aggiungere una collection di Item che deve contenere i dati che prendiamo dal servizio. Quindi diamo all'intero BestScore
il valore del primo elemento della lista che ci viene fornita dal servizio. Ma dovremmo cambiare lo script del servizio per farci ritornare direttamente il miglior punteggio (meno traffico, meno scambio dati, costi inferiori).
Ricompiliamo tutto e riesportiamo. Lanciamo tutto e notiamo che in questo modo abbiamo non il miglior punteggio ma il primo caricato sul servizio. Sistemiamolo. Dobbiamo modificare lo script server-side che dovrà ritornare solo il massimo risultato.
Andiamo sul tab Dati del mobile service e clicchiamo sulla tabella Leaderboard. Ora clicchiamo sul link Script.
Dal menu a tendina scegliamo lo script di lettura (Leggi) e lo modifichiamo come segue:
function read(query, user, request) {
query.orderByDescending('Score').take(1);
request.execute();
}
Clicchiamo su "Salva" e aspettiamo che le modifiche siano attive.
Questo breve script modifica il modo in cui il servizio restituisce i dati della nostra tabella. In sostanza ordiniamo in modo discendente i punteggi e preleviamo solo il primo elemento dell'elenco, quindi il miglior punteggio.
Poiché abbiamo modificato la parte server del codice non avremo bisogno di modificare o ricompilare la nostra applicazione. Possiamo testarla semplicemente mandandola in esecuzione da Visual Studio.
Abbiamo terminato il tutorial. È stata un po' lunga ma l'importante è che ora sappiamo come abilitare i nostri giochi all'utilizzo di servizi Azure in pochi minuti.