<파일 입출력을 이용한 게임데이터 저장하고 불러오기>
게임메이커 스튜디오에서는 game_save(filename) 함수를 제공합니다.
이 함수는 편리하게도 파일이름만 인자로 전달해주면 전달한 파일의 이름으로 세이브파일이 만들어주기에 상당히 편리합니다.
하지만 애석하게도 이 함수를 사용하면 게임의 버전이 올라감에 따른 세이브파일 호환이 어렵습니다.
때문에 데이터를 텍스트(.txt), 바이너리(.bin), 초기설정(.ini) 파일에 저장해놓고 불러오는 방법을 사용하곤 합니다.
우리는 이 방식중에 어떤 방식을 채택하여 사용하면 좋을지 알아보고, 직접 코드도 작성해봅시다.
<1-1> 바이너리(.bin), 텍스트(.txt) 파일중에 어떤걸 사용하지?
ini 파일과 txt 파일은 누가나 열어서 눈으로 볼 수 있습니다. 즉, 보안에 매우 취약하죠. 게임데이터로 쓰기에 적합한 파일이 아닙니다. 플레이어가 세이브파일을 열어서 수정할 수 있다면 당연히 문제가 되겠죠? 또, ini 파일이나 txt 파일은 아무래도 컴퓨터가 보기엔 조금 어려운감이 있습니다. 하지만 바이너리는 컴퓨터가 보기쉬운 데이터로 이루어져 있기 때문에 파일의 입출력속도가 txt파일에 비해 상당히 빠릅니다. 결론은 세이브파일을 저장하려면 바이너리파일이 적합합니다.
물론 요즘엔 버전과 데이터관리에 용이한 json이나 xml 파일을 이용해서 저장하기도 하지만 여기선 바이너리를 이용한 입출력을 다루도록 하겠습니다.
<1-2> 바이너리 파일을 이용한 데이터 저장
4
오브젝트의 Create 이벤트 에서 저장할 데이터변수 1개를 선언했습니다.
그리고 Step 이벤트에서 방향키 ↑ 누르면 데이터값을 증가하도록 하였고 키보드로 'S' 키와 'L' 키를 눌렀는지 체크하는 구문이 나옵니다.
이부분은 라인별로 분석해보록 하죠.
[8] var file = file_bin_open('save.bin', 1);
file_bin_open(fname, mode) 함수를 통해 바이너리 파일을 오픈합니다.(없으면 생성합니다.)
첫번째 인자(fname) 로 파일명, 두번째 인자(mode) 는 1을 대입하면 데이터를 쓰고, 0을 넣으면 데이터를 읽는다는 걸 의미합니다.
여기서는 데이터를 쓰는(적는) 부분이기 때문에 1을 대입한 모습입니다.
[9] file_bin_write_byte(file, save_number);
file_bin_write_byte(file, byte) 함수를 이용해서 2번째 인자로 입력한 데이터를 저장합니다.
여기선 save_number 라는 변수값을 저장하고있죠. 여기서 중요한건, 고작 '1' 바이트만! 바이너리 데이터로 기록한다는겁니다. 이는 끔찍한 사태로 번지게되는데.. 잠시후 다루어 볼 내용입니다.
[10] file_bin_close(file);
사용한 파일은 반드시 닫아주어야합니다. 그렇지않으면 버퍼가 비워지지 않고, 메모리가 그대로 램에 올라가있어요. (메모리 누수 발생함)
불러오기 부분은 거의 같은 맹락이라.. 생략하겠습니다.
마지막으로 Draw 이벤트에서 변수를 화면에 뿌려줍시다. 이렇게 오브젝트 설계 끝내고 룸에 박아놓고 시작해보면..
변수값을 방향키 ↑ 로 올려가며 값을 저장하고 불러와보면 아주 잘 됩니다. 근데 이 변수값을 255 보다 높은 숫자에서 숫자를 저장한 후 불러와보면 아주 무서운 현상이 일어납니다.
위와같이 '259' 의 값으로 저장한 후 불러오면 오른쪽 화면과 같이 '3' 으로 화면에 출력됩니다. 이는 아까 위에서 잠깐 언급했던file_bin_write_byte 함수때문인데요. 바이너리 데이터를 저장하고 불러올땐 1바이트 단위로 저장하고 불러옵니다. 그렇기때문에..
255 보다(1바이트 보다) 큰 데이터는 모두 잘려서 바이너리 파일에 저장됩니다. 게임메이커 스튜디오에서 사용하는 변수(정수와 실수)를 값의 손상없이 저장하려면 게임메이커 스튜디오에서 사용하는 변수의 기본 데이터크기인 double(8 바이트) 로 저장해야하는데 이는 이후 내용에서 다루어 봅시다.
여기까지 진행한 예제 파일 ┐
<1-3> 255보다 큰 바이너리 데이터를 저장해보자!
게임메이커에서 변수를 선언하면 8바이트의 double형으로 메모리를 잡아먹는데, 8바이트씩이나 되는 변수를 file_bin_write_byte 함수를 이용해서 저장하기엔 7바이트나 부족합니다. 때문에 다른 방법을 사용할까 합니다.
게임메이커 8.1 이하 버전대와 달리 게임메이커 스튜디오에서는 메모리접근에 좀 더 용이해진 만큼 버퍼관련 함수를 지원하네요.
과감히 file_bin_* 관련 함수 치워버리고 buffer_* 관련 함수를 이용하기로 했습니다. 바로 예제를 작성해봅시다.
이번에는 Create 이벤트에 변수를 하나 더 선언하여 255가 넘어가는 데이터와 함께 총 2개의 변수를 저장해봅시다.
Step 이벤트 입니다. 이전의 binery파일 입출력 관련 함수들을 모두 지워버리고 buffer_* 함수들로 변경했기때문에 사실 위에서 작성한 내용들을 싸그리 갈아 엎었다고 봐도 무방하네요. 그리고 이번에는 코드가 쪼큼 길어졌네요. 첫번째 라인부터 살펴봅시다.
이부분은 그냥 1바이트가 넘어가지 않는 한에서 방향키 ↑ 를 누르면 save_number의 값이 1씩 증가하도록 했습니다.
save_number2 같은경우는 2바이트가 넘어가지 않도록 제한하고 있습니다.
데이터를 저장하는 부분입니다. 라인별로 살펴보면..
[12] var buff_size = 0;
buff_size 변수는 데이터의 총 버퍼 사이즈를 담아둘 변수입니다.
[13] buff_size += buffer_sizeof(buffer_u8);
[14] buff_size += buffer_sizeof(buffer_u16);
buffer_sizeof 함수는 인자로 버퍼의 타입을 받습니다. 버퍼 타입의 크기를 반환해주네요.
이 버퍼의 타입은 게임메이커 스튜디오에서 위와같이 엄-청 많이 정의해놓았답니다. 사용할 데이터의 크기에 맞게 골라쓰면 되겠죠.
우리는 255 보다 작은 값을 가지는 변수 하나와 65535 보다 작은 값을 가지는 변수 하나를 저장하기위해 buffer_u8 과 buffer_u16 을 채택한겁니다. (영어 몰라도 대충 숫자만 훑어봐도 골라쓸 수 있습니다.)
[16] var buffer = buffer_create(buff_size, buffer_grow, 1);
buffer_create 함수로 버퍼를 생성하고 컨트롤 할수있는 객체를 생성하고 buffer 변수에 반환해줍니다.
첫번째 인자로 버퍼의 사이즈가 들어가고, 두번째 인자로는 'buffer_grow' 를 넣었는데..
grow_buffer 를 인자로 넣으면 버퍼의 사이즈를 넘어서면 사이즈가 계속해서 재정의 되는것 같습니다.
도움말을 살펴보니 인자에 buffer_fixed 를 넣으면 처음에 버퍼사이즈를 잡아준 것 이상으론 데이터가 저장되지 않는것 같습니다.
때문에 버퍼의 사이즈를 정확히 안다면 buffer_fixed 를 사용하는게 좋겠네요. (위 예제에서도 buffer_fixed 가 더 적합하겠네요.)
[18] buffer_write(buffer, buffer_u8, save_number);
[19] buffer_write(buffer, buffer_u16, save_number2);
buffer_write 함수를 사용하여 생성한 버퍼에 지정한 타입(buffer_u8 or buffer_u16)으로 데이터를 버퍼에 저장합니다.
[21] buffer_save(buffer, "save.bin");
버퍼를 외부 파일에 저장합니다.
[22] buffer_delete(buffer);
사용한 버퍼 컨트롤러도 삭제(메모리 헤제)해줍니다. 데이터 불러오는 부분은 같은 맥락이기 때문에 생략하겠습니다.
드로우 이벤트를 조금 수정해서 save_number와 save_number2 모두 화면에 뿌려주도록 했습니다. 저장이 잘되네요!
예제파일 첨부┐
원래 ini 파일을 통한 입출력도 포함하여 다루려고 했는데 글이 생각보다 너무 길어지고 중간중간 너무 핵심에서 벗어나는 모습때문에 가독이 힘들다고 판단해서 제외하고 작성하였습니다.
'GMStudio > GMS 팁/예제' 카테고리의 다른 글
게임메이커 스튜디오 :: 뷰 드래그해서 움직이기 (0) | 2015.10.11 |
---|---|
게임메이커 스튜디오 :: 안드로이드 빌드(apk 뽑아보기) (3) | 2015.10.04 |
게임메이커 스튜디오 :: 잔상효과(afterimage) 구현하기 (0) | 2015.09.28 |
게임메이커 스튜디오 :: 인스턴스 특정 위치 바라보게하기 (2) | 2015.07.19 |
게임메이커 스튜디오 :: 응용프로그램(.exe) 파일 뽑기 (0) | 2015.06.09 |