2017年5月27日土曜日

開発再開とバグフィックス

しばらく開発がストップしていましたね。
RPGによくある、ラスボス直前でやる気無くなるアレと大体同じ現象です。
ちょっとしたきっかけで、いいかげん完成させたくなったので、久しぶりにコードを描きました。

本当は久しぶりに弄ってみるくらいのつもりだったのですが、バグを発見してしまったので勢いで直しました。


バグの詳細は以下の通り。

  • セーブしようとすると、「ブブー」と言われてセーブできない。



過去記事に書いたことがあったか覚えていませんが、このゲームでは、独自実装している機能に関連するプロパティを保存するため、セーブデータ作成およびデータロード処理の一部を上書きして処理を追加しています。以下がその部分をまとめた処理です。なお、以前は各機能にばらけていましたが、今回の修正を受けてコードの見通しと保守性に問題があると考え、まとめました。

以下のような処理をしているだけの簡単な処理です。

  • セーブ時、"contents"というハッシュに、保存対象のオブジェクトを詰める
  • ロード時、同じく"contents"というハッシュから、復元されたオブジェクトを取り出す


この部分をコメントアウトすると正常にセーブできるようになったので、やはりセーブデータ作成処理を拡張した部分に問題があるようです。
調査のため、まず最初に、そもそものセーブ・ロード時の処理を追いかけてみようと思います。

上記スクショの処理は、オーバーライド対象のツクールの既存モジュール、DataManagerのmake_save_contentsとextract_save_contentsの処理に倣っています。
元の処理は以下の通り。

さらにコードを溯ると、ハッシュはMarshal.dumpされ、例外は呼び出し元でまとめてrescueされていることが分かります。

確認したところ、やはり「ブブー」と鳴るエラーが発生した場合は、このrescue内の処理に入っていることが分かりました。発生していた例外はTypeErrorでした。

Marshal.dumpの公式ドキュメントを当たってみましょう。
https://docs.ruby-lang.org/ja/latest/method/Marshal/m/dump.html

>再帰的に出力します。
>ファイルに書き出せないオブジェクトをファイルに書き出そうとすると 例外 TypeError が発生します。

…とあるので、ハッシュに突っ込んだオブジェクトのフィールドを辿った先のどこかに書き出せないものがあったのでしょう。

怪しい箇所をコメントアウトしながら二分探索したところ、$todays_resultが持っているSpriteのオブジェクトが原因であることが分かりました。
$todays_resultは、直前の記事で実装していた宿屋成長システムのクラスで、スプライトは宿泊時に敵キャラのグラフィックおよび撃破数・経験値の文字を表示するためのものです。
表示位置が固定なので、空のスプライトをあらかじめ作成した上で、表示時のみ中のビットマップを設定する方式にしています。

Spriteクラスの実装のどの部分が原因でエラーになったかは、予想はつきますが必要無いので調べていません。スプライトのオブジェクトはグラフィック表示時以外は不変であり、そもそもセーブする必要が無いからです。
そういうわけで、セーブ時にオブジェクトを破棄し、ロード時に再作成するように処理を修正しました。

これで直ったはずです、動かしてみましょう。

戦闘して

セーブして

ロードして

寝るとちゃんと本日の首級が表示されます。


以上、久しぶりのコード修正作業でした。

1 件のコメント:

  1. 上記の修正にバグがあり、セーブ後にゲームを継続して次に宿泊した時にスプライトが存在しないためにエラーで落ちました。
    セーブ処理を以前のものに戻し、スプライトの初期化と破棄を表示の前後のタイミングで行うように修正しました。

    返信削除