Unity Online-Ranglisten-Tutorial
In diesem Tutorial zeige ich, wie Sie in Unity eine Online-Bestenliste in Ihr Spiel implementieren.
Dies ist eine Fortsetzung eines früheren Tutorials: Unity Anmeldesystem mit PHP und MySQL.
Eine Bestenliste ist eine großartige Möglichkeit, den Wiederspielwert zu erhöhen, indem Sie Ihrem Spiel ein gewisses Maß an Wettbewerbsfähigkeit verleihen.
Wie zuvor erfordert dieses Tutorial einen Server mit cPanel sowie PHP und MySQLi (eine verbesserte Version von MySQL).
Schauen Sie sich gerne das erschwingliche Premium-Hosting VPS oder eine günstigere Alternative Shared Hosting an.
Also lasst uns weitermachen!
Nehmen Sie eine Änderung am vorhandenen Skript vor
Wenn Sie dem obigen Tutorial gefolgt wären, hätten Sie jetzt ein Skript namens 'SC_LoginSystem'. Wir werden die Bestenlistenfunktion implementieren, indem wir Code hinzufügen.
- Öffnen Sie das 'SC_LoginSystem'-Skript
Zunächst beginnen wir mit dem Hinzufügen der erforderlichen Variablen:
//Leaderboard
Vector2 leaderboardScroll = Vector2.zero;
bool showLeaderboard = false;
int currentScore = 0; //It's recommended to obfuscate this value to protect against hacking (search 'obfuscation' on sharpcoderblog.com to learn how to do it)
int previousScore = 0;
float submitTimer; //Delay score submission for optimization purposes
bool submittingScore = false;
int highestScore = 0;
int playerRank = -1;
[System.Serializable]
public class LeaderboardUser
{
public string username;
public int score;
}
LeaderboardUser[] leaderboardUsers;
HINWEIS: Die Variable currentScore ist die Variable, die Sie im Spiel verwenden werden, um die Punktestände der Spieler zu verfolgen. Dieser Wert wird an den Server übermittelt und in der Datenbank gespeichert. Es wird empfohlen, diesen Wert zum Schutz vor Hackerangriffen zu verschleiern.
Als Nächstes fügen wir zwei Enumeratoren hinzu, die für die Übermittlung der Ergebnisse und den Abruf der Bestenliste verantwortlich sind. Fügen Sie am Ende des Skripts vor dem Schließen der letzten Klammer den folgenden Code hinzu:
//Leaderboard
IEnumerator SubmitScore(int score_value)
{
submittingScore = true;
print("Submitting Score...");
WWWForm form = new WWWForm();
form.AddField("email", userEmail);
form.AddField("username", userName);
form.AddField("score", score_value);
using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "score_submit.php", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
print(www.error);
}
else
{
string responseText = www.downloadHandler.text;
if (responseText.StartsWith("Success"))
{
print("New Score Submitted!");
}
else
{
print(responseText);
}
}
}
submittingScore = false;
}
IEnumerator GetLeaderboard()
{
isWorking = true;
WWWForm form = new WWWForm();
form.AddField("email", userEmail);
form.AddField("username", userName);
using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "leaderboard.php", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
print(www.error);
}
else
{
string responseText = www.downloadHandler.text;
if (responseText.StartsWith("User"))
{
string[] dataChunks = responseText.Split('|');
//Retrieve our player score and rank
if (dataChunks[0].Contains(","))
{
string[] tmp = dataChunks[0].Split(',');
highestScore = int.Parse(tmp[1]);
playerRank = int.Parse(tmp[2]);
}
else
{
highestScore = 0;
playerRank = -1;
}
//Retrieve player leaderboard
leaderboardUsers = new LeaderboardUser[dataChunks.Length - 1];
for(int i = 1; i < dataChunks.Length; i++)
{
string[] tmp = dataChunks[i].Split(',');
LeaderboardUser user = new LeaderboardUser();
user.username = tmp[0];
user.score = int.Parse(tmp[1]);
leaderboardUsers[i - 1] = user;
}
}
else
{
print(responseText);
}
}
}
isWorking = false;
}
Als nächstes kommt die Bestenlisten-Benutzeroberfläche. Fügen Sie den folgenden Code nach dem void OnGUI() hinzu:
//Leaderboard
void LeaderboardWindow(int index)
{
if (isWorking)
{
GUILayout.Label("Loading...");
}
else
{
GUILayout.BeginHorizontal();
GUI.color = Color.green;
GUILayout.Label("Your Rank: " + (playerRank > 0 ? playerRank.ToString() : "Not ranked yet"));
GUILayout.Label("Highest Score: " + highestScore.ToString());
GUI.color = Color.white;
GUILayout.EndHorizontal();
leaderboardScroll = GUILayout.BeginScrollView(leaderboardScroll, false, true);
for (int i = 0; i < leaderboardUsers.Length; i++)
{
GUILayout.BeginHorizontal("box");
if(leaderboardUsers[i].username == userName)
{
GUI.color = Color.green;
}
GUILayout.Label((i + 1).ToString(), GUILayout.Width(30));
GUILayout.Label(leaderboardUsers[i].username, GUILayout.Width(230));
GUILayout.Label(leaderboardUsers[i].score.ToString());
GUI.color = Color.white;
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
}
}
Fügen Sie den folgenden Code in das leere OnGUI() ein (vor der schließenden Klammer):
//Leaderboard
if (showLeaderboard)
{
GUI.Window(1, new Rect(Screen.width / 2 - 300, Screen.height / 2 - 225, 600, 450), LeaderboardWindow, "Leaderboard");
}
if (!isLoggedIn)
{
showLeaderboard = false;
currentScore = 0;
}
else
{
GUI.Box(new Rect(Screen.width / 2 - 65, 5, 120, 25), currentScore.ToString());
if (GUI.Button(new Rect(5, 60, 100, 25), "Leaderboard"))
{
showLeaderboard = !showLeaderboard;
if (!isWorking)
{
StartCoroutine(GetLeaderboard());
}
}
}
Und schließlich void Update(), das einen Code enthält, der für die Übermittlung des Spielerstands verantwortlich ist, sobald dieser sich ändert. Fügen Sie den folgenden Code am Anfang des Skripts nach allen Variablen hinzu:
//Leaderboard
void Update()
{
if (isLoggedIn)
{
//Submit score if it was changed
if (currentScore != previousScore && !submittingScore)
{
if(submitTimer > 0)
{
submitTimer -= Time.deltaTime;
}
else
{
previousScore = currentScore;
StartCoroutine(SubmitScore(currentScore));
}
}
else
{
submitTimer = 3; //Wait 3 seconds when it's time to submit again
}
//**Testing** Increase score on key press
if (Input.GetKeyDown(KeyCode.Q))
{
currentScore += 5;
}
}
}
Beachten Sie den Teil **Testing**, da wir kein spielbares Spiel haben, erhöhen wir die Punktzahl einfach durch Drücken von Q (Sie können es später entfernen, wenn Sie bereits ein Spiel mit einem Punktesystem haben, z. B. sammle eine Münze +1 Punkt usw.)
Wenn Sie auf „Play“ drücken und sich anmelden, sollten Sie zwei neue Elemente bemerken: die Schaltfläche 'Leaderboard' und den Punktewert oben auf dem Bildschirm.
Jetzt gehen wir dazu über, eine MySQL-Tabelle zu erstellen.
Erstellen einer MySQL-Tabelle
Benutzerbewertungen werden in einer separaten MySQL-Tabelle gespeichert.
- Melden Sie sich bei CPanel an
- Klicken Sie im Abschnitt DATENBANKEN auf "phpMyAdmin"
- Klicken Sie auf die Datenbank, die Sie im vorherigen Tutorial erstellt haben, und klicken Sie dann auf die Registerkarte „SQL“.
- Fügen Sie den folgenden Code in den Abfrageeditor ein und klicken Sie dann auf "Go"
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
--
-- Table structure for table `sc_user_scores`
--
CREATE TABLE `sc_user_scores` (
`row_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`user_score` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Indexes for table `sc_user_scores`
--
ALTER TABLE `sc_user_scores`
ADD PRIMARY KEY (`row_id`),
ADD UNIQUE KEY `user_id` (`user_id`);
--
-- AUTO_INCREMENT for table `sc_user_scores`
--
ALTER TABLE `sc_user_scores`
MODIFY `row_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
COMMIT;
Die obige Abfrage erstellt eine neue Tabelle mit dem Namen 'sc_user_scores', in der die höchsten Punktzahlen zusammen mit der Benutzer-ID als Referenz auf die Haupttabelle 'sc_users' gespeichert werden.
Der letzte Teil ist die Implementierung der serverseitigen Logik.
Implementierung serverseitiger Logik
Die serverseitige Logik besteht aus PHP-Skripten, die für den Empfang/die Speicherung der Ergebnisse und den Abruf der Bestenliste verantwortlich sind.
Das erste Skript ist score_submit.php.
- Erstellen Sie ein neues PHP-Skript und fügen Sie den folgenden Code ein:
score_submit.php
<?php
if(isset($_POST["email"]) && isset($_POST["username"]) && isset($_POST["score"])){
$errors = array();
$email = $_POST["email"];
$username = $_POST["username"];
$submitted_score = intval($_POST["score"]);
$user_id = -1;
$current_highscore = -1;
//Connect to database
require dirname(__FILE__) . '/database.php';
//Check if the user already registered, retrieve its user_id and score value (if exist)
if ($stmt = $mysqli_conection->prepare("SELECT u.user_id,
(SELECT user_score FROM sc_user_scores WHERE user_id = u.user_id LIMIT 1) as user_score
FROM sc_users u WHERE u.email = ? AND u.username = ? LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ss', $email, $username);
/* execute query */
if($stmt->execute()){
/* store result */
$stmt->store_result();
if($stmt->num_rows > 0){
/* bind result variables */
$stmt->bind_result($user_id_tmp, $score_tmp);
/* fetch value */
$stmt->fetch();
$user_id = $user_id_tmp;
$current_highscore = $score_tmp;
}else{
$errors[] = "User not found.";
}
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
//Submit new score
if(count($errors) == 0){
if(is_null($current_highscore) || $submitted_score > $current_highscore){
if(is_null($current_highscore)){
//Insert new record
if ($stmt = $mysqli_conection->prepare("INSERT INTO sc_user_scores (user_id, user_score) VALUES(?, ?)")) {
/* bind parameters for markers */
$stmt->bind_param('ii', $user_id, $submitted_score);
/* execute query */
if($stmt->execute()){
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
//Update existing record
if ($stmt = $mysqli_conection->prepare("UPDATE sc_user_scores SET user_score = ? WHERE user_id = ? LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ii', $submitted_score, $user_id);
/* execute query */
if($stmt->execute()){
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
}
}else{
$errors[] = "Submitted score is lower than the current highscore, skipping...";
}
}
if(count($errors) > 0){
echo $errors[0];
}else{
echo "Success";
}
}else{
echo "Missing data";
}
?>
Das letzte Skript ist leaderboard.php.
- Erstellen Sie ein neues PHP-Skript und fügen Sie den folgenden Code ein:
Leaderboard.php
<?php
//Retrieve our score along with leaderboard
if(isset($_POST["email"]) && isset($_POST["username"])){
$returnData = array();
$email = $_POST["email"];
$username = $_POST["username"];
//Connect to database
require dirname(__FILE__) . '/database.php';
//Get our score and rank
$returnData[] = "User";
if ($stmt = $mysqli_conection->prepare("SELECT us.user_score,
(SELECT COUNT(row_id) FROM sc_user_scores WHERE user_score >= us.user_score LIMIT 1) as rank
FROM sc_user_scores us
WHERE us.user_id = (SELECT user_id FROM sc_users WHERE email = ? AND username = ? LIMIT 1) LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ss', $email, $username);
/* execute query */
if($stmt->execute()){
/* store result */
$stmt->store_result();
if($stmt->num_rows > 0){
/* bind result variables */
$stmt->bind_result($score_tmp, $user_rank);
/* fetch value */
$stmt->fetch();
//Append
$returnData[0] .= "," . $score_tmp . "," . $user_rank;
}
/* close statement */
$stmt->close();
}
}
//Get top 100 players
if ($stmt = $mysqli_conection->prepare("SELECT u.username, us.user_score
FROM sc_users u RIGHT JOIN sc_user_scores us ON u.user_id = us.user_id
WHERE u.user_id IS NOT NULL ORDER BY us.user_score DESC LIMIT 100")) {
/* execute query */
if($stmt->execute()){
$result = $stmt->get_result();
while ($row = $result->fetch_assoc())
{
$returnData[] = $row["username"] . "," . $row["user_score"];
}
/* close statement */
$stmt->close();
}
}
//The returned string will use '|' symbol for separation between player data and ',' for separation inside the player data
echo implode('|', $returnData);
}else{
echo "Missing data";
}
?>
- Laden Sie sowohl „score_submit.php“ als auch „leaderboard.php“ in denselben Ordner hoch, in den Sie die PHP-Skripte aus dem vorherigen Tutorial hochgeladen haben.
Nachdem alles eingerichtet ist und Sie auf „Bestenliste“ klicken, sollte Ihr Punktestand/Rang zusammen mit den 100 besten Spielern basierend auf ihren Punkteständen geladen werden: