본문 바로가기

로블록스 개발 중급

세이브와 로드

목차

 

로블록스 게임중에 게임상태를 저장하고 읽어오는 방법에 대한 튜토리얼입니다.

게임중에 레벨, 게임머니, 경험치, 아이템 관리를 할려면 데이터 세이브와 로드는 필수적이겠죠.

로블록스 스튜디오에서 접근 허용하기

기본적으로 로블록스 스튜디오에서 로블록스 서버에 데이터를 저장하고 로드를 허용하지 않는다. 스튜디오에서 테스트를 하기 위해서는 셋팅에서 활성화를 시켜줘야 한다. 우선 해당 게임을 로블록스 서버로 배포를 해 놓은 상태에서 아래의 게임셋팅에서 Security 탭에서 API 서비스에 접근을 허용해주자.

Enable Studio Access to API Services 를 허용하고 저장.

DataStoreService 사용하기

로블록스에서 게임 데이터를 저장/로드를 하기 위해서는 DataStoreService 서비스를 사용한다. 이 DataStoreService에서 Data Store라는 객체를 생성하고 그 객체에 데이터를 저장한다. 저장하고 싶은 데이터를 원하는 이름으로 Data Store를 만들고 그곳에 데이터를 저장하면 된다.

게임 데이터 저장은 서버에서 한다. 왜 서버에서 해야되냐고 반문이 들면 로블록스 서버-클라이언트 모델에 대한 포스팅을 참고하자.

ServerScriptService에 스크립트를 추가하고 "GoldManager"라고 이름을 바꾸자. ServerScriptService에 추가된 스크립트는 서버가 게임을 시작하면 실행한다.

 

우선, game오브젝트의 GetService 함수로 DataStoreService 서비스를 불러온다.

DataStoreService 서비스에서 GetDataStore()함수로 원하는 이름, 여기서는 "PlayerGold", 으로 호출하면 이미 존재하면 존재하는 Data Store를, 없으면 새로 만들어서 반환해준다.

local DataStoreService = game:GetService("DataStoreService")
local goldStore = DataStoreService:GetDataStore("PlayerGold")

여기서 반환된 goldStore 라는 Data Store 객체를 통해서 세이브/로드가 가능해진다.

데이터 저장하기

Data Store 객체는 결국 루아언어의 테이블형태이다. 그래서 키-값 매칭으로 데이터를 저장하게 된다. 플레이어 별로 저장하고 싶은 데이터는 플레이어의 UserId를 사용해서 저장하면 된다. 플레이어 별로 저장할 필요가 없는 데이터라면 그냥 원하는 키를 넣어도 상관없다.

UserId는 플레이어의 64비트 정수값으로 로블록스 내에서 유일하고 종속적이고 변하지 않는 값이다. 플레이어의 Instance.Name은 현재의 유저 네임으로 변경이 가능하기 때문에 Data Store의 키로 사용하기에는 UserId가 적합하다. 

실제로 DataStore를 사용하여 저장하는 방법을 구현해보자. 저장하길 원하는 것은 UserId(505306092), gold(250)이다.

저장 자체는 Data Store(goldStore)의 SetAsync()함수를 호출하여 구현한다.  함수명에서도 알 수 있듯이 비동기로 실행되는 함수이다. 네트워크를 통해 데이터를 저장하게될 SetAsync() 함수의 특성으로 개발자의 코드의 완벽함과는 상관없이 에러를 발생시킬 수 있다. 저품질의 네트워크 연결상태라든지, 너무 많은 세이브/로드 요구로 허용치를 벗어나버리는 상황이든지 같은 예상할 수 없는 에러가 발생할 경우를 대비하여 lua언어에서 제공하는 pcall()함수를 사용한다. pcall() 함수는 보호 모드안에서 주어진 함수를 호출하고 결과를 성공/실패와 에러메세지 두가지로 반환한다. pcall() 함수를 사용하면 SetAsync()함수에서 에러로 인해 스크립트가 깨지는 상황을 방지하고 에러 메세지를 확인하고 처리가 가능해진다.

local DataStoreService = game:GetService("DataStoreService")
local goldStore = DataStoreService:GetDataStore("PlayerGold")
 
-- Data store 의 키와 값
local playerUserID = 505306092
local playerGold = 250
 
-- 데이터 저장하기
local setSuccess, errorMessage = pcall(function()
    goldStore:SetAsync(playerUserID, playerGold)
end)
if not setSuccess then
    warn(errorMessage)
end

네트워크게임이라면 모두 마찬가지겠지만, 로블록스에서 데이터 저장/읽기를 자주 반복하는 것은 좋지 않다. 데이터 저장/읽기 작업을 작업큐에 넣어두고 하나씩 꺼내서 처리하기 때문에 많은 작업이 한번에 오면 처리가 다 되지 못한다.

예를 들어 아래의 이미지처럼 소닉이 코인을 하나 획득할 때마다 데이터 저장을 하면 안된다. 

이럴때는, 저장하고 싶은 코인값을 주기적으로 업데이트하기를 추천한다. 몇분, 몇십초의 간격을 두고 자동으로 세이브되게 만들고 플레이어가 게임을 끝낼 때, 저장하게 만들면 괜찮은 구현 방법이 될 것이다.

데이터 읽기

이번에는 반대로 Data Store에서 GetAsync() 함수를 통해 데이터를 읽어오자.

-- 키로 데이터 값 읽어오기
local getSuccess, currentGold = pcall(function()
    return goldStore:GetAsync(playerUserID)
end)
if getSuccess then
    print(currentGold)
end

마찬가지로 GetAsync() 함수를 바로 호출하지 않고 pcall() 함수안에서 호출하여 보호모드안에서 실행되게 한다. 

성공하면 Output 윈도우에 출력하게 했으므로 테스트 시작 몇초후에 출력이 제대로 되었는지 확인해보자.