2016-10-01 5 views
0

私はゲームを作っており、ユーザーの進行状況をバイナリファイルでコンピュータに保存しています。 Userクラスの店がいくつか:STAT値についてゲームがこのクラスをシリアル化しているのはなぜですか?

  1. 整数(直列化)
  2. ユーザー名のための文字列と皮膚の資産、私が作成したAchievementクラスとInventoryItemクラスの両方の
  3. リスト、私自身。すべての直列化可能です

    public string Username = ""; 
        // ID is used for local identification, as usernames can be changed. 
        public int ID; 
    
        public int Coins = 0; 
        public List<Achievement> AchievementsCompleted = new List<Achievement>(); 
        public List<InventoryItem> Inventory = new List<InventoryItem>(); 
        public List<string> Skins = new List<string>(); 
    
        public string CurrentSkinAsset { get; set; } 
    

    Achievementクラス店int秒、bool秒、およびstring秒、:ここで

Userフィールドです。 InventoryItemクラスには、その名前(文字列)とアイテムの使用時に呼び出されるデリゲートであるInventoryActionが格納されます。

これらはAchievementクラスのフィールドです:

public int ID = 0; 
    public string Name = ""; 
    public bool Earned = false; 
    public string Description = ""; 
    public string Image; 
    public AchievmentDifficulty Difficulty; 
    public int CoinsOnCompletion = 0; 

    public AchievementMethod OnCompletion; 
    public AchievementCriteria CompletionCriteria; 

    public bool Completed = false; 

そして、ここではInventoryItemクラスのフィールドです:

InventoryAction actionWhenUsed; 
    public string Name; 

    public string AssetName; 

はInventoryAction変数のソース私のXNAGameクラスです。つまり、XNAGameクラスには「UseSword()」などのメソッドがあり、これをInventoryItemクラスに渡します。以前は、メソッドはGame1クラスに格納されていましたが、Gameクラス(これはGame1から継承されています)は直列化できず、それを制御する方法はありません。これが私がXNAGameクラスを持っている理由です。

シリアル化しようとするとエラーが発生します。「 'SpriteFont'クラスはシリアル化可能とマークされていません」などです。まあ、私のXNAGameクラスにSpriteFontオブジェクトがあり、いくつかのクイックテストでは、これが問題の原因であることがわかりました。まあ、私はSpriteFontクラスがSerializableかどうかを制御できません。

なぜこのゲームが行われますか? XNAGameクラスのすべてのフィールドを直列化可能にしなければならない理由は何ですか?いくつかの方法がありますか?

私が13歳だと答えるときは、あなたが使用しているすべての用語を理解していない可能性があります。コードサンプルが必要な場合は、それらを提供してくれることをうれしく思います。前もって感謝します!

編集私が考えている解決策の1つは、DictionaryにInventoryActionデリゲートを保存することですが、これは苦痛になり、プログラミングの面ではあまり良くありません。これが唯一の方法だとすれば、私はそれを受け入れます(正直なところ、これが最良の解決策だと思います)。

EDIT 2:これはUser.Serializeメソッドのコードです(私は非効率で何をしているのか知っています。データベースを使用する必要があります、blah、blah、blah)。今すぐ私と一緒にクマ):。

 FileStream fileStream = null; 
     List<User> users; 
     BinaryFormatter binaryFormatter = new BinaryFormatter(); 
     try 
     { 
      if (File.Exists(FILE_PATH) && !IsFileLocked(FILE_PATH)) 
      { 
       fileStream = File.Open(FILE_PATH, FileMode.Open); 
       users = (List<User>)binaryFormatter.Deserialize(fileStream); 
      } 
      else 
      { 
       fileStream = File.Create(FILE_PATH); 
       users = new List<User>(); 
      } 

      for (int i = 0; i < users.Count; i++) 
      { 
       if (users[i].ID == this.ID) 
       { 
        users.Remove(users[i]); 
       } 
      } 

      foreach (Achievement a in AchievementsCompleted) 
      { 
       if (a.CompletionCriteria != null) 
       { 
        a.CompletionCriteria = null; 
       } 
       if (a.OnCompletion != null) 
       { 
        a.OnCompletion = null; 
       } 
      } 

      users.Add(this); 
      fileStream.Position = 0; 
      binaryFormatter.Serialize(fileStream, users); 
+0

単語を使って*説明するのではなく、コードを投稿する必要があります。 – Aybe

+0

いくつかのコードサンプルを投稿してください。シリアライズしているクラスのコードを見る必要があります。シリアライズ可能でないクラスへの参照があります。 – PhillipH

+0

@Aybe私は、Userクラス、InventoryInterfaceクラス、およびAchievementクラスのコードを追加しました。 –

答えて

0

わかりましたので、私はそれを考え出しました。

XNAGameクラスのディクショナリは、ItemType(列挙型)とInventoryActionの2つを格納するのが最善の解決策でした。基本的には、アイテムを使うときにタイプをチェックしてから、それを調べます。試してみた皆さん、ありがとうございました。質問が混乱していたら、すみません。

0

あなたがデザインでSpriteFontをシリアル化することはできません、実際にこれが可能である(.XNBファイル)が、それは公表されていません。

解決策:直列化されたクラス

ストリップそれをオフにします。

代替:

  1. あなたには、いくつかのフォントをシリアル化しなければならないいくつかの理由のために、私の心に来る最初の事はロールアウトするなど、独自のフォントシステムをBMFontようになりますが、それは大変なのです場合あなたがすでに行っているかもしれない場所であればどこでもそれを使用しなければならないからです。

  2. 事前定義された量のフォントを作成します(サイズ10/11/12などでArial/Times/Courier ... )を使用してXNAコンテンツアプリ(リカーすることはできませんl正確な名前)。このユーザープリファレンスを2つのストリングとして保管します。 string.Format(...)を使用すると、正しいフォントを簡単に読み込めるようになります。

選択肢2は確かに最も簡単でロールアウトするために数分以上かかることはありませんです。

EDIT

基本的に、私は次の操作を行う代わりに、デリゲートを保存する:

  • インベントリ項目は、独自の型を持つ
  • 各タイプ名はデ/適宜連載
  • ですそれらのロジックはメインゲームクラスではもう発生しません
  • あなたは手動で行う必要はありませんあなたが複数のクラスになってしまいますしながら、試合項目タイプ/アクションメソッド

だから、あなたは分離不安を持っていて、きれいにあなたのメインループを維持し、比較的ジェネリックことができます。

コード:

public static class Demo 
{ 
    public static void DemoCode() 
    { 
     // create new profile 
     var profile = new UserProfile 
     { 
      Name = "Bill", 
      Gold = 1000000, 
      Achievements = new List<Achievement>(new[] 
      { 
       Achievement.Warrior 
      }), 
      Inventory = new Inventory(new[] 
      { 
       new FireSpell() 
      }) 
     }; 

     // save it 
     using (var stream = File.Create("profile.bin")) 
     { 
      var formatter = new BinaryFormatter(); 
      formatter.Serialize(stream, profile); 
     } 

     // load it 
     using (var stream = File.OpenRead("profile.bin")) 
     { 
      var formatter = new BinaryFormatter(); 
      var deserialize = formatter.Deserialize(stream); 
      var userProfile = (UserProfile) deserialize; 

      // set everything on fire :) 
      var fireSpell = userProfile.Inventory.Items.OfType<FireSpell>().FirstOrDefault(); 
      if (fireSpell != null) fireSpell.Execute("whatever"); 
     } 
    } 
} 

[Serializable] 
public sealed class UserProfile 
{ 
    public string Name { get; set; } 
    public int Gold { get; set; } 
    public List<Achievement> Achievements { get; set; } 
    public Inventory Inventory { get; set; } 
} 

public enum Achievement 
{ 
    Warrior 
} 

[Serializable] 
public sealed class Inventory : ISerializable 
{ 
    public Inventory() // for serialization 
    { 
    } 

    public Inventory(SerializationInfo info, StreamingContext context) // for serialization 
    { 
     var value = (string) info.GetValue("Items", typeof(string)); 
     var strings = value.Split(';'); 
     var items = strings.Select(s => 
     { 
      var type = Type.GetType(s); 
      if (type == null) throw new ArgumentNullException(nameof(type)); 
      var instance = Activator.CreateInstance(type); 
      var item = instance as InventoryItem; 
      return item; 
     }).ToArray(); 
     Items = new List<InventoryItem>(items); 
    } 

    public Inventory(IEnumerable<InventoryItem> items) 
    { 
     if (items == null) throw new ArgumentNullException(nameof(items)); 
     Items = new List<InventoryItem>(items); 
    } 

    public List<InventoryItem> Items { get; } 

    #region ISerializable Members 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     var strings = Items.Select(s => s.GetType().AssemblyQualifiedName).ToArray(); 
     var value = string.Join(";", strings); 
     info.AddValue("Items", value); 
    } 

    #endregion 
} 

public abstract class InventoryItem 
{ 
    public abstract void Execute(params object[] objects); 
} 

public abstract class Spell : InventoryItem 
{ 
} 

public sealed class FireSpell : Spell 
{ 
    public override void Execute(params object[] objects) 
    { 
     // using 'params object[]' a simple and generic way to pass things if any, i.e. 
     // var world = objects[0]; 
     // var strength = objects[1]; 
     // now do something with these ! 
    } 
} 
+0

さて、問題は単なるSpriteFontオブジェクトではありません。 _All_ 'XNAGame'クラスのフィールドはシリアライズする必要がありますが、これを行う必要はありません。 –

+0

あなたはどのようにあなたのものをシリアライズしていますか? XML? JSON? – Aybe

+0

申し訳ありませんが、私はそれを説明するのを忘れていました。私はそれをバイナリファイルの.binファイルに保存しています。私はこれを表示するために私の質問を編集します。 –

関連する問題