YuDe - Unity MySql Score Sistemi Yapımı

GAME, SOFTWARE, NETWORKING AND MORE...

Contact us for cooperation

 

Unity MySql Score Sistemi Yapımı

Merhaba arkadaşlar. İlk blogumla karşınızdayım. Bu ilk blog da, Unity için mysql score sistemi nasıl yapılır onu anlatacağım. Şunu başta söylemeliyim ki yapacağımız sistem online olacağı için mutlaka bir hosting e ihtiyacımız olacak. Deneme amaçlı WampServer ya da Xampp gibi local sunucu programlarını kullanabilirsiniz.

Veritabanında tablomuzu oluşturma

İlk yapacağımız şey MySql veritabanımızda tablomuzu oluşturmak. Ben phpMyAdmin kullandığım için tablo oluşturmayı onun üzerinden göstereceğim. phpMyAdmin panelimize giriş yaptıktan sonra hemen soldan kullanacağımız veritabanımızı seçip tablo oluşturuyoruz. Benim yapacağım score panelinde sadece sıra, kullanıcı adı ve score olacak. Bu yüzden Sütun sayısı kısmına 3 yazıp Git diyorum.


Şimdi karşımıza 3 satırdan oluşan bir tablo çıkıyor. Bu tablonun birinci satırın birinci sütununa(yani Adı sütunu) id yazıyoruz. Bu satırımızın ikinci sütunu yani Türü sütunumuzun INT olduğuna dikkat edelim.
MySql'in bize sunduğu AUTO_INCREMENT özelliği sayesinde tabloya veri kayıt ederken sıra numarasını biz yazmadan otomatik sıra numarası verip kayıt edebiliriz. Bu özelliği kullanmak için birinci satırımızın son sütunundan bir önceki sütun olan AUTO_INCREMENT(A_I olarak ta geçebilir)'ı aktif ediyoruz.
Şimdi ikinci satırımıza geçtik. Adı sütununa username yazıp Türü sütunundan ise VARCHAR'ı seçiyoruz. Bunu seçmemizin sebebi bu kısma string ifadelerin gelmesidir.
Üçüncü satırımıza geçtik. Burada da Adı sütunumuza score yazıp Türü INT olarak seçiyoruz. Tablonun son hali:


(*)Bütün satırların uzunluk değeri 255 olacak.
Bilgileri doğru bir şekilde girdiyseniz Artık Git tuşuna tıklayıp tabloyu kayıt edebilirsiniz.

PHP Kısmı

Şimdi geldik oyun ile veritabanı arasındaki köprüyü kuracak olan PHP ye. İlk önce neden php kullanacağız onu cevaplıyayım. Arada köprü kurmadan C# ile doğrudan veritabanına bağlanamaz mıyız? Evet tabi ki yapabiliriz. Ama bu çok güvensiz olur. Veritabanına bağlanırken "sunucumuzun ip adresini", "kullanıcı adımızı", "şifremizi", "veritabanımızın adını" ve"tablomuzun adını" kaynak kodlarımızda kullanmak zorunda kalacağız. Yayınlanmış uygulamanızın/programınızın kaynak kodlarını ele geçirmek bu dönemde çok basit. Veritabanı bilgileriniz kötü kişilerin eline geçerse, istediği her veriyi ekleyebilir, güncelleyebilir ve hatta silebilir. Veritabanı ile kodlarımız arasında php köprüsü kurarsak, bilgilerimiz php sayfasında şifrelenir ve bu buyuk sorunun üstesinden geliriz.
Şimdi masaüstünde yada başka bir dizinde bir php dosyası oluşturun(Boş bir not defteri oluşturup uzantısını .txt den .php ye değiştirerek yapabilirsiniz). Tavsiyem bir klasör içinde oluşturun. Maksat dosyayı hostingimize attığımızda diğer dosyalarla karışmasın. Php dosyamızın ismini ScoreTable olarak değiştirip alttaki kodları olduğu gibi içine yapıştırın:
<?php
//Veritabanımzıa bağlanmak için boşluklara sırasıyla hostumuzu, kullanıcı adımızı, şifremizi ve veritabanı adımızı yazıyoruz
$mysqli = mysqli_connect("localhost","KullaniciAdi","Sifre","VeritabaniAdi");
//Bağlantıda hata olup olamdığını kontrol ediyoruz
if (mysqli_connect_errno()) 
{
	//Hata varsa, hatayı ekrana basıp kodları durduruyoruz
	echo "Connection error: ".mysqli_connect_error();
    exit();
}

// 'action' adında bir veri postlanırsa ve bu verinin değeri 'AddScore' olursa
if ($_REQUEST['action'] == "AddScore")
{
	//Post edilmiş olan 'username' verisini bu değişkene atıyoruz
     $username = $_POST["username"];
	//Post edilmiş olan 'score' verisini bu değişkene atıyoruz
	$score = $_POST["score"];
	
	//Oyundan post edilen kullanıcı adının veritabanında daha önce kayıtlı olup olmadığını öğrenmek için sorgu yapıyoruz
	$QueryUser = $mysqli->query("SELECT * FROM ScoreTable WHERE (username = '$username')");
	
	if (mysqli_num_rows($QueryUser) > 0)
	{//Kullanıcı zaten kayıtlı, score u güncellenecek
		
		//Veritabanında kayıtlı olan score u değişkene atıyoruz
		 $cur_score = intval(mysqli_fetch_assoc($QueryUser)['score']);
		 
		 //Oyundan post edlien score değerin, veritabanda kayıtlı olan score dan büyükse
		 if($score>$cur_score)
		 {
			  if ($mysqli->query("UPDATE ScoreTable SET score = '$score' WHERE username = '$username'"))
			  {//Veri güncelleme başarılı, ekrana başarılı yazdır
				  echo "success";
			  } 
			  else 
			  {//Veri güncelleme başarısız, hatayı ekrana yazdır
                  echo "Error:".mysqli_error($mysqli);
              }
		 }
		 else
		 {//Score, veritabanında kayıtlı olan score dan küçük
			  echo "Score is less than registered score";
		 }
		 
	}
	else 
	{//Kullanıcı kayıt edilip score u eklenecek
		
	   if ($mysqli->query("INSERT INTO ScoreTable (username, score) VALUES ('$username','$score')")) 
	   {//Veri ekleme başarılı, ekrana başarılı yaz
         echo "success";
       } 
	   else 
	   {//Veri ekleme başarısız, hatayı ekrana yazdır
         echo "Error:".mysqli_error($mysqli);
       }
	}
}
// 'action' adında bir veri postlanırsa ve bu verinin değeri 'GetScores' olursa
else if ($_REQUEST['action'] == "GetScores")
{
	//Veritbanında score u büyükten küçüğe sıralayarak ilk '100' kişiyi çek
	$QueryScores= $mysqli->query("SELECT * FROM ScoreTable Order By score DESC LIMIT 100");
	
	//Veritbanamızda daha veri kayıt edildiyse
	if (mysqli_num_rows($QueryScores) > 0)
	{
		
	while ($row = mysqli_fetch_assoc($QueryScores))	
	{
		//Verileri "," ile ayırarak parse ediyoruz ve ekrana yazdırıyoruz
		echo $row['username'].",".$row['score'].",";
		
	}
		
	}
	else 
	{//Kayıtlı veri bulunamadı
		echo "no_data";
	}
	
	
}
?>
PHP dosyanızı hostinge atma vakti. FileZilla ya da herhangi bir FTP programı kullanarak php dosyanızı hostinge bir dizine atın(Benim php min yolu: http://yudegames.com/Tutorials/ScoreTable/ScoreTable.php). Sonra ise php nizi bir tarayıcıda çalıştırın. Eğer benim gibi boş bir sayfa ile karşılaşırsanız doğru yoldasınız.
(*)PHP dosyasında veritabanı bilgilerimizi değiştirmeyi unutmuyoruz!

Unity Kısmı

Geldik Unity kısmına. Şimdi Score Table adında yeni bir Unity projesi açıyoruz.


Proje açıldıktan sonra klavyeden Ctrl + S ye basarak sahneyi kayıt ediyoruz. Sonra boş bir Game Object oluşturup adını Score Manager yapıyoruz.
Bu oluşturduğumuz boş objeye, ScoreManager adında bir script oluşturup ekleyeceğiz


Scripti oluşturduktan sonra alttaki kodları olduğu gibi içine yapıştırın:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Score_Class
{
    public int _rank;
    public string _username;
    public int _score;

    public Score_Class(int _rank, string _username, int _score)
    {
        this._rank = _rank;
        this._username = _username;
        this._score = _score;
    }

}
public class ScoreManager : MonoBehaviour
{

    //Score ların toplantığı liste
    public List<Score_Class> Scores = new List<Score_Class>();

    //Mevcut Score un tutulduğu değişken
    private int score = 100;


    //GUI için kullanıcı adı
    private string usernameField = "Set username...";
    //GUI için scroll pozisyonu
    private Vector2 scrollPosition = Vector2.zero;

    //GUI paneller için
    private bool isMainPanel = true;
    private bool isUsernamePanel = false;
    private bool isScorePanel = false;
    private bool isLoading = false;

    // PHP nin bulunduğu yol. Burayı kendi PHP nizin yolu ile değiştireceksiniz
    private string PHP_path = "http://yudegames.com/Tutorials/ScoreTable/ScoreTable.php";

    private void Start()
    {
        //Score ların toplanacağı listeyi sıfırlama
        Scores.Clear();
        //Daha önce PlayerPrefs de score kayıtlıysa değişkeni kayıtlı veriye eşitle, değilse default(100)değeri kullan
        score = PlayerPrefs.GetInt("score") == 0 ? score : PlayerPrefs.GetInt("score");
    }
    private void OnGUI()
    {

        //GUI style ları
        var GS1 = new GUIStyle(GUI.skin.box);
        var GS2 = new GUIStyle(GUI.skin.button);
        var GS3 = new GUIStyle(GUI.skin.button);
        GS1.fontSize = FontSizeForAllResolations(60f);
        GS2.fontSize = FontSizeForAllResolations(43f);
        GS3.fontSize = FontSizeForAllResolations(35f);


        //Ana Panel
        if (isMainPanel)
        {
            //Score u ekrana yazdır
            GUI.Box(RectForAllResolations(new Rect(34.3f, 35f, 28.8f, 10.3f)), string.Format("Score : {0}", score), GS1);

            //Score ekleme buttonu
            if (GUI.Button(RectForAllResolations(new Rect(31.4f, 50.3f, 16.4f, 10.3f)), "(+)\nAdd", GS2))
            {
                AddScore(50);
            }
            //Score düşürme buttonu
            if (GUI.Button(RectForAllResolations(new Rect(49.5f, 50.3f, 16.4f, 10.3f)), "(-)\nReduce", GS2))
            {
                AddScore(-50);
            }
            //Scorları al butonu
            if (GUI.Button(RectForAllResolations(new Rect(31.37f, 62.3f, 35, 10.3f)), "Get Online Score Panel", GS2))
            {

                if (PlayerPrefs.GetString("RegisteredUsername").Length > 1)
                {
                    //Daha önce kullanıcı adı girildiyse 'ReportScore' fonksiyonunu çağır.
                    //Bu fonksiyonda mevcut score veritabanına gönderiliyor
                    isMainPanel = false;
                    isUsernamePanel = false;
                    isScorePanel = true;
                    StartCoroutine(ReportScore(PlayerPrefs.GetString("RegisteredUsername")));
                }
                else
                {
                    //Daha önce kullanıcı adı girilmediyse, kullanıcı adı panelini göster
                    isMainPanel = false;
                    isUsernamePanel = true;
                    isScorePanel = false;
                }

            }
        }
        //Kullanıcı adı paneli
        if (isUsernamePanel)
        {
            //kullanıcı adı metin kutusu
            usernameField = GUI.TextField(RectForAllResolations(new Rect(32.68f, 34.86f, 30.55f, 8.5f)), usernameField, GS2);

            //Submit(Gönder) buttonu
            if (GUI.Button(RectForAllResolations(new Rect(32.7f, 44.8f, 30.53f, 8.24f)), "Submit", GS2))
            {
                //kullanıcı adı boş değilse ve (,) içermiyorsa ve (.) içermiyorsa ve boşluk içermiyorsa
                if (usernameField.Length > 0 && !usernameField.Contains(",") && !usernameField.Contains(".") && !usernameField.Contains(" "))
                {
                    //'ReportScore' fonksiyonunu çağır. Bu fonksiyonda mevcut score veritabanına gönderiliyor
                    StartCoroutine(ReportScore(usernameField));

                }
                else
                {//Aksi durumda konsolda hata verdir
                    Debug.LogError("Username incorrect!");
                }

            }
            //Geri
            if (GUI.Button(RectForAllResolations(new Rect(0, 0, 15, 15)), "Back", GS2))
            {
                isUsernamePanel = false;
                isMainPanel = true;
                isScorePanel = false;
            }
        }
        //Score Paneli
        if (isScorePanel)
        {
            //GUI için için scroll ve pozisyonu
            scrollPosition = GUI.BeginScrollView(RectForAllResolations(new Rect(26.54f, 30.6f, 48.25f, 40.3f)), scrollPosition, RectForAllResolations(new Rect(0, 0, 45, 9f * (Scores.Count + 1))));

            for (int i = 0; i < Scores.Count; i++)
            {
                //'Scores' listesinde kayıtlı olan veri sayısı kadar button oluştur ve bu buttonlara score bilgilerini yazdır
                GUI.Button(RectForAllResolations(new Rect(1, i * 10, 45, 8.9f)), string.Format("{0})  {1}  >>>  {2}", Scores[i]._rank, Scores[i]._username, Scores[i]._score), GS3);

            }
            //Scroll sonu
            GUI.EndScrollView();

            //Geri
            if (GUI.Button(RectForAllResolations(new Rect(0, 0, 15, 15)), "Back", GS2))
            {
                isUsernamePanel = false;
                isMainPanel = true;
                isScorePanel = false;
            }

        }

        //Loading
        if (isLoading)
        {
            GUI.Box(new Rect(0, 0, Screen.width, Screen.height), "LOADING...", GS1);
        }


    }

    //Bu fonksiyonda mevcut score veritabanına gönderiliyor
    private IEnumerator ReportScore(string _username)
    {

        Scores.Clear(); //Listeyi sıfırla
        isLoading = true;//Loading i aktifleştir
        string url = PHP_path;// PHP nin bulunduğu yol
        WWWForm form = new WWWForm();//Verileri postlamak için Form
        form.AddField("action", "AddScore");//Postlanacak veri
        form.AddField("username", _username);//Postlanacak veri
        form.AddField("score", score);//Postlanacak veri
        WWW www = new WWW(url, form);//İsteği gönder
        yield return www;//Cevap bekle
        Debug.Log(www.text);//Cevabı konsola yazdır
        PlayerPrefs.SetString("RegisteredUsername", _username);//Kullanıcının kayıt yaptığını playerprefs ile hafızada tut

        //Kayıt başarılı, Score pencerisini aç
        isLoading = true;
        isMainPanel = false;
        isUsernamePanel = false;
        isScorePanel = true;

        //Score ları almak için 'GetScores' fonksiyonunu çağır
        StartCoroutine(GetScores());
    }

    //Bu fonksiyonda Veritabanından score lar çekiliyor
    private IEnumerator GetScores()
    {
        isLoading = true;//Loading i aktifleştir
        string url = PHP_path;// PHP nin bulunduğu yol
        WWWForm form = new WWWForm();//Verileri postlamak için Form
        form.AddField("action", "GetScores");//Postlanacak veri
        WWW www = new WWW(url, form);//İsteği gönder
        yield return www;//Cevap bekle
        Debug.Log(www.text);//Cevabı konsola yazdır
        isLoading = false;//Loading i deaktif et

        string received = www.text.Substring(0, www.text.Length - 1);// PHP den gelen verinin son karakterini(',') silerek bu değişkene aktar
        string[] received_array = received.Split(',');//verileri virgül(,) ile ayır
        int _count = received_array.Length / 2; //PHP den gelen veriler sadece 'username' ve 'score' olduğu için gelen score sayısını bulmak için 2 ye bölüyoruz
        int _index = 0;
        for (int i = 0; i < _count; i++)
        {
            //'Scores' listesine score ekle
            Scores.Add(new Score_Class(i + 1, received_array[0 + _index], int.Parse(received_array[1 + _index])));
            _index += 2;
        }
    }

    //Deneme amaçlı kendi score umuzu güncellemek için score ekleme/çıkarma fonksiyonu
    private void AddScore(int _value)
    {
        score += _value;
        PlayerPrefs.SetInt("score", score);
    }

    //GUI ların bütün çözünürlüklere uyması için
    private Rect RectForAllResolations(Rect _rect)
    {
        return new Rect(_rect.x * Screen.width * 0.01f, _rect.y * Screen.height * 0.01f, _rect.width * Screen.width * 0.01f, _rect.height * Screen.height * 0.01f);
    }
    //GUI ların yazı büyüklüklerinin bütün çözünürlüklere uyması için
    private int FontSizeForAllResolations(float _size)
    {
        return Mathf.RoundToInt(_size * Screen.width / (1920f));
    }

}

Kodlarımız buraya kadar. Scripti olduğu gibi hiç değişiklik yapmadan derleyip çalıştırırsanız, benim kurduğum score sistemine bağlanıp, score ekleyip, güncelleyip, veritabanında kayıtlı olan bütün score ları görebilirsiniz.
Kendi veritabanınızı kullanmak için scriptte üstlerde yer alan PHP_path değişkenini, kendi PHP yolunuz ile değiştirmeyi Unutmayın.
Metin ile zor izah edileceğinden dolayı UI yerine GUI kullandım. Bunu Canvas kullanarak UI a çevirmek gayet basit. Az kodlama bilginiz varsa uydurabilirsiniz. Tek yapmanız gereken Scores listesinin içeriğini UI elementlerine ve özellikle text lere dökmek.
Bu tutorial ımızın sonuna geldik. Yaptığımız score sistemi çok basit bir sistem di. Bunu geliştirip bir Login/Register sistemine entegre edebilir hatta facebook ve google gibi API ları kullanarak score sistemini onlara uyumlu çalışabilecek hale getirebilirsiniz.
Yaşayacağınız sorunları Facebook adresimizden bana ulaşarak danışabilirsiniz. Kolay gelsin.
Ekran görüntüleri: