Unity编辑器功能Inspector快捷自动填充数据和可视化调试

我们有时候可能需要在面板增加一些引用,可能添加脚本后要手动拖动,这样如果有大量的脚本拖动也是不小的工作量

实例

例如:我的脚本需要添加一个Bone的列表,一个个拖动很麻烦。
在这里插入图片描述

在这里插入图片描述

实现脚本

我们可以用这样的脚本来实现。

public class FingerDyBone : MonoBehaviour
{
    public DynamicBoneCollider[] boneArray = null;

#if UNITY_EDITOR
   
    [ContextMenu("加入所有碰撞体")]
    private void MenuAddBone()
    {
        boneArray = GetComponentsInChildren<DynamicBoneCollider>();
        UnityEditor.EditorUtility.SetDirty(this);
    }
    void OnValidate()
    {
        Debug.Log("OnValidate");
        if (boneArray == null) MenuAddBone();
    }
#endif
}

ContextMenu是菜单,添加这个可以手动调用函数。
在这里插入图片描述
如果手动麻烦还可以自动添加,那么可以借助OnValidate函数,在添加脚本或者改变属性的时候会自动执行。解决这个原理就可以在添加脚本的时候自动添加。

最终效果

在这里插入图片描述
那么这样就比较事半功倍了。

调试显示

我们还可以通过OnDrawGizmos显示一些常用的图形
例如:
在这里插入图片描述

通过OnDrawGizmos方法,使用Gizmos画各种图形

 void OnDrawGizmos()
{
    Transform[] bornPoint = GetComponentsInChildren<Transform>();
    for (int i = 0; i < bornPoint.Length; i++)
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(bornPoint[i].position, 0.15f);
        Gizmos.color = Color.white;
        Gizmos.DrawLine(bornPoint[i].position, bornPoint[i].position + Vector3.up);
        Gizmos.color = Color.blue;
        Gizmos.DrawLine(bornPoint[i].position, bornPoint[i].position + Quaternion.Euler(bornPoint[i].eulerAngles) * Vector3.forward * 0.5f);
    }
}
<think>好的,用户现在问的是在Unity开发单机游戏时如何存储数据。之前他们问过如何清空PlayerPrefs里的JSON数据,所以可能他们现在需要更全面的存储方案。我需要先回顾之前的对话,确保这次的回答能衔接上。 首先,用户可能已经知道PlayerPrefs的基本用法,但可能遇到了存储复杂数据的问题,比如JSON,所以现在想了解更多的存储方法。之前的回答提到了PlayerPrefs文件系统,这次需要扩展其他方法,并比较它们的优缺点。 接下来,我需要考虑用户可能的背景。他们可能是一个刚入门的Unity开发者,正在开发单机游戏,需要存储玩家进度、设置或游戏状态。他们可能对数据存储的安全性、易用性扩展性有需求。由于是单机游戏,可能不需要网络存储,所以重点放在本地存储方案。 用户的问题比较广泛,所以需要覆盖多种存储方式,包括PlayerPrefs、JSON+文件系统、二进制序列化、ScriptableObject、SQLite等。同时,要给出使用场景示例代码,方便用户理解。此外,需要注意数据加密,因为用户可能关心数据的安全性,尤其是防止玩家篡改存档。 还要考虑不同平台的存储路径差异,比如Application.persistentDataPath在不同系统的位置,确保用户知道如何找到存储的文件。另外,是否需要提到第三方插件,比如Odin或Save System,可能对用户有帮助,但应该放在最后作为补充。 可能需要提醒用户每种方法的优缺点,比如PlayerPrefs不适合复杂数据,文件系统更灵活但需要处理序列化,SQLite适合大量数据等。同时,给出选择建议,根据数据类型需求来推荐合适的方案。 最后,确保回答结构清晰,分点说明,代码示例准确,注意事项最佳实践部分能够帮助用户避免常见错误。检查是否有遗漏的重要方法,比如Unity的SaveSystem在较新版本中的支持,或者加密方法的简单实现示例。</think>在 Unity 中开发单机游戏时,数据存储是管理玩家进度、设置游戏状态的核心需求。以下是常用的数据存储方案及其实现方法,涵盖简单到复杂场景: --- ### **1. PlayerPrefs(适合简单数据)** **适用场景**:存储少量简单数据(如音量设置、最高分、开关状态等)。 **原理**:Unity 内置的轻量级键值对存储,支持 `int`、`float`、`string` 类型。 **代码示例**: ```csharp // 存储数据 PlayerPrefs.SetInt("HighScore", 100); PlayerPrefs.SetFloat("Volume", 0.8f); PlayerPrefs.SetString("PlayerName", "Unity"); PlayerPrefs.Save(); // 确保数据持久化 // 读取数据 int score = PlayerPrefs.GetInt("HighScore", 0); float volume = PlayerPrefs.GetFloat("Volume", 1.0f); string name = PlayerPrefs.GetString("PlayerName", "Guest"); ``` **优点**:简单易用,无需文件操作。 **缺点**: - 不适合存储复杂数据(如对象、列表)。 - 数据未加密,易被玩家篡改(如通过注册表或文件修改)。 --- ### **2. JSON + 文件系统(推荐复杂数据)** **适用场景**:存储玩家存档、装备列表、任务进度等结构化数据。 **原理**:将对象序列化为 JSON 字符串,保存到 `Application.persistentDataPath`(跨平台安全路径)。 **代码示例**: ```csharp using UnityEngine; using System.IO; using System; [Serializable] public class PlayerData { public int level; public float health; public List<string> inventory; } public class SaveManager : MonoBehaviour { private string savePath; void Awake() { savePath = Path.Combine(Application.persistentDataPath, "save.json"); } // 保存数据 public void Save(PlayerData data) { string json = JsonUtility.ToJson(data, true); // 第二个参数为是否格式化 File.WriteAllText(savePath, json); } // 读取数据 public PlayerData Load() { if (File.Exists(savePath)) { string json = File.ReadAllText(savePath); return JsonUtility.FromJson<PlayerData>(json); } return new PlayerData(); // 返回默认数据 } // 删除存档 public void DeleteSave() { if (File.Exists(savePath)) { File.Delete(savePath); } } } ``` **优点**: - 支持复杂数据结构。 - 数据可读性强(JSON 明文)。 - 文件路径跨平台自动处理。 **缺点**: - 明文存储可能被玩家修改(可通过加密解决,见下文)。 --- ### **3. 二进制序列化(安全存储)** **适用场景**:需防止玩家直接修改存档(如商业单机游戏)。 **原理**:将数据转换为二进制格式并加密。 **代码示例**: ```csharp using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Text; public class BinarySaveManager { private string savePath; private byte[] encryptionKey; // 自定义密钥 public BinarySaveManager() { savePath = Path.Combine(Application.persistentDataPath, "save.dat"); encryptionKey = Encoding.UTF8.GetBytes("YourSecretKey123"); // 实际项目使用更复杂密钥 } // 保存加密数据 public void Save(PlayerData data) { BinaryFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { formatter.Serialize(ms, data); byte[] bytes = Encrypt(ms.ToArray()); File.WriteAllBytes(savePath, bytes); } } // 读取解密数据 public PlayerData Load() { if (File.Exists(savePath)) { byte[] bytes = File.ReadAllBytes(savePath); bytes = Decrypt(bytes); BinaryFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream(bytes)) { return (PlayerData)formatter.Deserialize(ms); } } return new PlayerData(); } // 简单 AES 加密(示例) private byte[] Encrypt(byte[] data) { using (Aes aes = Aes.Create()) { aes.Key = encryptionKey; aes.IV = new byte[16]; // 实际需生成随机 IV using (ICryptoTransform encryptor = aes.CreateEncryptor()) { return encryptor.TransformFinalBlock(data, 0, data.Length); } } } // 解密 private byte[] Decrypt(byte[] data) { using (Aes aes = Aes.Create()) { aes.Key = encryptionKey; aes.IV = new byte[16]; using (ICryptoTransform decryptor = aes.CreateDecryptor()) { return decryptor.TransformFinalBlock(data, 0, data.Length); } } } } ``` **优点**:数据安全性高,难以直接篡改。 **缺点**:实现复杂,调试困难。 --- ### **4. ScriptableObject(编辑器友好)** **适用场景**:存储游戏配置(如物品属性、技能数据),适合设计阶段快速调整。 **原理**:Unity 内置资源类型,数据保存在 `.asset` 文件中。 **步骤**: 1. 创建 ScriptableObject 类: ```csharp using UnityEngine; [CreateAssetMenu(fileName = "GameConfig", menuName = "Data/GameConfig")] public class GameConfig : ScriptableObject { public int initialGold; public float playerSpeed; public List<Item> items; } ``` 2. 在 Unity 编辑器中通过右键菜单生成 `.asset` 文件。 3. 通过代码读取配置: ```csharp public class GameManager : MonoBehaviour { public GameConfig config; void Start() { Debug.Log("初始金币: " + config.initialGold); } } ``` **优点**:无需代码即可编辑数据,适合策划测试。 **缺点**:数据随项目打包,运行时无法动态修改(需配合其他存储方案)。 --- ### **5. SQLite(大型数据管理)** **适用场景**:需要复杂查询或大量数据存储(如 RPG 游戏的任务、物品数据库)。 **原理**:轻量级数据库,通过 SQL 语句操作数据。 **步骤**: 1. 导入 SQLite 插件(如 [sqlite-unity](https://github.com/rizasif/sqlite-unity))。 2. 创建数据表: ```csharp using SQLite; public class Item { [PrimaryKey, AutoIncrement] public int Id { get; set; } public string Name { get; set; } public int Price { get; set; } } public class DatabaseManager { private SQLiteConnection db; public DatabaseManager() { string dbPath = Path.Combine(Application.persistentDataPath, "game.db"); db = new SQLiteConnection(dbPath); db.CreateTable<Item>(); } public void AddItem(Item item) { db.Insert(item); } public List<Item> GetAllItems() { return db.Table<Item>().ToList(); } } ``` **优点**:支持复杂查询,性能高效。 **缺点**:需学习 SQL 语法,过度设计对小项目不友好。 --- ### **选择建议** | **方案** | **适用场景** | **学习成本** | **安全性** | |----------------------|----------------------------------|-------------|-----------| | `PlayerPrefs` | 简单键值对(设置、分数) | 低 | 低 | | `JSON/文件` | 玩家存档、复杂数据 | 中 | 中 | | `二进制 + 加密` | 防篡改存档 | 高 | 高 | | `ScriptableObject` | 静态配置数据 | 低 | 低 | | `SQLite` | 大量结构化数据(如物品库) | 高 | 中 | --- ### **注意事项** 1. **跨平台路径**: - 使用 `Application.persistentDataPath` 自动处理不同平台路径: - **Windows**:`%userprofile%\AppData\LocalLow\<公司名>\<项目名>` - **Android**:`/data/data/<包名>/files` - **iOS**:`/var/mobile/Containers/Data/Application/<GUID>/Documents` 2. **版本兼容性**: - 数据结构变更时(如新增字段),需处理旧版本存档的兼容性(如默认值填充)。 3. **性能优化**: - 避免频繁保存大数据(如每帧保存),可定时或触发关键事件时保存。 4. **加密扩展**: - 推荐使用 `AES` 或 `RSA` 加密算法,避免简单异或(XOR)等弱加密。 --- ### **扩展工具推荐** - **Odin Inspector**:增强序列化功能可视化编辑复杂数据。 - **Unity Save System**:Unity 官方实验性存档系统(2021+版本)。 - **Easy Save 3**:付费插件,提供加密、云存储等高级功能。 根据项目规模需求选择合适的方案,小型游戏推荐 `JSON + 文件`,中大型项目可结合 `二进制加密` 或 `SQLite`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thinbug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值