절차 생성, 게임 업데이트 및 나비 효과


10

참고 : 며칠 전에 Stack Overflow에서이를 요청했지만 뷰가 거의없고 응답이 없었습니다. 대신 gamdev.stackexchange를 요청해야한다고 생각했습니다.

이는 이전에 생성 된 컨텐츠를 손상시키지 않고 여러 릴리스 후 업데이트를 통해 절차 생성 시스템을 유지 보수하는 데 대한 일반적인 질문 / 조언입니다.

게임용 절차 콘텐츠를 만들 때 "버터 플라이 효과"문제를 피하기위한 정보와 기술을 찾으려고합니다. 시드 난수 생성기를 사용할 때 반복 가능한 난수 시퀀스를 사용하여 재현 가능한 세계를 만들 수 있습니다. 일부 게임은 생성 된 세계를 한 번 생성 된 디스크에 간단히 저장하지만 절차 생성의 강력한 기능 중 하나는 숫자 시퀀스의 재현성에 의존하여 동일한 방식으로 영역을 여러 번 다시 생성 할 수 있다는 사실입니다. 고집. 특정 상황의 제약 때문에 지속성을 최소화해야하며 가능한 한 순수하게 시드 된 농도에 의존해야합니다.

이 접근법의 가장 큰 위험은 절차 적 생성 시스템의 작은 변화조차도 전 세계를 변화시키는 나비 효과를 일으킬 수 있다는 것입니다. 이것은 플레이어가 탐험하는 세계를 파괴하지 않고 게임을 업데이트하는 것이 매우 까다로워집니다.

이 문제를 피하기 위해 사용한 주요 기술은 여러 단계로 절차 생성을 설계하는 것입니다. 각 단계에는 자체 시드 난수 생성기가 있습니다. 즉, 각 하위 시스템은 자체 포함되어 있으며, 어떤 것이 고장 나더라도 세계의 모든 것에 영향을 미치지 않습니다. 그러나 이것은 게임의 고립 된 부분에 있더라도 "손상"에 대한 많은 잠재력을 가지고있는 것처럼 보입니다.

이 문제를 처리하는 또 다른 방법은 코드 내에서 완전한 버전의 생성기를 유지하고 주어진 세계 인스턴스에 적합한 생성기를 계속 사용하는 것입니다. 이것은 나에게 유지 보수의 악몽처럼 보이고, 누군가 실제로 이것을하면 궁금합니다.

따라서 제 질문은 특히 출시 후 게임 업데이트와 관련하여 나비 효과 의이 문제를 처리하기위한 일반적인 조언, 기술 및 디자인 패턴에 대한 요청입니다. (아쉽게도 그것은 광범위한 질문이 아닙니다.)

나는 언어에 무관심한 질문이지만 현재 Unity3D / C #에서 일하고 있습니다.

최신 정보:

답장을 보내 주셔서 감사합니다.

정적 데이터가 가장 안전하고 안전한 접근 방식 인 것 같습니다. 또한 정적 데이터를 많이 저장하는 것이 옵션이 아닌 경우 생성 된 세계에서 긴 캠페인을 수행하려면 사용 된 생성기의 엄격한 버전 관리가 필요합니다. 필자의 경우 제한의 이유는 모바일 기반 클라우드 저장 / 동기화가 필요하기 때문입니다. 내 해결책은 필수 사항에 대한 소량의 컴팩트 데이터를 저장하는 방법을 찾는 것입니다.

스톰윈드의 "케이지 (Cages)"개념은 사물에 대해 특히 유용한 사고 방식이라고 생각합니다. 케이지는 기본적으로 재 시드 지점으로, 작은 변화, 즉 나비 케이지의 실행 영향을 방지합니다.


이 질문은 너무 광범위해서 주제를 벗어난 주제로 마무리하려고합니다.
Almo

나는 그것이 매우 광범위하다는 것을 알고 있습니다. gamedev 포럼이나 다른 것을 시도해 보시겠습니까? 질문을 좀 더 구체적으로 만들 수있는 방법은 없습니다. 나는이 분야에서 많은 경험을 가진 사람에게서 나에게 일어나지 않은 교묘 한 속임수를 들었기를 바랐습니다.
null

2
알 모는 착각합니다. 전혀 광범위하지 않습니다. 이것은 훌륭한 질문이며 좋은 답변을 얻을 수있을만큼 좁습니다. 그것은 많은 우리의 절차 적 사람들이 종종 숙고 한 것이라고 생각합니다.
엔지니어

답변:


8

나는 당신이 여기에 기초를 덮었다 고 생각합니다.

  • 여러 생성기를 사용하거나 간격으로 다시 시드 (예 : 공간 해시 사용)하여 유출로 인한 유출을 제한합니다. 이것은 아마도 화장품 내용에 효과적이지만, 지적한 것처럼 여전히 한 섹션 내에 파손이 발생할 수 있습니다.

  • 저장 파일에 사용 된 생성기 버전을 추적하고 적절하게 응답합니다. "적절한"의 의미는 ...

    • 게임 실행 파일에 모든 이전 버전의 생성기 이력을 유지하고 저장과 일치하는 것을 사용하십시오. 플레이어가 오래된 저장을 계속 사용하면 버그를 패치하기가 더 어려워집니다.
    • 플레이어에게이 저장 파일이 이전 버전의 파일임을 경고하고 해당 버전에 별도의 실행 파일로 액세스 할 수있는 링크를 제공하십시오. 몇 시간에서 며칠 동안 지속되는 캠페인이있는 게임에 적합하며 몇 주 이상 플레이 할 것으로 예상되는 캠페인에는 좋지 않습니다.
    • n실행 파일 에는 마지막 생성기 버전 만 유지하십시오 . 저장 파일이 최신 버전 중 하나를 사용하는 경우 저장 파일을 최신 버전으로 업데이트하십시오. 이는 적절한 생성기를 사용하여 오래된 상태를 리터럴 (또는 동일한 생성기의 새로운 생성기 출력의 델타로 압축 해제)로 압축 해제합니다. 여기서부터 새로운 상태는 최신 발전기에서 나옵니다. 오랫동안 게임을하지 않는 플레이어는 남겨질 수 있습니다. 최악의 경우 전체 게임 상태를 리터럴 형태로 저장하게되는데,이 경우에도 마찬가지입니다.
  • 생성 로직을 자주 변경하고 이전 버전과의 호환성을 유지하지 않으려면 생성기 결정에 의존하지 마십시오. 전체 상태를 저장 파일에 저장하십시오. (예 : "궤도에서 나옵니다. 확실한 유일한 방법")


생성 규칙을 작성한 경우 생성을 되돌릴 수있는 방법이 있습니까? 게임 상태가 주어진 IE는 이것을 씨앗으로 되돌릴 수 있습니까? 플레이어와 다른 게임 버전을 연결하는 대신 데이터로 가능하다면 이전 시스템의 시드에서 월드를 생성하는 업데이트 유틸리티를 제공 한 다음 생성 된 상태를 사용하여 새 생성기의 시드를 생성 할 수 있습니다. 그러나 플레이어에게 전환 대기를 경고해야 할 수도 있습니다.
Joe

1
이것은 일반적으로 가능하지 않습니다. 이전 발전기와 동일한 출력을 제공하는 새로운 발전기에 대한 시드가 있다고 보장조차하지 않습니다. 일반적으로 이러한 시드에는 약 64 비트가 포함되지만 게임에서 지원할 수있는 세계 수는 2 ^ 64보다 클 가능성이 높으므로 각 생성기는 이들 중 일부만 생성합니다. 생성기를 변경하면 새로운 레벨의 하위 세트가 생겨 이전 생성기 세트와 거의 또는 전혀 교차하지 않을 수 있습니다.
DMGregory

"오른쪽"답변을 선택하기가 어려웠습니다. 간결하고 주요 문제를 명확하게 요약했기 때문에 이것을 선택했습니다. 감사.
null

4

그러한 버터 플라이 효과의 주요 원인은 숫자 생성이 아니라 단일 숫자 생성기에서 결정 성을 유지하기에 충분히 쉬울 것입니다. 클라이언트 코드에서 이러한 숫자를 사용 입니다. 코드 변경은 상황을 안정적으로 유지하는 데있어 실질적인 문제입니다.

코드 : 단위 테스트 어딘가에 약간의 변경이 의도하지 않은 곳에 표시되지 않도록하는 가장 좋은 방법은 모든 생성 측면에 대한 철저한 단위 테스트를 빌드에 포함시키는 것입니다. 이것은 하나의 변경이 많은 다른 것들에 영향을 줄 수있는 소형 코드의 경우에 해당됩니다. 영향을받는 단일 빌드에서 볼 수 있도록 모두 테스트해야합니다.

숫자 : 주기적 시퀀스 / 슬롯 모든 것을 처리하는 하나의 숫자 생성기가 있다고 가정 해 봅시다. 의미를 부여하지 않고 PRNG처럼 번호를 순서대로 뱉어냅니다. 두 번의 런에 대해 동일한 시드가 주어지면 동일한 시퀀스를 얻습니다. 이제 몇 가지 생각을하고 정기적으로 임의의 값을 제공해야 할 게임의 30 가지 측면이있을 것이라고 결정합니다. 여기서 우리는 30 슬롯의 사이클링 시퀀스를 할당합니다. 예를 들어 시퀀스의 첫 번째 숫자는 모두 거친 지형 레이아웃이고, 두 번째 숫자는 모두 지형 섭동입니다. ... 매 10 번째 숫자마다 AI 상태에 약간의 오류가 추가되어 사실적입니다. 그래서 당신의 기간 은 30입니다.

10 이후에는 게임 디자인이 진행됨에 따라 다른 측면에 사용할 수있는 20 개의 슬롯이 무료입니다. 여기서 비용은 슬롯 이 현재 사용 중이 아니더라도 ( 즉, 기간을 완료하여) 1-10의 다음 순서로 돌아가려면 슬롯 11-30에 대해 숫자를 생성해야합니다 . 사용 가능한 슬롯 수에 따라 약간의 CPU 비용이 발생하지만 CPU 비용이 발생합니다. 다른 단점은 확실 최종 디자인이 매우 개발 과정의 시작에 사용할 슬롯의 수에 수용 ... 그리고 더 많은 당신은 시작에 지정 될 수 있다는 것을, 더 많은 슬롯을 "비어" 당신은 잠재적으로 각각을 통해 일을 작동하게해야합니다.

이것의 영향은 다음과 같습니다.

  • 하나의 발전기가 모든 것을 위해 숫자를 생성합니다.
  • 숫자를 생성해야하는 측면의 수를 변경해도 결정론에 영향을 미치지 않습니다 (기간이 모든 측면을 수용 할 수있을 정도로 클 경우)

물론, 게임을 대중에게 이용할 수없는 기간이 오래 지속될 것입니다. 즉, 알파로 말하면, 당신은 플레이어에게 영향을주지 않고 30 ~ 20 개 측면을 줄일 수 있습니다. 당신은 할당 한 방법으로 처음에 너무 많은 슬롯을. 이것은 물론 일부 CPU주기를 절약 할 수 있습니다. 그러나 좋은 해시 함수 (자신이 직접 작성할 수 있음)는 어쨌든 번개처럼 빨라야합니다. 따라서 추가 슬롯을 실행하는 데 많은 비용이 들지 않아야합니다.


안녕. 그것은 내가하고있는 일과 비슷하게 들립니다. 나는 보통 초기 세계 종자를 기반으로 많은 하위 시드를 미리 생성합니다. 최근에는 긴 노이즈 배열을 미리 생성하기 시작했으며 각 "슬롯"은 단순히 해당 배열의 인덱스입니다. 이렇게하면 각 하위 시스템이 올바른 시드를 잡고 격리 된 상태로 작업 할 수 있습니다. 또 다른 훌륭한 기술은 x, y 좌표를 사용하여 각 위치에 대한 시드를 생성하는 것입니다. 이 스택 페이지에서 Euphoric의 답변 코드를 사용하고 있습니다 : programmers.stackexchange.com/questions/161336/…
null

3

PCG로 지속성을 유지 하려면 PCG 코드 자체를 data로 취급하는 것이 좋습니다 . 일반 컨텐츠, 생성 된 컨텐츠를 사용하여 개정간에 데이터를 유지하는 것과 마찬가지로 개정간에 데이터를 유지하려면 생성기를 유지해야합니다.

물론 가장 널리 사용되는 방법은 앞에서 설명한 것처럼 생성 된 데이터를 정적 데이터로 변환하는 것입니다.

PCG 게임에서 지속성이 드물기 때문에 많은 발전기 버전을 유지하는 게임의 예를 모르겠습니다. 왜냐하면 permadeath가 종종 PCG와 함께하는 이유입니다. 그러나 동일한 게임 내에 동일한 유형의 여러 PCG에 대한 예가 많이 있습니다. 예를 들어, Unangband 에는 던전 실을위한 별도의 발전기가 많이 있으며, 새로운 것을 추가 할 때 기존의 발전기는 여전히 동일하게 작동합니다. 유지 관리 가능 여부는 구현에 달려 있습니다. 유지 보수를 유지하는 한 가지 방법은 스크립트를 사용하여 생성기를 구현하고 나머지 게임 코드와 분리하여 생성기를 유지하는 것입니다.


단순히 다른 지역에 다른 발전기를 사용하는 것이 현명한 아이디어입니다.
null

2

나는 약 3 백만 평방 킬로미터의 면적을 유지하고 기타 물건의 무작위 배치 외에도 약 1 백만 개의 건물과 기타 물건을 보관합니다. 야외 시뮬레이션 c. 저장된 데이터는 약 4GB입니다. 저장 공간이있어 운이 좋지만 무제한은 아닙니다.

무작위는 무작위이며 통제되지 않습니다. 그러나 우리는 그것을 조금 감쌀 수 있습니다 :

  • 시작 끝점을 제어합니다 (다른 게시물, 시드 번호 및 생성 된 수 참조).
  • 숫자 공간을 제한하십시오 (예 : 0에서 100 사이의 정수만 생성하십시오.
  • 값을 추가하여 숫자 공간을 오프셋합니다 (예 : 100 + [0에서 100 사이의 생성 된 숫자]는 100에서 200 사이의 난수를 생성합니다)
  • 크기 조정 (예 : 0.1 곱하기)
  • 그리고 주위에 다양한 케이지를 적용하십시오. 이것은 세대의 일부를 깎아 내고 있습니다. 예 : 2 차원 공간에서 생성하는 경우 숫자 쌍 위에 사각형을 놓고 외부를 스크랩 할 수 있습니다. 또는 원 또는 다각형. 3D 공간에서 구와 같은 다른 모양 (예 : 시각적으로 생각하지만 실제 시각화 또는 위치 지정과 반드시 ​​관련이있는 것은 아님) 만 허용 할 수 있습니다.

그게 다야. 우리는 또한 불행히도 데이터를 소비합니다.

핀란드어로 Hajota ja hallitse라는 말이 있습니다. 나누기와 정복 으로 번역합니다 .

나는 작은 세부 사항에 대한 정확한 정의라는 생각을 빨리 버렸다. 랜덤은 자유를 원하므로 자유를 얻습니다. 나비가 날아 가자-그 안에 새장. 대신에 나는 우리를 정의 할 수있는 풍부한 방법에 집중했습니다. 파란색 또는 진한 파란색 (지루한 고용주가 한 번 말한 것)이라면 어떤 자동차인지는 중요하지 않습니다. "파란색 또는 진한 파란색"은 여기에서 색상 차원에 따라 (매우 작은) 우리입니다.

숫자 공간을 제어하고 관리하기 위해 관리 할 수있는 것은 무엇입니까?

  • 부울 그리드는 (비트가 작습니다!)
  • 코너 포인트는
  • 나무 구조 그대로 (= "케이지 홀딩 케이지"에 따름)

유지 관리 측면 및 버전 상호 호환성 측면 ... 우리는
: if version = n 다음
: elseif version = m then ...
그래, 코드베이스가 커집니다 :-).

익숙한 것들. 당신의 올바른 길은 나눌 수 있는 풍부한 방법을 정의하는 것입니다 하고 그것에 대한 일부 데이터를 희생 입니다. 그런 다음 가능하면 (로컬) 무작위 배정의 자유를 주어야합니다.

DMGregory가 제안한 재미있는 "nuke it fom 궤도"와 완전히 호환되지 않지만 작고 정확한 핵무기를 사용할 수 있습니까? :-)


답변 주셔서 감사합니다. 그것은 유지하기 위해 상당히 큰 절차 영역처럼 들립니다. 많은 스토리지에 액세스 할 수있는 경우에도 모든 것을 저장하는 것은 여전히 ​​불가능합니다. 버전이 지정된 생성기가 앞으로 나아갈 것 같습니다. 그래서 :)
null

모든 대답 중에서 나는 이것에 대해 가장 많이 생각하고 있습니다. 나는 당신의 약간 철학적 인 설명을 즐겼습니다. 아이디어를 설명 할 때 "케이지"라는 용어가 매우 유용하다는 것을 알게되었습니다. 감사합니다. 새장에 나비를 날아 보자. :)
null

PS : 어떤 게임을하고 있는지 궁금합니다. 그 정보를 공유 할 수 있습니까?
null

숫자 공간에 대해 한 가지 더 추가 할 수 있습니다. 항상 0에 가깝게 유지하는 것이 좋습니다. 아마 이미 알고 있었을 것입니다. 0에 가까울수록 최고의 수치 정확도를 제공하고 비트 수가 가장 적습니다. 나중에 항상 0에 가까운 모든 숫자를 상쇄 할 수 있지만 단일 숫자 만 필요합니다. 마찬가지로 오프셋을 사용하여 먼 계산을 0에 가깝게 이동할 수 있습니다 (거의 말해야합니다). - 스톰윈드
스톰윈드

이전의 평가에서는 작은 차량 이동, 1 프레임 단위 0.01 [미터, 단위]를 고려하십시오. 32 비트 숫자 정확도 (단일)로 10000.1 + 0.01을 정확하게 계산할 수는 없지만 0.1 + 0.01을 계산할 수 있습니다. 따라서 "행동"이 멀리 떨어져있는 경우 (산 뒤 :-)) 대신 이동하지 말고 산을 자신에게 이동하십시오 (10000으로 이동하면 현재 0.1이됩니다). 저장 공간에도 유효합니다. 숫자 값을 서로 가깝게 저장하면 욕심이 생길 수 있습니다. 공통 부분을 한 번 저장하고 변형을 개별적으로 저장하십시오-비트를 절약 할 수 있습니다! 링크를 찾았습니까? ;-)
Stormwind
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.