質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

解決済

2回答

4321閲覧

構造体の配列を使用したゲームのセーブ・ロード機能について

_26_K

総合スコア11

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

0クリップ

投稿2019/07/14 07:54

編集2019/07/14 14:56

前提・実現したいこと

現在C++のDxライブラリを使用してプレイヤーと敵が大量に登場するゲームを作っています。
プレイヤーと敵は構造体を使用して管理していたのですが、このゲームにファイル入出力機能を付けて
セーブ・ロード機能を付けたいと思い方法を何日か調査していたのですが、方法が思い浮かばず、
また参考になるサイトを見つけることが出来ませんでした。

参考になるサイト、もしくは方法(アルゴリズム)があれば教えていただけないでしょうか?

該当のソースコード

C++

1struct Test { 2 char name[30]; 3 int zanki; 4 int score; 5 }; 6 7 struct Test player[100]; //プレイヤー 保存対象 8 struct Test enemy[100]; //敵 保存対象 9

補足情報

プレイヤー、敵の100個ずつの情報をそのまま保存したり読み込みしたい感じです。
出来れば同一ファイルでプレイヤーと敵は管理したいです

char name[50];のところをstd::string Name;にすると保存が上手くいかなくなったのですがこれらはまた別の方法を使用する必要があるのですかね...?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2019/07/14 08:01

どんな風にセーブ/ロード? 単純な保存ならば、ファイルをオープンして、構造体データをバイナリと見なし(char * でキャストとか)、そのまま、書出し。読出しは逆。 全てなら、100個分のデータをそのまま、同様の処理。 どんな風にしたいかで、方法ありすぎ。
_26_K

2019/07/14 08:14

ご指摘ありがとうございます、補足情報を追加しました。実現したい内容はpepperleafさんのおっしゃる内容通りです。
pepperleaf

2019/07/14 15:05

> char name[50];のところをstd::string Name;にすると保存が上手くいかなくなった 質問を編集されたようですが、どちらの回答に対する変更でしょうか? char name[50] は、単なるバイト列ですが、string Nameはちょっと違います。まず、単純な fwrite()では無理。(と言うより、面倒)
_26_K

2019/07/14 18:10

すみません、他の作業と混ざって変な編集をしてしまいました。 やっぱり厳しいのですね...
guest

回答2

0

ベストアンサー

FILE* fp = fopen("xxxx.dat","w");
fwrite(player, sizeof(struct Test), 100, fp);

でよくね? (読み込みは fread)

投稿2019/07/14 08:04

編集2019/07/14 11:26
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2019/07/14 08:11

細かい話ですが、 > foprn("xxxx.dat","w"); --> fopen("xxxx.dat","wb"); で、敵味方、両方らしいで、 fwrite() 2行。
episteme

2019/07/14 10:08

ですね、binary扱うなら"wb"/”rb"。
_26_K

2019/07/15 03:49

ありがとうございました、こちらの方法で解決できました
guest

0

こんにちは。

寿命の短いプログラムなら、epistemeさんのような方法が簡単で間違いがないので、よく使われます。
ただ、Test構造体を変更する場合、古いデータを捨てるか、苦労してデータ引継ぎ用プログラムを書くことになります。複数の古いバージョンをサポートするのは地獄なのであまり古いものは断念するしかないのが実態です。

それを緩和する方法として、ファイルにバージョン番号を記録し、Test構造体を変更したらバージョンを上げ、古いデータを新しいプログラムが読む時に変更を吸収するという手法があります。
そのためにはメンバ変数毎に最初から分離して読み出しておいた方が融通が効きます。

例えば、こんな感じです。(意外に面倒なのでそこまでやるのか?悩ましいですが。)

C++

1#include <iostream> 2#include <fstream> 3#include <string> 4#include <array> 5 6struct Test 7{ 8 constexpr static int kVersion=1; 9 static inline int version; 10 11 std::string name; 12 int zanki; 13 int score; 14 15 Test() : name(""), zanki(0), score(0) { } 16 17 friend std::ostream& operator<<(std::ostream& os, Test const& rhs) 18 { 19 os << rhs.name << ":"; 20 os << rhs.zanki << " " << rhs.score << "\n"; 21 return os; 22 } 23 friend std::istream& operator>>(std::istream& is, Test& rhs) 24 { 25 std::getline(is, rhs.name, ':'); 26 is >> rhs.zanki >> rhs.score; 27 is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 28 return is; 29 } 30}; 31 32struct GameData 33{ 34 std::array<Test, 5> player; //プレイヤー 保存対象 35 std::array<Test, 5> enemy; //敵 保存対象 36 37 GameData() { Test::version=Test::kVersion; } 38 39 friend std::ostream& operator<<(std::ostream& os, GameData const& rhs) 40 { 41 os << Test::version << "\n"; 42 for(auto const& data : rhs.player) os << data; 43 for(auto const& data : rhs.enemy) os << data; 44 return os; 45 } 46 friend std::istream& operator>>(std::istream& is, GameData& rhs) 47 { 48 is >> Test::version; 49 is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 50 for(auto& data : rhs.player) is >> data; 51 for(auto& data : rhs.enemy) is >> data; 52 return is; 53 } 54}; 55 56int main() 57{ 58 { 59 GameData aGameData; 60 for(std::size_t i=0; i < aGameData.player.size(); ++i) 61 { 62 aGameData.player[i].name="player" + std::to_string(i); 63 aGameData.player[i].zanki=3; 64 aGameData.player[i].score=0; 65 } 66 for(std::size_t i=0; i < aGameData.enemy.size(); ++i) 67 { 68 aGameData.enemy[i].name="enemy" + std::to_string(i); 69 aGameData.enemy[i].zanki=1; 70 aGameData.enemy[i].score=100; 71 } 72 73 std::ofstream ofs("game_data.txt"); 74 ofs << aGameData; 75 } 76 77 { 78 GameData aGameData; 79 80 std::ifstream ifs("game_data.txt"); 81 ifs >> aGameData; 82 std::cout << aGameData; 83 } 84}

wandbox

boost::serializationは上記のような処理を簡単にかけるようになります。(メンバ変数一つひとつの保存と回復処理は意外に面倒です。)


私も似たようなライブラリを公開してます。operator<<, >>に相当する関数を書かなくて良いので更に簡単なのですが、う~~ん、最近は別件が忙しく開発が止まってて Visual C++ 2017のバージョンアップに対応できていないので今は動かないです。orz

投稿2019/07/14 12:35

編集2019/07/14 12:37
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_26_K

2019/07/15 04:04

ありがとうございます、今後の参考に使わせてもらいます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問