Сегодня мы разберёмся как подключить проект на Unity3D к БД MySQL.
Если точнее, то мы разберём как сохранять в БД состояния игровых объектов, а затем загружать их из БД. За основу взят гайд Джонатана Вуда для Unity 3.0.0f5 и MySQL 5.2.28. Он дополнен и адаптирован для 4-й версии Юнити.
Нам понадобятся:
1. Unity3D 4.x.
2. Доступ к БД MySQL.
3. Библиотека MySql.Data.dll.
В папке с проектом необходимо создать каталог Libraries, в который необходимо поместить библиотеку MySQL.Data.dll. Её можно скачать из этого архива, но если у вас уже установлен MySQL, то можете скопировать из c:\Program Files (x86)\MySQL\MySQL Connector Net 6.0.3\Assemblies\.
Чтобы избежать проблем совместимости версий сборок, а также сэкономить себе несколько часов времени и нервов (спасибо Джоэлю) установите уровень API совместимости Edit —> Project Settings —> Player —>Optimization—>Api Compatibility Level = .NET 2.0.
Предварительная работа:
1. Объекты состояние, которых необходимо сохранять помечаем тэгом «Savable».
2. Создаём таблицу в БД, в которой будет храниться информация об объектах.
Чтобы пользоваться новой библиотекой добавьте в начало скрипта:
using MySql.Data; using MySql.Data.MySqlClient;
А также не забудьте прописать параметры подключения в переменную:
// MySQL настройки string constr = "Server=localhost;Database=demo;User ID=demo;Password=demo;Pooling=true;CharSet=utf8;";
Создаём структуру, в которой будет храниться информация об объектах:
// Названия синхронизируемых полей таблицы в БД string ID, Name, levelname, objectType; float posx, posy, posz, tranx, trany, tranz; // описание структуры синхронизируемых данных public struct data { public int UID; public string ID, Name, levelname, objectType; public float posx, posy, posz, tranx, trany, tranz; } // коллекция в которую будут записываться данные о синхронизируемых объектах List<data> _GameItems;
При запуске скрипт подключается к БД, а при выключении разрывает соединение:
void Awake() { try { // установка элемента соединения con = new MySqlConnection(constr); // посмотрим, сможем ли мы установить соединение con.Open(); Debug.Log("Connection State: " + con.State); } catch (IOException ex) {Debug.Log(ex.ToString());} } void OnApplicationQuit() { Debug.Log("killing con"); if (con != null) { // Конечно, правильнее использовать: // if (con.State != ConnectionState.Closed) // но из-за проблем с версиями сборок приходится использовать костыли if (con.State.ToString()!="Closed") con.Close(); con.Dispose(); } }
Есть две процедуры, отвечающие за работу со объектами на сцене:
/// Этот метод подготавливает данные для записи в БД void prepData() { bodies = GameObject.FindGameObjectsWithTag("Savable"); _GameItems = new List<data>(); data itm; foreach (GameObject body in bodies) { itm = new data(); itm.ID = body.name + "_" + body.GetInstanceID(); itm.Name = body.name; itm.levelname = Application.loadedLevelName; itm.objectType = body.name.Replace("(Clone)", ""); itm.posx = body.transform.position.x; itm.posy = body.transform.position.y; itm.posz = body.transform.position.z; itm.tranx = body.transform.rotation.x; itm.trany = body.transform.rotation.y; itm.tranz = body.transform.rotation.z; _GameItems.Add(itm); } Debug.Log("Items in collection: " + _GameItems.Count); } }
/// Этот метод устанавливает загруженные объекты на сцене void loadData() { // Удаляем все лишние объекты со сцены bodies = GameObject.FindGameObjectsWithTag("Savable"); DestroyObject(bodies); // Создаём сохранённые в БД объекты if (_GameItems != null) { if (_GameItems.Count > 0) { foreach (data itm in _GameItems) { if (itm.objectType="CUBE") {Instantiate(mCUBE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} else if (itm.objectType="SPHERE") {Instantiate(mSPHERE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} else if (itm.objectType="TRIANGLE") {Instantiate(mTRIANGLE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} } } } } }
А также четыре основных процедуры, отвечающие за работу с БД:
// Вставка новой записи в таблицу void InsertEntries() { prepData(); string query = string.Empty; // Вылавливаем ошибки try { query = "INSERT INTO demo_table (ID, Name, levelname, objectType, posx, posy, posz, tranx, trany, tranz) VALUES (?ID, ?Name, ?levelname, ?objectType, ?posx, ?posy, ?posz, ?tranx, ?trany, ?tranz)"; if (con.State.ToString()!="Open") con.Open(); using (con) { foreach (data itm in _GameItems) { using (cmd = new MySqlCommand(query, con)) { MySqlParameter oParam = cmd.Parameters.Add("?ID", MySqlDbType.VarChar); oParam.Value = itm.ID; MySqlParameter oParam1 = cmd.Parameters.Add("?Name", MySqlDbType.VarChar); oParam1.Value = itm.Name; MySqlParameter oParam2 = cmd.Parameters.Add("?levelname", MySqlDbType.VarChar); oParam2.Value = itm.levelname; MySqlParameter oParam3 = cmd.Parameters.Add("?objectType", MySqlDbType.VarChar); oParam3.Value = itm.objectType; MySqlParameter oParam4 = cmd.Parameters.Add("?posx", MySqlDbType.Float); oParam4.Value = itm.posx; MySqlParameter oParam5 = cmd.Parameters.Add("?posy", MySqlDbType.Float); oParam5.Value = itm.posy; MySqlParameter oParam6 = cmd.Parameters.Add("?posz", MySqlDbType.Float); oParam6.Value = itm.posz; MySqlParameter oParam7 = cmd.Parameters.Add("?tranx", MySqlDbType.Float); oParam7.Value = itm.tranx; MySqlParameter oParam8 = cmd.Parameters.Add("?trany", MySqlDbType.Float); oParam8.Value = itm.trany; MySqlParameter oParam9 = cmd.Parameters.Add("?tranz", MySqlDbType.Float); oParam9.Value = itm.tranz; cmd.ExecuteNonQuery(); } } } } catch (IOException ex) { Debug.Log(ex.ToString()); } finally {} }
// Обновление существующих записей в таблице void UpdateEntries() { prepData(); string query = string.Empty; // Вылавливаем ошибки try { query = "UPDATE demo_table SET ID=?ID, Name=?Name, levelname=?levelname, objectType=?objectType, posx=?posx, posy=?posy, posz=?posz, tranx=?tranx, trany=?trany, tranz=?tranz WHERE iddemo_table=?UID"; if (con.State.ToString()!="Open") con.Open(); using (con) { foreach (data itm in _GameItems) { using (cmd = new MySqlCommand(query, con)) { MySqlParameter oParam = cmd.Parameters.Add("?ID", MySqlDbType.VarChar); oParam.Value = itm.ID; MySqlParameter oParam1 = cmd.Parameters.Add("?Name", MySqlDbType.VarChar); oParam1.Value = itm.Name; MySqlParameter oParam2 = cmd.Parameters.Add("?levelname", MySqlDbType.VarChar); oParam2.Value = itm.levelname; MySqlParameter oParam3 = cmd.Parameters.Add("?objectType", MySqlDbType.VarChar); oParam3.Value = itm.objectType; MySqlParameter oParam4 = cmd.Parameters.Add("?posx", MySqlDbType.Float); oParam4.Value = itm.posx; MySqlParameter oParam5 = cmd.Parameters.Add("?posy", MySqlDbType.Float); oParam5.Value = itm.posy; MySqlParameter oParam6 = cmd.Parameters.Add("?posz", MySqlDbType.Float); oParam6.Value = itm.posz; MySqlParameter oParam7 = cmd.Parameters.Add("?tranx", MySqlDbType.Float); oParam7.Value = itm.tranx; MySqlParameter oParam8 = cmd.Parameters.Add("?trany", MySqlDbType.Float); oParam8.Value = itm.trany; MySqlParameter oParam9 = cmd.Parameters.Add("?tranz", MySqlDbType.Float); oParam9.Value = itm.tranz; cmd.ExecuteNonQuery(); } } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} }
// Удаляем запись из таблицы void DeleteEntries() { string query = string.Empty; // Вылавливаем ошибки try { // лучше всего если вы знаете ID записи, которую необходимо удалить //----------------------------------------------------------------------- // query = "DELETE FROM demo_table WHERE iddemo_table=?UID"; // MySqlParameter oParam = cmd.Parameters.Add("?UID", MySqlDbType.Int32); // oParam.Value = 0; //----------------------------------------------------------------------- query = "DELETE FROM demo_table WHERE iddemo_table"; if (con.State.ToString()!="Open") con.Open(); using (con) { using (cmd = new MySqlCommand(query, con)) { cmd.ExecuteNonQuery(); } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} }
// Чтение всех записей из таблицы void ReadEntries() { string query = string.Empty; if (_GameItems == null) _GameItems = new List<data>(); if (_GameItems.Count > 0) _GameItems.Clear(); // Отлавливаем ошибки try { query = "SELECT * FROM view_demo"; if (con.State.ToString()!="Open") con.Open(); using (con) { using (cmd = new MySqlCommand(query, con)) { rdr = cmd.ExecuteReader(); if(rdr.HasRows) while (rdr.Read()) { data itm = new data(); itm.UID = int.Parse(rdr["iddemo_table"].ToString()); itm.ID = rdr["ID"].ToString(); itm.levelname = rdr["levelname"].ToString(); itm.Name = rdr["Name"].ToString(); itm.objectType = rdr["objectType"].ToString(); itm.posx = float.Parse(rdr["posx"].ToString()); itm.posy = float.Parse(rdr["posy"].ToString()); itm.posz = float.Parse(rdr["posz"].ToString()); itm.tranx = float.Parse(rdr["tranx"].ToString()); itm.trany = float.Parse(rdr["trany"].ToString()); itm.tranz = float.Parse(rdr["tranz"].ToString()); _GameItems.Add(itm); } rdr.Dispose(); } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} }
Остаётся только сделать пару кнопок для загрузки и сохранения сцены:
// Кнопки загрузки и сохранения void OnGUI() { if (GUI.Button(new Rect(10, 70, 50, 30), "Save") && !saving) { saving = true; // Для начала очистим таблицу DeleteEntries(); // теперь сохраним информацию о сцене InsertEntries(); // можно также использовать обновление если известен ID уже сохранённого элемента saving = false; } if (GUI.Button(new Rect(10, 110, 50, 30), "Load") && !loading) { loading = true; // считаем информацию из БД ReadEntries(); // создадим загруженные объекты loadData(); // теперь отобразим информацию из лога LogGameItems(); loading = false; } }
Вот в общем-то и всё. В комментах приветствуются примечания и дополнения.
using UnityEngine; using MySql.Data; using MySql.Data.MySqlClient; using System.IO; using System.Collections; using System.Collections.Generic; public class MySQLCS : MonoBehaviour { public GameObject mCUBE; public GameObject mSPHERE; public GameObject mTRIANGLE; bool saving = false; bool loading = false; // MySQL настройки string constr = "Server=localhost;Database=demo;User ID=demo;Password=demo;Pooling=true;CharSet=utf8;"; // соединение MySqlConnection con = null; // команда к БД MySqlCommand cmd = null; // чтение MySqlDataReader rdr = null; // ошибки MySqlError er = null; // массив синхронизируемых игровых объектов GameObject[] bodies; // Названия синхронизируемых полей таблицы в БД string ID, Name, levelname, objectType; float posx, posy, posz, tranx, trany, tranz; // описание структуры синхронизируемых данных public struct data { public int UID; public string ID, Name, levelname, objectType; public float posx, posy, posz, tranx, trany, tranz; } // коллекция в которую будут записываться данные о синхронизируемых объектах List<data> _GameItems; void Awake() { try { // установка элемента соединения con = new MySqlConnection(constr); // посмотрим, сможем ли мы установить соединение con.Open(); Debug.Log("Connection State: " + con.State); } catch (IOException ex) {Debug.Log(ex.ToString());} } void OnApplicationQuit() { Debug.Log("killing con"); if (con != null) { // Конечно, правильнее использовать: // if (con.State != ConnectionState.Closed) // но из-за проблем с версиями сборок приходится использовать костыли if (con.State.ToString()!="Closed") con.Close(); con.Dispose(); } } // Use this for initialization void Start() { } // Update is called once per frame void Update() { } // Кнопки загрузки и сохранения void OnGUI() { if (GUI.Button(new Rect(10, 70, 50, 30), "Save") && !saving) { saving = true; // Для начала очистим таблицу DeleteEntries(); // теперь сохраним информацию о сцене InsertEntries(); // можно также использовать обновление если известен ID уже сохранённого элемента saving = false; } if (GUI.Button(new Rect(10, 110, 50, 30), "Load") && !loading) { loading = true; // считаем информацию из БД ReadEntries(); // создадим загруженные объекты loadData(); // теперь отобразим информацию из лога LogGameItems(); loading = false; } } // Вставка новой записи в таблицу void InsertEntries() { prepData(); string query = string.Empty; // Вылавливаем ошибки try { query = "INSERT INTO demo_table (ID, Name, levelname, objectType, posx, posy, posz, tranx, trany, tranz) VALUES (?ID, ?Name, ?levelname, ?objectType, ?posx, ?posy, ?posz, ?tranx, ?trany, ?tranz)"; if (con.State.ToString()!="Open") con.Open(); using (con) { foreach (data itm in _GameItems) { using (cmd = new MySqlCommand(query, con)) { MySqlParameter oParam = cmd.Parameters.Add("?ID", MySqlDbType.VarChar); oParam.Value = itm.ID; MySqlParameter oParam1 = cmd.Parameters.Add("?Name", MySqlDbType.VarChar); oParam1.Value = itm.Name; MySqlParameter oParam2 = cmd.Parameters.Add("?levelname", MySqlDbType.VarChar); oParam2.Value = itm.levelname; MySqlParameter oParam3 = cmd.Parameters.Add("?objectType", MySqlDbType.VarChar); oParam3.Value = itm.objectType; MySqlParameter oParam4 = cmd.Parameters.Add("?posx", MySqlDbType.Float); oParam4.Value = itm.posx; MySqlParameter oParam5 = cmd.Parameters.Add("?posy", MySqlDbType.Float); oParam5.Value = itm.posy; MySqlParameter oParam6 = cmd.Parameters.Add("?posz", MySqlDbType.Float); oParam6.Value = itm.posz; MySqlParameter oParam7 = cmd.Parameters.Add("?tranx", MySqlDbType.Float); oParam7.Value = itm.tranx; MySqlParameter oParam8 = cmd.Parameters.Add("?trany", MySqlDbType.Float); oParam8.Value = itm.trany; MySqlParameter oParam9 = cmd.Parameters.Add("?tranz", MySqlDbType.Float); oParam9.Value = itm.tranz; cmd.ExecuteNonQuery(); } } } } catch (IOException ex) { Debug.Log(ex.ToString()); } finally {} } // Обновление существующих записей в таблице void UpdateEntries() { prepData(); string query = string.Empty; // Вылавливаем ошибки try { query = "UPDATE demo_table SET ID=?ID, Name=?Name, levelname=?levelname, objectType=?objectType, posx=?posx, posy=?posy, posz=?posz, tranx=?tranx, trany=?trany, tranz=?tranz WHERE iddemo_table=?UID"; if (con.State.ToString()!="Open") con.Open(); using (con) { foreach (data itm in _GameItems) { using (cmd = new MySqlCommand(query, con)) { MySqlParameter oParam = cmd.Parameters.Add("?ID", MySqlDbType.VarChar); oParam.Value = itm.ID; MySqlParameter oParam1 = cmd.Parameters.Add("?Name", MySqlDbType.VarChar); oParam1.Value = itm.Name; MySqlParameter oParam2 = cmd.Parameters.Add("?levelname", MySqlDbType.VarChar); oParam2.Value = itm.levelname; MySqlParameter oParam3 = cmd.Parameters.Add("?objectType", MySqlDbType.VarChar); oParam3.Value = itm.objectType; MySqlParameter oParam4 = cmd.Parameters.Add("?posx", MySqlDbType.Float); oParam4.Value = itm.posx; MySqlParameter oParam5 = cmd.Parameters.Add("?posy", MySqlDbType.Float); oParam5.Value = itm.posy; MySqlParameter oParam6 = cmd.Parameters.Add("?posz", MySqlDbType.Float); oParam6.Value = itm.posz; MySqlParameter oParam7 = cmd.Parameters.Add("?tranx", MySqlDbType.Float); oParam7.Value = itm.tranx; MySqlParameter oParam8 = cmd.Parameters.Add("?trany", MySqlDbType.Float); oParam8.Value = itm.trany; MySqlParameter oParam9 = cmd.Parameters.Add("?tranz", MySqlDbType.Float); oParam9.Value = itm.tranz; cmd.ExecuteNonQuery(); } } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} } // Удаляем запись из таблицы void DeleteEntries() { string query = string.Empty; // Вылавливаем ошибки try { // лучше всего если вы знаете ID записи, которую необходимо удалить //----------------------------------------------------------------------- // query = "DELETE FROM demo_table WHERE iddemo_table=?UID"; // MySqlParameter oParam = cmd.Parameters.Add("?UID", MySqlDbType.Int32); // oParam.Value = 0; //----------------------------------------------------------------------- query = "DELETE FROM demo_table WHERE iddemo_table"; if (con.State.ToString()!="Open") con.Open(); using (con) { using (cmd = new MySqlCommand(query, con)) { cmd.ExecuteNonQuery(); } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} } // Чтение всех записей из таблицы void ReadEntries() { string query = string.Empty; if (_GameItems == null) _GameItems = new List<data>(); if (_GameItems.Count > 0) _GameItems.Clear(); // Отлавливаем ошибки try { query = "SELECT * FROM view_demo"; if (con.State.ToString()!="Open") con.Open(); using (con) { using (cmd = new MySqlCommand(query, con)) { rdr = cmd.ExecuteReader(); if(rdr.HasRows) while (rdr.Read()) { data itm = new data(); itm.UID = int.Parse(rdr["iddemo_table"].ToString()); itm.ID = rdr["ID"].ToString(); itm.levelname = rdr["levelname"].ToString(); itm.Name = rdr["Name"].ToString(); itm.objectType = rdr["objectType"].ToString(); itm.posx = float.Parse(rdr["posx"].ToString()); itm.posy = float.Parse(rdr["posy"].ToString()); itm.posz = float.Parse(rdr["posz"].ToString()); itm.tranx = float.Parse(rdr["tranx"].ToString()); itm.trany = float.Parse(rdr["trany"].ToString()); itm.tranz = float.Parse(rdr["tranz"].ToString()); _GameItems.Add(itm); } rdr.Dispose(); } } } catch (IOException ex) {Debug.Log(ex.ToString());} finally {} } /// Запишем в лог всё что было считано из БД void LogGameItems() { if (_GameItems != null) { if (_GameItems.Count > 0) { foreach (data itm in _GameItems) { Debug.Log("UID: " + itm.UID); Debug.Log("ID: " + itm.ID); Debug.Log("levelname: " + itm.levelname); Debug.Log("Name: " + itm.Name); Debug.Log("objectType: " + itm.objectType); Debug.Log("posx: " + itm.posx); Debug.Log("posy: " + itm.posy); Debug.Log("posz: " + itm.posz); Debug.Log("tranx: " + itm.tranx); Debug.Log("trany: " + itm.trany); Debug.Log("tranz: " + itm.tranz); } } } } /// Этот метод подготавливает данные для записи в БД void prepData() { bodies = GameObject.FindGameObjectsWithTag("Savable"); _GameItems = new List<data>(); data itm; foreach (GameObject body in bodies) { itm = new data(); itm.ID = body.name + "_" + body.GetInstanceID(); itm.Name = body.name; itm.levelname = Application.loadedLevelName; itm.objectType = body.name.Replace("(Clone)", ""); itm.posx = body.transform.position.x; itm.posy = body.transform.position.y; itm.posz = body.transform.position.z; itm.tranx = body.transform.rotation.x; itm.trany = body.transform.rotation.y; itm.tranz = body.transform.rotation.z; _GameItems.Add(itm); } Debug.Log("Items in collection: " + _GameItems.Count); } } /// Этот метод устанавливает загруженные объекты на сцене void loadData() { // Удаляем все лишние объекты со сцены bodies = GameObject.FindGameObjectsWithTag("Savable"); DestroyObject(bodies); // Создаём сохранённые в БД объекты if (_GameItems != null) { if (_GameItems.Count > 0) { foreach (data itm in _GameItems) { if (itm.objectType="CUBE") {Instantiate(mCUBE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} else if (itm.objectType="SPHERE") {Instantiate(mSPHERE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} else if (itm.objectType="TRIANGLE") {Instantiate(mTRIANGLE, new Vector3(itm.posx, itm.posy , itm.posz),Quaternion.Euler(itm.tranx, itm.trany, itm.tranz));} } } } } }
ссылка на оригинал статьи http://habrahabr.ru/post/185594/
Добавить комментарий