بازی سازی

استفاده از SQLite در یونیتی به همراه مثال

نوشته شده توسط امین سجودی

SQLite در یونیتی

با سلام

توی این آموزش قراره یکسری اطلاعات بازیمون رو به جای اینکه روی فایل یا PlayerPrefs ذخیره کنیم ، روی دیتابیس Local ذخیره کنیم .

سورس فایل ها و پروژه یونیتی کامل

این پروژه با یونیتی ۵ تست شده است .

قراره که از پلاگینی به  اسم SQLite4Unity3d استفاده کنیم . به گفته نویسنده این پلاگین ، روی موبایل هم کار می کنه .

برای این که اطلاعات دیتابیس مون رو مرور کنیم و بتونیم جداول مون رو بسازیم از یک نرم افزار ساده و محانی به اسم DB Browser for SQLite استفاده کردم .

گام اول :

یک پروژه جدید یونیتی ایجاد کنید .

گام دوم :

این لینک رو دانلود کنید و بازش کنید . پس از اکسترکت کردن باید یک فولدر ببینید به اسم Plugins که این فولدر رو عینا کپی می کنید توی فولدر Assets پروژه خودتون(اگه قبلا فولدر Plugins داشتید این با اون باید یکی بشه) . فایل SQLite.cs رو هم کپی کنید توی پروژه تون هر کجا که خواستید.

گام سوم :

توی فولدر Assets بازیتون یک فولدر به اسم StreamingAssets درست کنید .

گام چهارم :

با استفاده از نرم افزار DB Browser for SQLite یک دیتابیس توی فولدر StreamingAssets درست کنید .

تا اینجا گام های عمومی بود . یعنی اگه برای پروژه خودتون می خواهید از SQLite استفاده کنید باید این مراحل رو برید . از این جا به بعد مخصوص این مثال خاص ما خواهد بود .

من در دیتابیسم یک جدول به اسم Team ساختم که ۳ تا فیلد داره . Id ، Name ، Score .

حالا عینا توی کلاس هام هم یک کلاس به اسم Team درست کردم . به این کلاس در حقیقت مدل می گن . یعنی عینا یک مدل از شکل داده هامون توی دیتابیسمون هستش .

using UnityEngine;
using System.Collections;
using SQLite4Unity3d;

public class Team  {

	[PrimaryKey, AutoIncrement]
	public int _Id {
				get;
				set;
	}
	public string Name {
				get;
				set;
	}
	public int Score {
				get;
				set;
	}

	public override string ToString ()
	{
		return string.Format
			("[Id: Id={0}, Name={1}, Score={2}]",
			 _Id, Name, Score);
	}
}

برای اینکه با دیتابیس هم ارتباط بر قرار کنیم از این کلاس استفاده کردم.


using UnityEngine;
#if !UNITY_EDITOR
using System.Collections;
using System.IO;
#endif
using SQLite4Unity3d;
using System.Collections.Generic;

public class DatabaseHandler {

	private SQLiteConnection _connection;

	public DatabaseHandler(string DatabaseName){

		#if UNITY_EDITOR
		var dbPath = string.Format(@"Assets/StreamingAssets/{0}", DatabaseName);
		#else
		// check if file exists in Application.persistentDataPath
		var filepath = string.Format("{0}/{1}", Application.persistentDataPath, DatabaseName);

		if (!File.Exists(filepath))
		{
			Debug.Log("Database not in Persistent path");
			// if it doesn't ->
			// open StreamingAssets directory and load the db ->

			#if UNITY_ANDROID
			var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + DatabaseName);  // this is the path to your StreamingAssets in android
			while (!loadDb.isDone) { }  // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check
			// then save to Application.persistentDataPath
			File.WriteAllBytes(filepath, loadDb.bytes);
			#elif UNITY_IOS
			var loadDb = Application.dataPath + "/Raw/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
			// then save to Application.persistentDataPath
			File.Copy(loadDb, filepath);
			#elif UNITY_WP8
			var loadDb = Application.dataPath + "/StreamingAssets/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
			// then save to Application.persistentDataPath
			File.Copy(loadDb, filepath);

			#elif UNITY_WINRT
			var loadDb = Application.dataPath + "/StreamingAssets/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
			// then save to Application.persistentDataPath
			File.Copy(loadDb, filepath);
			#endif

			Debug.Log("Database written");
		}

		var dbPath = filepath;
		#endif
		_connection = new SQLiteConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create);
		Debug.Log("Final PATH: " + dbPath);
	}

	public void addTeam(Team _team)
	{
		_connection.BeginTransaction();
		_connection.Insert(_team);
		_connection.Commit();
	}

	public void updateTeam(Team newTeam)
	{
		_connection.Update(newTeam);
	}

	public List<Team> getTeams()
	{
		_connection.BeginTransaction();
		var Teams = _connection.Table<Team>();
		List<Team> _teams = new List<Team>();
		foreach (var item in Teams) {
			_teams.Add(item);
		}
		_connection.Commit();
		return _teams;
	}

}

حالا دست آخر برای تست کار کردن باید یک کلاس دیگه درست کنم که این ها رو تست کنه من اسمش رو می ذارم Test.cs . پس اول یکسری داده توی دیتابیسمون می ریزم ، با استفاده از DB Browser for SQLite ، بعد توی این کلاس Test  اول لیست تیم ها رو میگیرم ، بعد یک تیم اضافه می کنم ، اطلاعات یک تیم رو آپدیت می کنم و دوباره لیست تیم ها رو چاپ می کنم .

اینم کلاس تست :

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {

	public DatabaseHandler dataHandler;

	// Use this for initialization
	void Start () {
		dataHandler = new DatabaseHandler("TestDB");

		Debug.Log("---------------------Teams---------------------");
		var teams = dataHandler.getTeams();
		foreach (var item in teams) {
			Debug.Log(item.ToString());
		}
		Debug.Log("---------------------AddTeam---------------------");
		var team = new Team();
		team.Name = "new Team";
		team.Score = 0;
		dataHandler.addTeam(team);
		Debug.Log("---------------------UpdateScoreOfTeam---------------------");
		teams[1].Score = 200;
		dataHandler.updateTeam(teams[1]);
		Debug.Log("---------------------Teams---------------------");
		teams = dataHandler.getTeams();
		foreach (var item in teams) {
			Debug.Log(item.ToString());
		}

	}

}

 

سورس فایل ها و پروژه یونیتی کامل

درباره نویسنده

امین سجودی

امین یک توسعه دهنده نرم افزار و علاقه مند به بازی می باشد که بیشتر وقت خود را صرف برنامه نویسی و یادگیری تکنولوژی های جدید می کند .

دیدگاه

  • امین جان مشکلی از پلتفرم و…نیست
    مشکل اینه که این پلاگین آپدیت شده مخصوصا برای Unity5 که بنده استفاده میکنم و این Tutorial باید مثالش تغییر کنه
    چون Sample که در GitHub برای Unity وجود دارد کاملا کار میکند
    ممنون باتشکر

    • تا شما اطلاعات ندید من نمی تونم ارور شما رو ایجاد کنم ، من سورس پروژه خودم رو دانلود کردم و با یونیتی ۵ تستش کردم . کار می کرد . پلتفرمی که خودم روش تست کردم مک هستش . من پلاگین رو آپدیت می کنم و تست می کنم ببینم مشکلی می بینم یا نه . این طور که الان من فهمیدم اگه طبق آموزش پیش برم باید به مشکل بخورم درسته ؟

    • سلام، لطف دارین. چند تا راه حل هست، فکر کنم خود SQLite امکان رمز گذاری رو داره، اینو نمی دونم که این پلاگین این قابلیت رو به شما می ده یا نه. ولی اگه راه حل دیگه ای خواستید می تونید خودتون دیتا ها رو به صورت رمز شده وارد دیتابیس کنید و موقع خوندن رمز گشایی کنید.

  • سپاس فراوان
    ببخشید فقط من یک سوال دارم و حقیقتش در این مدتی که درباره اش تحقیق کردم به نتیجه ای نرسیدم.
    راستش من این آموزش رو برای استفاده در اپلیکیشن واقعیت افزوده با یونیتی دنبال کردم. الان راستش به مشکل خوردم و قسمتهایی از کار برام مبهمه. مثلا کد اسکریپتی که باید برای اتصال به پایگاه داده استفاده بشه رو میدونم و دارم. مشکلم در قسمتی هست که اشیا رو فرزند تصویر هدف قرار میدیم. چون هدف من این هست که اشیای ar کاملا از پایگاه داده گرفته بشن و دیگه تو محیط ادیتور نباشند اما نمیدونم برای اون قسمت فرزند قرار دادن چه کار میشه کرد . میشه اگر آموزشی سراغ دارید یا جوابش رو میدونید یک راهنمایی بدید؟ من خیلی ممنون میشم.

    • اگه درست متوجه شده باشم راه حلی که به شما پیشنهاد می کنم اینه که آبجکت ها تون رو به صورت Prefab در فولدر Resources قرار بدید و سپس لینک به موقعیت اون ها(مثلا “Resources/Objects/1”) رو در دیتابیس ذخیره کنید و در موقع لزوم اون ها رو با استفاده از Resources.Load لود کنید و به کمک transform.SetParent فرزند آبجکت مد نظر تون قرار بدید.

  • خوب من میخوام وقتی اپلیکیشن رو درست کردم واشیای ar رو داخلش قرار دادم اگر خواستم این اشیا رو تغییر بدم یا بهشون چیزی اضافه کنم مجبور نباشم کل فایل apk رو تغییر بدم، قبلی رو پاک کنم، فایل جدیدو دوباره نصب کنم و….
    هدفم اینه که اگر خواستم اشیای ar رو اضافه یا کم کنم بدون اینکه به اپلیکیشنم دست بزنم این کار رو با استفاده از پایگاه داده انجام بدم طوریکه دیگه نیاز نباشه برنامه رو تغییر بدم . اشیا رو توی پایگاه تغییر بدم و دفعه ی بعد که گوشی رو روی تصویر هدف گرفتم همون چیزهای توی پایگاه داده رو نمایش بده.
    فقط …این راه حلی که شما معرفی کردید کدهاش برای اتصال به sql server هم کاربرد داره؟ چون اون حالت برای شرایط من مطلوب تر هست. کدهای اتصال یونیتی به sql server رو هم از نت پیدا کردم منتها فقط با همین قسمت که باید اشیا فرزند تصویر هدف باشن مشکل دارم.
    خیلی ممنونم

    • در مورد بخش اول : این کار نشدنی است یا حداقل من بلد نیستم، چون هر گیم آبجکتی که وارد موتور می شود دارای بخش های مختلف از جمله مش، متریال و یکسری تنظیمات Import هستش، نمیشه مستقیما بدون Import کردن و بدون متریال چیزی به فضای بازی اضافه کرد. در نتیجه گیم آبجکت را نمی شود در دیتابیس قرار داد و حتی هم اگر بشود کار خوبی نیست.
      و اما در مورد بخش دوم : دیتابیسی که توی این آموزش در موردش صحبت شده یک دیتابیس لوکال هستش و در واقع این دیتابیس روی گوشی هست نه روی سرور! چیزی که شما می خواهید متفاوت است. به طور کلی وصل شدن مستقیم کلاینت به دیتابیس اصلا معماری درستی نیست و به شدت مشکل امنیتی دارد. کلاینت باید به یک برنامه در سمت سرور وصل شود و این برنامه سمت سرور هست که باید با دیتابیس صحبت کند.
      در نهایت پاسخ به سوال اصلی شما :
      شما یک سیستم AR می خواهید درست کنید که بشود تارگت ها و محتوای افزوده اون رو به صورت آنلاین عوض کرد بدون تغییر کلاینت. در هر صورت باید کلاینت تارگت ها و محتوا ها را دریافت کند منتها این کار باید به صورت نا محسوس انجام شود.
      راه حل های پیش روی شما :
      1- خود سیستم هایی که SDK واقعیت افزوده تولید می کنند این قابلیت رو به صورت جداگانه روی ابر خودشون ارائه می کنند با پرداخت هزینه این کار.
      2- استفاده از Asset Bundle ها در یونیتی. به کمک Asset Bundle شما می توانید داده های بازی خود را اپدیت کنید(تقریبا شامل هر چیزی می شود).
      3- راه های پیچیده تر که از نه بنده بلدم و نه شما حوصله اش رو دارید 🙂

  • نه…فکر کنم منظورم رو بد گفتم. نکته اول اینه که اشیای من به اون صورت رایج تو یونیتی نیست چیزای ساده ای که تو دیتا بیس میشه گذاشتشون متن و فیلم و عکسه. نکته دوم : من به سرور نمیخوام وصل بشم sql server رو روی لپتاپم دارم . کد اتصال یونیتی به sql server رو هم دارم. تصویر هدفم رو هم نمیخوام تغییر بدم فقط میخوام بشه محتوای نمایش داده شده رو تغییر داد. اما اگر برای این کار هم احتیاج به این راه حل ها هست من همین رو پیگیری میکنم.
    خیلی ممنونم از شما

    • البته من به شخصه عکس رو هم توی دیتابیس نمی گذارم. از مطلب بعدی تون متوجه شدم که پروژه یک پروژه دانشجوییه 🙂 ، با توجه به شرایط برای قرار دادن عکس و متن کافیه که به اون آبجکتی که فرزند تصویر هدف هست چند تا کامپوننت مختلف (Text , SpriteRenderer) داد و با توجه به آیتمی که می خواهید لود کنید کامپوننت مد نظرتون رو فعال و باقی کامپوننت ها رو غیرفعال کنید تا محتوای مد نظرتون نمایش داده بشه.

  • بله پروژه دانشجویی هست ولی خوب دیتابیسش لازمه …خیلی ممنونم از راهنمایی شما. پس به هر حال من مجبورم فیلم و عکسها رو موقع ساخت برنامه تو محیط یونیتی بیارم برای اینکه فرزند تصویر هدف قرارش بدم؟ راهی نداره که به صورت داینامیک از دیتا بیس بگیره و فرزند تصویر هدفم قرار بده؟

    • آسون ترین راه همون Asset Bundle هستش
      البته یه راه سخت هم هست که باید یک وب سرور راه اندازی کنید(لزوما نه روی سرور بلکه روی سیستم خودتون هم میشه) بعد فیلم ها و عکس ها را روی اون قرار بدید ، لینک اون ها رو در دیتابیس بگذارید، با یونیتی فایلها رو از فایل سرور دانلود کنید و تبدیل به محتوای مد نظر خودتون کنید.

  • سلام . ببخشید من درباره ی راه حل شما تحقیق کردم فقط یک سوال کوچیک داشتم. الان برنامه ی من یک تصویر هدف داره و چند تا شی با button به صورت ترتیبی روش نمایش داده میشن. با استفاده از این روش asset bundle همچنان میشه این کارو انجام داد یا کلا فقط یک شی میتونم نمایش بدم؟ این رو متوجه نشدم

  • سلام و خسته نباشید
    ببخشید که من سوالم رو اینجا میپرسم با اونکه شاید بازم خیلی مرتبط نباشه…اگر سایت دیگه ای یا راه ارتباطی دیگری هست بفرمایید که من از همونجا سوالم رو مطرح کنم.
    راستش من درباره ی همین بحث assetbundle ها سوال دارم. الان خیلی وقته که دارم تحقیق میکنم ولی متاسفانه به نتیجه ای نرسیدم. خود یونیتی یک پکیج داره برای اینکار که دانلود نمیشه و از محیط است استورش نمیشه تو یونیتی استفاده کرد به خاطر تحریم.
    بعد یکسری آپدبت و کدهای دیگه مرتبط با است باندل پیدا کردم که بیشتر مربوط به برنامه های ویندوزی بودن اما اپلیکیشن واقعیت افزوده ی من برای اندروید هست . تو ووفوریا هم سرچ کردم برای است باندل و کدی که پیدا شد ( فکر میکنم که برای اندروید باشه با توجه به کاری که ووفوریا انجام میده) تو محیط یونیتی کار نمیکرد. و یا اگر هم اسکریپتش ارور نده موقع بیلد کردن ارور کامپایل میده. من میخواستم بپرسم که از این روش برای اپ های اندروید هم میشه استفاده کرد یا نه…چون واقعا گیج شدم و نمیدونم ایراد از کجا میتونه باشه.
    خیلی ممنونم

  • سلام
    ممنون از شما آقای سجودی
    در مورد خذف باید چکار کنیم در کلاس تست یک نمونه delete را هم بگذارید یا همین جا در جواب بنویسید ممنون
    سپاس از شما

اضافه کردن دیدگاه

1 + 12 =