【问题标题】:What's the best way to save terraindata to file in Runtime?在运行时将地形数据保存到文件的最佳方法是什么?
【发布时间】:2019-06-27 17:04:50
【问题描述】:

我的游戏允许用户在运行时修改地形,但现在我需要保存所述地形。我尝试将地形的高度图直接保存到一个文件中,但是对于这个 513x513 高度图,这需要将近两分钟的时间来编写。

解决这个问题的好方法是什么?有什么办法可以优化写入速度,还是我的方法不对?

    public static void Save(string pathraw, TerrainData terrain)
    {
        //Get full directory to save to
        System.IO.FileInfo path = new System.IO.FileInfo(Application.persistentDataPath + "/" + pathraw);
        path.Directory.Create();
        System.IO.File.Delete(path.FullName);
        Debug.Log(path);

        //Get the width and height of the heightmap, and the heights of the terrain
        int w = terrain.heightmapWidth;
        int h = terrain.heightmapHeight;
        float[,] tData = terrain.GetHeights(0, 0, w, h);

        //Write the heights of the terrain to a file
        for (int y = 0; y < h; y++)
        {
            for (int x = 0; x < w; x++)
            {
                //Mathf.Round is to round up the floats to decrease file size, where something like 5.2362534 becomes 5.24
                System.IO.File.AppendAllText(path.FullName, (Mathf.Round(tData[x, y] * 100) / 100) + ";");
            }
        }
    }

作为旁注,Mathf.Round 似乎不会对节省时间产生太大影响,如果有的话。

【问题讨论】:

    标签: unity3d terrain unity3d-terrain


    【解决方案1】:

    您正在进行大量的小型单独文件 IO 调用。文件 IO 总是耗时且昂贵,因为它包含打开文件、写入文件、保存文件和关闭文件。


    相反,我宁愿使用例如生成完整的字符串。 StringBuilder 这也比使用类似的东西更有效

    var someString 为了(...) { someString += "xyz" }

    因为后者总是分配一个新的string

    然后使用例如FileStreamStringWriter.WriteAsync(string) 用于异步编写。

    也宁愿使用Path.Combine,而不是直接通过/ 连接字符串。 Path.Combine 根据所使用的操作系统自动使用正确的连接器。

    而不是FileInfo.Directory.Create,而是使用Directory.CreateDirectory,如果目录已经存在,它不会引发异常。

    类似

    using System.IO;
    
    ...
    
    public static void Save(string pathraw, TerrainData terrain)
    {
        //Get full directory to save to
        var filePath = Path.Combine(Application.persistentDataPath, pathraw);
        var path = new FileInfo(filePath);
        Directory.CreateDirectory(path.DirectoryName);
    
        // makes no sense to delete 
        // ... rather simply overwrite the file if exists
        //File.Delete(path.FullName);
        Debug.Log(path);
    
        //Get the width and height of the heightmap, and the heights of the terrain
        var w = terrain.heightmapWidth;
        var h = terrain.heightmapHeight;
        var tData = terrain.GetHeights(0, 0, w, h);
    
        // put the string together
        // StringBuilder is more efficient then using
        // someString += "xyz" because latter always allocates a new string
        var stringBuilder = new StringBuilder();
        for (var y = 0; y < h; y++)
        {
            for (var x = 0; x < w; x++)
            {
                //                                                         also add the linebreak if needed
                stringBuilder.Append(Mathf.Round(tData[x, y] * 100) / 100).Append(';').Append('\n');
            }
        }
    
        using (var file = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
        {
            using (var streamWriter = new StreamWriter(file, Encoding.UTF8))
            {
                streamWriter.WriteAsync(stringBuilder.ToString());
            }
        }
    }
    

    您可能想要指定如何以某种精度准确地打印数字,例如

    (Mathf.Round(tData[x, y] * 100) / 100).ToString("0.00000000");
    

    【讨论】:

    • 啊,这很有道理,是的!您发布的示例不仅看起来有效,而且还完美地指出了为什么它没有按预期工作,因为我之前没有与 System.IO 合作过那么多。谢谢!
    猜你喜欢
    • 2016-09-30
    • 1970-01-01
    • 2010-10-16
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 2018-06-16
    相关资源
    最近更新 更多