简单的二进制读写器代码不起作用

本文关键字:代码 不起作用 读写器 二进制 简单 | 更新日期: 2023-09-27 17:57:32

MS VS 2010,XNA 4.0
所以,我有一个类Planet&它具有保存和加载功能。

public void SaveToFile(ContentManager content)
    {
        string path = content.RootDirectory + @"'Objects'Planets'" + this.name +@".planet"; 
        using (BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create)))
        {
            bw.Write(name);
            //sprite names
            bw.Write(planet.Sprite.Name); //"planet" is an animation.
            bw.Write(planet.HorFrames);   //and thats why it has a sprite
            bw.Write(planet.VerFrames);   //that has a name
            bw.Write((double)planet.FPS);
            bw.Write(asteroid1.Name);
            bw.Write(asteroid2.Name);
            bw.Write(asteroid3.Name);
            bw.Write(backgroundA.Name);
            //update related
            bw.Write((double)RSpeed);
            bw.Write((double)ASVariety);
            bw.Write((double)A1Chance);
            bw.Write((double)A2Chance);
            bw.Write((double)A3Chance);
            bw.Close();
        }
    }
public void LoadFromFile(ContentManager content, string name)
    {
        string path = content.RootDirectory + @"'Objects'Planets'" + name + @".planet";
        using (BinaryReader br = new BinaryReader(File.OpenRead(path)))
        {
            this.name = br.ReadString();
            this.planet = new Animation(Cont.Texture2D(br.ReadString()), br.ReadInt32(), br.ReadInt32(), (float)br.ReadDecimal(), true);
            this.asteroid1 = Cont.Texture2D(br.ReadString());
            this.asteroid2 = Cont.Texture2D(br.ReadString());
            this.asteroid3 = Cont.Texture2D(br.ReadString());
            this.backgroundA = Cont.Texture2D(br.ReadString());
            this.RSpeed = (float)br.ReadDouble();
            this.ASVariety = (float)br.ReadDouble();
            this.A1Chance = (float)br.ReadDouble();
            this.A2Chance = (float)br.ReadDouble();
            this.A3Chance = (float)br.ReadDouble();
            bposB = new Vector2(backgroundA.Width - 1, 0);
            bspd = new Vector2(-RSpeed / 8f, 0);
            pEngine1 = new ParticleEngine(MSTime, 40, new Vector2(20, -30), new Vector2(2, 1), asteroid1, new Color(100, 100, 100));
            pEngine1.Follow(new Vector2(-200, Game1.window_height / 2));
            pEngine2 = new ParticleEngine(MSTime * 3, 40, new Vector2(20, -30), new Vector2(2, 1), asteroid2, new Color(100, 100, 100));
            pEngine2.Follow(new Vector2(-200, Game1.window_height / 2));
            br.Close();
        }

这很容易理解,不是吗
现在,当我尝试加载行星动画的精灵时,我得到了一个错误,它说:
"值不能为null。
参数名称:assetName"
这发生在
this.planet=新动画(Cont.Texture2D(br.ReadString()),br.ReadInt32(),br.ReadInt32((),(float)br.ReadDecimal(),true)
Cont.Texture2D是一个静态函数,它返回一个Texture2D开关名称等于它加载的路径,它看起来像这样:

public static Texture2D Texture2D(string path)
    {
        Texture2D sprite = content.Load<Texture2D>(path);
        sprite.Name = path;
        return sprite;
    }

所以,当我保存它时,它保存了正确的路径。测试功能如下所示:

private void testFunction()
    {
        /*
        p = new Planet("Mars", 
            new Animation(Cont.Texture2D("Sprites''Planets''mars"), 8, 2, 0.9f, true),
            Cont.Texture2D("Sprites''Backgrounds''space"),
            Cont.Texture2D("Sprites''Asteroids''small''small 1"),
            Cont.Texture2D("Sprites''Asteroids''medium''medium 1"),
            Cont.Texture2D("Sprites''Asteroids''big''big 1"),
            100, 50, 40, 20, 40, 40);
        p.SaveToFile(Content);
        */
        p = new Planet(Content, "Mars");
        tests = p.ToString();
    }

"tests"只是一个测试字符串。现在,我首先执行带注释的代码,这样它就可以保存文件,然后执行未注释的代码。这个行星构造函数只调用LoadFromFile函数,仅此而已。此外,我在项目的内容中保存了文件。我确实说过要把那个文件当作内容(不要编译它)。所以,代码"看到"了文件,这是为了shure,但它在从mars.planet读取的路径上找不到.png。如果我一个接一个地存储了两个字符串,然后读者看不到第一个字符串的末尾在哪里,这可能是错的吗?我可能保存错了吗

我的目标是加载和保存二进制文件,其中包括行星、火箭、地图等,这些文件是这些类的构造函数所需的名称和值的集合。

简单的二进制读写器代码不起作用

由于二进制编写器读取器的不必要复杂性,我决定使用流编写器读取器。非常感谢@Blas Soriano&彼得·杜尼霍。

二进制编写器似乎无法以二进制读取器可以读取的方式一个接一个地写入2个字符串,至少在我的情况下是这样。我确实在另一个项目中尝试过用二进制w-r编写和读取2个字符串,它们在那里似乎很好。我希望没有人能原谅发生在我身上的这种事。再次感谢Blas和Peter。

编辑:
我的文件似乎包含在解决方案的内容"Mars.planet"中,在它的属性中:复制到输出,从3个可能的选项中选择:复制如果更新,从不复制,始终复制,选择了始终复制,这不允许对该文件进行更改,所以,我确实通过使用我的功能保存文件来更改该文件,但随后我退出了游戏,所以这个文件又回到了旧版本(不是真的很简单),那个版本是一个非常旧的版本,没有我现在需要的所有行,所以当我注释保存代码并取消注释加载代码时,启动游戏,加载的功能实际上是加载文件的第一个版本(从我包含文件时起的版本)

它现在可以工作了,但不是因为我正在使用Stream w-r,而是因为我将该文件的属性更改为:请勿复制。我将回到二进制w-r。

testFunction()中,您创建了一个新的Planet并将其保存到一个文件中,而不指定精灵名称(我猜它在Animation构造函数中没有指定),因此保存时精灵名称将为null。为了避免这种情况,你需要指定行星。Sprite.Name,然后将其保存到文件中。

private void testFunction()
{
    Animation planetAnimation = new Animation(Cont.Texture2D("Sprites''Planets''mars"));
    planetAnimation.Sprite.Name = "Sprites''Planets''mars";
    p = new Planet("Mars", 
        planetAnimation , 8, 2, 0.9f, true),
        Cont.Texture2D("Sprites''Backgrounds''space"),
        Cont.Texture2D("Sprites''Asteroids''small''small 1"),
        Cont.Texture2D("Sprites''Asteroids''medium''medium 1"),
        Cont.Texture2D("Sprites''Asteroids''big''big 1"),
        100, 50, 40, 20, 40, 40);
    p.SaveToFile(Content);
    /*
    p = new Planet(Content, "Mars");
    tests = p.ToString();
    */
}

相反,您可以修改LoadSave方法,以避免保存两次该字符串。首先删除或注释SaveToFile():中的bw.Write(planet.Sprite.Name)

public void SaveToFile(ContentManager content)
{
    string path = content.RootDirectory + @"'Objects'Planets'" + this.name +@".planet"; 
    using (BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create)))
    {
        bw.Write(name);
        //sprite names
        //bw.Write(planet.Sprite.Name); //"planet" is an animation.
        bw.Write(planet.HorFrames);   //and thats why it has a sprite
        bw.Write(planet.VerFrames);   //that has a name
        bw.Write((double)planet.FPS);
...

然后更改LoadFromFile()以重用字符串:

public void LoadFromFile(ContentManager content, string name)
{
    string path = content.RootDirectory + @"'Objects'Planets'" + name + @".planet";
    using (BinaryReader br = new BinaryReader(File.OpenRead(path)))
    {
        this.name = br.ReadString();
        this.planet = new Animation(Cont.Texture2D(this.name), br.ReadInt32(), br.ReadInt32(), br.ReadDouble(), true);
        this.asteroid1 = Cont.Texture2D(br.ReadString());
        this.asteroid2 = Cont.Texture2D(br.ReadString());

注意,根据cubrr的建议,我在阅读planet.FPS时将十进制替换为双进制。


EDIT:根据您的评论,您似乎认为应该使用静态方法来分配空字符串,但这里有两件不同的事情
首先看一下Cont.Texture2D():中的名称

public static Texture2D Texture2D(string path)
{
    Texture2D sprite = content.Load<Texture2D>(path);
    sprite.Name = path;
    return sprite;
}

此名称为Texture2D。名称
现在看看SaveToFile():内部

bw.Write(name);
//sprite names
bw.Write(planet.Sprite.Name); //"planet" is an animation.

在这里我们可以看到两个不同的名称,Planet.NamePlanet.Sprite.Name。你把第二个名字分配在哪里?这就是我使用planetAnimation.Sprite.Name = "Sprites''Planets''mars";的原因。