비디오 게임 프로그래밍 과정을 위해 결승을 코딩하고 있는데 사용자가 게임을하고 나중에 다시 올 수 있도록 게임용 저장 파일을 만드는 방법을 알고 싶습니다. 이것이 어떻게 이루어 졌는지, 내가 전에 한 모든 일은 단일 실행 프로그램이었습니다.
비디오 게임 프로그래밍 과정을 위해 결승을 코딩하고 있는데 사용자가 게임을하고 나중에 다시 올 수 있도록 게임용 저장 파일을 만드는 방법을 알고 싶습니다. 이것이 어떻게 이루어 졌는지, 내가 전에 한 모든 일은 단일 실행 프로그램이었습니다.
답변:
직렬화를 사용해야합니다변수를 메모리의 하드 드라이브에 저장 를 합니다. 사용 가능한 바이너리 및 JSON 직렬 변환기가 있지만 .NET XML은 일반적인 형식으로 많은 직렬화 유형이 있습니다. 나는 C ++ 프로그래머가 아니지만 빠른 검색은 C ++의 직렬화에 대한 예를 제시했습니다.
직렬화 기능을 제공하는 라이브러리가 있습니다. 일부는 다른 답변에 언급되어 있습니다.
관심있는 변수는 게임 상태와 관련이있을 것입니다. 예를 들어이 유형의 정보를 알고 싶을 것입니다.
어떤 텍스처가 사용되고 있는지는 신경 쓰지 않아도됩니다 (플레이어가 모양을 바꿀 수 없다면 특별한 경우입니다). 중요한 게임 상태 데이터 저장에 집중해야합니다.
게임을 시작할 때 "새로운"게임 (텍스처, 모델 등이로드 됨)에 대해 정상적으로 시작하지만 적절한 시간에 저장 파일의 값을 게임 상태 오브젝트로 다시로드하여 "기본"을 바꿉니다. 게임 상태. 그런 다음 플레이어가 재생을 다시 시작하도록 허용합니다.
여기에서 크게 단순화했지만 일반적인 아이디어를 얻어야합니다. 보다 구체적인 질문이 있으시면 여기에 새로운 질문을하시면 도와 드리겠습니다.
일반적으로 이것은 게임에 따라 다릅니다. 지금까지 클래스의 파일에 쓰고 읽는 방법에 대해 배웠습니다. 기본 아이디어는 다음과 같습니다.
당신이 쓰는 것은 당신에게 달려 있으며, 그것은 게임에 달려 있습니다. 작성하는 한 가지 방법은 원하는 변수를 특정 순서로 바이트 스트림으로 작성하는 것입니다. 그런 다음로드 할 때 동일한 순서로 프로그램을 읽어보십시오.
예를 들어 (빠른 의사 코드로) :
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 값을 사용하여 파일에 데이터를 fwrite / fread합니다. inventoryCount는 파일의 기본 SaveGameData 구조 이후에 저장되는 Item 구조의 수이므로 해당 데이터를 가져온 후 읽을 구조 수를 알고 있습니다. 여기서 핵심은 항목 목록 등이 아닌 한 새로운 것을 저장하고 싶을 때 구조에 값을 추가하는 것입니다. 항목 목록 인 경우 이미 Item 개체, 기본 헤더의 카운터 및 항목에 대해 암시 한 것처럼 읽기 패스를 추가해야합니다.
이것은 주 버전 구조의 각 항목에 대한 기본값 일지라도 특별한 처리없이 서로 다른 버전의 저장 파일을 서로 호환되지 않는 단점이 있습니다. 그러나 전반적으로 새로운 데이터 값을 추가하고 필요할 때 값을 입력하면 시스템을 쉽게 확장 할 수 있습니다.
다시 말하지만,이 작업을 수행하는 몇 가지 방법이 있으며 C ++보다 C로 더 많이 이끌 수 있지만 작업이 완료되었습니다!
먼저 어떤 데이터를 저장해야하는지 결정해야합니다. 예를 들어, 이것은 캐릭터의 위치, 점수 및 동전 수일 수 있습니다. 물론 게임은 훨씬 더 복잡 할 수 있으므로 레벨 번호 및 적 목록과 같은 추가 데이터를 저장해야합니다.
다음으로 이것을 파일에 저장하는 코드를 작성하십시오 (스트림 사용). 사용할 수있는 비교적 간단한 형식은 다음과 같습니다.
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를 사용하지 마십시오 .