ビデオゲームプログラミングコースの最終版をコーディングしています。ゲームの保存ファイルを作成して、ユーザーがプレイして後で戻ってくる方法を知りたいです。これがどのように行われるかについての考えは、私が以前に行ったことはすべて、単一実行プログラムです。
ビデオゲームプログラミングコースの最終版をコーディングしています。ゲームの保存ファイルを作成して、ユーザーがプレイして後で戻ってくる方法を知りたいです。これがどのように行われるかについての考えは、私が以前に行ったことはすべて、単一実行プログラムです。
回答:
メモリ内の変数をハードドライブに保存するには、シリアル化を使用する必要があります。シリアル化には多くの種類があります。.NETXMLでは一般的な形式ですが、バイナリおよびJSONシリアライザーを使用できます。私はあまりC ++プログラマーではありませんが、クイック検索でC ++のシリアル化の例を見つけました。
シリアル化機能を提供するライブラリがあります。いくつかは他の回答で言及されています。
興味のある変数は、おそらくゲームの状態に関連するでしょう。たとえば、おそらくこのタイプの情報を知りたいと思うでしょう
使用されているテクスチャは気にしません(プレーヤーが外観を変更できない限り、それは特別な場合です)。これらは通常同じであるためです。重要なゲーム状態データの保存に集中する必要があります。
ゲームを開始すると、「新しい」ゲームの通常どおりに起動します(これにより、テクスチャ、モデルなどが読み込まれます)が、適切なタイミングで、保存ファイルからゲーム状態オブジェクトに値を読み込み、「デフォルト」の新しいゲームの状態。次に、プレーヤーが再生を再開できるようにします。
ここでは大幅に簡略化しましたが、一般的な考え方を理解しておく必要があります。より具体的な質問がある場合は、ここで新しい質問をしてください。私たちはそれを手助けすることができます。
通常、これはゲームに固有です。これまでに、クラス内のファイルの書き込みと読み取りについて学習したことは間違いありません。基本的な考え方は次のとおりです。
あなたが書くことはあなた次第です、それはあなたのゲームに依存します。書き方の1つは、必要な変数を特定の順序でバイトストリームとして書き出すことです。次に、ロードするときに、同じ順序でプログラムに読み込みます。
例(クイック疑似コード):
SaveGame(FileInput file) {
file.writeInt(playerLevel);
file.writeInt(playerHealth);
file.writeInt(gameProgress);
}
LoadGame(FileInput file) {
if(file.exists()) {
playerLevel= file.readInt();
playerHealth = file.readInt();
gameProgress = file.readInt();
} else {
playerLevel = 1;
playerHealth = 100;
gameProgress = 0;
}
}
これを行う方法はおそらく多数ありますが、私が常に見つけて個人的にも専門的にも使用している最も簡単な方法は、保存したいすべての値を含む構造を作成することです。
struct SaveGameData
{
int characterLevel; // Any straight up values from the player
int inventoryCount; // Number of items the player has on them or stored or what not
int[STAT_COUNT] statistics; // This is usually a constant size (I am tracking X number of stats)
// etc
}
struct Item
{
int itemTypeId;
int Durability; // also used as a 'uses' count for potions and the like
int strength; // damage of a weapon, protection of armor, effectiveness of a potion
// etc
}
次に、基本的なファイルIO値を使用して、ファイルとの間でデータを読み書きします。inventoryCountは、ファイル内のメインのSaveGameData構造体の後に保存されるItem構造体の数です。そのため、そのデータを取得した後に読み取る構造体の数がわかります。ここで重要なのは、アイテムのリストなどを除き、何か新しいものを保存したい場合、どこかに構造体に値を追加するだけです。アイテムのリストの場合は、アイテムオブジェクト、メインヘッダーのカウンター、およびエントリに対して既に暗示されているように、読み取りパスを追加する必要があります。
これには、保存ファイルのさまざまなバージョンが特別な処理なしで互いに互換性がないという欠点があります(メイン構造の各エントリの単なるデフォルト値であっても)。ただし、これにより、新しいデータ値を追加し、必要なときに値を入力するだけで、システムを簡単に拡張できます。
繰り返しになりますが、これを行うにはかなり多くの方法があり、これはC ++よりもCの方につながる可能性がありますが、仕事は完了しました!
最初に、保存する必要があるデータを決定する必要があります。たとえば、これはキャラクターの位置、彼のスコア、コインの数である可能性があります。もちろん、ゲームははるかに複雑になる可能性が高いため、レベル番号や敵リストなどの追加データを保存する必要があります。
次に、これをファイルに保存するコードを記述します(ofstreamを使用)。使用できる比較的単純な形式は次のとおりです。
x y score coins
そのため、ファイルは次のようになります。
14 96 4200 100
つまり、彼は4200と100コインのスコアでポジション(14、96)にいたということです。
また、このファイルをロードするコードを記述する必要があります(ifstreamを使用)。
敵の保存は、ファイルに自分の位置を含めることで実行できます。次の形式を使用できます。
number_of_enemies x1 y1 x2 y2 ...
最初にnumber_of_enemies
が読み取られ、次に単純なループで各位置が読み取られます。
あなたの最善の策は、boost :: serializationであると思います。なぜなら、あなたの階層に伝播しやすいからです。一番上のオブジェクトの保存/読み込み関数を呼び出すだけで、すべてのクラスを簡単に作成できます。
参照:http : //www.boost.org/doc/libs/1_49_0/libs/serialization/doc/index.html
ゲームは、データ構造を危険にさらし(うまくいけば)、バイトに変換(シリアル化)してデータを保存する必要があります。将来、それらのバイトをロードし直して、元の構造に戻すことができます(逆シリアル化)。C ++では、反射が非常に制限されているため、それほど複雑ではありません。それでも、いくつかのライブラリはここであなたを助けることができます。私はそれについて記事を書きました:https : //rubentorresbonet.wordpress.com/2014/08/25/an-overview-of-data-serialization-techniques-in-c/ 基本的に、私はあなたが見てみることをお勧めしますC ++ 11コンパイラを対象とする場合は、シリアルライブラリ。protobufのように中間ファイルを作成する必要がないため、迅速な結果が必要な場合はそこに時間を節約できます。バイナリとJSONを選択することもできるため、ここでのデバッグに非常に役立ちます。
それに加えて、セキュリティが懸念される場合、特にJSONのような人間が読める形式を使用している場合は、保存しているデータを暗号化/復号化することができます。ここでは、AESのようなアルゴリズムが役立ちます。
fstream
入力/出力ファイルに使用する必要があります。構文は簡単なEXです。
#include <fstream>
// ...
std::ofstream flux ; // to open a file in ouput mode
flux.open("myfile.whatever") ;
または
#include <fstream>
// ...
std::ifstream flux ; // open a file in input mode
flux.open("myfile.whatever") ;
ファイルでは、append、binary、truncなど、他のアクションも可能です。代わりに、std :: ios::( flags)を置く代わりに上記と同じ構文を使用します。
ios::out
出力操作用ios::in
入力操作用ios::binary
文字ベースではなく、バイナリ(生バイト)IO操作用ios::app
ファイルの終わりから書き込みを開始するためios::trunc
ファイルが既に存在する場合は、古いコンテンツを削除し、新しいものに置き換えますios::ate
-入出力用にファイルポインタを「最後に」配置する例:
#include <fstream>
// ...
std::ifstream flux ;
flux.open("myfile.whatever" , ios::binary) ;
以下は、より完全ですがシンプルな例です。
#include <iostream>
#include <fstream>
using namespace std ;
int input ;
int New_Apple ;
int Apple_Instock ;
int Eat_Apple ;
int Apple ;
int main()
{
bool shouldQuit = false;
New_Apple = 0 ;
Apple_Instock = 0 ;
Eat_Apple = 0 ;
while( !shouldQuit )
{
cout << "------------------------------------- /n";
cout << "1) add some apple " << endl ;
cout << "2) check apple in stock " << endl ;
cout << "3) eat some apple " << endl ;
cout << "4) quit " << endl ;
cout << "------------------------------------- /n";
cin >> input ;
switch (input)
{
case 1 :
{
system("cls") ;
cout << "------------------------------------ /n";
cout << " how much apple do you want to add /n";
cout << "------------------------------------ /n";
cin >> New_Apple ;
ifstream apple_checker ;
apple_checker.open("apple.apl") ;
apple_checker >> Apple_Instock ;
apple_checker.close() ;
Apple = New_Apple + Apple_Instock ;
ofstream apple_adder ;
apple_adder.open("apple.apl") ;
apple_adder << Apple ;
apple_adder.close() ;
cout << "------------------------------------ /n";
cout << New_Apple << " Apple has been added ! /n";
cout << "------------------------------------ /n";
break;
}
case 2 :
{
system("cls") ;
ifstream apple_checker ;
apple_checker.open("apple.apl") ;
apple_checker >> Apple_Instock ;
apple_checker.close() ;
cout << "------------------------------------ /n";
cout << " there is " << Apple_Instock ;
cout << "apple in stock /n" ;
cout << "------------------------------------ /n";
break;
}
case 3 :
{
system("cls") ;
cout << "------------------------------------ /n";
cout << "How many apple do you want to eat /n" ;
cout << "------------------------------------ /n";
cin >> Eat_Apple ;
ifstream apple_checker ;
apple_checker.open("apple.apl") ;
apple_checker >> Apple_Instock ;
apple_checker.close() ;
Apple = Apple_Instock - Eat_Apple ;
ofstream apple_eater ;
apple_eater.open("apple.apl") ;
apple_eater << Apple ;
apple_eater.close() ;
cout << "----------------------------------- /n";
cout << Eat_Apple ;
cout << " Apple has been eated! /n";
cout << "----------------------------------- /n";
cout << Apple << " Apple left in stock /n";
cout << "----------------------------------- /n";
break;
}
case 4 :
{
shouldQuit = true;
break;
}
default :
{
system("cls") ;
cout << "------------------------------------ /n";
cout << " invalide choice ! /n";
cout << "------------------------------------ /n";
break;
}
}
}
return 0;
}
goto
s を使用すると、公共の場所でリンクされます。goto
sを使用しないでください。