トップページ > 記事閲覧
構造体を使って作ったセーブデータの読み書き
名前:しろ 日時: 2018/06/14 04:24

初書き込みです。内容がDXライブラリの要素ではなくて恐縮です。 最近、全くC++の事を知らない状態で漠然とゲーム制作を始めたんですが、 プログラミングのセオリーとかが判ってないので以下の解釈で大丈夫なのか不安で書き込みました。 参考にしたサンプルコードは「新・ゲームプログラムの館」さんの セーブデータの作り方の項目 (https://dixq.net/g/58.html)で、構造体を使ってセーブファイルを読み書きする、という内容です。 //--------------------------------------------------------------------------------------- 「save.cpp内の記述」 //セーブデータの構造体 typedef struct { int start_soft; //001起動回数 int play_time; //002起動時間 int highscore; //003ハイスコア }save_data_t; //構造体変換用 int START_SOFT = 0; //001起動回数 int PLAY_TIME = 0; //002起動時間 int HIGHSCORE = 0; //003ハイスコア //ロードの処理 void Savedata_Load() { char *name = "save_data.dat"; //ファイルの場所 FILE *fp; save_data_t save_data; if( ( fp = fopen( name, "rb" ) ) == NULL ) { //セーブファイルが開けない・存在しない時の処理 printfDx("セーブファイルを開けませんでした\n初期値を適用します\n"); //以下の初期値を適用 START_SOFT = 1; //001起動回数 PLAY_TIME = 0; //002起動時間 HIGHSCORE = 0; //003ハイスコア } else { //セーブファイルの読み込みが成功した時の処理 fread( &save_data, sizeof(save_data_t), 1, fp ) ; //ファイルからデータを読み込む fclose( fp ); //構造体→関数 START_SOFT = save_data.start_soft; //001起動回数 PLAY_TIME = save_data.play_time; //002起動時間 HIGHSCORE = save_data.highscore; //003ハイスコア } //モニタリング用:ソフトを立ち上げた時のセーブファイルの数値を表示 printfDx("ソフトを立ち上げた時の数値\n起動回数:%d\n起動時間:%d\nハイスコア:%d\n", START_SOFT, PLAY_TIME, HIGHSCORE); } //セーブの処理 void Savedata_Save() { char *name = "save_data.dat"; //ファイルの場所 FILE *fp; save_data_t save_data; //関数→構造体 save_data.start_soft = START_SOFT; //001起動回数 save_data.play_time = PLAY_TIME; //002起動時間 save_data.highscore = HIGHSCORE; //003ハイスコア //セーブファイルが作成される fp = fopen( name, "wb" ); fwrite( &save_data, sizeof(save_data_t), 1, fp ) ; fclose( fp ); } //-------------------------------------------------------------------------------------------- 上のロードとセーブの処理を、「main.cpp」で、 Savedata_Load();  ↓(ループに入る手前で読み込み) メインのループ処理  ↓(ループ抜けてソフトを終了する手前) Savedata_Save(); と処理させる。 //--------------------------------------------------------------------- 最初、構造体を別の.cppファイルから読ませてセーブファイルの数値を利用した処理に使おうとしてたのですが、 構造体の利用方法が判ってないせいかエラーばかり出てしまって結局エラーが無くなることがなかったのと、 思った数字にならないという状態が続き、無い知恵をフルに搾って上のように 構造体と似た名前のint関数を用意して、 読み書きの時にわざわざ変換し合うような上の書き方にしたらエラーも出さずに、 ファイルも読み込みと書き込みが出来て中身も変な数字にならずに目的の数値を保持したまま動作し、 セーブファイルの値を持った関数を別の処理に利用もエラー無しに出来るようになりました。 目的通りに動くようになったのですが、本当に正解なのか?いずれ問題を起こす要因を持ってるのではないか?とか、 プログラミングのことをよく知らないからか、とても不安に感じてしまいます。 すいません上手く説明出来なくて長々と書いてしまったのですが、 端的な質問にすると、「エラーなく動いてればこれでも良い」ということで解釈してしまっても大丈夫なんでしょうか?
メンテ

Page: 1 |

Re: 構造体を使って作ったセーブデータの読み書き ( No.1 )
名前:_NODATA 日時:2018/06/14 06:32

サンプルだから書いていないのかもしれませんが、セーブ側でエラー処理が無いのが気になります。 また、START_SOFTなどの変数は save.cpp 内にあり、「変換用」として用意したもの、と書いてありますが、 ということは、同じ内容を意味する変数が main.cpp 側などにもあるのでしょうか? Save関数内では START_SOFT などの変数を保存していますが、これらの変数は main.cpp 側から見えるように (いじれるように)しているのでしょうか?そうでないと、これらの変数は最初にLoad関数で読み込んだ値から 変更されないことになります。
メンテ
Re: 構造体を使って作ったセーブデータの読み書き ( No.2 )
名前:しろ 日時:2018/06/14 08:09

>セーブ側でエラー処理が無い セーブ時は要らないという判断で、こうしました。 ロードの時は、もしセーブファイルが無い時(初回起動や意図的にファイルを削除されてる時)、 初期値を与える事で間違いない数値にしてやる事と、数値が代入されない事によるエラーを避ける為に設けてます。 これは、PCゲームにて予め製作者側が用意していたセーブファイルがトラブルで破損したり、プレイヤーが消した時、 データ破損を想定していない時にソフト自体が数値のエラーで立ち上がらない深刻なバグを生む。という記事を見たことがあり、 それに対する自分なりの回答と対策です。 セーブ側に無い理由は、単純に書く文字数の手間が減るってだけです。 セーブ処理でのセーブファイル作成は確定の処理ですので、その前の変換と他で使った時の数値がきちんとしてれば、ほぼ100%ファイルが作られます。 もしも、何かの理由でファイルが作られない時、次の起動時はロード処理で初期値の指定が行われて・・・・と、なるから文字数だけ増える印象があったので削りました。 >変換用として用意した変数に関して どう説明をすれば良いのか判らないのですが、 main.cppでも他でもどこでもSTART_SOFTが利用・組み込み可能で値も指定・変更可能にしてます。 例えば、トロフィー機能つけるために起動回数の値をトリガーにする処理に利用するとかなど。 変数START_SOFTが処理の中で例えば値を0から1に増やしてソフトを終了した時、 START_SOFTの1は構造体start_softになり保存。 次にソフトを起動した時、ファイルが読み込まれているなら、構造体start_softは1なのでSTART_SOFTも1。 START_SOFT ++;などでカウントアップしても、 終了時777だとしたら、次回起動時は777から始まるので、きちんと数値を読み書きして保持できているんじゃないかと自分は思っている感じです。
メンテ
Re: 構造体を使って作ったセーブデータの読み書き ( No.3 )
名前:yumetodo 日時:2018/06/14 13:40

>START_SOFT ++;などでカウントアップしても、 なんというか、少なくとも6つの過度の放射線被曝事故を引き起こし、3人が死亡した例を思い出す・・・ 非推奨だった bool 型に対するインクリメント演算子を削除 - cpprefjp C++日本語リファレンス ttps://cpprefjp.github.io/lang/cpp17/remove_deprecated_increment_of_bool.html
メンテ
Re: 構造体を使って作ったセーブデータの読み書き ( No.4 )
名前:しろ 日時:2018/06/14 15:12

>なんというか、少なくとも6つの過度の放射線被曝事故を引き起こし、3人が死亡した例を思い出す・・・ ?????正直良くわかりません、それに作るものもそこまでのモノでも無いんですが。 そういう事があったって事は覚えておきます。 ありがとうございます。 自分でも読み返してみると、質問が質問として機能してないですかね? 自分としては、 コードを書く→なんかエラー→違う書き方してみる→なんかエラーなしで動いた→動いたならOK?→次行ってみよう と、ど素人が進んで行った過程で、動いたならOK?から次行ってみようの判断の基準に悩んでるという質問する予定だったんですが、 屁理屈じみた如何様にも解釈できる文章になっていたのかもしれないです・・・。 すいません、ど素人なんでただただ不安なだけっぽいです。 割り切って、次行ってみますエラーが出た時にはまたその時考えます。
メンテ
Re: 構造体を使って作ったセーブデータの読み書き ( No.5 )
名前:yumetodo 日時:2018/06/17 13:15

正直構造体にセーブデータを書くのは落とし穴がいくつかあり、初心者にはお勧めできないので json11 ttps://github.com/dropbox/json11/ 紹介記事: C++11でjsonを扱う方法。json11 - Qiita ttps://qiita.com/YukiMiyatake/items/497e2fe807d09141e000 とかを使ってjsonというテキストファイルのフォーマットにしてあげるほうがいいのではないかなとだけ言っておきます。
メンテ
Re: 構造体を使って作ったセーブデータの読み書き ( No.6 )
名前:しろ(解決) 日時:2018/06/22 23:33

>>yumetodoさん 情報ありがとうございます。 リンク先見た感じ実際扱えるかどうか判らないですが、 紐解いて勉強してみたいと思います。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存