Unity——脚本与序列化

简介: Unity——脚本与序列化

在介绍序列化之前,我们先来了解一下为什么要对数据进行序列化

数据序列化有以下几个主要的应用场景和目的:

1. 持久化存储:序列化可以将对象或数据结构转换为字节序列,使得其可以被存储在磁盘上或数据库中。通过序列化,我们可以将应用程序中运行时的数据持久化保存,以便在后续运行时重新加载和使用。

2. 数据传输:序列化可以将对象转换为字节序列,以便在网络上进行传输。通过序列化,我们可以方便地将数据发送给远程服务器或其他系统,实现不同系统之间的数据交互和通信。

3. 数据缓存:序列化可以将对象存储在缓存中,以提高读取和访问的性能。通过序列化,我们可以将经常需要使用的数据对象序列化到缓存中,避免频繁地从数据库或其他存储介质中读取数据,从而提高应用程序的响应速度和效率。

4. 跨平台和版本兼容性:通过序列化,我们可以将对象转换为一种通用的数据格式,如 XML 或 JSON,使得数据在不同的平台和系统之间可以进行传递和解析。而且,序列化也留下了数据的结构信息,使得即使在对象结构发生变化或升级时,仍能够进行兼容性处理。

5. 调试和日志记录:在调试过程中,我们可以将对象的状态序列化为日志文件,以便后续查看和分析。通过序列化,我们可以捕获应用程序在某一特定时刻的状态,并将其存储下来,方便调试和故障排查。

总结来说,数据序列化可以使数据在不同的环境和系统中进行存储、传输和使用,以及提供持久化存储、数据交互、性能优化和兼容性处理等方面的好处。


一、序列化的概念

计算机硬盘中的文件只能保存纯数据,不能直接保存对象,网络传输亦是如此。在游戏存档、发送网络数据包的时候,都需要先将数据转化为纯粹的二进制数据,才能进行发送。反之,读取存档、接收数据包的时候,要进行相反的操作——把二进制数据转化为对象。

将对象转化为二进制数据的操作就叫做“序列化(Seriallize)”;相反的过程,将二进制数据转化为对象就叫做“反序列化(Deseriallize)”。

常用的序列化方案有以下几种:

  1. 自定义二进制序列化
  2. C#提供的序列化方案
  3. JSON
  4. XML
  5. ProtoBuf

1、自定义二进制序列化

自定义二进制序列化是一种在代码级别定义对象如何转换为二进制数据的过程,以及如何将二进制数据转换回对象。在Unity中,通过自定义二进制序列化,我们可以完全控制对象的序列化和反序列化过程,以适应特定的需求。

下面是一个简单的示例,演示如何自定义二进制序列化:

首先,我们需要为要序列化的对象创建一个自定义的数据结构。

[Serializable]
public class CustomData
{
    public int value1;
    public float value2;
    // ...
}

然后,我们可以创建一个自定义的二进制序列化器。

public static class CustomSerializer
{
    public static byte[] Serialize(CustomData data)
    {
        MemoryStream stream = new MemoryStream();
        BinaryWriter writer = new BinaryWriter(stream);
        // 将字段写入二进制流中
        writer.Write(data.value1);
        writer.Write(data.value2);
        // ...
        writer.Close();
        return stream.ToArray();
    }
    public static CustomData Deserialize(byte[] data)
    {
        MemoryStream stream = new MemoryStream(data);
        BinaryReader reader = new BinaryReader(stream);
        CustomData customData = new CustomData();
        // 从二进制流中读取字段
        customData.value1 = reader.ReadInt32();
        customData.value2 = reader.ReadSingle();
        // ...
        reader.Close();
        return customData;
    }
}

最后,我们可以使用自定义的二进制序列化器来序列化和反序列化对象。

CustomData obj = new CustomData();
// 设置对象的值...
byte[] serializedData = CustomSerializer.Serialize(obj);
// 将二进制数据存储到磁盘或发送给其他系统...
CustomData deserializedObj = CustomSerializer.Deserialize(serializedData);
// 使用反序列化后的对象...

通过自定义二进制序列化,我们可以按需存储和传输对象的状态,或者与其他系统进行数据交换。在实际应用中,我们可能需要考虑字节顺序、对象版本控制、数据压缩等因素,以提高自定义二进制序列化的效率和可靠性。

2、C#提供的序列化方案

C# 提供了几种常用的序列化方案,用于将对象转换为字节序列并进行存储、传输或持久化。下面是一些常见的 C# 序列化方案:

1. 二进制序列化(Binary Serialization):

  C# 提供了 BinaryFormatter 类,可用于将对象序列化为二进制格式,并将其保存到文件或传输到其他地方。二进制序列化是一种简单而高效的方式,适用于需要快速序列化和反序列化的场景。但它的二进制数据不可读,也难以进行跨平台和版本兼容。

2. XML 序列化(XML Serialization):

  XML 序列化使用 `XmlSerializer` 类,将对象序列化成 XML 格式。XML 是一种自描述的格式,可读性较好,并具备跨平台和版本兼容性。通过 XML 序列化,我们可以将对象保存为 XML 文件,或将 XML 数据传输给其他系统。但 XML 格式会带来一定的性能开销,并且对于大型对象或复杂的数据结构,XML 格式可能会产生较大的文件大小。

3. JSON 序列化(JSON Serialization):

  C# 中的 JSON 序列化通过 `JsonSerializer` 类来实现。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它具有可读性好、跨平台和版本兼容性,并且与 Web 开发密切相关。JSON 序列化可以将对象转换为 JSON 格式进行存储、传输和与其他系统进行数据交互。相对于 XML 格式,JSON 格式更加紧凑,但仍然具备很好的可读性。

4. Protobuf 序列化(Protocol Buffers Serialization):

  Protobuf 是 Google 发布的一种高效的二进制序列化格式,适用于跨平台和高性能的数据传输。在 C# 中,可以使用谷歌开源的 protobuf-net库进行 Protobuf 序列化。Protobuf 的优点包括高性能、小尺寸和协议版本兼容性,但其二进制数据不可读,需要定义数据的结构和消息格式。

这些序列化方案根据不同的需求和场景可以选择合适的方案。一般而言,二进制序列化适用于性能要求较高且不需进行数据查看的场景,XML 和 JSON 序列化适用于可读性好、跨平台和版本兼容性要求较高的场景,Protobuf 序列化适用于高性能和小尺寸的数据传输。

序列化的方案还有很多,也可以自己定义独特的序列化方案。理论上来说,只要能保存并正确读取数据的序列化方案都是合理的

二、简单存储PlayerPrefs

除了通用的序列化方法外,在很多游戏和应用程序中还需要保存一些简单的游戏偏好数据(Preference)。如音乐音量、音效音量、屏幕分辨率等,某些小游戏的最高分、游戏进度也可以用简单的方式保存在设备上。

Unity提供了PlayerPrefs,以满足保存简单数据的需求。它的共嗯比较单纯,用一个键(字符串类型)对应一个之,值的类型只支持整数、浮点数和字符串3种。PlayerPrefs不擅长保存复杂数据类型,其常用方法如下

当使用Unity进行游戏开发时,可以使用PlayerPrefs类来保存和访问玩家的偏好设置和游戏数据。

1、以下是一些PlayerPrefs的常用方法示例:

1. 设置偏好设置或游戏数据:

 PlayerPrefs.SetInt("HighScore", 100); // 设置整数值
   PlayerPrefs.SetFloat("Volume", 0.8f); // 设置浮点数值
   PlayerPrefs.SetString("PlayerName", "John"); // 设置字符串值

2. 获取偏好设置或游戏数据:

   int highScore = PlayerPrefs.GetInt("HighScore"); // 获取整数值
   float volume = PlayerPrefs.GetFloat("Volume"); // 获取浮点数值
   string playerName = PlayerPrefs.GetString("PlayerName"); // 获取字符串值

3. 检查是否存在特定键:

bool hasHighScore = PlayerPrefs.HasKey("HighScore"); // 检查是否存在HighScore键

4. 删除特定键的偏好设置或游戏数据:

PlayerPrefs.DeleteKey("HighScore"); // 删除HighScore键的数据

5. 删除所有偏好设置或游戏数据:

PlayerPrefs.DeleteAll(); // 删除所有偏好设置和游戏数据

请注意,PlayerPrefs类用于存储简单的键值对数据,不适合存储大量复杂的游戏数据。对于大型游戏或复杂数据结构,应该考虑使用其他方法,如数据序列化和数据库。

2、应用实例

这里举一个能够在游戏退出时仍然保存数值的计数器

  1. 在场景中创建一个3D Text
  2. 默认的3D Text有点模糊,建议将Font Size设置为50,然后缩小Character Size为0.2(Font Size决定字符间隔大小,Character Size决定字体大小)
  3. 创建脚本TsetPrefs经挂到3D Text上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//这个写法的用途是强制物体具有TextMesh组件
[RequireComponent(typeof(TextMesh))]
public class TestPrefs : MonoBehaviour
{
    int counter = 0;
    TextMesh textMesh;
    void Start()
    {
        counter = PlayerPrefs.GetInt("counter");
        textMesh = GetComponent<TextMesh>();
        textMesh.text=counter.ToString();
    }
    // Update is called once per frame
    void Update()
    {
        if(Input.GetButtonDown("Jump"))   //按空格加一
        {
            counter++;
            PlayerPrefs.SetInt("counter", counter);
            textMesh.text=counter.ToString();
        }
        if (Input.GetButtonDown("Cancel"))     //按Esc清零
        {
            counter=0;
            PlayerPrefs.SetInt("counter", counter);
            textMesh.text = counter.ToString();
        }
    }
}

完成之后就可以测试计数器效果了。运行游戏,按康哥可以让数字加1,按Esc数字清0.停止游戏后再次启动,数字会还原成上次退出时的值。

3、PlayerPrefs的实际保存位置

在Unity中,PlayerPrefs的实际保存位置取决于不同的操作系统。以下是不同操作系统上PlayerPrefs的实际保存位置:

1. Windows:

  PlayerPrefs数据在Windows系统中默认保存在注册表文件中。具体路径为:

  HKEY_CURRENT_USER\Software\[公司名]\[产品名]

2. macOS:

  PlayerPrefs数据在macOS系统中默认保存在plist文件中。具体路径为:

  ~/Library/Preferences/[公司名].[产品名].plist

3. Linux:

  在Linux系统中,PlayerPrefs数据默认保存在用户主目录的".config"目录下。具体路径为:

  ~/.config/unity3d/[公司名]/[产品名]/

4. iOS:

  在iOS设备上,PlayerPrefs数据会存储在应用的沙盒目录中。具体路径取决于应用的Bundle Identifier。

5. Android:

  在Android设备上,PlayerPrefs数据会存储在设备的Shared Preferences中,并根据应用的包名进行命名,并保存在应用的沙盒目录下。

需要注意的是,PlayerPrefs保存的数据是以明文形式存储的,因此不推荐将敏感或重要的数据直接保存在PlayerPrefs中。


相关文章
|
存储 人工智能 Java
Unity优化——脚本优化策略4
Unity优化——脚本优化策略4
262 0
|
10月前
|
图形学 开发者
Unity编辑器脚本(添加/删除)碰撞盒
这段代码提供了两个Unity编辑器工具,用于批量处理模型的碰撞盒。一是“一键添加所有碰撞盒”,通过选择模型的父物体,自动为其子物体添加`MeshCollider`。二是“一键清理所有Collider碰撞盒”,同样选择父物体后,递归删除子物体上的`BoxCollider`组件。两者均通过Unity的菜单项实现便捷操作,方便开发者快速调整场景中的物理属性。
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
884 3
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
673 0
|
人工智能 图形学
【unity小技巧】使用动画状态机脚本实现一个简单3d敌人AI功能
【unity小技巧】使用动画状态机脚本实现一个简单3d敌人AI功能
350 0
|
人工智能 定位技术 图形学
【Unity小技巧】一个脚本实现控制3D远程/近战敌人AI
【Unity小技巧】一个脚本实现控制3D远程/近战敌人AI
317 0
|
自然语言处理 图形学
【unity实战】一个通用的FPS枪支不同武器射击控制脚本
【unity实战】一个通用的FPS枪支不同武器射击控制脚本
658 0
|
程序员 图形学 Android开发
Unity脚本生命周期
Unity脚本生命周期
|
API C# 图形学
【Unity 3D】常见API的讲解以及在C#脚本中的执行(附源码)
【Unity 3D】常见API的讲解以及在C#脚本中的执行(附源码)
388 1
|
存储 人工智能 缓存
Unity优化——脚本优化策略3
Unity优化——脚本优化策略3
233 0

热门文章

最新文章