롤백 시스템
롤백 시스템이란?
온라인 게임을 할 때 지연 현상을 경험하는 것은 흔한 일입니다. 원격으로 다른 사람과 플레이할 경우, 그들의 입력이 당신에게 도달하는 데 몇 분의 일초가 걸릴 수 있으며, 이로 인해 게임 경험이 망가질 수 있습니다. 롤백 시스템은 이러한 지연의 영향을 줄이기 위해 예측을 사용합니다. 이전 입력을 기반으로 상대방이 다음에 무엇을 할지를 예측하고, 그 예측의 결과를 즉시 보여줍니다.
예측이 맞으면 지연을 느끼지 않게 되어 게임이 훨씬 더 반응성이 좋아집니다. 그러나 때때로 시스템은 예측이 잘못되었음을 인식합니다. 이 경우, 마지막으로 올바른 상태로 "롤백"하여 그 지점에서 게임을 계속 진행합니다. 그래서 "롤백 멀티플레이어"라고 불립니다.
결정론
롤백은 결정론적입니다. 즉, 다른 플레이어와 입력만 공유하며, 모든 플레이어가 주어진 입력에 대해 동일한 논리를 실행하여 모든 클라이언트에서 동일한 결과를 기대합니다. 멀티플레이어에 대한 다른 접근 방식은 "상태 복제"로, 클라이언트 간의 게임 상태를 지속적으로 동기화하여 항상 동일한 작업을 수행하도록 보장합니다. 롤백은 입력만 전송하며, 잘못된 예측이 발생할 경우 롤백할 수 있도록 상태를 주시합니다.
클라이언트란?
"클라이언트"는 게임의 플레이어를 의미하며, 그들의 기계에서 실행되는 게임의 복사본을 가리킵니다.
롤백 시스템의 작동 방식
롤백은 플레이어 간의 입력만 통신합니다. 롤백이 처리하는 두 가지 주요 사항은 다음과 같습니다:
- 입력: 각 플레이어의 입력이 다른 플레이어에게 전송됩니다. 예를 들어, 플레이어 0이 자신의 클라이언트에서 "발사" 버튼을 누르면, 롤백은 다른 클라이언트에서도 플레이어 0이 "발사" 버튼을 누른 것을 볼 수 있도록 합니다. 예측은 입력에 대해서만 실행됩니다.
- 상태: 관리되는 모든 객체와 그 변수들이 포함됩니다. 이들은 플레이어 간에 동기화되지 않으며, 한 클라이언트에서 변수 하나를 변경해도 다른 클라이언트에서 자동으로 업데이트되지 않습니다. 상태는 롤백을 위해서만 관리됩니다.
입력과 상태의 차이
입력은 상태를 변경하며, 이는 롤백 멀티플레이어의 기본 개념입니다. 예를 들어:
- 입력: 플레이어 0이 "발사" 버튼을 누릅니다.
- 상태: 플레이어 0이 발사 버튼을 눌렀기 때문에 발사체가 생성됩니다. 이 발사체는 결국 바위와 충돌하여 플레이어 0이 점수를 얻습니다.
게임의 모든 것은 입력에 의존합니다. "입력"은 롤백이 모든 플레이어 간에 통신하는 것이며, 상태는 아닙니다. 그러나 모든 게임 클라이언트가 수신된 입력에 대해 동일한 논리를 실행하기 때문에 동일한 상태가 결과적으로 생성됩니다.
상태란 무엇인가?
입력만 동기화된다면 상태는 무엇을 위한 것인가? 입력이 상태에 영향을 미치기 때문에 잘못된 입력 예측은 잘못된 상태를 초래할 수 있습니다. 롤백이 예측이 잘못되었음을 발견하면 현재 상태를 올바른 상태로 교체하고 그 지점에서 입력과 예측을 다시 실행합니다. 여기에는 모든 관리되는 객체와 그 변수들이 포함됩니다.
관리되는 객체
객체에는 "관리됨" 체크박스가 있으며, 기본적으로 새로운 객체에 대해 활성화되어 있습니다. 관리되는 객체는 롤백할 수 있는 능력과 예측이 실행될 수 있는 능력을 가지고 있습니다. 게임 플레이의 일부인 모든 객체, 예를 들어 플레이어, 관리자/컨트롤러 객체, 아이템 픽업, 발사체 등은 관리로 표시되어야 합니다. 게임 플레이에 영향을 미치지 않는 정적 세계 객체, 비주얼, 효과 등은 동기화할 필요가 없으므로 관리 표시를 해제할 수 있습니다.
동기화 테스트
rollback_create_game()
은 기본적으로 동기화 테스트를 위한 인수를 받습니다. 동기화 테스트는 오프라인에서 게임을 테스트하는 데 사용됩니다. 동기화 문제 발생 시 오류를 출력 로그에 인쇄하여 알려줍니다. 동기화 테스트는 Windows, macOS 및 GX.games에서 사용할 수 있습니다. 동기화 테스트는 게임의 모든 코드를 프레임 내에서 두 번 실행하여 동기화 문제를 확인합니다.
랜덤 및 모의 입력
동기화 테스트 중 "원격" 플레이어 인스턴스는 정의된 입력에 대해 랜덤 입력 값을 받습니다. 이 기능은 rollback_use_random_input()
을 사용하여 비활성화할 수 있습니다. 또한 동기화 테스트 중 원격 플레이어에게 임시 모의 입력을 할당할 수 있습니다.
멀티플레이어 효과적으로 개발하기
모든 게임 클라이언트가 동일한 입력을 받을 때 동일한 논리를 실행해야 합니다. 특정 인스턴스가 한 클라이언트에서만 생성되거나 이동되면 다른 클라이언트에 반영되지 않습니다. 이 문제는 모든 플레이어 인스턴스에 대해 동일한 방식으로 플레이어 로직을 실행하는 경우 발생하지 않습니다.
플레이어 객체 정의
플레이어 인스턴스를 자동으로 생성하려면 rollback_define_player()
를 사용하여 플레이어 객체를 정의할 수 있습니다. 이 시스템은 연결된 각 플레이어에 대해 인스턴스를 자동으로 생성하고, 연결이 끊어진 플레이어에 대한 인스턴스를 파괴합니다.
플레이어 인스턴스 수동 생성
플레이어 인스턴스를 수동으로 관리하려면 rollback_define_player()
를 호출하지 마십시오. 이렇게 하면 플레이어 인스턴스가 생성되지 않은 상태로 게임이 시작됩니다. 그런 다음 Rollback Start
이벤트에서 수동으로 플레이어 인스턴스를 생성하고 사용자 정의 변수에 플레이어 ID를 부여합니다.
플레이어 인스턴스 유지
rollback_define_player()
를 사용하는 경우 생성된 플레이어 인스턴스를 파괴하지 마십시오. 플레이어를 패배로 표시해야 하는 경우 스프라이트를 변경하거나 다른 방법으로 숨기되, 인스턴스를 유지해야 합니다.
싱글 플레이어
롤백 시스템은 싱글 플레이어 게임을 만들 때도 사용할 수 있습니다. rollback_create_game()
을 호출할 때 플레이어 수를 1로 지정하면 됩니다. 이렇게 하면 시스템이 서버에 연결되지 않으며, 게임은 본질적으로 오프라인 상태가 됩니다.
수동 시작 vs. 자동 시작
기본적으로 멀티플레이어 게임은 모든 플레이어가 참여하면 즉시 시작됩니다. 그러나 rollback_start_game()
을 호출하여 그 시점 이전에 시작할 수 있습니다. rollback_use_manual_start()
를 호출하여 자동 시작 동작을 완전히 비활성화할 수 있습니다.
활용 예제
// 플레이어 객체 정의
rollback_define_player();
// 게임 시작
rollback_create_game(2); // 2명의 플레이어로 게임 생성
// 플레이어 입력 처리
var player_input = rollback_get_input();
if (player_input.fire) {
// 발사 로직
}
// 상태 관리
if (player_health <= 0) {
// 플레이어 패배 처리
}
// 수동 플레이어 인스턴스 생성
var player_instance = instance_create_layer(x, y, "Players", obj_player);
player_instance.player_id = 1; // 플레이어 ID 설정
기능 | 설명 |
---|---|
롤백 시스템 | 온라인 게임에서 지연을 줄이기 위해 입력 예측 사용 |
결정론 | 모든 클라이언트가 동일한 입력에 대해 동일한 결과를 생성 |
클라이언트 | 플레이어의 게임 복사본 |
입력 | 플레이어의 행동을 다른 플레이어에게 전송 |
상태 | 관리되는 객체와 변수, 동기화되지 않음 |
관리되는 객체 | 롤백 및 예측이 가능한 객체 |
동기화 테스트 | 오프라인에서 동기화 문제를 테스트 |
랜덤 입력 | 테스트 중 원격 플레이어에 랜덤 입력 제공 |
플레이어 정의 | 자동으로 플레이어 인스턴스 생성 |
수동 생성 | 플레이어 인스턴스를 수동으로 관리 |