확장성을 위한 게임 역학 모델링 #

게임을 만들 때 특히 진행 기반 메커니즘의 경우 플레이어의 경험을 직접 본받아 서버 코드를 모델링하고 싶을 것입니다. 그러나 이렇게 하려면 큰 문제가 있습니다.

플레이어가 경험치를 획득하고 일주일 동안 매일 작업을 완료하면 보상을 주는 가상의 롤플레잉 게임을 생각해 보십시오. 두 가지 시스템을 만들 수 있습니다. 하나는 플레이어가 보상을 받기 위해 충분한 경험치를 획득하는 순간 수준을 올려주는 시스템이고 다른 하나는 매일 자정에 플레이어의 일일 작업 진행 상황을 확인(또는 cron 작업을 사용)하는 시스템입니다.

이 두 시스템을 판단하기는 쉽지만 시간이 지나면서 게임에 추가 시스템이 추가될 가능성이 높습니다. 바로 이 때 이 접근의 문제점이 드러납니다. 비용이 폭발적으로 증가하고 더욱 복잡해지며 취약점은 가려집니다.

새로운 플레이어가 있을 때마다 처리가 선형적으로 증가하기 때문에 비용이 많이 발생합니다. 야간 cron 작업을 완료하는 데 시간이 점점 더 오래 걸리거나 서버를 저하시키는 야간 부하 뿐만 아니라 충분히 빠르게 실행하기 위해 값비싼 컴퓨팅 성능이 추가로 필요해집니다.

새로운 역학, 타이머 또는 이벤트마다 시스템을 새로 구축해야 하기 때문에 복잡해집니다. 수준 진행 시스템의 경우 일일 작업 시스템의 코드를 쉽게 재사용할 수 없으며 그 반대의 경우도 마찬가지입니다.

서버 코드를 클록에 연결시킬 수 있으므로 취약합니다. 자정에 일일 진행 상황 확인을 완료하지 않으면 게임 플레이가 중단되거나 야간 해결 작업을 요구할 수 있습니다. 더 나쁜 것은 플레이어 리소스의 지속적인 고갈 또는 축적과 같은 일부 주기적 시스템이 완전히 유지 불가능해질 수 있다는 것입니다. 해당 cron 작업은 매초 모든 플레이어에 대해 합리적으로 실행될 수 없습니다.

그렇다면 게임 개발자는 어떻게 해야 하나요?

순진한 접근 방식에서 벗어나는 방법: 플레이어 중심 처리 #

좋은 소식은 많은 게임 시스템에서 작동하는 일반화된 방식으로 서버 코드를 모델링하는 방법이 있다는 것입니다. 로그인, 로그아웃, 대결 종료 등과 같은 플레이어 이벤트에 반응 등.

특정 플레이어, 팀 또는 항목에 적용될 수 있는 변경 사항을 주기적으로 확인하는 대신 실제로 발생한 이벤트를 기다리고 대응합니다. 어떤 면에서 이것은 이벤트 중심 프로그래밍 패러다임과 비슷합니다. 서버는 콜백 함수를 트리거하는 메인 루프처럼 작동합니다.

이 접근 방식의 경우 다음과 같은 이유로 서버 비용을 줄이고 복잡성을 최소화하며 더 강력한 게임을 만들 수 있습니다:

  • 진행 코드는 플레이어에게 직접적인 영향을 끼치는 경우에만 서버에서 실행됩니다.
  • 서버 부하는 시간에 따라 더 고르게 분산됩니다.
  • 이벤트 처리는 예약된 cron 작업을 기다리는 대신 플레이어 활동에 가까운 시간에 발생합니다.
  • 진행 코드는 게임 메커니즘 사이에서 더 쉽게 재사용할 수 있습니다.

이 접근 방식의 개략적인 개요를 확인하고 실제 예를 살펴보겠습니다.

구현 패턴: 진행 템플릿 #

이 모델을 구현하기 위한 하나의 패턴은 세 부분으로 나뉘어 작동합니다:

  1. 정적 진행 정의: 시스템 진행을 위한 이정표, 보상 및 기본값을 정의하는 템플릿을 작성합니다.
  2. 진행 시작: 진행이 시작되면 템플릿을 플레이어의 데이터에 복사합니다.
  3. 플레이어 행동 시 업데이트: 관련 이벤트가 발생할 때마다 플레이어의 진행 상황 사본을 업데이트합니다.

템플릿 및 이벤트 처리로 일일 연속 실행 구현 #

예를 살펴보겠습니다. 가상의 게임에서 연속적으로 매일 게임에 로그인하는 플레이어에게 보상을 주려고 합니다. 플레이어가 24시간마다 한 번 이상 로그인을 7회하면 완료 보상과 3일 차의 작은 보상을 함께 받게 됩니다.

이를 설정하기 위해 JSON 형식의 정적 진행 템플릿을 생성합니다(JSON은 여기에서 하나의 옵션일 뿐입니다. 다른 형식이나 데이터 구조를 사용할 수 있지만 이 개념은 계속 적용됨).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "title":"7-day check-in challenge",
  "progress":0,
  "next_login_after":"1602092170",
  "rewards": [
    {}, {},
    { "gold":300 },
    {}, {}, {},
    {
      "gold":1000,
      "items":[
        "item374"
      ]
    }
  ]
}

플레이어가 로그인할 때마다 해당 플레이어가 활성 연속 기록이 있는지 확인하기 위해 일부 코드가 실행됩니다. 활성 연속 실행이 없는 경우(또는 기존 연속 실행이 중단된 경우), 해당 플레이어의 데이터에 템플릿이 복사됩니다:

function onLoginEvent(player)
  if (player.streak == undefined or streakIsExpired(player.streak))
    player.streak = copyNewStreakFromTemplate()

플레이어가 이미 활성 연속 실행을 갖고 있고 적시에 로그인한 경우, 연속 실행 잠금 해제를 통해 플레이어 진행이 계속될 수 있습니다:

if (time.now() > next_login_after and time.now() < next_login_after + ONE_DAY)
    player.streak.progress += 1
    awardUnlock(player, player.streak.rewards[player.streak.progress])
    setTimeForNextUnlock(player.streak)

연속 실행의 끝에 도달한 후, 다시 시작하려면 몇 가지 추가 논리가 필요합니다(더 정교한 템플릿은 승수를 지원하고 연속 실행을 반복할 수 있음).

다른 이벤트도 연속 실행에 대한 작업을 트리거할 수 있습니다. 예를 들어, 플레이어는 연속 실행을 취소할 수 있습니다(다른 진행을 시작하기 위해서 등). 이 경우에는 자체 이벤트 핸들러가 있을 것입니다.

Nakama의 이벤트 후크 #

Nakama에서는 이 패턴을 사후 후크로 구현할 수 있습니다. 서버에서 각 메시지를 수신한 후 실행되는 기능을 등록할 수 있습니다. 해당 기능에서 보다 구체적인 이벤트 핸들러에 전달하여 플레이어의 수준을 올리거나 트로피를 수여하거나 이 예에서는 연속 실행을 업데이트할 수 있습니다.

이 경우 클라이언트가 연속 실행에 대한 대역 외 알림을 보내는 getAccount() 기능을 호출할 때마다 플레이어의 연속 실행 진행을 업데이트하는 사후 후크를 작성할 수 있습니다.

getAccount 기능이 호출될 때 플레이어의 연속 실행 진행을 업데이트하는 사후 후크
getAccount 기능이 호출될 때 플레이어의 연속 실행 진행을 업데이트하는 사후 후크
이 경우 Nakama가 이미 제공하고 어쨌든 여러분이 사용할 가능성이 있는 API에서 이벤트 트리거를 얻습니다. getAccount() 클라이언트 측에서는 연속 실행 업데이트를 트리거하기 위한 추가 코드가 필요하지 않습니다.

하나의 패턴, 많은 애플리케이션 #

이 접근 방식은 다음을 포함하여 수많은 진행 스타일 게임 메커니즘에 작동합니다.

  • 플레이어, NPC, 항목 수준 향상
  • 항목 분해, 에너지 충전 등 리소스 소모 및 재생
  • 도전, 퀘스트 및 달성
  • 연속 실행 및 일일 보상과 같은 유지 인센티브

끝없는 cron 작업으로 인한 고통을 덜어주고 이벤트 중심의 게임 메커니즘 모델링을 생각해 보십시오.

자세한 내용 #

Nakama에서 후크 등록 방법을 알아 보세요

Related Pages