私はSkyrimのセーブゲームマネージャーを作成中で、問題が発生しました。 SaveGameオブジェクトを単独で作成すると、保存のビットマップ部分が正しく機能します。しかし、そのメソッドをループで呼び出すと、ビットマップは誤った値をとります。主に別のセーブ・ゲームに似ています。ビットマップ内のデータが範囲外になるのはなぜですか?
TL; DR - 埋め込まれている画像以外のキャラクターセーブ用の正しい情報がフォームのリストボックスに表示されるのはなぜですか?正しい画像を選択するのではなく、最後に処理された画像を選択するように見えます。開いているファイルダイアログで選択したときとプロセスがどのように異なるのですか?
編集:アップデート - 私は、各セーブデータオブジェクトに格納されているビットマップに見て、scanDirectoryForSavesでセーブデータの作成中に何とかそれをめちゃくちゃにされることがわかりました。ビットマップにオブジェクトスコープの問題があり、わからないバイトポインタを使用していますか?ここで
は私のセーブゲームオブジェクトの静的なファクトリのためのコードです:私のフォームで
public string Name { get; private set; }
public int SaveNumber { get; private set; }
public int PictureWidth { get; private set; }
public int PictureHeight { get; private set; }
public Bitmap Picture { get; private set; }
public DateTime SaveDate { get; private set; }
public string FileName { get; private set; }
public static SaveGame ReadSaveGame(string Filename)
{
SaveGame save = new SaveGame();
save.FileName = Filename;
byte[] file = File.ReadAllBytes(Filename);
int headerWidth = BitConverter.ToInt32(file, 13);
save.SaveNumber = BitConverter.ToInt32(file, 21);
short nameWidth = BitConverter.ToInt16(file, 25);
save.Name = System.Text.Encoding.UTF8.GetString(file, 27, nameWidth);
save.PictureWidth = BitConverter.ToInt32(file, 13 + headerWidth - 4);
save.PictureHeight = BitConverter.ToInt32(file, 13 + headerWidth);
save.readPictureData(file, 13 + headerWidth + 4, save.PictureWidth, save.PictureHeight);
save.SaveDate = DateTime.FromFileTime((long)BitConverter.ToUInt64(file, 13 + headerWidth - 12));
return save;
}
private void readPictureData(byte[] file, int startIndex, int width, int height)
{
IntPtr pointer = Marshal.UnsafeAddrOfPinnedArrayElement(file, startIndex);
Picture = new Bitmap(width, height, 3 * width, System.Drawing.Imaging.PixelFormat.Format24bppRgb, pointer);
}
、私は特定のディレクトリ内のすべてのセーブファイルを読み取る方法を使用し、外のセーブデータオブジェクトを作成しますそれらを文字の名前に基づいて辞書に格納します。
private Dictionary<string, List<SaveGame>> scanDirectoryForSaves(string directory)
{
Dictionary<string, List<SaveGame>> saves = new Dictionary<string, List<SaveGame>>();
DirectoryInfo info = new DirectoryInfo(directory);
foreach (FileInfo file in info.GetFiles())
{
if (file.Name.ToLower().EndsWith(".ess") || file.Name.ToLower().EndsWith(".bak"))
{
string filepath = String.Format(@"{0}\{1}", directory, file.Name);
SaveGame save = SaveGame.ReadSaveGame(filepath);
if (!saves.ContainsKey(save.Name))
{
saves.Add(save.Name, new List<SaveGame>());
}
saves[save.Name].Add(save);
}
}
foreach (List<SaveGame> saveList in saves.Values)
{
saveList.Sort();
}
return saves;
}
私はリストボックスにキーを追加します。リストボックスで名前を選択すると、その文字の最新の保存がフォームに表示されます。名前、日付、およびその他のフィールドは各文字に適していますが、ビットマップはゲームの画像を保存する特定の文字のバリエーションです。
開いているファイルダイアログボックスとリストボックスからの保存を選択する際に、同じ方法を呼び出してフォームフィールドを更新します。あなたがIntPtr
を取るconstructorを使用してBitmap
を作成すると
private void updateLabels(SaveGame save)
{
nameLabel.Text = "Name: " + save.Name;
filenameLabel.Text = "File: " + save.FileName;
saveNumberLabel.Text = "Save Number: " + save.SaveNumber;
saveDateLabel.Text = "Save Date: " + save.SaveDate;
saveGamePictureBox.Image = save.Picture;
saveGamePictureBox.Image = ScaleImage(
saveGamePictureBox.Image, saveGamePictureBox.Width, saveGamePictureBox.Height);
saveGamePictureBox.Invalidate();
}
を= File.ReadAllBytes(Filename); '?答えてくれてありがとう! – Gilbrilthor
はい。 'file'はバイト配列への唯一の参照です。したがって、メソッドが返ってくると、いつでもガベージコレクタはメモリを解放することができます。 (あなたの 'IntPtr'は配列を指していますが、マネージ*リファレンスではないのでガベージコレクタはそれを無視します。)しかし、GCはすぐには動作しないかもしれません。 –