Unity Çevrimiçi Skor Tablosu Eğitimi

Bu eğitimde Unity'te oyununuzda çevrimiçi skor tablosunu nasıl uygulayacağınızı göstereceğim.

Bu önceki eğitimin devamı niteliğindedir: Unity PHP ve MySQL ile Oturum Açma Sistemi.

Liderlik tablosuna sahip olmak, oyununuza rekabet gücü katarak tekrar oynanabilirliği artırmanın harika bir yoludur.

Daha önce olduğu gibi, bu eğitimde cPanel'in yanı sıra PHP ve MySQLi (MySQL'in geliştirilmiş bir sürümü) içeren bir sunucu gerekir.

Uygun fiyatlı premium VPS barındırma veya daha ucuz Paylaşılan Barındırma alternatifini kontrol etmekten çekinmeyin.

Öyleyse devam edelim!

Mevcut komut dosyasında değişiklik yapma

Yukarıdaki eğitimi izlediyseniz artık 'SC_LoginSystem' adında bir komut dosyasına sahip olursunuz. Liderlik tablosu özelliğini bazı kodlar ekleyerek hayata geçireceğiz.

  • 'SC_LoginSystem' betiğini açın

İlk olarak gerekli değişkenleri ekleyerek başlıyoruz:

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

NOT: currentScore değişkeni oyunda oyuncu puanlarını takip etmek için kullanacağınız değişkendir. Bu değer sunucu'e gönderilecek ve veritabanında saklanacaktır; bilgisayar korsanlığına karşı koruma sağlamak için bu değerin obfuscate ayarlanması önerilir.

Daha sonra, puanların gönderilmesinden ve skor tablosunun alınmasından sorumlu olacak 2 Numaralandırıcı ekliyoruz. Aşağıdaki kodu, son parantez kapatılmadan önce betiğin sonuna ekleyin:

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

Sırada liderlik tablosu kullanıcı arayüzü var. void OnGUI()'den sonra aşağıdaki kodu ekleyin:

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

Aşağıdaki kodu void OnGUI() içine ekleyin (kapanış parantezinden önce):

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

Ve son olarak, değiştiğinde oyuncu puanını göndermekten sorumlu bir kod içeren void Update(). Tüm değişkenlerden sonra betiğin başına aşağıdaki kodu ekleyin:

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

**Test** kısmına dikkat edin, oynanabilir bir oyunumuz olmadığından, Q tuşuna basarak puanı artırıyoruz (Puanlama sistemine sahip bir oyununuz varsa daha sonra kaldırabilirsiniz, örn.). jeton +1 puan vb. toplayın)

Oynat tuşuna bastığınızda ve giriş yaptığınızda 2 yeni öğeyi fark edeceksiniz: 'Leaderboard' düğmesi ve ekranın üst kısmındaki Puan değeri.

Şimdi MySQL tablosu oluşturmaya geçiyoruz.

MySQL tablosu oluşturma

Kullanıcı puanları ayrı bir MySQL tablosunda saklanacaktır.

  • CPanel'e giriş yapın
  • VERİTABANLARI bölümünde "phpMyAdmin" seçeneğine tıklayın

  • Önceki eğitimde oluşturduğunuz veritabanına tıklayın ve ardından SQL sekmesine tıklayın.

  • Aşağıdaki kodu sorgu düzenleyicisine yapıştırın ve ardından tıklayın. "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;

Yukarıdaki sorgu, ana 'sc_users' tablosuna referans olarak user_id ile birlikte en yüksek puanları saklayacak 'sc_user_scores' adında yeni bir tablo oluşturacaktır.

Son kısım sunucu tarafı mantığının uygulanmasıdır.

Sunucu tarafı mantığını uygulama

Sunucu tarafı mantığı, puanların alınmasından/saklanmasından ve sıralama tablosunun alınmasından sorumlu olacak PHP komut dosyalarından oluşacaktır.

İlk komut dosyası score_submit.php'dir.

  • Yeni bir PHP betiği oluşturun ve içine aşağıdaki kodu yapıştırın:

skor_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";
	}
?>

Son komut dosyası leaderboard.php'dir.

  • Yeni bir PHP betiği oluşturun ve içine aşağıdaki kodu yapıştırın:

lider tablosu.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";
	}
?>
  • Hem Score_submit.php'yi hem de Leaderboard.php'yi önceki eğitimde PHP betiklerini yüklediğiniz klasöre yükleyin.

Her şey ayarlandıktan sonra Liderlik Tablosu'na tıkladığınızda puanınız/sıralamanız, puanlarına göre en iyi 100 oyuncuyla birlikte yüklenecektir:

Önerilen Makaleler
PHP ve MySQL ile Unity Giriş Sistemi
PUN 2'yi Kullanarak Sert Cisimleri Ağ Üzerinden Senkronize Etme
Unity'de Photon Fusion 2'ye Giriş
Unity'de Çok Oyunculu Ağ Bağlantılı Oyunlar Oluşturma
Çok Oyunculu Veri Sıkıştırma ve Bit İşleme
PUN 2 ile Çok Oyunculu Araba Oyunu Yapın
PUN 2 Gecikme Telafisi