Unity 开发实战:实现银行存取款功能系统
在许多游戏中,银行系统都是重要的经济组成部分,它能帮助玩家管理虚拟资产、实现安全存储。本文将详细介绍如何在 Unity 中设计并实现一个完整的银行存取款功能,包括数据结构设计、UI 交互逻辑和安全验证机制。
一、银行系统核心需求分析
一个基础的银行系统应包含以下核心功能:
账户余额查询
存款功能(将背包货币存入银行)
取款功能(从银行取出货币到背包)
交易记录保存
安全验证(可选,如密码保护)
在开始编码前,我们需要明确两个关键数据实体:玩家背包货币和银行账户,以及它们之间的交互规则。
二、数据结构设计
首先设计存储货币和交易记录的数据结构,建议使用 ScriptableObject 存储配置数据,使用普通类存储运行时数据。
1. 货币类型定义
csharp
运行
// 定义货币类型枚举public enum CurrencyType{
Gold, // 金币
Diamond, // 钻石
Crystal // 水晶}// 货币数据类[System.Serializable]public class CurrencyData{
public CurrencyType type;
public int amount;
public CurrencyData(CurrencyType type, int amount)
{
this.type = type;
this.amount = amount;
}}2. 交易记录类
csharp
运行
// 交易类型public enum TransactionType{
Deposit, // 存款
Withdraw // 取款}// 交易记录[System.Serializable]public class TransactionRecord{
public string transactionId; // 交易ID
public TransactionType type; // 交易类型
public CurrencyType currencyType; // 货币类型
public int amount; // 金额
public DateTime timestamp; // 时间戳
public TransactionRecord(TransactionType type, CurrencyType currencyType, int amount)
{
transactionId = System.Guid.NewGuid().ToString();
this.type = type;
this.currencyType = currencyType;
this.amount = amount;
timestamp = DateTime.Now;
}}3. 银行账户数据类
csharp
运行
public class BankAccountData{
public string accountId; // 账户ID
public List<CurrencyData> currencies = new List<CurrencyData>(); // 账户货币
public List<TransactionRecord> transactionHistory = new List<TransactionRecord>(); // 交易记录
public int maxTransactionRecords = 100; // 最大交易记录数
public BankAccountData(string accountId)
{
this.accountId = accountId;
// 初始化各种货币为0
foreach (CurrencyType type in Enum.GetValues(typeof(CurrencyType)))
{
currencies.Add(new CurrencyData(type, 0));
}
}
// 获取指定货币的余额
public int GetCurrencyAmount(CurrencyType type)
{
var currency = currencies.Find(c => c.type == type);
return currency != null ? currency.amount : 0;
}
// 更新货币余额
private void UpdateCurrencyAmount(CurrencyType type, int newAmount)
{
var currency = currencies.Find(c => c.type == type);
if (currency != null)
{
currency.amount = newAmount;
}
}
// 添加交易记录
private void AddTransactionRecord(TransactionRecord record)
{
transactionHistory.Add(record);
// 保持记录数量不超过最大值
if (transactionHistory.Count > maxTransactionRecords)
{
transactionHistory.RemoveAt(0);
}
}}三、银行系统核心逻辑实现
接下来实现银行系统的核心管理类,负责处理存取款业务逻辑。
1. 银行管理器(单例模式)
csharp
运行
using UnityEngine;using System.Collections.Generic;public class BankManager : MonoBehaviour{
public static BankManager Instance { get; private set; }
// 银行账户字典(key: 玩家ID)
private Dictionary<string, BankAccountData> playerAccounts = new Dictionary<string, BankAccountData>();
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
// 获取或创建玩家银行账户
public BankAccountData GetPlayerAccount(string playerId)
{
if (!playerAccounts.ContainsKey(playerId))
{
playerAccounts[playerId] = new BankAccountData(playerId);
}
return playerAccounts[playerId];
}
// 存款操作
public bool Deposit(string playerId, CurrencyType type, int amount, out string message)
{
message = "";
if (amount <= 0)
{
message = "存款金额必须大于0";
return false;
}
// 检查玩家背包中是否有足够的货币(需要与你的背包系统对接)
int playerCurrency = PlayerInventory.Instance.GetCurrencyAmount(type);
if (playerCurrency < amount)
{
message = "背包中货币不足";
return false;
}
// 获取玩家银行账户
var account = GetPlayerAccount(playerId);
// 更新银行余额
int currentBankAmount = account.GetCurrencyAmount(type);
account.UpdateCurrencyAmount(type, currentBankAmount + amount);
// 扣除玩家背包货币
PlayerInventory.Instance.SubtractCurrency(type, amount);
// 记录交易
account.AddTransactionRecord(new TransactionRecord(TransactionType.Deposit, type, amount));
message = $"成功存入 {amount} {type}";
return true;
}
// 取款操作
public bool Withdraw(string playerId, CurrencyType type, int amount, out string message)
{
message = "";
if (amount <= 0)
{
message = "取款金额必须大于0";
return false;
}
// 获取玩家银行账户
var account = GetPlayerAccount(playerId);
// 检查银行余额
int currentBankAmount = account.GetCurrencyAmount(type);
if (currentBankAmount < amount)
{
message = "银行账户余额不足";
return false;
}
// 更新银行余额
account.UpdateCurrencyAmount(type, currentBankAmount - amount);
// 增加玩家背包货币
PlayerInventory.Instance.AddCurrency(type, amount);
// 记录交易
account.AddTransactionRecord(new TransactionRecord(TransactionType.Withdraw, type, amount));
message = $"成功取出 {amount} {type}";
return true;
}
// 获取交易记录
public List<TransactionRecord> GetTransactionHistory(string playerId)
{
var account = GetPlayerAccount(playerId);
return new List<TransactionRecord>(account.transactionHistory);
}}2. 玩家背包接口(示例)
上面的代码中用到了
PlayerInventory,这里提供一个简单的接口示例:csharp
运行
public class PlayerInventory : MonoBehaviour{
public static PlayerInventory Instance { get; private set; }
// 简化的玩家货币存储
private Dictionary<CurrencyType, int> currencies = new Dictionary<CurrencyType, int>();
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
// 初始化货币
foreach (CurrencyType type in Enum.GetValues(typeof(CurrencyType)))
{
currencies[type] = 0;
}
}
else
{
Destroy(gameObject);
}
}
// 获取货币数量
public int GetCurrencyAmount(CurrencyType type)
{
if (currencies.ContainsKey(type))
{
return currencies[type];
}
return 0;
}
// 添加货币
public void AddCurrency(CurrencyType type, int amount)
{
if (currencies.ContainsKey(type))
{
currencies[type] += amount;
}
else
{
currencies[type] = amount;
}
}
// 减少货币
public void SubtractCurrency(CurrencyType type, int amount)
{
if (currencies.ContainsKey(type))
{
currencies[type] = Mathf.Max(0, currencies[type] - amount);
}
}}四、银行 UI 界面实现
银行系统需要直观的 UI 界面让玩家进行操作,以下是一个基础的 UI 实现方案。
1. UI 结构设计
建议的 UI 层级结构:
BankPanel(银行主面板)
HistoryScrollView
HistoryContent
CurrencyTypeDropdown(货币类型选择)
AmountInputField(金额输入)
DepositButton(存款按钮)
WithdrawButton(取款按钮)
GoldBalanceText
DiamondBalanceText
BalanceDisplay(余额显示区域)
TransactionPanel(交易操作区域)
TransactionHistoryPanel(交易记录区域)
CloseButton(关闭按钮)
2. UI 逻辑代码
csharp
运行
using UnityEngine;using UnityEngine.UI;using System.Collections.Generic;using TMPro;public class BankUI : MonoBehaviour{
[Header("余额显示")]
[SerializeField] private TextMeshProUGUI goldBalanceText;
[SerializeField] private TextMeshProUGUI diamondBalanceText;
[Header("交易操作")]
[SerializeField] private Dropdown currencyTypeDropdown;
[SerializeField] private InputField amountInputField;
[SerializeField] private Button depositButton;
[SerializeField] private Button withdrawButton;
[SerializeField] private TextMeshProUGUI messageText;
[Header("交易记录")]
[SerializeField] private Transform historyContent;
[SerializeField] private GameObject historyItemPrefab;
private string currentPlayerId = "Player1"; // 实际项目中应使用真实玩家ID
private CurrencyType selectedCurrencyType = CurrencyType.Gold;
private void Start()
{
// 初始化下拉菜单
InitializeCurrencyDropdown();
// 绑定按钮事件
depositButton.onClick.AddListener(OnDepositButtonClicked);
withdrawButton.onClick.AddListener(OnWithdrawButtonClicked);
currencyTypeDropdown.onValueChanged.AddListener(OnCurrencyTypeChanged);
// 刷新UI
RefreshUI();
}
// 初始化货币类型下拉菜单
private void InitializeCurrencyDropdown()
{
currencyTypeDropdown.ClearOptions();
List<string> options = new List<string>();
foreach (CurrencyType type in Enum.GetValues(typeof(CurrencyType)))
{
options.Add(type.ToString());
}
currencyTypeDropdown.AddOptions(options);
OnCurrencyTypeChanged(0); // 选中第一个
}
// 货币类型改变
private void OnCurrencyTypeChanged(int index)
{
selectedCurrencyType = (CurrencyType)index;
}
// 存款按钮点击
private void OnDepositButtonClicked()
{
if (int.TryParse(amountInputField.text, out int amount))
{
string message;
bool success = BankManager.Instance.Deposit(currentPlayerId, selectedCurrencyType, amount, out message);
messageText.text = message;
messageText.color = success ? Color.green : Color.red;
if (success)
{
RefreshUI();
amountInputField.text = "";
}
}
else
{
messageText.text = "请输入有效的金额";
messageText.color = Color.red;
}
}
// 取款按钮点击
private void OnWithdrawButtonClicked()
{
if (int.TryParse(amountInputField.text, out int amount))
{
string message;
bool success = BankManager.Instance.Withdraw(currentPlayerId, selectedCurrencyType, amount, out message);
messageText.text = message;
messageText.color = success ? Color.green : Color.red;
if (success)
{
RefreshUI();
amountInputField.text = "";
}
}
else
{
messageText.text = "请输入有效的金额";
messageText.color = Color.red;
}
}
// 刷新UI显示
public void RefreshUI()
{
var account = BankManager.Instance.GetPlayerAccount(currentPlayerId);
// 更新余额显示
goldBalanceText.text = $"银行金币: {account.GetCurrencyAmount(CurrencyType.Gold)} (背包: {PlayerInventory.Instance.GetCurrencyAmount(CurrencyType.Gold)})";
diamondBalanceText.text = $"银行钻石: {account.GetCurrencyAmount(CurrencyType.Diamond)} (背包: {PlayerInventory.Instance.GetCurrencyAmount(CurrencyType.Diamond)})";
// 更新交易记录
UpdateTransactionHistory();
}
// 更新交易记录
private void UpdateTransactionHistory()
{
// 清除现有记录
foreach (Transform child in historyContent)
{
Destroy(child.gameObject);
}
// 获取交易记录
var records = BankManager.Instance.GetTransactionHistory(currentPlayerId);
// 倒序显示(最新的在上面)
records.Reverse();
// 创建记录项
foreach (var record in records)
{
GameObject item = Instantiate(historyItemPrefab, historyContent);
TextMeshProUGUI text = item.GetComponent<TextMeshProUGUI>();
string typeStr = record.type == TransactionType.Deposit ? "存入" : "取出";
text.text = $"{record.timestamp:yyyy-MM-dd HH:mm} {typeStr} {record.amount} {record.currencyType}";
}
}
// 显示银行界面
public void Show()
{
gameObject.SetActive(true);
RefreshUI();
}
// 隐藏银行界面
public void Hide()
{
gameObject.SetActive(false);
}}五、数据持久化
为了保证银行数据在游戏重启后不丢失,需要实现数据持久化功能。
使用 PlayerPrefs 进行简单存储(适合小型项目)
csharp
运行
public class BankDataPersistence : MonoBehaviour{
private const string BankDataKey = "BankData";
// 保存银行数据
public void SaveBankData()
{
// 将银行数据转换为可序列化的格式
string jsonData = JsonUtility.ToJson(BankManager.Instance.playerAccounts);
PlayerPrefs.SetString(BankDataKey, jsonData);
PlayerPrefs.Save();
}
// 加载银行数据
public void LoadBankData()
{
if (PlayerPrefs.HasKey(BankDataKey))
{
string jsonData = PlayerPrefs.GetString(BankDataKey);
// 从JSON加载数据到银行管理器(实际实现需要根据你的数据结构调整)
}
}}注意:
对于复杂项目,建议使用:
二进制序列化
SQLite 数据库
服务器端存储(联网游戏)
六、进阶功能扩展
- 银行密码保护:
添加密码设置和验证功能
错误次数限制和冷却机制
- 利息系统:csharp运行
// 简单的利息计算示例public void CalculateInterest(string playerId, float interestRate){ var account = BankManager.Instance.GetPlayerAccount(playerId); foreach (var currency in account.currencies) { if (currency.amount > 0) { int interest = Mathf.RoundToInt(currency.amount * interestRate); account.UpdateCurrencyAmount(currency.type, currency.amount + interest); // 记录利息交易 } }} - 存款限额:
为每种货币设置存款上限
可以通过升级银行账户提升限额
- 交易手续费:
在存取款时收取一定比例的手续费
会员可以减免手续费
七、常见问题与解决方案
- 数据同步问题:
确保 UI 在每次操作后都刷新
多线程操作时注意加锁保护数据
- 输入验证:
严格验证输入金额的有效性
防止负数和过大数值
- 性能优化:
交易记录过多时分页显示
定期清理过旧的交易记录
- 安全问题:
防止客户端篡改数据(重要数据应在服务器验证)
敏感操作添加二次确认
结语
银行系统作为游戏经济循环的重要环节,其设计需要兼顾功能性和安全性。本文实现的基础框架可以满足大多数游戏的需求,你可以根据具体项目特点进行扩展和优化。
在实际开发中,建议将银行系统与游戏的整体经济系统紧密结合,设计合理的存取规则和激励机制,提升玩家的游戏体验。
希望本文对你的 Unity 开发有所帮助,祝你的项目开发顺利!
