Unity简单商城系统案例
- 流程
- 最后效果展示
- 1. 创建项目并导入SQLite需要的dll文件
- 2. 创建数据库表(玩家表和商店表)
- 3. Singleton 单例脚本
- 4. 封装SQLite数据库的操作方法(SQLiteManager 脚本)
- 5. 基于 SQLiteManager脚本进行二次封装(ShopManager 脚本)
-
- 5-1. 买装备的方法实现
- 5-2. 卖装备方法的实现
- 5-3. ShopManager 脚本内容
- 6. 测试买/卖装备
-
- 6-1.买装备
- 6-2. 卖装备
- 7. UI的搭建
- 8. 生成商城图片
- 9. 装备图片脚本
- 10. 玩家信息的初始化和更新
- 11. 购买装备的点击事件
- 12. 出售装备的点击事件
- 13. 最后效果
不会在Unity使用SQLite数据库可以看一下这篇文章Unity2021中使用SQLite数据库
流程
- 封装数据库方法脚本(打开数据库,关闭数据库,增删改,查单个数据,查多个数据)
- 根据数据库脚本再封装一个买装备卖装备的脚本(获取英雄名称,金钱,属性,背包中的装备、获取装备的价格,属性、属性的相加/相减,更新玩家金钱,属性,身上的装备到数据库中)
- 商店系统脚本实现(商店初始化)
- 玩家数据脚本实现(更新玩家的名称,金钱,属性到UI界面中)
- 商店格子的脚本和背包格子的脚本实现(点击买装备或卖装备)
最后效果展示
1. 创建项目并导入SQLite需要的dll文件
将需要3个dll文件导入到 Plugins 文件夹中
mono.data.sqlite.dll,System.data.dll,sqlite3.dll
2. 创建数据库表(玩家表和商店表)
- 打开可视化工具创建数据库并添加两个表(玩家表和商城表)
- 玩家表(玩家拥有的装备保存格式:在每个装备之间用 # 分割 –> 例: 幽梦#电刀#)
- 商城表
3. Singleton 单例脚本
使用: 别的脚本只需要继承 Singleton脚本 并创造一个私有的构造函数即可
例:public class Test : Singleton<Test> // 继承{private Test(){} // 私有构造}```
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Singleton<T> where T : class
{private static T instance;public static T Instance{get{if(instance == null){instance = (T)Activator.CreateInstance(typeof(T), true);}return instance;}}
}
4. 封装SQLite数据库的操作方法(SQLiteManager 脚本)
继承与 Singleton脚本, 别的脚本可以通过 SQLiteManager.Instance 来访问当前脚本的方法
封装的方法:
- 打开数据库
- 关闭数据库
- 非查询语句的执行
3-1. 插入语句
3-2. 更新语句
3-3. 删除语句- 查询单个数据的执行方法
- 查询多个数据的执行方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mono.Data.Sqlite;public class SQLiteManager : Singleton<SQLiteManager>
{protected SQLiteManager() { }private SqliteConnection con;private SqliteCommand command;private SqliteDataReader reader;// 打开数据库public void OpenDatabase(string fileName){if(!fileName.EndsWith(".db")){fileName += ".db";}string path = "Data Source=" + Application.streamingAssetsPath + "/" + fileName;con = new SqliteConnection(path);con.Open();}// 关闭数据库public void CloseDatabase(){if(reader != null){reader.Close();reader = null;}if(command != null){command.Dispose();command = null;}if(con != null){con.Close();con = null;}}// 非查询语句执行private int NonQuery(string query){if (command != null){command.Dispose();command = null;}command = con.CreateCommand();command.CommandText = query;return command.ExecuteNonQuery();}// 添加public int Insert(string query){return NonQuery(query);}// 更新public int Update(string query){return NonQuery(query);}// 删除public int Delete(string query){return NonQuery(query);}// 查询单个数据public object SelectSingleData(string query){if (command != null){command.Dispose();command = null;}command = con.CreateCommand();command.CommandText = query;return command.ExecuteScalar();}// 查询多个数据public List<ArrayList> SelectMultipleData(string query){if (command != null){command.Dispose();command = null;}if (reader != null){reader.Close();reader = null;}command = con.CreateCommand();command.CommandText = query;reader = command.ExecuteReader();List<ArrayList> result = new List<ArrayList>();while(reader.Read()){ArrayList list = new ArrayList();for(int i = 0; i < reader.FieldCount; i++){list.Add(reader.GetValue(i));}result.Add(list);}return result;}}
5. 基于 SQLiteManager脚本进行二次封装(ShopManager 脚本)
封装的方法:
- 更新玩家身上的装备
- 获取玩家身上的装备
- 更新玩家属性到数据库中
- 玩家添加或移除装备属性
- 获取玩家的属性
- 获取装备属性
- 更新玩家的钱到数据库中
- 获取玩家身上的钱
- 获取装备价格
封装的方法:
// 更新玩家身上的装备
public void SetPlayerEquips(string playerName, string equips)
{query = "update playertable set equips='" + equips + "' where name = '" + playerName + "'";Update(query);
}// 获取玩家身上的装备
public string GetPlayerEquips(string playerName)
{query = "select equips from playertable where name = '" + playerName + "'";object obj = SelectSingleData(query);if(obj == null){return null;}return obj.ToString();
}// 更新玩家属性到数据库中
public void SetPlayerProperties(string playerName, int[] properties)
{query = "update playertable set ad = " + properties[0] + ", ap = " + properties[1] + ", ar = " + properties[2] + ", sr = " + properties[3] + " where name = '" + playerName + "'";Update(query);
}// 玩家添加或移除装备属性, 参数3,传入1:Add,2:Remove
public int[] PlayerAddOrRemoveProperties(int[] playerProperties, int[] equipProperties, int operation)
{int[] result = new int[playerProperties.Length];if(operation == 1){for(int i = 0; i < result.Length; i++){result[i] = playerProperties[i] + equipProperties[i];}}else if(operation == 2){for(int i = 0; i < result.Length; i++){result[i] = playerProperties[i] - equipProperties[i];}}return result;
}// 获取玩家的属性
public int[] GetPlayerProperties(string playerName)
{query = "select * from playertable where name = '" + playerName + "'";List<ArrayList> arrayLists = SelectMultipleData(query);int[] properties = new int[4];for(int i = 0; i < properties.Length; i++){properties[i] = Convert.ToInt32(arrayLists[0][i + 3]);}return properties;
}// 获取装备属性
public int[] GetEquipProperties(string equipName)
{query = "select * from shoptable where name = '" + equipName + "'";List<ArrayList> arrayLists = SelectMultipleData(query);int[] properties = new int[4];for (int i = 0; i < properties.Length; i++){properties[i] = Convert.ToInt32(arrayLists[0][i + 3]);}return properties;
}// 更新玩家的钱到数据库中
public void SetPlayerMoney(string playerName, int money)
{query = "Update playertable set money = " + money + " where name = '" + playerName + "'";Update(query);
}// 获取玩家身上的钱
public int GetPlayerMoney(string playerName)
{query = "select money from playertable where name = '" + playerName + "'";object obj = SelectSingleData(query);return Convert.ToInt32(obj);
}// 获取装备价格
public int GetEquipPrice(string equipName)
{query = "select price from shoptable where name = '" + equipName + "'";object obj = SelectSingleData(query);return Convert.ToInt32(obj);}
5-1. 买装备的方法实现
- 查看装备价格,玩家身上的钱
- 判断玩家身上的钱是否大于装备的价格
- 不够前就不能买(return),够钱了就给玩家购买
- 获取装备属性,获取玩家的属性, 属性相加形成新的值, 更新到玩家表中,
- 将装备名称拼接到玩家装备字符串上,将玩家装备保存到数据库中
- 扣除玩家的钱
// 买装备
public void BuyEquip(string playerName, string equipName)
{// 查看装备价格,玩家身上的钱int playerMoney = GetPlayerMoney(playerName);int equipPrice = GetEquipPrice(equipName);// 判断玩家身上的钱是否大于装备的价格,不够前就不能买(return)if (playerMoney < equipPrice){Debug.Log("钱不够");return;}// 够钱了就给玩家购买// 获取装备属性,获取玩家的属性, 属性相加形成新的值, 更新到玩家表中,int[] playerProperties = GetPlayerProperties(playerName);int[] equipProperties = GetEquipProperties(equipName);int[] newProperties = PlayerAddOrRemoveProperties(playerProperties, equipProperties, 1);SetPlayerProperties(playerName, newProperties);// 将装备名称拼接到玩家装备字符串上,将玩家装备保存到数据库中string playerEquips = GetPlayerEquips(playerName);playerEquips += equipName + "#";SetPlayerEquips(playerName, playerEquips);// 扣除玩家的钱SetPlayerMoney(playerName, playerMoney - equipPrice);
}
5-2. 卖装备方法的实现
- 获取玩家身上的钱和装备价格
- 获取玩家和装备的属性
- 移除玩家身上该装备的属性
- 更新玩家属性
- 获取玩家装备字符串
- 找到装备字符串中的下标,移除该装备
- 更新玩家装备
- 卖掉的装备是原价的一半,将玩家身上的钱加上该装备价格的一半的价钱
- 更新玩家的金钱
// 卖装备public void SellEquip(string playerName, string equipName){// 获取玩家身上的钱和装备价格int playerMoney = GetPlayerMoney(playerName);int equipPrice = GetEquipPrice(equipName);// 获取玩家和装备的属性int[] playerProperties = GetPlayerProperties(playerName);int[] equipProperties = GetEquipProperties(equipName);// 移除玩家身上该装备的属性int[] newPlayerProperties = PlayerAddOrRemoveProperties(playerProperties, equipProperties, 2);// 更新玩家属性SetPlayerProperties(playerName, newPlayerProperties);// 获取玩家装备字符串string playerEquips = GetPlayerEquips(playerName);// 找到装备字符串中的下标,移除该装备playerEquips = playerEquips.Remove(playerEquips.LastIndexOf(equipName), equipName.Length + 1); // 这里最后的加一是为将装备名字后面的 # 删除// 更新玩家装备SetPlayerEquips(playerName, playerEquips);// 卖掉的装备是原价的一半,将玩家身上的钱加上该装备价格的一半的价钱playerMoney += equipPrice / 2;// 更新玩家的金钱SetPlayerMoney(playerName, playerMoney);}
5-3. ShopManager 脚本内容
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ShopManager : SQLiteManager
{// 单例private static ShopManager instance;public static new ShopManager Instance{get{if(instance == null){instance = new ShopManager();}return instance;}}private ShopManager() { }private string query;// 买装备public void BuyEquip(string playerName, string equipName){// 查看装备价格,玩家身上的钱int playerMoney = GetPlayerMoney(playerName);int equipPrice = GetEquipPrice(equipName);// 判断玩家身上的钱是否大于装备的价格,不够前就不能买(return)if (playerMoney < equipPrice){Debug.Log("钱不够");return;}// 够钱了就给玩家购买// 获取装备属性,获取玩家的属性, 属性相加形成新的值, 更新到玩家表中,int[] playerProperties = GetPlayerProperties(playerName);int[] equipProperties = GetEquipProperties(equipName);int[] newProperties = PlayerAddOrRemoveProperties(playerProperties, equipProperties, 1);SetPlayerProperties(playerName, newProperties);// 将装备名称拼接到玩家装备字符串上,将玩家装备保存到数据库中string playerEquips = GetPlayerEquips(playerName);playerEquips += equipName + "#";SetPlayerEquips(playerName, playerEquips);// 扣除玩家的钱SetPlayerMoney(playerName, playerMoney - equipPrice);} // 卖装备public void SellEquip(string playerName, string equipName){// 获取玩家身上的钱和装备价格int playerMoney = GetPlayerMoney(playerName);int equipPrice = GetEquipPrice(equipName);// 获取玩家和装备的属性int[] playerProperties = GetPlayerProperties(playerName);int[] equipProperties = GetEquipProperties(equipName);// 移除玩家身上该装备的属性int[] newPlayerProperties = PlayerAddOrRemoveProperties(playerProperties, equipProperties, 2);// 更新玩家属性SetPlayerProperties(playerName, newPlayerProperties);// 获取玩家装备字符串string playerEquips = GetPlayerEquips(playerName);// 找到装备字符串中的下标,移除该装备playerEquips = playerEquips.Remove(playerEquips.LastIndexOf(equipName), equipName.Length + 1); // 这里最后的加一是为将装备名字后面的 # 删除// 更新玩家装备SetPlayerEquips(playerName, playerEquips);// 卖掉的装备是原价的一半,将玩家身上的钱加上该装备价格的一半的价钱playerMoney += equipPrice / 2;// 更新玩家的金钱SetPlayerMoney(playerName, playerMoney);}// 更新玩家身上的装备public void SetPlayerEquips(string playerName, string equips){query = "update playertable set equips='" + equips + "' where name = '" + playerName + "'";Update(query);}// 获取玩家身上的装备public string GetPlayerEquips(string playerName){query = "select equips from playertable where name = '" + playerName + "'";object obj = SelectSingleData(query);if(obj == null){return null;}return obj.ToString();}// 更新玩家属性到数据库中public void SetPlayerProperties(string playerName, int[] properties){query = "update playertable set ad = " + properties[0] + ", ap = " + properties[1] + ", ar = " + properties[2] + ", sr = " + properties[3] + " where name = '" + playerName + "'";Update(query);}// 玩家添加或移除装备属性, 参数3,传入1:Add,2:Removepublic int[] PlayerAddOrRemoveProperties(int[] playerProperties, int[] equipProperties, int operation){int[] result = new int[playerProperties.Length];if(operation == 1){for(int i = 0; i < result.Length; i++){result[i] = playerProperties[i] + equipProperties[i];}}else if(operation == 2){for(int i = 0; i < result.Length; i++){result[i] = playerProperties[i] - equipProperties[i];}}return result;}// 获取玩家的属性public int[] GetPlayerProperties(string playerName){query = "select * from playertable where name = '" + playerName + "'";List<ArrayList> arrayLists = SelectMultipleData(query);int[] properties = new int[4];for(int i = 0; i < properties.Length; i++){properties[i] = Convert.ToInt32(arrayLists[0][i + 3]);}return properties;}// 获取装备属性public int[] GetEquipProperties(string equipName){query = "select * from shoptable where name = '" + equipName + "'";List<ArrayList> arrayLists = SelectMultipleData(query);int[] properties = new int[4];for (int i = 0; i < properties.Length; i++){properties[i] = Convert.ToInt32(arrayLists[0][i + 3]);}return properties;}// 更新玩家的钱到数据库中public void SetPlayerMoney(string playerName, int money){query = "Update playertable set money = " + money + " where name = '" + playerName + "'";Update(query);}// 获取玩家身上的钱public int GetPlayerMoney(string playerName){query = "select money from playertable where name = '" + playerName + "'";object obj = SelectSingleData(query);return Convert.ToInt32(obj);}// 获取装备价格public int GetEquipPrice(string equipName){query = "select price from shoptable where name = '" + equipName + "'";object obj = SelectSingleData(query);return Convert.ToInt32(obj);}}
6. 测试买/卖装备
6-1.买装备
创建Test脚本(挂载在空对象)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Test : MonoBehaviour
{private void Start(){// 打开数据库ShopManager.Instance.OpenDatabase("ShopSystem");// 买装备ShopManager.Instance.BuyEquip("Akali", "电刀");}private void OnDestroy(){// 关闭数据库ShopManager.Instance.CloseDatabase();}
}
6-2. 卖装备
将Test脚本进行修改
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Test : MonoBehaviour
{private void Start(){// 打开数据库ShopManager.Instance.OpenDatabase("ShopSystem");// 买装备// ShopManager.Instance.BuyEquip("Akali", "电刀");// 卖装备ShopManager.Instance.SellEquip("Akali", "电刀");}private void OnDestroy(){ShopManager.Instance.CloseDatabase();}}
7. UI的搭建
背包和商城两个界面
8. 生成商城图片
// 获取商店里面所有的装备名称
public string[] GetShopEquipName()
{query = "select name from shoptable";List<ArrayList> obj = SelectMultipleData(query);string[] names = new string[obj.Count];for(int i = 0; i < names.Length; i++){// 每一行里面的名字保存在namesnames[i] = obj[i][0].ToString();}return names;
}
// 获取玩家名称
public string GetPlayerName()
{query = "select name from playertable";object obj = SelectSingleData(query);return obj.ToString();
}
4 初始化商店
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ShopWindow : MonoBehaviour
{private GameObject shopEquipPrefab;private void Awake(){// 加载预制体shopEquipPrefab = Resources.Load<GameObject>("Prefabs/ShopEquip");}private void Start(){// 打开数据库ShopManager.Instance.OpenDatabase("ShopSystem");ShopInit();}// 初始化商店private void ShopInit(){// 获取商店所有装备的名称string[] equipNames = ShopManager.Instance.GetShopEquipName();for(int i = 0; i < equipNames.Length; i++){// 实例化预制体,并修改其父对象GameObject go = Instantiate(shopEquipPrefab, transform.GetChild(i));go.transform.localPosition = Vector3.zero;go.transform.localScale = Vector3.one;// 获取装备图片Sprite sprite = Resources.Load<Sprite>("LOLicon/" + equipNames[i]);// 修改装备图片go.GetComponent<Image>().sprite = sprite;}}private void OnDestroy(){ShopManager.Instance.CloseDatabase();}}
9. 装备图片脚本
创建Equip脚本,挂载在装备图片预制体,让其生成出来的时候绑定点击事件,由于是在自身的脚本,获取到的button组件也是自身的。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Equip : MonoBehaviour
{public void Init(){GetComponent<Button>().onClick.AddListener(OnClickEvent);}// 按钮点击事件private void OnClickEvent(){}
}
调用自身的初始化方法是在 ShopWindow脚本生成装备的时候。
// 初始化商店private void ShopInit(){// 获取商店所有装备的名称string[] equipNames = ShopManager.Instance.GetShopEquipName();for(int i = 0; i < equipNames.Length; i++){// 实例化预制体,并修改其父对象GameObject go = Instantiate(prefab, transform.GetChild(i));go.transform.localPosition = Vector3.zero;go.transform.localScale = Vector3.one;// 获取装备图片Sprite sprite = Resources.Load<Sprite>("LOLicon/" + equipNames[i]);// 修改装备图片go.GetComponent<Image>().sprite = sprite;// 初始化装备图片go.GetComponent<Equip>().Init();}}
10. 玩家信息的初始化和更新
- 需要更新玩家名称,金钱,属性,装备
- 每一个玩家信息都封装成方法,然后通过一个方法来调用全部方法
- 需要给玩家背包加上BagEquip,也是获取按钮初始(跟上面一样)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class PlayerData : MonoBehaviour
{public static PlayerData instance;private GameObject bagEquipPrefab; // 背包装备private Transform bagEquipPrefabParent; // 背包装备的父对象private Text playerNameText; // 玩家名称文本private Text[] propertiesText; // 4个属性文本private Text moneyText; // 金钱文本[HideInInspector]public string playerName; // 玩家名称private void Awake(){instance = this;playerNameText = transform.Find("Name").GetComponent<Text>();moneyText = transform.Find("Money/Text").GetComponent<Text>();bagEquipPrefabParent = transform.Find("Bag/Item/Scroll View/Viewport/Content");propertiesText = new Text[4];for(int i = 0; i < propertiesText.Length; i++){propertiesText[i] = transform.Find("Values").GetChild(i).GetComponent<Text>();}// 加载预制体bagEquipPrefab = Resources.Load<GameObject>("Prefabs/BagEquip");}private void Start(){ShopManager.Instance.OpenDatabase("ShopSystem");UpdatePlayerData();}// 设置玩家名称文本private void SetPlayerName(){// 获取玩家名称playerName = ShopManager.Instance.GetPlayerName();// 修改文本playerNameText.text = playerName;}// 设置玩家属性文本private void SetPlayerProperties(){// 获取玩家属性int[] playerProperties = ShopManager.Instance.GetPlayerProperties(playerName);for(int i = 0; i < playerProperties.Length; i++){propertiesText[i].text = playerProperties[i].ToString();}}// 设置玩家金钱文本private void SetPlayerMoney(){int playerMoney = ShopManager.Instance.GetPlayerMoney(playerName);moneyText.text = playerMoney.ToString();}// 清空玩家装备private void ClearPlayerEquip(){for(int i = 0; i < bagEquipPrefabParent.childCount; i++){if(bagEquipPrefabParent.GetChild(i).childCount > 0){Destroy(bagEquipPrefabParent.GetChild(i).GetChild(0).gameObject);}}}// 设置玩家装备private void SetPlayerEquip(){string playerEquip = ShopManager.Instance.GetPlayerEquips(playerName);string[] playerEquips = playerEquip.Split(new char[] { '#' }); // 获取所有装备for(int i = 0; i < playerEquips.Length; i++){if (playerEquips[i] == "") continue;GameObject go = Instantiate(bagEquipPrefab, bagEquipPrefabParent.GetChild(i));go.transform.localPosition = Vector3.zero;go.transform.localScale = Vector3.one;// 获取图片Sprite sprite = Resources.Load<Sprite>("LOLicon/" + playerEquips[i]);// 设置图片go.GetComponent<Image>().sprite = sprite;go.GetComponent<BagEquip>().Init();}}// 更新玩家信息public void UpdatePlayerData(){SetPlayerName();SetPlayerProperties();SetPlayerMoney();ClearPlayerEquip();SetPlayerEquip();}private void OnDestroy(){ShopManager.Instance.CloseDatabase();}}
BagEquip
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class BagEquip : MonoBehaviour
{public void Init(){GetComponent<Button>().onClick.AddListener(OnClickEvent);}// 按钮点击事件private void OnClickEvent(){// 卖装备}}
11. 购买装备的点击事件
shopEquip身上的脚本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Equip : MonoBehaviour
{private string equip; // 要购买的装备private string playerName;public void Init(){GetComponent<Button>().onClick.AddListener(OnClickEvent);equip = GetComponent<Image>().sprite.name;}// 按钮点击事件private void OnClickEvent(){// 买装备先获取玩家名字playerName = PlayerData.instance.playerName;// 买装备ShopManager.Instance.BuyEquip(playerName, equip);// 买完装备更新玩家信息PlayerData.instance.UpdatePlayerData();}}
12. 出售装备的点击事件
BagEquip身上的脚本
using UnityEngine;
using UnityEngine.UI;public class BagEquip : MonoBehaviour
{private string playerName;private string equip; // 要卖掉的装备public void Init(){GetComponent<Button>().onClick.AddListener(OnClickEvent);equip = GetComponent<Image>().sprite.name;}// 按钮点击事件private void OnClickEvent(){playerName = PlayerData.instance.playerName;// 卖装备ShopManager.Instance.SellEquip(playerName, equip);PlayerData.instance.UpdatePlayerData();}}