初心者は C# 独自のメソッドを使用して Unity アーカイブ システムを作成します (プラグインは使用しません)

純粋にオリジナル、自家製

まだ高校生なので至らない点があればご指摘ください。

まずはデモプロジェクトがどのようなものかを見てみましょう。

デモプロジェクトエンジニアリングファイルのダウンロード

詳細なビデオチュートリアルは後ほどステーション B に投稿されます (そのため、記事は後で修正されます)

面倒な場合はプロジェクトに直接コピーして使用しても構いません。

(すべての SaveSystem ソース コードは、誰でもコピーできるように、最後に公開されます)

共通の値型と文字列型のフィールドを持つオブジェクトを格納できる

使用方法は、SaveSystem.Save <格納オブジェクトタイプ> (格納データのオブジェクト名); です。

読み込みは SaveSystem.Load <オブジェクトタイプ読み取り> (読み取られたデータのオブジェクト名);

クラス内のフィールドが共通の値型と文字列型であれば、非常に簡単です。

珍しい値の型については、私の記事の Load 関数に関するコメントを参照して、switch ステートメントに追加してください。

これを使って保存してください

(注: 使用するには、使用するシステム、UnityEngine、System.Reflection、System.IO 名前空間が必要です)

(このアーカイブ方法は他の場所でも使用できます。UnityEngine を使用せずにコード内のすべての Debug ステートメントを削除できます)

(互換性のないクラスの保存によるエラーを防ぐため、[CanSave] 属性が追加されたクラスのみがアーカイブ システムで受け入れられます)

(この機能は誰もが確認できるように追加されました)

(詳しい使用方法はチュートリアルにあります)

UI を使用してデータの変更を表示し、保存ボタンとロードボタンを使用してファイルの読み取りとアーカイブの機能を実装します。

新しいSaveSystemスクリプトを作成し、エディタで自動生成されたUpdate関数とStart関数を削除します。最初のSava関数を書きましょう。初心者が知らないかもしれない各オブジェクトについて説明するコメントを書きます(十分配慮しています)

public class SaveSysteam
{//泛型以保存各种类型的数据
   public static void Save<T>(T obj)
    {
        int N=0;//创建一个int变量来控制我要保存的数据所在数组位置
        string[]Data=new string[10];
        Type type = typeof(T);//利用反射获得类的信息
        if (type.IsDefined(typeof(CanSaveAttribute), false))
        {//这个if先不看可以,就是判断这个类是否存在我们后面的自定义特性,不存在是不可以存的哦
         //因为存的数据要求是值类型或字符串类型,为了防止其他人使用不会注意,我们要写一个特性,起提示作用
            CanSaveAttribute can=type.GetCustomAttribute<CanSaveAttribute>();//获得该类下的特性
            FieldInfo[] fields = type.GetFields();//利用反射获得该类的所有字段
            Data[N] = can.author;//保存特性中的信息
            N++;
            Data[N] = can.versionNumber;
            N++;
         //从上个注释到这都是存特性的
            foreach (FieldInfo field in fields)
            {
        //遍历字段的数组获得每个字段的值,并转换成字符串类型
                Data[N] = Convert.ToString(field.GetValue(obj));
                N++;

                // Debug.Log(field.GetValue(obj));
            }
            File.WriteAllLines(@"D:\\c#\\存档系统\\GameData.txt", Data);
                 //前面的参数是存的路径,请您自己改哦,后面的参数是存完数据的string数组
            Debug.Log("IsSave");//控制台输出保存的消息
        }
        else//如果不包含特性的警告
        {
            Debug.LogError("你保存了一个不包含特性CanSaveAttribute的类,请检查保存的类是否符合规定");
        }
    }
    
    
}

これは Save 関数です。比較的単純ではないでしょうか? 次に、SaveSystem クラスに Load 関数を追加しましょう。

//泛型老样子(不会有人没注意听讲吧)
 public static void Load<T>(T obj)
    {
        int N = 0;//N的作用和上面的一样
        Type type = typeof(T);
        if (type.IsDefined(typeof(CanSaveAttribute), false))
        {
            CanSaveAttribute can = type.GetCustomAttribute<CanSaveAttribute>();
            FieldInfo[] fields = type.GetFields();
            string[] Data = new string[10];
            Data = File.ReadAllLines(@"D:\\c#\\存档系统\\GameData.txt");//按行读取文件里的数据
               //上面用到的保存方法也是按行读取
            if (Data[N] == can.author && Data[N+1]==can.versionNumber)
            {//判断要读取的类的特性里的信息和当时存储的信息是否一致
                N = N + 2;
                
                foreach (FieldInfo field in fields)
                {//遍历要读取的类的字段的类型,好把数据按类型传回去,因为存的都是string类型的
                    switch (Convert.ToString(field.FieldType))
                    {//用switch语句,现在字段的类型是啥就把string转换成什么
                       //为什么变量类型都是这些名字呢
                     //因为反射获得的字段的类型都是对应的.NET Framework 中的类型
                    // 下张图片我会放一个表,C#类型对应的.NET Framework 类型
                        case "System.Int32":
                            field.SetValue(obj, Convert.ToInt32(Data[N]));
                             //设置字段值的方法SetValue,前面要求的参数是你要设置字段的对象,可以这么理解
                             //但是我建议你自己查一下微软的文档里面有详细解释
                            break;
                        case "System.Double":
                            field.SetValue(obj, Convert.ToDouble(Data[N]));
                            break;
                        case "System.String":
                            field.SetValue(obj, Data[N]);
                            break;
                        case "System.Single":
                            field.SetValue(obj, Convert.ToSingle(Data[N]));
                            break;
                        case "System.Decimal":
                            field.SetValue(obj, Convert.ToDecimal(Data[N]));
                            break;



                    }
                   
                    N++;
                }
            }
            else
            {
                Debug.LogError("现在的类与存储时的特性有所差异,可以查看文件中的原作者名字取得联系并修改");
            }
        }
        else
        {
            Debug.LogError("你加载了一个不包含特性CanSaveAttribute的类,请检查加载的类是否符合规定或存在");
        }
    }

以下は私が同意した表です(別のブログで見つけましたが、元の著者が見つからないため、リンクを貼ることができません。整理してくれた著者に感謝します)

(エラーがある場合は、最新の Microsoft ドキュメントを確認してください)

C# 类型       .NET Framework 类型

bool            System.Boolean               

4Byte 32bit ,true或者false,默认值为false

byte            System.Byte                

1Byte 8bit 无符号整数 无符号的字节,所存储的值的范围是0~255,默认值为0

sbyte         System.SByte 1Byte

8bit 有符号整数 带符号的字节,所存储的值的范围是-128~127,默认值为0

char           System.Char 

2Byte 16bit 无符号Unicode字符,默认值为’\0’


decimal      System.Decimal

16Byte 128bit十进制数不遵守四舍五入规则的十进制数,28个有效数字,通常用于财务方面的计算,默认值为0.0m



double       System.Double

8Byte 64bit双精度的浮点类型,默认值为0.0d

float          System.Single

4Byte 32bit单精度的浮点类型,默认值为0.0f



int             System.Int32

4Byte 32bit有符号整数,默认值为0

uint           System.UInt32

4Byte 32bit无符号整数,默认值为0

long          System.Int64

8Byte 64bit有符号整数,默认值为0

それから、以前に掘った穴について書かなければなりません、はい、それは特徴です。

//哈哈哈,自定义特性上还要加特性,这个特性标明它是给类用的
[AttributeUsage(AttributeTargets.Class)]
//创造特性需要继承Attribute,且名字后必须以Attribute结尾,使用时不需要Attribute结尾
public class CanSaveAttribute : System.Attribute
{
   //下面都是希望存在特性里的信息作者,版本号,和是否检查过
    public string author="";
    public string versionNumber="";
    public bool isCheck;
}

那我们该如何使用这个存档系统呢,拿我的模板当个实例,我需要存储玩家的位置信息和名字信息,我把模板项目的玩家控制代码发出来,挂到玩家上即可,看好注释哦,后面放游戏内容截图

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Player : MonoBehaviour
{
    public Rigidbody2D Rigidbody2D;
    public float speed = 10f;
    public SaveDataObject SObject;//先声明我们要存的对象
    public Text X;
    public Text Y;
    public Text Z;
    public Text NameUI;

    // Start is called before the first frame update
    void Start()
    {
        Rigidbody2D=GetComponent<Rigidbody2D>();

    }

    // Update is called once per frame
    void Update()
    {
        Rigidbody2D.velocity = new Vector2(Input.GetAxis("Horizontal") * speed, Input.GetAxis("Vertical") *speed);
        X.text = Convert.ToString(transform.position.x);
        Y.text = Convert.ToString(transform.position.y);
        Z.text = Convert.ToString(transform.position.z);
    }
   //要用button的事件链接这两个函数哦
    public void ClickSave()
    {
        Player player=GetComponent<Player>();//获得玩家对象
        SObject=new SaveDataObject(player,"LiLei");//嘿嘿偷懒,把名字写这里传了
         SaveSysteam.Save<SaveDataObject>(SObject);//保存实际就这一行,传入我们要存的对象即可
        
    }
    public void ClickLoad()
    {
        Player player = GetComponent<Player>();
        SObject = new SaveDataObject(player);
        SaveSysteam.Load<SaveDataObject>(SObject);//和保存的使用方法一样
       //下面就是把获得的数据传回到游戏中了
        transform.position = new Vector3(SObject.X,SObject.Y,SObject.Z);
        NameUI.text = SObject.playerName;
        Debug.Log("IsLoad");
    }

}
//这是我要存储的类型获得玩家名称和位置信息
//想存别的东西就现创建一个类就行了,不用动存档系统的代码哦,方便吧
[CanSave(author = "小羊宝正", versionNumber = "版本1.1",isCheck =true)]
public class SaveDataObject
{
    
    public float X;
    public float Y;
    public float Z;
    public string playerName;

    public  SaveDataObject(Player player,string name)
    {
        X = player.transform.position.x;
        Y = player.transform.position.y;
        Z = player.transform.position.z;
        playerName = name;
    }
    public SaveDataObject(Player player)
    {
        X = player.transform.position.x;
        Y = player.transform.position.y;
        Z = player.transform.position.z;
        
    }
}

该放截图了,先让小球走几步(走到load按钮上)

然后点击save按钮 控制台发出消息

打开我们存的文件,看数据被存好了

然后我们关掉游戏,让小球回到原点

然后再次运行,再点击load按钮,看小球回到存档的位置了,并且被起名LiLei(李雷)

这就是使用方法了,我写的存档系统还不错吧,非常简便且灵活,其他功能大家可以自己探索(比如存档位,在此基础上更改都不难,虽然我设计了其他完整的功能,但是临近期末没精力写出来了,以后要是反响好我就补)

下面是答应大家的SaveSystem完整源代码,被注释的是之前写错懒得删的不影响使用

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.IO;

public class SaveSysteam
{
   public static void Save<T>(T obj)
    {
        int N=0;
        string[]Data=new string[10];
        Type type = typeof(T);
        if (type.IsDefined(typeof(CanSaveAttribute), false))
        {
            CanSaveAttribute can=type.GetCustomAttribute<CanSaveAttribute>();
            FieldInfo[] fields = type.GetFields();
            Data[N] = can.author;
            N++;
            Data[N] = can.versionNumber;
            N++;
            foreach (FieldInfo field in fields)
            {
                //field.GetValue(obiect);
                Data[N] = Convert.ToString(field.GetValue(obj));
                N++;

                // Debug.Log(field.GetValue(obj));
            }
            File.WriteAllLines(@"D:\\c#\\存档系统\\GameData.txt", Data);
            Debug.Log("IsSave");
        }
        else
        {
            Debug.LogError("你保存了一个不包含特性CanSaveAttribute的类,请检查保存的类是否符合规定");
        }
    }
    public static void Load<T>(T obj)
    {
        int N = 0;
        Type type = typeof(T);
        if (type.IsDefined(typeof(CanSaveAttribute), false))
        {
            CanSaveAttribute can = type.GetCustomAttribute<CanSaveAttribute>();
            FieldInfo[] fields = type.GetFields();
            string[] Data = new string[10];
            Data = File.ReadAllLines(@"D:\\c#\\存档系统\\GameData.txt");
            if (Data[N] == can.author && Data[N+1]==can.versionNumber)
            {
                N = N + 2;
                //PropertyInfo[] propertyInfos = type.GetProperties();
                foreach (FieldInfo field in fields)
                {
                    switch (Convert.ToString(field.FieldType))
                    {
                        case "System.Int32":
                            field.SetValue(obj, Convert.ToInt32(Data[N]));
                            break;
                        case "System.Double":
                            field.SetValue(obj, Convert.ToDouble(Data[N]));
                            break;
                        case "System.String":
                            field.SetValue(obj, Data[N]);
                            break;
                        case "System.Single":
                            field.SetValue(obj, Convert.ToSingle(Data[N]));
                            break;
                        case "System.Decimal":
                            field.SetValue(obj, Convert.ToDecimal(Data[N]));
                            break;



                    }
                    Debug.Log(Convert.ToString(field.FieldType));
                    N++;
                }
            }
            else
            {
                Debug.LogError("现在的类与存储时的特性有所差异,可以查看文件中的原作者名字取得联系并修改");
            }
        }
        else
        {
            Debug.LogError("你加载了一个不包含特性CanSaveAttribute的类,请检查加载的类是否符合规定或存在");
        }
    }
    
}
[AttributeUsage(AttributeTargets.Class)]
public class CanSaveAttribute : System.Attribute
{
    public string author="";
    public string versionNumber="";
    public bool isCheck;
}

自己设计的代码无论多烂,自己都觉得像诗一样美好,自己总会去回味。自己不是专业的程序,一开始只是一个叛逆的爱打游戏的少年。可能是为了做一个游戏,又或者是儿时的科普读物让我向往计算机,我走上了游戏制作人的道路,开始自学unity和C#,我走过好多弯路,无论人生还是学习编程的过程中,我失败无数次。也长大了对游戏不再那么痴迷,但是我对编程的热爱却没有减退,希望这篇文章能帮助向我一样的自学者。希望每位读者能从我这读到你需要的知识。感谢阅读,感谢您的认真观看。

おすすめ

転載: blog.csdn.net/wsxybz/article/details/128486717