In questo articolo, creeremo la nostra prima classifica MySQL da ospitare su un sito Web o un server Web utilizzando semplici PHP e alcuni SQL. Quindi faremo un semplice esempio di Unity in C # usando GUIText
oggetti per aggiungere nuovi punteggi alla nostra classifica, visualizzare i primi dieci punteggi e visualizzare il punteggio e il punteggio di un utente.
I giochi per giocatore singolo sono divertenti, ma battere il tuo record può diventare noioso. Aggiungere una classifica al tuo gioco fornisce una reale motivazione per i giocatori a migliorare i loro punteggi e giocare di più al tuo gioco, e può anche essere usato per capire se il tuo gioco è troppo facile o difficile. Nei giochi che durano per sempre, le classifiche possono essere l'unico motivo per cui i tuoi giocatori giocano. Se hai il tuo sito web o server, potresti voler ospitare la tua classifica personale, in modo da avere il controllo completo sul gioco.
Prima di tutto, avrai bisogno di avere un database SQL sul tuo server o sito. I siti web sono spesso dotati di un database MySQL integrato. I dettagli di questo variano a seconda del servizio che utilizzi, ma dovresti riuscire a trovare l'host, il nome utente e la password SQL (oltre al nome del tuo database) dal pannello di amministrazione o dall'email di registrazione.
In questo esempio, phpMyAdmin viene utilizzato per accedere al database (creato direttamente nel pannello di amministrazione). Dovrai aprire il tuo database e aprire la scheda SQL. Se hai più controllo sul tuo server, puoi creare un nuovo database.
Quindi, inserisci il seguente SQL:
CREATE TABLE Scores (nome VARCHAR (10) NOT NULL DEFAULT 'Anonymous' PRIMARY KEY, score INT (5) UNSIGNED NOT NULL DEFAULT '0', ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE = InnoDB;
Questo creerà una tabella con tre variabili:
nome
, che contiene i nomi dei tuoi utenti e che memorizzerà 10 caratteri. Questo è l'identificatore principale della nostra tabella, quindi significa che può memorizzare solo una riga per nome utente.Punto
, che contiene il punteggio più alto di ogni utente. In questo esempio è una variabile senza segno, quindi può essere solo positiva. Se vuoi avere punteggi negativi, dovrai cambiarlo.ts
, un timestamp che possiamo usare per cambiare l'ordine della nostra classifica.Ora, se stai usando SQL Server e non MySQL, puoi ancora usarlo TIMESTAMP
, ma per il valore che dovrai usare GETDATE ()
invece di CURRENT_TIMESTAMP
.
Una cosa in più da tenere a mente: se stai facendo un gioco molto semplice, potresti non voler legare i punteggi ai nomi (per permettere ad ogni giocatore di avere più punteggi nella Top 10, ad esempio). Questa può essere una cattiva idea; potresti avere un giocatore che è così bravo da poter dominare la tua Top 10 intera! In questo caso non vorrai nome
come chiave primaria, e dovrai aggiungere anche questo:
id INT (8) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
Ciò assicurerà una nuova riga visibile per ogni punteggio.
Clic Partire e hai finito! Il tuo tavolo è tutto pronto ora.
Ora è necessario creare alcuni file PHP. Questi sono gli intermediari dell'operazione, che forniscono un modo per Unity di accedere al tuo server. Il primo file PHP di cui avrai bisogno è AddScore.php
. Avrai bisogno di sapere le informazioni sul server di prima.
(Sostituire
sqlhost
,SQLUSER
,SQLPASSWORD
eYOURDATABASE
con le tue informazioni.)Qui abbiamo appena provato a connetterci al database. Se la connessione fallisce, Unity verrà informata che la richiesta non è andata a buon fine. Ora, vorrai passare alcune informazioni al server:
$ username = mysql_real_escape_string ($ _ OTTIENI ['nome'], $ db); $ score = mysql_real_escape_string ($ _ OTTIENI ['punteggio'], $ db); $ hash = $ _GET ['hash']; $ PrivateKey = "ADDYOURKEY";L'hash è usato per crittografare i tuoi dati e impedire alle persone di hackerare la tua classifica. Viene generato con una chiave nascosta in Unity e qui, e se i due hash corrispondono, ti è consentito l'accesso al tuo database.
$ expected_hash = md5 ($ username. $ score. $ privateKey); if ($ expected_hash == $ hash)Qui generiamo l'hash e controlliamo che l'hash che inviamo da Unity sia identico all'hash che ci aspettiamo. Se lo è, possiamo inviare la nostra richiesta!
$ query = "INSERT INTO Punteggi Nome SET = '$ nome', punteggio = '$ punteggio', ts = CURRENT_TIMESTAMPQuesta è la prima metà della nostra query SQL. Dovrebbe essere abbastanza auto-esplicativo; il punteggio e il nome utente inviati vengono aggiunti alla tabella e il timestamp viene aggiornato. La seconda parte è più complicata:
ON DUPLICATE KEY UPDATE ts = if ('$ score'> punteggio, CURRENT_TIMESTAMP, ts), score = if ('$ score'> punteggio, '$ score', punteggio); ";Per prima cosa controlliamo se il nome utente (la nostra chiave primaria) ha già una riga. Se lo fa, invece di inserire una nuova voce, la nostra voce verrà aggiornata. Vogliamo aggiornare il timestamp e il punteggio, ma solo se il nuovo punteggio è più alto!
utilizzando
Se
affermazioni, ci assicuriamo che i nuovi valori vengano usati solo se il nuovo punteggio è maggiore del punteggio corrente, altrimenti vengono utilizzati i valori originali.$ result = mysql_query ($ query) o die ('Query failed:'. mysql_error ()); ?>Finalmente eseguiamo la nostra query e chiudiamo il nostro PHP.
Questo file va sul nostro server. Dovrai ricordare l'URL. Allo stesso modo, abbiamo bisogno di creare altri due file PHP con query diverse, che chiameremo
TopScores.php
eGetRank.php
.Il
Migliori risultati
la query è semplicemente:SELECT * FROM Scores ORDER per punteggio DESC, ts ASC LIMIT 10Questo prenderà i primi 10 valori in base al punteggio, e per i gradi legati mette i giocatori che hanno ottenuto il punteggio più in alto sul tavolo. Questa volta vogliamo estrarre anche i dati, quindi aggiungiamo anche:
$ result_length = mysql_num_rows ($ result); per ($ i = 0; $ i < $result_length; $i++) $row = mysql_fetch_array($result); echo $row['name'] . "\t" . $row['score'] . "\n";Questo estrae i nostri risultati e li tabula in un modo che possiamo metterli in array in Unity.
Finalmente, abbiamo
GrabRank
:SELECT uo. *, (SELECT COUNT (*) FROM Punteggi ui WHERE (ui.score, -ui.ts)> = (uo.score, -uo.ts)) AS rank FROM Punteggi uo WHERE name = '$ name' ;Questo ci darà il punteggio del nostro giocatore nel tabellone. Possiamo quindi estrarlo facendo eco
$ Row [ 'rango']
.Il nostro codice sorgente include anche una funzione di sanificazione, che impedirà agli utenti di immettere parole parolacce nella tua classifica o di tentare un attacco di SQL injection.
Creare un minigioco semplice in Unity
Ora abbiamo bisogno di un gioco per usare la nostra scheda punteggi migliori! Stiamo solo testando quanti clic ogni utente può fare in dieci secondi, ma puoi aggiungere la tua classifica a qualsiasi gioco.
disposizione
Inizieremo facendo quattro
GUIText
oggetti. Questi dovrebbero essere ancorati intorno al centro centrale per comodità. Puoi regolarli con l'offset dei pixel per metterli nel posto giusto, ma se vuoi che regoli la loro posizione per qualsiasi risoluzione, è più semplice cambiare ilX
eY
posizione (tra0
e1
); altrimenti, dovrai regolarli all'avvio.Dovrai, tuttavia, regolare la dimensione del carattere all'avvio se desideri eseguire tutte le risoluzioni. Un modo rapido per farlo è basandoli sull'altezza dello schermo. Possiamo farlo creando una classe che faccia questo e collegandolo a tutti i nostri oggetti di testo, ma è molto più semplice farlo tutto da una classe.
Non importa quale oggetto scegliamo come nostro "manager", quindi possiamo semplicemente mettere questa classe sul nostro contatore dei clic. Quindi nella nostra prima lezione scriviamo:
void Start () foreach (GUIText chosentext in FindObjectsOfType (typeof (GUIText)) come GUIText []) chosentext.blah.fontSize = Mathf.FloorToInt (Screen.height * 0.08f);Questo troverà ogni oggetto di testo nella scena e lo ridimensionerà a una dimensione ragionevole.
Ora vogliamo che il contatore dei clic sia più grande dell'altro testo, quindi se applichiamo questa lezione, abbiamo il bonus in più che possiamo anche verificare se il
guiText
in questione è quello allegato a questoGameObject
:if (blah == guiText) blah.fontSize = Mathf.FloorToInt (Screen.height * 0.18f); altro [ecc.]gameplay
Il componente di selezione del gioco sarà molto semplice. All'inizio, non vogliamo che il timer effettui il conto alla rovescia fino al primo clic, quindi ne faremo due privati
Caccio
nella nostra classe -firstClick
eallowedToClick
. NelInizio()
possiamo impostarefirstClick
afalso
eallowedToClick
avero
.Ora abbiamo bisogno del contatore per registrare effettivamente i clic e ci sono un paio di modi per farlo. Potremmo mantenere una variabile intera che tiene traccia del punteggio, o potremmo renderla leggermente meno efficiente ma in una linea (e con qualcosa di così semplice non abbiamo davvero bisogno di ottimizzare, ma è una buona pratica). Quindi registreremo il clic nel
Aggiornare()
funzione, e incrementare il valore leggendo la stringa.void Update () if (allowedToClick && Input.GetMouseButtonUp (0)) if (! firstClick) firstClick = true; StartCoroutine (Countdown ()); guiText.text = (System.Int32.Parse (guiText.text) + 1) .ToString ();Come potete vedere qui, l'incremento si ottiene leggendo la stringa come numero intero, aggiungendone una e quindi riconvertendola in una stringa. Vedrai anche qui che abbiamo eseguito una coroutine non appena l'utente fa clic per primo, che avvia il conto alla rovescia.
Useremo la ricorsione in questa funzione. Ancora una volta, potremmo usare un numero intero che contiene il valore del conto alla rovescia per l'efficienza, ma useremo nuovamente la manipolazione delle stringhe.
IEnumerator Countdown () yield return new WaitForSeconds (1); counter.guiText.text = (System.Int32.Parse (counter.guiText.text) - 1) .ToString (); if (counter.guiText.text! = "0") StartCoroutine (Countdown ()); else allowedToClick = false; GetComponent() .Setscore (System.Int32.Parse (guiText.text)); toptext.guiText.text = "Inserisci il tuo nome utente."; GetComponent () .enabled = true; Nota: è importante che abbiamo usato
StartCoroutine ()
e non ho appena chiamato questa funzione, perché è unIEnumerator
. Ildare la precedenza
l'istruzione fa attendere un secondo prima che venga intrapresa un'azione. Rimuove uno dal contatore e, se il valore non è zero, si chiama di nuovo. In questo modo, la funzione conta alla rovescia finché non raggiunge0
.Nome
Dopodiché, impedisce all'utente di fare clic, richiede il nome utente e accede alle nostre seconde e terze classi (che stiamo per scrivere!). Daremo un'occhiata a cosa fanno ora, iniziando con
NameEnter
.Nel
NameEnter ()
consentiremo a un utente di digitare il proprio nome utente, con alcuni vincoli. Inizialmente vogliamo visualizzare il carattere di sottolineatura_
, che verrà cancellato non appena inizieranno a digitare il loro nome. Inoltre, non vogliamo che siano in grado di utilizzare personaggi come\
o'
, in quanto ciò potrebbe rovinare le nostre query SQL.Useremo un generatore di stringhe per creare questo. Per prima cosa inseriremo alcune variabili nella parte superiore della nostra classe:
int privato MaxNameLength = 10; private StringBuilder playerName; backspacepossible bool privato; private bool initialpress;Il
MaxNameLength
dovrebbe essere impostato alla stessa lunghezza che hai usato per il tuoVARCHAR
lunghezza quando hai fatto il tuo tavolo. Qui abbiamo il nostro costruttore di corde,nome del giocatore
, e duebooleani
. Il primo,backspacepossible
, è quello di controllare la capacità dell'utente di tenere premuto backspace per cancellare i caratteri. Il secondo è indicare se hanno iniziato a digitare il loro nome ancora.Nel
Inizio()
, dobbiamo prenderci cura di alcune cose. Disattiveremo tutto il testo tranne quello chiamatoTesto in alto
; possiamo farlo in aper ciascuno
loop, come prima.void Start () foreach (testo GUIText in FindObjectsOfType (typeof (GUIText)) come GUIText []) if (text.name! = "Toptext") text.guiText.enabled = false; GetComponent() .enabled = false; playerNameTemp = new StringBuilder (); playerNameTemp.Append ( "_"); backspacepossible = true; initialpress = false; Qui puoi vedere che abbiamo fatto alcune cose. Abbiamo disattivato la nostra classe iniziale (
ClickTimes
) poiché non lo usiamo più. Abbiamo anche creato un'istanza diplayerNameTemp
e lo ha aggiunto con_
, così i giocatori possono vedere dove va il loro nome e abbiamo inizializzato le nostre variabili.Ora dobbiamo consentire al giocatore di inserire effettivamente il loro nome. Alla fine di
Aggiornare()
inseriamo il seguente frammento:guiText.text = playerNameTemp.ToString ()Ciò assicurerà che il testo mostri ciò che il nostro generatore di stringhe registra.
Successivamente gestiamo l'input dei caratteri:
if (playerNameTemp.Length < MaxNameLength) foreach (char c in Input.inputString) if (char.IsLetterOrDigit(c) || c == '_' || c ==") if (!initialpress) initialpress = true; playerNameTemp.Remove(0, 1); playerNameTemp.Append(c);Quindi, a condizione che la lunghezza del costruttore di stringhe sia inferiore alla lunghezza massima del nome e fintanto che l'utente inserisce caratteri che sono lettere, cifre, spazi o caratteri di sottolineatura (sebbene si possa scegliere solo di consentire caratteri alfanumerici), la stringa sarà aggiunto alla nuova cifra. Nel caso in cui questa sia la prima pressione, il carattere di sottolineatura originale verrà rimosso prima che venga aggiunta la nuova lettera.
Il prossimo:
if (playerNameTemp.Length> 0) if (Input.GetKeyDown (KeyCode.Backspace)) if (! initialpress) initialpress = true; backspacepossible = false; StartCoroutine (BackspaceInitialHold ()); playerNameTemp.Remove (playerNameTemp.Length - 1, 1); else if (backspacepossible && Input.GetKey (KeyCode.Backspace)) backspacepossible = false; StartCoroutine (BackspaceConstantHold ()); playerNameTemp.Remove (playerNameTemp.Length - 1, 1);Finché non ci sono caratteri rimanenti nel nostro generatore di stringhe e il backspace è possibile, l'utente può rimuovere i caratteri. Notare la differenza tra la prima e la seconda affermazione. Il primo utilizza
GetKeyDown ()
, mentre quest'ultimo usaGetKey ()
(e controlla il nostro bool). La distinzione è che dovremmo cancellare un carattere ogni volta che l'utente preme backspace, ma non costantemente mentre l'utente lo tiene premuto.Le coroutine
BackspaceInitialHold ()
e()
semplicemente aspetta0.15
e0.05
secondi, rispettivamente, e quindi impostarebackspacepossible
avero
. Quindi, dopo che il nostro utente ha trattenuto il backspace per0.15
secondi, a patto che siano ancora in possesso di backspace, un personaggio verrà cancellato ogni0.05
secondi (a condizione che illunghezza
è maggiore di codice> 0).Inoltre, stabiliamo che se questo è il primo pulsante che l'utente preme,
initialpress
viene attivato (quindi non tenterà di rimuovere un personaggio dopo aver premuto qualcos'altro).Per completare il tutto, dobbiamo consentire all'utente di premere Ritorno per finire il nome inserito.
if (playerNameTemp.Length> 0 && initialpress) if (Input.GetKeyDown (KeyCode.Return)) foreach (testo GUIText in FindObjectsOfType (typeof (GUIText)) come GUIText []) text.guiText.enabled = false; GetComponent() .SetName (guiText.text); GetComponent () .enabled = true; abilitato = falso; Finché l'utente ha realizzato una sorta di input e il
lunghezza
è più grande di0
, il nome sarà accettato Tutti i nostri oggetti di testo vengono cancellati, disabilitiamo questa classe e attiviamo la nostra terza classe,Punteggio alto
. Tutte e tre le nostre classi devono essere inserite nel nostro oggetto nell'editor.Abbiamo appena chiamato
Punteggio alto
'SImposta nome()
funzione, e prima abbiamo chiamatoSetScore ()
. Ognuna di queste funzioni imposta semplicemente i valori delle variabili private che invieremo ora alla nostra classifica.
Accedere alla tua classifica in Unity
In cima a
Punteggio alto
vogliamo dichiarare alcune variabili. Primo:pubblico GameObject BaseGUIText;Questo è il
GUIText
prefabbricato su cui baseremo la nostra classifica. Dovresti assicurarti che il testo sia ancorato al centro-sinistra e allineato a sinistra. Puoi anche scegliere un font anche qui.private string privateKey = "LA CHIAVE CHE HAI GENERATO PRIMA"; stringa privata AddScoreURL = "http://yoursite.com/AddScore.php?"; private string TopScoresURL = "http://yoursite.com/TopScores.php"; stringa privata RankURL = "http://yoursite.com/GrabRank.php?"; highscore privato int; nome utente stringa privata; rank int privato;Abbiamo bisogno di tutti i nostri valori di prima - la chiave che hai generato, gli URL in cui hai caricato i tuoi file PHP e così via. Il
punteggio alto
enome utente
le variabili sono impostate utilizzando due funzioni pubbliche chiamateSetScore ()
eImposta nome()
, che abbiamo usato nella sezione precedente.Mancia: È molto importante che metti dei punti interrogativi dopo
AddScore.php
eGrabRank.php
! Questi ti permettono di passare variabili ai tuoi file PHP.Dobbiamo usare
IEnumerators
qui per gestire le nostre query SQL, perché dobbiamo aspettare una risposta. Inizieremo la nostra prima coroutine,AddScore ()
, non appena la classe è abilitata.IEnumerator AddScore (nome stringa, punteggio int) string hash = Md5Sum (nome + punteggio + privateKey); WWW ScorePost = new WWW (AddScoreURL + "name =" + WWW.EscapeURL (nome) + "& score =" + score + "& hash =" + hash); yield return ScorePost; if (ScorePost.error == null) StartCoroutine (GrabRank (name)); else Error ();Innanzitutto, creiamo il nostro hash con la chiave privata, utilizzando una funzione per creare un hash MD5 allo stesso modo di PHP
md5 ()
. C'è un esempio di questo sul wiki della comunità di Unity.Qui, se il server è inaccessibile per qualsiasi motivo, eseguiamo un
Errore()
funzione. Puoi scegliere cosa vuoi che si verifichi nel gestore degli errori. Se il punteggio viene pubblicato correttamente, tuttavia, lanceremo la nostra prossima coroutine:GrabRank ()
.IEnumerator GrabRank (nome stringa) WWW RankGrabAttempt = new WWW (RankURL + "name =" + WWW.EscapeURL (nome)); yield return RankGrabAttempt; if (RankGrabAttempt.error == null) rank = System.Int32.Parse (RankGrabAttempt.text); StartCoroutine (GetTopScores ()); else Error ();Di nuovo, accediamo al sito e questa volta memorizziamo il grado se è stato preso con successo.
Ora possiamo usare la nostra ultima coroutine. Questo legherà tutto. Iniziamo accedendo all'URL per l'ultima volta:
IEnumerator GetTopScores () WWW GetScoresAttempt = new WWW (TopScoresURL); rendimento restituito GetScoresAttempt; if (GetScoresAttempt.error! = null) Error (); altroMa questa volta vogliamo dividere i dati che riceviamo in una serie di stringhe. Prima di tutto possiamo usare una suddivisione delle stringhe in questo modo:
string [] textlist = GetScoresAttempt.text.Split (nuova stringa [] "\ n", "\ t", System.StringSplitOptions.RemoveEmptyEntries);Ciò assicurerà che ogni risultato sarà un nuovo elemento nel nostro array di stringhe, purché venga trovata una nuova riga o una scheda (che sarà!). Ora divideremo questo in due ulteriori array chiamati
nomi
eI punteggi
.string [] Names = new string [Mathf.FloorToInt (textlist.Length / 2)]; string [] Punteggi = nuova stringa [Names.Length]; per (int i = 0; i < textlist.Length; i++) if (i % 2 == 0) Names[Mathf.FloorToInt(i / 2)] = textlist[i]; else Scores[Mathf.FloorToInt(i / 2)] = textlist[i];Ora abbiamo creato due nuovi array, ognuno della metà della dimensione del primo array. Quindi dividiamo ogni prima stringa nella nostra
nomi
array e ogni secondo nel nostroI punteggi
schieramento.Ora vogliamo mostrarli come testo, quindi dobbiamo posizionare le nostre tre colonne. Li scaleremo sullo schermo, quindi si adattano a qualsiasi risoluzione. Per prima cosa dichiareremo le posizioni iniziali in cui andrà il nostro testo del titolo:
Vector2 LeftTextPosition = new Vector2 (0.22f, 0.85f); Vector2 RightTextPosition = new Vector2 (0,76f, 0.85f); Vector2 CentreTextPosition = new Vector2 (0.33f, 0.85f);E ora siamo pronti per creare i nostri oggetti di testo, in base al nostro
BaseGUIText
prefabbricato. Istanziamo singolarmente i titoli e impostiamo il loro testo, ad esempio:GameObject Scoresheader = Instantiate (BaseGUIText, nuovo Vector2 (0.5f, 0.94f), Quaternion.identity) come GameObject; Scoresheader.guiText.text = "Punteggi più alti"; Scoresheader.guiText.anchor = TextAnchor.MiddleCenter; Scoresheader.guiText.fontSize = 35;Una volta fatto questo per tutti i nostri titoli, regoliamo le nostre posizioni in modo che il nuovo testo venga visualizzato più in basso.
LeftTextPosition - = new Vector2 (0, 0.062f); RightTextPosition - = new Vector2 (0, 0.062f); CentreTextPosition - = new Vector2 (0, 0.062f);Quindi eseguiamo a
per
loop che scorrerà tutta la nostra top 10, impostando il nome, il rank e il punteggio (e assicurandosi che il testo sia ancorato sensibilmente), e quindi regolando nuovamente le posizioni. Ogni iterazione, controlliamo se il rango dell'utente è uguale al rango visualizzato e, in tal caso, ricolora il testo in modo che il punteggio dell'utente sia evidenziato in giallo:per (int i = 0; iE poi, finalmente, controlliamo se il punteggio dell'utente è superiore a 10. Se lo è, pubblichiamo il loro punteggio in fondo all'undicesima casella, insieme al loro rango, e lo colorano di giallo.
if (rank> 10) GameObject Score = Instantiate (BaseGUIText, RightTextPosition, Quaternion.identity) come GameObject; Score.guiText.text = "" + punteggio migliore; Score.guiText.anchor = TextAnchor.MiddleCenter; GameObject Name = Instantiate (BaseGUIText, CentreTextPosition, Quaternion.identity) come GameObject; Name.guiText.text = username; GameObject Rank = Instantiate (BaseGUIText, LeftTextPosition, Quaternion.identity) come GameObject; Rank.guiText.text = "" + (rank); Rank.guiText.anchor = TextAnchor.MiddleCenter; Score.guiText.material.color = Color.yellow; Name.guiText.material.color = Color.yellow; Rank.guiText.material.color = Color.yellow;
Conclusione
Ecco; la nostra classifica è completa! Nei file sorgente ho anche incluso un file PHP che catturerà i ranghi sopra e sotto il nome utente dell'utente, in modo che tu possa mostrare esattamente dove si trovano sulla scheda.