एकता ऑनलाइन लीडरबोर्ड ट्यूटोरियल

इस ट्यूटोरियल में, मैं दिखाऊंगा कि आपके गेम में Unity में ऑनलाइन लीडरबोर्ड कैसे लागू किया जाए।

यह पिछले ट्यूटोरियल की निरंतरता है: Unity PHP और MySQL के साथ लॉगिन सिस्टम

लीडरबोर्ड का होना आपके गेम में प्रतिस्पर्धात्मकता का स्तर जोड़कर पुन:प्लेबिलिटी बढ़ाने का एक शानदार तरीका है।

पहले की तरह, इस ट्यूटोरियल के लिए PHP और MySQLi (MySQL का एक उन्नत संस्करण) के साथ cPanel वाले सर्वर की आवश्यकता है।

बेझिझक किफायती प्रीमियम VPS होस्टिंग या सस्ता साझा होस्टिंग विकल्प देखें।

तो चलिए जारी रखें!

मौजूदा स्क्रिप्ट में संशोधन करना

यदि आपने उपरोक्त ट्यूटोरियल का अनुसरण किया है, तो अब आपके पास 'SC_LoginSystem' नामक एक स्क्रिप्ट होगी। हम इसमें कुछ कोड जोड़कर लीडरबोर्ड सुविधा को लागू करेंगे।

  • 'SC_LoginSystem' स्क्रिप्ट खोलें

सबसे पहले, हम आवश्यक चर जोड़कर शुरू करते हैं:

    //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;

ध्यान दें: currentScore वेरिएबल वह है जिसका उपयोग आप गेम में खिलाड़ी के स्कोर को ट्रैक करने के लिए करेंगे। यह मान सर्वर पर सबमिट किया जाएगा और डेटाबेस में संग्रहीत किया जाएगा, हैकिंग से बचाने के लिए उस मान को obfusate करने की अनुशंसा की जाती है।

इसके बाद, हम 2 प्रगणक जोड़ते हैं जो स्कोर सबमिट करने और लीडरबोर्ड पुनर्प्राप्त करने के लिए जिम्मेदार होंगे। अंतिम ब्रैकेट के बंद होने से पहले स्क्रिप्ट के अंत में नीचे दिया गया कोड जोड़ें:

    //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;
    }

अगला लीडरबोर्ड यूआई है। शून्य OnGUI() के बाद नीचे दिया गया कोड जोड़ें:

    //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();
        }
    }

नीचे दिए गए कोड को void OnGUI() के अंदर जोड़ें (क्लोजिंग ब्रैकेट से पहले):

        //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());
                }
            }
        }

और अंत में, शून्य अद्यतन(), जिसमें एक बार परिवर्तन होने पर खिलाड़ी का स्कोर सबमिट करने के लिए जिम्मेदार एक कोड होगा। सभी वेरिएबल्स के बाद स्क्रिप्ट की शुरुआत में नीचे दिया गया कोड जोड़ें:

    //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;
            }
        }
    }

**टेस्टिंग** भाग पर ध्यान दें, चूंकि हमारे पास खेलने योग्य गेम नहीं है, हम केवल Q दबाकर स्कोर बढ़ाते हैं (यदि आपके पास पहले से ही स्कोरिंग सिस्टम वाला गेम है तो आप इसे बाद में हटा सकते हैं, उदाहरण के लिए). एक सिक्का इकट्ठा करें +1 अंक, आदि)

जब आप प्ले दबाते हैं और लॉगिन करते हैं, तो आपको 2 नए तत्व दिखाई देने चाहिए: 'Leaderboard' बटन और स्क्रीन के शीर्ष पर स्कोर मान।

अब हम एक MySQL तालिका बनाने के लिए आगे बढ़ते हैं।

MySQL तालिका बनाना

उपयोगकर्ता स्कोर एक अलग MySQL तालिका में संग्रहीत किया जाएगा।

  • CPanel में लॉग इन करें
  • डेटाबेस अनुभाग के अंतर्गत "phpMyAdmin" पर क्लिक करें

  • पिछले ट्यूटोरियल में आपके द्वारा बनाए गए डेटाबेस पर क्लिक करें और फिर SQL टैब पर क्लिक करें

  • नीचे दिए गए कोड को क्वेरी एडिटर में पेस्ट करें और फिर क्लिक करें "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;

उपरोक्त क्वेरी 'sc_user_scores' नामक एक नई तालिका बनाएगी जो मुख्य 'sc_users' तालिका के संदर्भ के रूप में user_id के साथ उच्चतम स्कोर संग्रहीत करेगी।

अंतिम भाग सर्वर-साइड लॉजिक लागू कर रहा है।

सर्वर-साइड लॉजिक लागू करना

सर्वर-साइड लॉजिक में PHP स्क्रिप्ट शामिल होंगी जो स्कोर प्राप्त करने/भंडारित करने और लीडरबोर्ड को पुनः प्राप्त करने के लिए जिम्मेदार होंगी।

पहली स्क्रिप्ट score_submit.php है।

  • एक नई PHP स्क्रिप्ट बनाएं और उसके अंदर नीचे दिया गया कोड पेस्ट करें:

स्कोर_सबमिट.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";
	}
?>

अंतिम स्क्रिप्ट leaderboard.php है।

  • एक नई PHP स्क्रिप्ट बनाएं और उसके अंदर नीचे दिया गया कोड पेस्ट करें:

लीडरबोर्ड.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";
	}
?>
  • Score_submit.php और लीडरबोर्ड.php दोनों को उसी फ़ोल्डर में अपलोड करें, जहां आपने पिछले ट्यूटोरियल से PHP स्क्रिप्ट अपलोड की थी।

सब कुछ सेट हो जाने के बाद, जब आप लीडरबोर्ड पर क्लिक करते हैं तो इसे आपके स्कोर/रैंक को शीर्ष 100 खिलाड़ियों के साथ उनके स्कोर के आधार पर लोड करना चाहिए:

लिंक
Unity 6