Dans cet article, nous allons créer notre premier classement MySQL à héberger sur un site Web ou un serveur Web à l'aide de PHP simple et de SQL. Nous allons ensuite faire un exemple simple d'Unity en C # en utilisant GUIText
objets pour ajouter de nouveaux scores à notre classement, afficher les dix meilleurs scores et afficher le score et le classement d'un utilisateur.
Les jeux en solo sont amusants, mais battre son propre meilleur score peut devenir ennuyeux. L'ajout d'un classement à votre jeu donne aux joueurs une réelle motivation pour améliorer leurs scores et jouer davantage à votre jeu. Il peut même être utilisé pour déterminer si votre jeu est trop facile ou difficile. Dans les jeux qui durent éternellement, les classements peuvent être la seule raison pour laquelle vos joueurs jouent. Si vous avez votre propre site Web ou serveur, vous pouvez héberger votre propre classement afin de contrôler totalement votre jeu..
Tout d'abord, vous aurez besoin d'une base de données SQL sur votre serveur ou votre site. Les sites Web sont souvent fournis avec une base de données MySQL intégrée. Les détails varient en fonction du service que vous utilisez, mais vous devriez pouvoir trouver votre hôte SQL, votre nom d'utilisateur et votre mot de passe (ainsi que le nom de votre base de données) à partir de votre panneau d'administration ou de votre courrier électronique d'enregistrement..
Dans cet exemple, phpMyAdmin est utilisé pour accéder à la base de données (intégrée dans le panneau d'administration). Vous voudrez ouvrir votre base de données et ouvrir l'onglet SQL. Si vous avez plus de contrôle sur votre serveur, vous pouvez créer une nouvelle base de données..
Ensuite, insérez le code SQL suivant:
CREATE TABLE Scores (nom VARCHAR (10) NON NULL PAR DÉFAUT 'anonyme' PRIMARY KEY, score INT (5) NON SIGNÉ NON NULL PAR DÉFAUT '0', ts TIMESTAMP NON NULL PAR DÉFAUT CURRENT_TIMESTAMP) ENGINE = InnoDB;
Cela va créer une table avec trois variables:
prénom
, qui contient les noms de vos utilisateurs et qui stockera 10 caractères. Ceci est l'identifiant principal de notre table, ce qui signifie qu'il ne peut stocker qu'une seule ligne par nom d'utilisateur..But
, qui détient le score le plus élevé de chaque utilisateur. Dans cet exemple, il s’agit d’une variable non signée, elle ne peut donc être que positive. Si vous voulez avoir des scores négatifs, vous devrez changer cela.ts
, un horodatage que nous pouvons utiliser pour changer l'ordre de notre classement.Maintenant, si vous utilisez SQL Server et non MySQL, vous pouvez toujours utiliser TIMESTAMP
, mais pour la valeur que vous devrez utiliser AVOIR UN RENDEZ-VOUS()
au lieu de CURRENT_TIMESTAMP
.
Une chose supplémentaire à garder à l’esprit: si vous créez un jeu très simple, vous pouvez ne pas vouloir lier les scores aux noms (afin de permettre à chaque joueur d’avoir plusieurs scores dans votre Top 10, par exemple). Cela peut être une mauvaise idée cependant; Vous pouvez avoir un joueur qui est si bon qu'il peut dominer tout votre Top 10! Dans ce cas vous ne voudrez pas prénom
en tant que clé primaire, et vous voudrez également ajouter ceci:
id INT (8) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY
Cela garantira qu'une nouvelle ligne visible est ajoutée pour chaque partition..
Cliquez sur Aller et tu as fini! Votre table est prête maintenant.
Maintenant, vous devez créer des fichiers PHP. Ce sont les intermédiaires de l'opération, fournissant à Unity un moyen d'accéder à votre serveur. Le premier fichier PHP dont vous aurez besoin est AddScore.php
. Vous aurez besoin de connaître les informations du serveur avant.
(Remplacer
SQLHOST
,SQLuser
,SQLPASSWORD
etVOTRE BASE DE DONNEES
avec vos propres informations.)Ici, nous venons d'essayer de vous connecter à la base de données. Si la connexion échoue, Unity sera informé que la demande a échoué. Maintenant, vous allez vouloir passer des informations au serveur:
$ username = mysql_real_escape_string ($ _GET ['nom'], $ db); $ score = mysql_real_escape_string ($ _GET ['score'], $ db); $ hash = $ _GET ['hash']; $ privateKey = "ADDYOURKEY";Le hachage sert à chiffrer vos données et à empêcher les gens de pirater votre classement. Il est généré avec une clé cachée dans Unity et ici, et si les deux hachages correspondent, vous êtes autorisé à accéder à votre base de données..
$ attendu_hash = md5 ($ username. $ score. $ privateKey); if ($ attendu_hash == $ hash)Ici, nous générons nous-mêmes le hachage et vérifions que le hachage que nous soumettons de Unity est identique à celui que nous attendons. Si c'est le cas, nous pouvons envoyer notre requête!
$ query = "INSERT INTO Scores SET nom = '$ nom', score = '$ score', ts = CURRENT_TIMESTAMPCeci est la première moitié de notre requête SQL. Cela devrait être assez explicite; le score et le nom d'utilisateur soumis sont ajoutés à la table et l'horodatage est mis à jour. La seconde moitié est plus compliquée:
ON DUPLICATE KEY UPDATE ts = if ('$ score'> score, CURRENT_TIMESTAMP, ts), score = if ('$ score'> score, '$ score', score); ";Nous vérifions d’abord si le nom d’utilisateur (notre clé primaire) a déjà une ligne. Si c'est le cas, au lieu d'insérer une nouvelle entrée, notre entrée sera mise à jour. Nous voulons mettre à jour l'horodatage et le score, mais uniquement si le nouveau score est plus élevé!
En utilisant
si
instructions, nous nous assurons que les nouvelles valeurs ne sont utilisées que si le nouveau score est supérieur au score actuel, sinon les valeurs d'origine sont utilisées.$ result = mysql_query ($ query) ou die ('Échec de la requête:'. mysql_error ()); ?>Enfin, nous lançons notre requête et fermons notre PHP.
Ce fichier va sur notre serveur. Vous devrez vous rappeler l'URL. De même, nous devons créer deux autres fichiers PHP avec des requêtes différentes, que nous appellerons
TopScores.php
etGetRank.php
.le
Meilleurs scores
la requête est simplement:SELECT * FROM Scores ORDER by score DESC, ts ASC LIMIT 10Cela prendra les 10 premières valeurs en fonction du score, et pour les rangs à égalité, les joueurs qui ont obtenu le score le plus loin dans le classement. Cette fois, nous voulons aussi extraire des données, alors nous ajoutons aussi:
$ result_length = mysql_num_rows ($ result); pour ($ i = 0; $ i < $result_length; $i++) $row = mysql_fetch_array($result); echo $row['name'] . "\t" . $row['score'] . "\n";Cela va extraire nos résultats et les tabuler de manière à pouvoir les mettre dans des tableaux dans Unity.
Enfin, nous avons
GrabRank
:SELECTIONNER uo. *, (SELECT COUNT (*) FROM Scores ui WHERE (ui.score, -ui.ts)> = (uo.score, -uo.ts)) EN TANT QUE classement à partir des scores uo WHERE name = '$ name' ;Cela nous donnera le classement de notre joueur dans le tableau de bord. On peut ensuite l'extraire en faisant écho
$ row ['rang']
.Notre code source comprend également une fonction de désinfection, qui empêche les utilisateurs de saisir des gros mots dans votre classement ou de tenter une attaque par injection SQL..
Faire un mini-jeu simple dans Unity
Nous avons maintenant besoin d’un jeu pour utiliser notre tableau des meilleurs scores! Nous allons juste tester le nombre de clics que chaque utilisateur peut faire en dix secondes, mais vous pouvez ajouter votre classement à n'importe quel jeu..
Disposition
Nous allons commencer par faire quatre
GUIText
objets. Ceux-ci devraient être ancrés au centre-centre pour plus de commodité. Vous pouvez les ajuster avec un décalage de pixel pour les placer au bon endroit, mais si vous souhaitez qu’ils ajustent leur position pour n’importe quelle résolution, il est plus simple de modifier laX
etY
position (entre0
et1
) sinon, vous devrez les ajuster au démarrage.Cependant, vous devrez ajuster la taille de la police au démarrage si vous souhaitez exécuter toutes les résolutions. Un moyen rapide de le faire est de les baser sur la hauteur de l'écran. Nous pouvons le faire en créant une classe qui le fait et en l'attachant à tous nos objets texte, mais il est beaucoup plus simple de faire tout cela à partir d'une classe..
Peu importe l’objet que nous avons choisi comme "gestionnaire", nous pouvons simplement mettre cette classe sur notre compteur de clics. Donc, dans notre premier cours, nous écrivons:
void Start () foreach (GUIText chosentext dans FindObjectsOfType (typeof (GUIText)) en tant que GUIText []) chosentext.blah.fontSize = Mathf.FloorToInt (Screen.height * 0.08f);Ceci trouvera chaque objet texte dans la scène et le redimensionnera à une taille raisonnable.
Maintenant, nous voulons que le compteur de clics soit plus grand que l’autre texte, donc si nous y collons cette classe, nous avons le bonus supplémentaire que nous pouvons aussi vérifier si le
guiText
en question est celui attaché à cetteGameObject
:if (blah == guiText) blah.fontSize = Mathf.FloorToInt (Screen.height * 0.18f); sinon [etc.]Gameplay
Le composant en cliquant du jeu sera très simple. Au début, nous ne voulons pas que le chronomètre compte à rebours avant le premier clic. Nous allons donc créer deux
bools
dans notre classe -premier clic
etallowedToClick
. DansDébut()
nous pouvons définirpremier clic
àfaux
etallowedToClick
àvrai
.Nous avons maintenant besoin du compteur pour enregistrer les clics, et il existe deux façons de procéder. Nous pourrions garder une variable entière qui suit le score, ou la rendre légèrement moins efficace mais sur une seule ligne (et avec quelque chose d'aussi simple, nous n'avons pas vraiment besoin d'optimiser, mais c'est une bonne pratique). Nous allons donc enregistrer le clic dans le
Mettre à jour()
fonction et incrémente la valeur en lisant la chaîne.void Update () if (allowedToClick && Input.GetMouseButtonUp (0)) if (! firstClick) firstClick = true; StartCoroutine (Compte à rebours ()); guiText.text = (System.Int32.Parse (guiText.text) + 1) .ToString ();Comme vous pouvez le voir ici, l'incrémentation est obtenue en lisant la chaîne sous forme d'entier, en en ajoutant un, puis en la reconvertissant en chaîne. Vous verrez également ici que nous avons exécuté une coroutine dès le premier clic de l'utilisateur, ce qui démarre le compte à rebours..
Nous allons utiliser la récursion dans cette fonction. Encore une fois, nous pourrions utiliser un entier contenant la valeur du compte à rebours pour plus d'efficacité, mais nous utiliserons à nouveau la manipulation de chaîne..
IEnumerator Countdown () return 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 = "Entrez votre nom d'utilisateur."; GetComponent () .enabled = true; Note: il est important que nous utilisions
StartCoroutine ()
et n'a pas simplement appelé cette fonction, parce que c'est unIEnumerator
. lerendement
Cette instruction l’attend une seconde avant que toute action soit entreprise. Il en supprime un du compteur et si la valeur n'est pas égale à zéro, il appelle à nouveau. De cette façon, la fonction comptera jusqu'à ce qu'elle atteigne0
.Nom d'entrée
Après cela, il empêche l'utilisateur de cliquer, demande le nom d'utilisateur et accède à nos deuxième et troisième classes (que nous sommes sur le point d'écrire!). Nous verrons ce que cela fait maintenant, en commençant par
NameEnter
.Dans
NameEnter ()
nous allons permettre à un utilisateur de taper son nom d'utilisateur, avec quelques contraintes. Initialement, nous voulons afficher le caractère de soulignement_
, qui sera effacé dès qu’ils commenceront à taper leur nom. De plus, nous ne voulons pas qu’ils puissent utiliser des caractères tels que\
ou'
, comme ceux-ci gâcher nos requêtes SQL.Nous allons utiliser un constructeur de chaînes pour créer cela. Nous allons d’abord placer quelques variables en haut de notre classe:
private int MaxNameLength = 10; private StringBuilder playerName; backbool privé possible; privé bool initialpress;le
MaxNameLength
doit être réglé sur la même longueur que celle utilisée pour votreVARCHAR
longueur quand vous avez fait votre table. Ici nous avons notre constructeur de cordes,nom de joueur
, et deuxBooléens
. La première,backspacepossible
, est de contrôler la capacité de l'utilisateur à maintenir la touche arrière enfoncée pour effacer des caractères. La seconde est d’indiquer s’ils ont déjà commencé à taper leur nom.Dans
Début()
, nous devons nous occuper de quelques choses. Nous allons désactiver tout le texte sauf celui appeléTexte du Haut
; on peut faire ça dans unpour chaque
boucle, comme avant.void Start () foreach (texte GUIText dans FindObjectsOfType (typeof (GUIText)) sous la forme GUIText []) if (text.name! = "Toptext") text.guiText.enabled = false; GetComponent() .enabled = false; playerNameTemp = new StringBuilder (); playerNameTemp.Append ("_"); backspacepossible = true; initialpress = false; Ici vous pouvez voir que nous avons fait quelques choses. Nous avons désactivé notre classe initiale (
ClickTimes
) car nous ne l'utilisons plus. Nous avons également créé une instance deplayerNameTemp
et l'a ajouté avec_
, afin que les joueurs puissent voir où leur nom va, et nous avons initialisé nos variables.Nous devons maintenant permettre au joueur d’entrer son nom. Au bout du
Mettre à jour()
nous plaçons l'extrait suivant:guiText.text = playerNameTemp.ToString ()Cela garantira que le texte affiche ce que notre constructeur de chaînes enregistre.
Ensuite, nous traitons la saisie de caractères:
si (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);Ainsi, à condition que la longueur du constructeur de chaînes soit inférieure à la longueur maximale du nom et que l'utilisateur saisisse des caractères (lettres, chiffres, espaces ou traits de soulignement) (vous pouvez toutefois choisir d'autoriser uniquement les caractères alphanumériques). ajouté avec le nouveau chiffre. S'il s'agit de la première pression, le trait de soulignement d'origine sera supprimé avant l'ajout de la nouvelle lettre..
Suivant:
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);Tant qu'il ne reste plus de caractères dans notre générateur de chaînes et qu'un retour arrière est possible, l'utilisateur peut supprimer des caractères. Notez la différence entre les première et deuxième déclarations. Le premier utilise
GetKeyDown ()
, tandis que ce dernier utiliseObtenir la clé()
(et vérifie notre bool). La distinction est que nous devrions effacer un caractère chaque fois que l'utilisateur appuie sur la touche de retour arrière, mais pas de façon constante pendant que l'utilisateur le maintient enfoncé.Les coroutines
BackspaceInitialHold ()
et()
attendez simplement0,15
et0,05
secondes, respectivement, puis définirbackspacepossible
àvrai
. Donc, après que notre utilisateur a maintenu backspace pour0,15
secondes, tant qu’ils tiennent toujours en arrière, un personnage sera effacé tous les0,05
secondes (tant que lelongueur
est supérieur à code> 0).De plus, nous stipulons que s’il s’agit du premier bouton, l’utilisateur appuie sur,
presse initiale
est déclenché (donc il ne tentera pas de supprimer un caractère une fois qu'ils appuieront sur autre chose).Pour couronner le tout, nous devons permettre à l'utilisateur d'appuyer sur Revenir pour terminer la saisie du nom.
if (playerNameTemp.Length> 0 && initialpress) if (Input.GetKeyDown (KeyCode.Return)) foreach (texte GUIText dans FindObjectsOfType (typeof (GUIText))) en tant que GUIText []) text.guiText.enabled = false; GetComponent() .SetName (guiText.text); GetComponent () .enabled = true; enabled = false; Tant que l'utilisateur a fait quelque chose et que le
longueur
est supérieur à0
, le nom sera accepté. Tous nos objets texte sont supprimés, nous désactivons cette classe et nous allumons notre troisième classe,Score élevé
. Tous les trois de nos classes doivent être mis sur notre objet dans l'éditeur.Nous venons d'appeler
Score élevé
deSetName ()
fonction, et plus tôt nous avons appeléSetScore ()
. Chacune de ces fonctions définit simplement les valeurs des variables privées que nous soumettons maintenant à notre classement.
Accéder à votre classement dans Unity
Au sommet de
Score élevé
nous voulons déclarer des variables. Premier:public GameObject BaseGUIText;C'est le
GUIText
préfabriqué sur lequel nous baserons notre classement. Assurez-vous que le texte est ancré au centre-gauche et aligné à gauche. Vous pouvez également choisir une police ici aussi.private string privateKey = "LA CLÉ QUE VOUS AVEZ GÉNÉRÉE AVANT"; chaîne privée AddScoreURL = "http://votresite.com/AddScore.php?"; chaîne privée TopScoresURL = "http://votresite.com/TopScores.php"; chaîne privée RankURL = "http://votresite.com/GrabRank.php?"; private int highscore; chaîne privée nom d'utilisateur; privé int rang;Nous avons besoin de toutes nos valeurs antérieures - la clé que vous avez générée, les URL vers lesquelles vous avez importé vos fichiers PHP, etc. le
score élevé
etNom d'utilisateur
les variables sont définies à l'aide de deux fonctions publiques appeléesSetScore ()
etSetName ()
, que nous avons utilisé dans la section précédente.Pointe: C'est vraiment important de mettre des points d'interrogation après
AddScore.php
etGrabRank.php
! Ceux-ci vous permettent de passer des variables à vos fichiers PHP.Nous devons utiliser
IEnumerators
ici pour gérer nos requêtes SQL, car nous devons attendre une réponse. Nous allons commencer notre première coroutine,AddScore ()
, dès que la classe est activée.IEnumerator AddScore (nom de chaîne, score int) string hash = Md5Sum (nom + score + clé privée); WWW ScorePost = new WWW (AddScoreURL + "name =" + WWW.EscapeURL (name) + "& score =" + score + "& hash =" + hash); rendement retour ScorePost; if (ScorePost.error == null) StartCoroutine (GrabRank (nom)); else Erreur ();Tout d'abord, nous créons notre hachage avec la clé privée, en utilisant une fonction pour créer un hachage MD5 de la même manière que PHP
md5 ()
. Il y a un exemple de cela sur le wiki de la communauté d'Unity.Ici, si le serveur est inaccessible pour une raison quelconque, nous exécutons un
Erreur()
une fonction. Vous pouvez choisir ce que vous voulez voir dans votre gestionnaire d'erreurs. Si le score est correctement affiché, nous lancerons notre prochaine coroutine:GrabRank ()
.IEnumerator GrabRank (nom de chaîne) WWW RankGrabAttempt = new WWW (RankURL + "name =" + WWW.EscapeURL (name)); return return RankGrabAttempt; if (RankGrabAttempt.error == null) rank = System.Int32.Parse (RankGrabAttempt.text); StartCoroutine (GetTopScores ()); else Erreur ();Encore une fois, nous accédons au site, et cette fois nous stockons le classement s'il est pris avec succès.
Nous pouvons maintenant utiliser notre dernière coroutine. Celui-ci va tout ligoter. Nous commençons par accéder à l'URL pour une dernière fois:
IEnumerator GetTopScores () WWW GetScoresAttempt = new WWW (TopScoresURL); return return GetScoresAttempt; if (GetScoresAttempt.error! = null) Erreur (); autreMais cette fois, nous voulons diviser les données que nous recevons en un tableau de chaînes. Tout d'abord, nous pouvons utiliser une chaîne scindée comme ceci:
string [] textlist = GetScoresAttempt.text.Split (nouvelle chaîne [] "\ n", "\ t", System.StringSplitOptions.RemoveEmptyEntries);Cela garantira que chaque résultat sera un nouvel élément dans notre tableau de chaînes, tant qu'une nouvelle ligne ou un nouvel onglet est trouvé (ce qui sera le cas!). Nous allons maintenant diviser cela en deux autres tableaux appelés
Des noms
etScores
.chaîne [] Noms = nouvelle chaîne [Mathf.FloorToInt (textlist.Length / 2)]; string [] Scores = new string [Names.Length]; pour (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];Nous avons maintenant créé deux nouveaux tableaux qui ont chacun la moitié de la taille du premier tableau. Nous avons ensuite divisé chaque première chaîne dans notre
Des noms
tableau et chaque seconde dans notreScores
tableau.Nous voulons maintenant les afficher sous forme de texte. Nous devons donc positionner nos trois colonnes. Nous allons les redimensionner à l’écran, afin qu’elles correspondent à toutes les résolutions. Commençons par déclarer les positions initiales où notre texte de titre ira:
Vector2 LeftTextPosition = new Vector2 (0.22f, 0.85f); Vector2 RightTextPosition = new Vector2 (0.76f, 0.85f); Vector2 CentreTextPosition = new Vector2 (0.33f, 0.85f);Et maintenant, nous sommes prêts à créer nos objets texte à partir de notre
BaseGUIText
préfabriqué Nous instancions les titres individuellement et définissons leur texte - par exemple:GameObject Scoresheader = Instanciez (BaseGUIText, nouveau Vector2 (0.5f, 0.94f), Quaternion.identity) en tant que GameObject; Scoresheader.guiText.text = "Meilleurs scores"; Scoresheader.guiText.anchor = TextAnchor.MiddleCenter; Scoresheader.guiText.fontSize = 35;Une fois que cela est fait pour tous nos titres, nous ajustons nos positions pour que le nouveau texte soit affiché plus bas..
LeftTextPosition - = new Vector2 (0, 0.062f); RightTextPosition - = new Vector2 (0, 0.062f); CentreTextPosition - = new Vector2 (0, 0.062f);Ensuite, nous courons un
pour
une boucle qui parcourra toute notre liste des 10 meilleurs, en définissant le nom, le rang et le score (et en s'assurant que le texte est bien ancré), puis en ajustant à nouveau les positions. A chaque itération, nous vérifions si le rang de l'utilisateur est égal au rang affiché et si c'est le cas, nous recolorisons le texte afin que le score de l'utilisateur soit surligné en jaune:pour (int i = 0; iEt puis, finalement, nous vérifions si le classement de l'utilisateur est supérieur à 10. Si c'est le cas, nous affichons son score au bas de la onzième position, ainsi que son classement, et le colorions en jaune..
if (rang> 10) Score GameObject = Instanciation (BaseGUIText, RightTextPosition, Quaternion.identity) en tant que GameObject; Score.guiText.text = "" + meilleur score; Score.guiText.anchor = TextAnchor.MiddleCenter; Nom de l'objet de jeu = Instanciez (BaseGUIText, CentreTextPosition, Quaternion.identity) en tant que GameObject; Name.guiText.text = nom d'utilisateur; Classement GameObject = Instanciation (BaseGUIText, LeftTextPosition, Quaternion.identity) en tant que GameObject; Rank.guiText.text = "" + (rang); Rank.guiText.anchor = TextAnchor.MiddleCenter; Score.guiText.material.color = Color.yellow; Name.guiText.material.color = Color.yellow; Rank.guiText.material.color = Color.yellow;
Conclusion
Voilà; notre classement est complet! Dans les fichiers sources, j'ai également inclus un fichier PHP qui saisira les rangs situés au-dessus et au-dessous du nom d'utilisateur de l'utilisateur, afin que vous puissiez leur montrer exactement où ils se trouvent sur le tableau..