2015-06-20 99 views
0

MS VS 2010,XNA 4.0
所以,我有一个行星&它具有保存和加载功能。简单的二进制读写器代码不工作

public void SaveToFile(ContentManager content) 
    { 
     string path = content.RootDirectory + @"\Objects\Planets\" + this.name [email protected]".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(); 
     } 

这很容易理解,现在不是吗?
现在,当我尝试加载星球动画精灵,我得到一个错误,即说:“值不能为空
参数名:ASSETNAME”

,这是在该行
这种情况发生。 planet = new Animation(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。如果我一个接一个地存储2个字符串,那么读者可能不知道第一个字符的结尾在哪里?我可能保存错了吗?

我的目标是让二进制文件被加载和保存,并且它们是行星,火箭,地图等,它们是这些类的构造函数所需的名称和值的集合。

+1

你写'planet.FPS'为'double',但是你试着把它看作一个'decimal'? – cubrr

+0

错误消息告诉你有一个名为'assetName'的参数,当需要非空值时,它的值为'null'。当然,这与'BinaryReader'没有直接关系。至于它可能是什么,除非您提供可靠地再现问题的[良好_minimal_,_complete_代码示例](http://stackoverflow.com/help/mcve),否则不可能说。 –

+0

FPS是一个浮动。二进制写入器读取器没有浮点数,所以当我保存一个浮点数时,我将其保存为十进制数,当我加载它时,我加载小数点并将其转换为浮点数:(float)br.ReadDecimal();. – Monset

回答

0

在您的testFunction()中,您创建一个新的Planet并将其保存到一个文件中,但不分配精灵名称(我猜它没有在Animation构造函数中分配),所以当它保​​存时精灵名称将为空。 为了避免这种情况,您需要先将planet.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 [email protected]".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翻番。


编辑:从您的评论似乎你认为空字符串应该使用静态方法来分配,但这里有2米不同的东西。
首先来看看这个名字里面Cont.Texture2D()

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

这个名字是Texture2D.Name
现在看看里面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";

+0

this.name代表地球的名称。对不起,我没有提到一个星球有它的名字。所以,这个星球的名字是一个简单的名字,可以说,asteroid1.Name是精灵的路径。正如你没有注意到的,每次我加载Texture2D,我用Cont.Texture2D(字符串路径)来做,并且该函数返回一个新的Texture2D,它的名字就是它从中加载的路径。 – Monset

+0

@Monset通过编辑我的答案添加了解释。关于FPS,你可以使用[BinaryReader.ReadSingle()](https://msdn.microsoft.com/en-us/library/system.io.binaryreader.readsingle(v = vs.110).aspx)和[BinaryReader.ReadDouble()](https://msdn.microsoft.com/en-us/library/system.io.binaryreader.readdouble(v = vs.110).aspx)for double。 –

+0

正如你所说的,“name”是Planet类的实例的名称,而“planet”是Planet类中的行星动画,它具有名为Sprite的Texure2D。请原谅我可怜的变量命名系统,在这堂课中我没有太在意。当我将这个星球保存到一个文件中时,首先我保存这个星球的名字,第二个我保存* path *到这个星球动画sprite.There没有任何错误或者对这个错误的理解。我的问题是另一种。 – Monset

1

由于二元书写器阅读器的不协调问题,我决定使用Stream writer-reader。非常感谢@Blas Soriano & @Peter Duniho。

二元作家似乎无法一个接一个地写出2个字符串,这样二进制阅读器就可以读取它们,至少在我的情况下是这样。我曾尝试在另一个项目中使用二进制w-r编写和读取2个字符串,并且他们似乎在那里工作得很好。我希望没有人能够看到发生在我身上的这种事情。再次感谢Blas和Peter。

编辑:
看来,我的文件,我包括在解决方案的内容,“Mars.planet”,在它的属性:复制到输出,从3种可能的选择:是否有更新的,绝不能复制,始终复制复制,选择了总是复制,并且不允许对该文件进行更改,因此,我通过使用我的函数保存文件来更改文件,但是,然后退出游戏,文件返回到旧版本(不是真的如何),而且该版本是一个真正的老版本,并没有我现在需要的所有行,所以当我评论保存代码并取消注释加载代码时,启动游戏,加载函数实际上会加载文件的第一个版本(包含文件时的版本)。

它现在可以工作,但并不是因为我使用Stream w-r,而是因为我将该文件的属性更改为:不要复制。我会回到Binary w-r。