请求以大块方式加载我的文件的方向(仅需要建议)

|| 最近几天,我一直在研究一种方法,可以将保存我的xna游戏的1.44亿个图块表示压缩到非常小的尺寸。设法实现这一目标之后,我现在发现自己很困惑如何将它们从文件中大块地取回来。 在文件中,我有。 整数(使用7BitEncodedInt方法将其压缩为字节) 一个字节 压缩的整数表示切片的数量,其后的字节确定切片的类型。这一切都很好,而且效果很好。最重要的是,它将文件大小平均缩小到仅50mb。 问题是我目前正在回读整个文件。 从文件中我得到了这个。 每个图块的索引值(在我抓取图块时只是一个基本迭代) 每个图块的类型(以字节值表示) 一个字节值,代表该图块的纹理(这很难解释,但在每个图块的基础上是必需的) 所有这些的最终结果是我正在设法保存文件,并且只使用了大约50mb。但是通过将整个东西装回去,它可以在公羊上扩展到将近1.5 gig。我真的无法再牺牲瓷砖信息了。因此,我需要一种仅根据玩家位置加载地图部分的方法。目标是在100-200mb范围内 我一直在研究使用四叉树映射文件的内存,几乎可以找到以块加载文件的任何方式。尽管这些选项看起来都不错,但我不确定哪个是最好的,或者如果给出这种情况,可能还有另一个更好的选择。所有这一切的另一个问题是这些解决方案似乎都非常复杂(特别是因为这是我第一次使用它们),尽管我不反对致力于冗长的编码,但我想知道它会我需要的东西之前。 我的问题是,鉴于我在拉入文件时必须如何处理该文件,以及需要根据播放器位置进行处理的事实,哪种方法最好?我只是在这里寻找方向。代码始终受到欢迎,但不是必需的。     
已邀请:
        您希望在Tile类中具有固定长度的变量,并实现类似以下内容的方法: 这是一个集合类(人)的示例,该类可以从序列化到文件的集合中基于索引获取值。 人是作为“人”集合基础的类。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FileStreamDatabaseTest
{
    class Program
    {
        static void Main(string[] args)
        {
            People.OpenCollection();
            People.Test_WillOverwriteData();
            People.CloseCollection();
            Console.ReadLine();
        }
    }

    public class Person
    {
        // define maxium variable sizes for serialisation
        protected static int pMaxLength_FirstName = 64;
        protected static int pMaxLength_Age = 10;
        public static int MaxObjectSize
        {
            get
            {
                // return the sum of all the maxlegnth variables to define the entire object size for serialisation
                return pMaxLength_FirstName + pMaxLength_Age;
            }
        }

        // define each object that will be serialised as follows 
        protected string pFirstName;
        public string Firstname
        {
            set
            {
                // ensure the new value is not over max variable size
                if (value.Length > pMaxLength_FirstName)
                    throw new Exception(\"the length of the value is to long.\");

                pFirstName = value;
            }
            get
            {
                return pFirstName;
            }
        }
        protected int pAge;
        public int Age
        {
            get
            {
                return pAge;
            }
            set
            {
                pAge = value;
            }
        }

        public byte[] Serialise()
        {
            // Output string builder
            StringBuilder Output = new StringBuilder();

            // Append firstname value
            Output.Append(Firstname);

            // Add extra spaces to end of string until max length is reached
            if (Firstname.Length < pMaxLength_FirstName)
                for (int i = Firstname.Length; i < pMaxLength_FirstName; i++)
                    Output.Append(\" \");

            // Append age value as string
            Output.Append(Age.ToString());

            // Add extra spaces to end of string until max length is reached
            int AgeLength = Age.ToString().Length;
            if (AgeLength < pMaxLength_Age)
                for (int i = AgeLength; i < pMaxLength_Age; i++)
                    Output.Append(\" \");

            // Return the output string as bytes using ascii encoding
            return System.Text.Encoding.ASCII.GetBytes(Output.ToString());
        }

        public void Deserialise(byte[] SerialisedData)
        {
            string Values = System.Text.Encoding.ASCII.GetString(SerialisedData);

            pFirstName = Values.Substring(0, pMaxLength_FirstName).Trim();
            pAge = int.Parse(Values.Substring(pMaxLength_FirstName, pMaxLength_Age).Trim());
        }
    }

    public static class People
    {
        private static string tileDatasource = @\"c:\\test.dat\";
        private static System.IO.FileStream FileStream;

        public static void OpenCollection()
        {
            FileStream = new System.IO.FileStream(tileDatasource, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None);
        }

        public static void CloseCollection()
        {
            FileStream.Close();
            FileStream.Dispose();
            FileStream = null;
        }

        public static void SaveCollection(Person[] People)
        {
            FileStream.SetLength(People.Length * Person.MaxObjectSize);
            FileStream.Position = 0;

            foreach (Person PersonToWrite in People)
            {
                // call serialise to get bytes
                byte[] OutputBytes = PersonToWrite.Serialise();

                // write the output buffer
                // note: this will always be the same size as each variable should 
                //       append spaces until its max size is reached
                FileStream.Write(OutputBytes, 0, OutputBytes.Length);
            }
        }

        public static Person GetValue(int Index)
        {
            // set the stream position to read the object by multiplying the requested index with the max object size
            FileStream.Position = Index * Person.MaxObjectSize;

            // read the data
            byte[] InputBytes = new byte[Person.MaxObjectSize];
            FileStream.Read(InputBytes, 0, Person.MaxObjectSize);

            // deserialise
            Person PersonToReturn = new Person();
            PersonToReturn.Deserialise(InputBytes);

            // retun the person
            return PersonToReturn;
        }

        public static void Test_WillOverwriteData()
        {
            long StartTime;
            long EndTime;
            TimeSpan TimeTaken;

            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Creating 2,000,000 test people... \");
            StartTime = DateTime.Now.Ticks;
            Person[] People = new Person[2000000];
            for (int i = 0; i < 2000000; i++)
            {
                People[i] = new Person();
                People[i].Firstname = \"TestName.\" + i;
                People[i].Age = i;
            }
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");

            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Serialising Collection to disk... \");
            StartTime = DateTime.Now.Ticks;
            SaveCollection(People);
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");

            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Redundancy Test... \");
            StartTime = DateTime.Now.Ticks;
            bool Parsed = true;
            int FailedCount = 0;
            for (int i = 0; i < 2000000; i++)
            {
                if (GetValue(i).Age != i)
                {
                    Parsed = false;
                    FailedCount++;
                }
            }
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> \" + (Parsed ? \"PARSED\" : \"FAILED (\" + FailedCount + \" failed index\'s\"));
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");

            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Reading 10,000 index\'s at once... \");
            StartTime = DateTime.Now.Ticks;
            Person[] ChunkOfPeople = new Person[10000];
            for (int i = 0; i < 10000; i++)
                ChunkOfPeople[i] = GetValue(i);
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");


            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Reading 100,000 index\'s at once... \");
            StartTime = DateTime.Now.Ticks;
            ChunkOfPeople = new Person[100000];
            for (int i = 0; i < 100000; i++)
                ChunkOfPeople[i] = GetValue(i);
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");

            Console.WriteLine(\"-------------------------------------------------------------------\");
            Console.WriteLine(\"*** Reading 1,000,000 index\'s at once... \");
            StartTime = DateTime.Now.Ticks;
            ChunkOfPeople = new Person[1000000];
            for (int i = 0; i < 1000000; i++)
                ChunkOfPeople[i] = GetValue(i);
            EndTime = DateTime.Now.Ticks;
            TimeTaken = new TimeSpan(EndTime - StartTime);
            Console.WriteLine(\"-> Completed in \" + TimeTaken.TotalSeconds + \" seconds\");
        }
    }     
}
    
        有很多选项,但并非所有选项都适合您的特定项目: 不要将单个文件用于所有数据。将地图分为较小的“房间”,然后将每个地图存储在自己的文件中。仅加载玩家开始进入的“房间”,并抢先加载相邻的“房间”,然后卸载旧的“房间”。 减少您需要存储的图块数量。使用程序生成来创建区域的布局。 如果您有一个10x10的房间,并且地板是由单个瓷砖类型制成的,则不要存储100个单独的瓷砖,而要使用一个特定的标记“此区域的地板为10x10的地板”。如果是墙,则保存开始和结束位置以及纹理类型。如果您在一个开放字段的中间有一个多瓦片的doodad,并且它的位置与故事无关,则将其随机放置在该字段中(并将种子保存为随机数生成器在地图文件中,因此,下一步时间,它将出现在同一位置)。     

要回复问题请先登录注册