잠재적으로 무한한 2D지도 데이터를 저장하는 방법은 무엇입니까?


29

현재 100 x 100 타일의 청크를 처리 할 수있는 2D 플랫 포머가 있습니다. 청크 좌표가 길게 저장되므로 맵의 유일한 제한입니다 (maxlong * maxlong). 모든 엔티티 위치 등은 청크와 관련이 있으므로 제한이 없습니다.

내가 겪고있는 문제는 수천 개의 파일 없이이 덩어리를 저장하고 액세스하는 방법입니다. 모든 것을 한 번에 열 필요가없는 빠르고 저렴한 HD 비용 아카이브 형식에 대한 아이디어가 있습니까?


2
더 많은 영감을 얻기 위해 살펴볼 수있는 일부 데이터 구조는 희소 행렬(다단계) 페이지 테이블 입니다.
Andrew Russell

낮은 우선 순위 : "긴"데이터 유형이 32 비트인지 64 비트인지 명확히 할 수 있습니까?
Randolf Richardson

2
@Randolf는 이것이 C #이라고 가정했을 때, 아마도 그는 long64 비트 인 C # 을 의미합니다 (따라서 maxlong은 Int64.MaxValue).
앤드류 러셀

: 노치는 여기에 자신의 블로그에서 마인 크래프트 무한 맵에 대해 할 말이 몇 가지 흥미로운 일이 notch.tumblr.com/post/3746989361/terrain-generation-part-1
dlras2

답변:


17

게임에 대한 사용자 지정 맵 형식을 만듭니다. 생각보다 쉽습니다. BinaryWriter 클래스를 사용하십시오. 먼저 헤더를 몇 개의 정수 또는 uint로 작성하십시오. 헤더에 포함 할 정보 :

  • 파일 형식의 마법 문자열 / 마법 번호.
  • 이 파일에 설명 된 청크의 시작 / 종료 / 크기

또한 성능에 중요한 부분이 있습니다.

  • 파일 내부의 시작 위치를 나타내는 int입니다. 따라서 특정 청크를 검색 할 필요가 없습니다.

위의 방법을 사용하면 일종의 설명 (지역 / 청크에 대한 사용자 지정 이름 또는 좌표)과 파일의 위치를 ​​두 번째 값으로 포함하여 파일 내용의 색인을 만들 수 있습니다.

그런 다음 특정 청크를로드하려면 인덱스 내부를 검색하면됩니다. 위치를 얻었을 때 그냥 fileStream.Position = PositionOfChunkFromIndex를 설정하고로드 할 수 있습니다.

파일 내용을 가장 효율적으로 설명하는 헤더가있는 파일 형식 디자인에 관한 것입니다.

구성한 사용자 지정 확장명으로 파일을 저장하면됩니다.

보너스 : 파일의 특정 영역 / 전체 내용 (헤더가 아닌 !!)에 BZip2 압축을 추가하면 파일에서 특정 청크의 압축을 풀 수있어 메모리 공간이 매우 작습니다.


12
이 파일을 즉석에서 수정하려는 경우 고정 크기 또는 외부 헤더 / 인덱스를 원하므로 파일을 다시 쓰지 않고도 청크를 파일에 추가 할 수 있습니다. 전체 파일 (오프셋 변경으로 인해).
Andrew Russell

이 시점에서 플랫 파일 데이터베이스 만 구현하고 있지 않습니까?
Ape-inago

13

비슷한 문제가 발생하여 데이터를 처리하는 자체 구조를 만들기로 결정했습니다. 쿼드 트리를 느슨하게 기반으로하지만 모든 방향에서 무한대 (적어도 Int만큼) 확장 성이 있습니다. 현재 Minecraft와 마찬가지로 중앙 지점에서 확장 된 그리드 기반 데이터를 처리하도록 설계되었습니다. 메모리에서 공간 효율적이며 매우 빠릅니다.

각 노드에 대해 최소 크기 (7의 크기는 128x128 임)를 지정할 수 있으며 노드에 지정된 비율의 하위 노드가 채워지면 자동으로 2 차원 배열로 평탄화됩니다. 이는 매우 인구 밀도가 높은 부분 (예 : 완전히 탐험 된 대륙)이 배열의 성능 (매우 빠름)을 갖지만 희소하게 채워진 부분 (예 : 누군가가 상하로 방황했지만 내륙을 탐험하지 않은 해안선)을 갖게됨을 의미합니다. 성능이 좋고 메모리 사용량이 적습니다.

내 코드는 여기 에서 찾을 수 있습니다 . 코드는 완전하고 테스트 (단위 및로드 테스트)되며 최적화되어 있습니다. 내부 작업은 아직 잘 문서화되어 있지 않지만 모든 공개 방법이 사용 가능해야합니다. 누군가 시도해보기로 결정한 경우 질문이나 의견이 있으면 언제든지 저에게 연락하십시오.

아직 데이터를 파일에 저장하는 데 사용하지는 않았지만 흥미로운 문제이며 다음에 해결할 수 있습니다.


이것은 기본적으로 확장 가능한 나무입니다. 내가 무엇을 놓치고 있습니까?
kaoD

2
확장 가능한 트리에 비해 가장 큰 개선점은 트리의 구조를 유지하는 대신 트리의 특정 노드를 2D 배열로 크게 채운 (기본 70 %) 것입니다. 이것은 무한 배열의 (무한) 크기없이 배열 조회 속도를 제공합니다.
dlras2 2016 년

잎과 안쪽 노드 둘 다 맞지? 재미있는 아이디어는 좋은 결과를 줄 수 있습니다. 필요할 때 시도해 보겠습니다. 코드와 빠른 답변을 제공하는 Btw, +1! 아, 그리고 단위는 내가 :) 내 개인 프로젝트에 그렇게하지 (슬프게도)도 수행 테스팅을
kaoD

우리는 내 작업에서 단위 테스트를 수행하지 않으므로 슬프게도 반란의 방법입니다. 나는 그것을 채우고 평평하게하는 방법을 보여주는 데모 응용 프로그램을 만들었습니다. 그래서 다음 몇 년 동안 정리할 수 있다면 며칠 동안 발표 가능하므로 여기에 게시하겠습니다. 당신이 그것을 볼 때 훨씬 더 의미가 있습니다.
dlras2

1
나는 그것을 보지 못했다, 죄송합니다! 나는 여전히 그것을 정리하고 싶지만 수업과 숙제 사이의 코드 중 일부를 천천히 재 작업하고 있으므로 잠시 동안은 아닙니다. 지금은 예쁘고 예쁘지 않은 데모가 여기 있습니다 : j.mp/qIwKYt 예쁘지 않다는 것은 부분적으로 설명이 많이 필요하다는 것을 의미하므로 README를 읽고 여기에 질문을하거나 이메일을 통해.
dlras2

3

대신 데이터베이스를 사용할 수 있습니다-PostgreSQL에는 X 및 Y 좌표로 위치한 이러한 유형의 데이터에 최적화 된 특수 색인 기능이 있습니다. 반환 된 데이터가 정사각형 또는 직사각형 모양 영역이 아닌 특정 반경 내에 있음을 지정할 수도 있습니다.

  PostgreSQL (무료 및 오픈 소스)
  http://www.postgresql.org/

다른 데이터베이스도 있으며 클라이언트 측에서는 독립 실행 형 (게임 클라이언트 응용 프로그램에서 시작)을 실행하거나 코드 라이브러리의 일부로 포함 할 수 있기 때문에 특정 유형에 더 적합한 유형을 찾을 수 있습니다 "그냥 사용할 수 있습니다." 대부분의 SQL 데이터베이스 엔진은 이미이 작업을 잘 수행하므로 인덱싱 구성표를 디자인 할 필요가 없다는 장점이 있습니다.

데이터베이스 접근 방식의 장점은 청크를 작게 만들 수 있다는 것입니다 (또는 청크를 완전히 제거하고 타일을 직접 사용하지만 디자인에 따라 최소한 작은 청크 / 그룹을 사용하는 것이 더 효율적일 수 있음), 그런 다음 SQL 쿼리를 사용하여 볼 수있는 것보다 넓은 영역을 가져옵니다. 볼 수없는 영역 근처에 겹치도록 사전로드 하면 플레이어가 캐릭터를 이동 하기 전에 타일을 준비 할 수있어 게임 환경이 더 좋고 (더 부드럽게) 향상됩니다.

Ashen Empires와 같은 일부 게임은 처음으로 얻은 후 로컬 하드 드라이브에 맵 데이터의 "캐시"를 유지하는 것으로 나타났습니다 (확실히 네트워크 I / O를 줄이는 것임).

  hen 빛 제국 (무료, 아름다운 2D 구현)
  http://www.ashenempires.com/

로컬로 저장된 데이터를 사용할 수있는 위치에 SQL 쿼리에 추가 "WHERE timestamp_column> $ local_timestamp"절이 포함되어 업데이트 된 청크 / 타일 만 얻을 수 있으므로 각 청크 / 타일의 "마지막 업데이트 된"타임 스탬프를 추적하는 것도 도움이됩니다. 이와 같이 대역폭 절약의 두 가지 이점은 연결 비용이 낮고 플레이어의 지연이 적어 게임이 대중화 될 때 더 분명해질 것입니다.

Ashen Empires의 스크린 샷 (일부 캐릭터는 지역 은행에 있으며 바닥에있는 뼈 모양으로 인해 소수의 해골 괴물이 방황해야하며 지역 마을 경비원에 의해 도살되었을 가능성이 있음) :

enter image description here


2

그것들을 저장하고 접근하지 말고, 필요한 임의의 씨앗과 플레이어의 맵 변경 사항 만 저장하십시오. 그런 다음 런타임에 필요한 부분을 생성하십시오 (생성 알고리즘을 실행 한 다음 플레이어의 변경 사항을 적용하십시오). 정확하고 일관된 생성 절차를 사용하면 동일한 시작 시드에 대해 결과 맵이 항상 동일합니다.

이론적으로 당신은이 방법으로 아주 작은 파일에 저장할 문자 그대로 무한 맵을 할 수 있습니다.


@Josh Petrie 내 게시물에 대한 중요하고 훌륭한 언어 / 문법 수정에 감사드립니다. 동정 나는 편집을 공표 할 수 없다 : -D
sh code

1

청크를 분할 할 수있는 방법이 있습니까 (세계의 일부 '대륙 / 국가')? 따라서 메모리에 청크를 갖기 위해로드 해야하는 하위 파일 / 큰 파일의 일부를 빠르게 찾을 수있는 일종의 색인 파일이있을 수 있습니다 ...


청크를 분할 할 수있는 방법은 항상 있습니다. 항상. 플레이어에게 보여 지거나 시스템의 나머지 부분과 관련이 있는지 여부에 관계없이 항상 월드 데이터를 청크로 분할 할 수있는 방법이 항상 있습니다.
sh 코드

0

Minecraft에서 아이디어를 얻을 수 있습니다. 원래 그들은 청크 당 파일을 가지고있었습니다. 이제 청크를 32x32 영역으로 그룹화하고 파일 당 하나를 저장하는 MCRegion 형식을 사용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.