전체지도 디자인과 타일 배열 디자인


11

나는 일반적인 던전 / 타운 맵 (사전 생성)을 특징으로하는 2D RPG를 만들고 있습니다.

타일을 사용하고 있으며 맵을 만들기 위해 결합합니다. 저의 원래 계획은 맵으로 사용할 수있는 하나의 큰 그림을 만들기 위해 Photoshop 또는 다른 그래픽 프로그램을 사용하여 타일을 조립하는 것이 었습니다.

그러나 사람들이 배열을 사용 하여 엔진에서 맵을 작성하는 방법에 대해 사람들이 이야기 한 곳을 읽었습니다 (그래서 x 타일 배열을 엔진에 제공하고 맵으로 조립합니다). 어떻게했는지 이해할 수는 있지만 구현하기가 훨씬 복잡해 보이며 명백한 장점을 볼 수 없습니다.

가장 일반적인 방법은 무엇이며 각각의 장단점은 무엇입니까?


1
주요 문제는 메모리입니다. 1080p 화면을 한 번 채우는 텍스처는 약 60MB입니다. 따라서 이미지는 픽셀 당 int를 사용하고 타일은 픽셀 당 (pixel / (tilesize * tileize))을 사용합니다. 타일이 32,32 인 경우 타일과 픽셀을 사용하여 1024 배 큰 맵을 나타낼 수 있습니다. 또한 텍스처 스와핑 시간으로 인해 많은 양의 메모리를 밀어 넣는 데
어려움을 겪을 것입니다

답변:


19

우선, 2D RPG가 내 마음에 가깝고 사랑스럽고 오래된 DX7 VB6 MORPG 엔진 (웃지 말고, 8 년 전, 지금 :-))이 게임 개발에 관심을 갖게 된 것이 가장 중요합니다. . 최근에는 XNA를 사용하기 위해 엔진 중 하나에서 작업 한 게임을 변환하기 시작했습니다.

즉, 맵에 레이어를 사용하여 타일 기반 구조를 사용하는 것이 좋습니다. 사용하는 모든 그래픽 API를 사용하면로드 할 수있는 텍스처의 크기가 제한됩니다. 그래픽 카드 텍스처 메모리 제한은 말할 것도 없습니다. 따라서이를 고려하여 메모리에로드하는 텍스처의 양과 크기를 최소화 할뿐만 아니라 사용자의 하드 드라이브 및로드 시간에서 자산의 크기를 줄이면서 맵 크기를 최대화하려는 경우 타일과 함께 가고 싶을 것입니다.

구현이 진행되는 한 여기 GameDev.SE와 내 블로그 (아래 링크 모두)에 대한 몇 가지 질문에 대해 어떻게 처리했는지 자세히 설명했습니다. 그게 정확히 당신이 요구하는 것이 아니기 때문에 그냥 여기에 기본으로 이동하십시오. 또한 미리 렌더링 된 여러 개의 큰 이미지를로드 할 때 유용하게 사용할 수있는 타일의 기능에 대해서도 설명합니다. 분명하지 않은 사항이 있으면 알려주십시오.

  1. 가장 먼저해야 할 일은 타일 시트를 만드는 것입니다. 이것은 타일에 정렬 된 모든 타일을 포함하는 큰 이미지 일뿐입니다. 이것은 (그리고 타일 수에 따라 여분의 것)로드 해야하는 유일한 것입니다. 단 1 개의 이미지! 게임에서 맵당 1 개 또는 타일마다 하나씩로드 할 수 있습니다. 어떤 조직이든 당신을 위해 일합니다.
  2. 다음으로, "시트"를 가져 와서 각 타일을 숫자로 변환하는 방법을 이해해야합니다. 이것은 간단한 수학으로 매우 간단합니다. 여기에서 나누기는 정수 나누기 이므로 소수점 이하 자릿수가 삭제됩니다 (또는 원하는 경우 반올림). 셀을 좌표로 변환하고 다시 변환하는 방법
  3. 이제 타일 시트를 일련의 셀 (숫자)로 나누었으므로 숫자를 가져와 원하는 컨테이너에 꽂을 수 있습니다. 간단하게하기 위해 2D 배열 만 사용할 수 있습니다.

    int[,] mapTiles = new int[100,100]; //Map is 100x100 tiles without much overhead
  4. 다음으로 그립니다. 이 맵을보다 효율적으로 만들 수있는 방법 중 하나 (맵 크기에 따라 다름)는 카메라가 현재보고있는 셀만 계산하고 해당 셀을 반복하는 것입니다. 카메라의 왼쪽 상단 ( tl) 및 오른쪽 하단 ( br) 모서리 의 맵 타일 배열 좌표를 가져 와서이를 수행 할 수 있습니다 . 그런 다음 tl.X to br.X중첩 된 루프에서 시작 tl.Y to br.Y하여 반복 합니다. 아래 예제 코드 :

    for (int x = tl.X; x <= br.X;x++) {
        for (int y = tl.Y; y <= br.Y;y++) {
            //Assuming tileset setup from image
            Vector2 tilesetCoordinate = new Vector2((mapTiles[x,y] % 8) * 32,(mapTiles[x,y] / 8) * 32);
            //Draw 32x32 tile using tilesetCoordinate as the source x,y
        }
    }
    
  5. 공동 자금! 이것이 타일 엔진의 기본입니다. 오버 헤드가 많지 않은 1000x1000 맵도 쉽게 가질 수 있습니다. 또한 타일이 255 개 미만인 경우 바이트 배열을 사용하여 셀당 3 바이트 씩 메모리를 줄일 수 있습니다. 바이트가 너무 작 으면 ushort는 아마도 당신의 요구에 충분할 것입니다.

참고 : 세계 좌표 개념 (카메라 위치가 기반으로하는 개념)은 생략 했으므로이 답변의 범위를 벗어난 것 같습니다. GameDev.SE에서 여기를 읽을 수 있습니다.

내 타일 엔진 리소스
참고 :이 모든 것은 XNA를 대상으로하지만 거의 모든 것에 적용됩니다. 그리기 호출 만 변경하면됩니다.

  • 질문에 대한 나의 대답은 게임에서 맵 셀과 레이어링을 처리하는 방법을 설명합니다. (세 번째 링크 참조)
  • 질문에 대한 나의 대답 은 데이터를 이진 형식으로 저장하는 방법을 설명합니다.
  • 이것은 내가 작업하고있는 게임의 개발에 관한 첫 번째 (기술적으로는 두 번째이지만 "기술적 인"첫 번째) 블로그 게시물입니다. 전체 시리즈에는 픽셀 쉐이더, 조명, 타일 동작, 움직임 및 모든 재미있는 것들에 대한 정보가 포함되어 있습니다. 나는 실제로 내가 게시 한 첫 번째 링크에 대한 답변의 내용을 포함하도록 게시물을 업데이트 했으므로 대신 읽을 수도 있습니다 (추가 한 내용이있을 수 있음). 질문이 있으시면 여기 또는 여기에 의견을 남겨 주시면 기꺼이 도와 드리겠습니다.

다른 타일 엔진 리소스

  • 사이트 의 타일 엔진 튜토리얼을 통해 지도를 만들 때 사용한 기초를 얻었습니다.
  • 실제로 시청하지 않은 나는 시간이 없었어요 때문에 아직 비디오 자습서를,하지만 그들은 아마 도움이있어. :) XNA를 사용하는 경우 구식 일 수 있습니다.
  • 사이트에는 위의 비디오를 기반으로 한 자습서가 더 있습니다. 체크 아웃 할 가치가 있습니다.

와우, 그것은 내가 요구 한 것보다 두 배 더 많은 정보이며, 내가 묻지 않은 모든 질문에 거의 대답합니다. 감사합니다 :)
Cristol.GdM

@Mikalichov-기꺼이 도와 드리겠습니다! :)
Richard Marskell-Drackir 2016 년

일반적으로 2D 배열의 경우 첫 번째 차원을 Y로 사용하고 다음 차원을 X로 사용하려고합니다. 메모리에서 배열은 순차적으로 0,0-i, 1,0i입니다. X로 중첩 루프를 수행하는 경우 순차적으로 읽는 경로를 따르지 않고 실제로 메모리에서 앞뒤로 점프합니다. 항상 (y)에 대해 (x)에 대해.
Brett W

@BrettW-유효한 포인트. 감사. 2D 배열이 .Net에 저장되는 방법을 궁금해했습니다 (행 주요 순서. 오늘 새로운 것을 배웠습니다! :-)). 그러나 코드를 업데이트 한 후 변수를 전환 한 것만으로 설명하는 것과 정확히 동일하다는 것을 알았습니다. 차이점은 타일이 그려지는 순서입니다. 현재 예제 코드는 위에서 아래로, 왼쪽에서 오른쪽으로 그리는 반면 설명하는 내용은 왼쪽에서 오른쪽으로, 위에서 아래로 그리는 것입니다. 그래서 단순화를 위해 원본으로 되돌리기로 결정했습니다. :-)
Richard Marskell-Drackir 2016 년

6

타일 ​​기반 시스템과 정적 모델 / 텍스처 시스템은 모두 세계를 나타내는 데 사용될 수 있으며 각각 다른 강점을 가지고 있습니다. 하나가 다른 것보다 더 좋은지 여부는 조각을 사용하는 방법과 기술 및 요구에 가장 적합한 방법으로 요약됩니다.

즉, 두 시스템 모두 별도로 또는 함께 사용할 수 있습니다.

표준 타일 기반 시스템은 다음과 같은 장점이 있습니다.

  • 타일의 간단한 2D 배열
  • 각 타일에는 단일 재질이 있습니다
    • 이 재질은 단일 텍스처, 다중 또는 주변 타일과 혼합 될 수 있습니다.
    • 해당 유형의 모든 타일에 텍스처를 재사용 할 수있어 자산 생성 및 재 작업 감소
  • 각 타일은 통과 가능 또는 비통과 가능 (충돌 감지)
  • 지도의 일부를 쉽게 렌더링하고 식별
    • 캐릭터 위치와 맵 위치는 절대 좌표입니다
    • 화면 영역의 관련 타일을 간단하게 반복

타일의 단점은이 타일 기반 데이터를 구축하기위한 시스템을 만들어야한다는 것입니다. 각 픽셀을 타일로 사용하는 이미지를 만들어 텍스처에서 2D 배열을 만들 수 있습니다. 독점 형식을 만들 수도 있습니다. 비트 플래그를 사용하면 타일 당 많은 수의 데이터를 상당히 작은 공간에 저장할 수 있습니다.

대부분의 사람들이 타일을 만드는 주된 이유는 작은 자산을 만들어 재사용 할 수 있기 때문입니다. 이것은 당신이 훨씬 더 큰 그림 작은 조각을 만들 수 있습니다. 전 세계지도를 약간 변경하여 변경하지 않으므로 재 작업이 줄어 듭니다. 예를 들어 모든 잔디의 그늘을 변경하려는 경우. 큰 이미지에서는 모든 잔디를 다시 칠해야합니다. 타일 ​​시스템에서는 잔디 타일 만 업데이트하면됩니다.

전체적으로 큰 그래픽 맵보다 타일 기반 시스템으로 재 작업을하는 것이 훨씬 적습니다. 지상지도에 사용하지 않더라도 충돌을 위해 타일 기반 시스템을 사용하게 될 수 있습니다. 내부적으로 타일을 사용한다고해서 공간에 둘 이상의 타일을 사용할 수있는 환경 객체를 표현하기 위해 모델을 사용할 수 없다는 의미는 아닙니다.

코드 예제를 제공하려면 환경 / 엔진 / 언어에 대한 자세한 내용을 제공해야합니다.


감사! 나는 C #에서 일하고 있으며 비슷한 (하지만 재능이 적은) Final Fantasy 6 버전 (또는 기본적으로 대부분의 Square SNES RPG)을 사용하므로 바닥 타일 및 구조 타일 (예 : 주택). 가장 큰 걱정거리는 "시간이 지나면 잔디 코너가 있고, 가로 세 개, 가로 세 개가있는 집, 그리고 .."를 확인하지 않고 2D 어레이를 구축하는 방법을 볼 수 없다는 것입니다. 방법.
Cristol.GdM

Richard가 코드 특정 측면에서 다루는 것처럼 보입니다. 개인적으로 타일 유형 열거 형을 사용하고 비트 플래그를 사용하여 타일 값을 식별합니다. 이를 통해 32 개 이상의 값을 평균 정수로 저장할 수 있습니다. 타일 ​​당 여러 개의 플래그를 저장할 수도 있습니다. 따라서 별도의 변수없이 Grass = true, Wall = true, Collision = true 등을 말할 수 있습니다. 그런 다음 특정지도 영역의 그래픽에 대한 타일 시트를 결정하는 "테마"를 지정하기 만하면됩니다.
Brett W

3

맵 그리기 : 엔진에서 타일을 쉽게 사용할 수 있습니다. 맵은 타일 배열의 거대한 배열로 표현 될 수 있기 때문입니다. 그리기 코드는 중첩 루프입니다.

for i from min_x to max_x:
    for j from min_y to max_y:
        Draw(Tiles[i][j], getPosition(i,j))

큰지도의 경우 전체지도에 대해 하나의 거대한 비트 맵 이미지가 메모리에서 많은 공간을 차지할 수 있으며 그래픽 카드가 단일 이미지 크기를 지원하는 것보다 더 클 수 있습니다. 그러나 각 타일에 대해 그래픽 메모리를 한 번만 할당하기 때문에 (또는 한 시트에 모두있는 경우 최적으로 총 하나만 할당하므로) 타일에 문제가 없습니다.

충돌 등 타일 정보를 재사용하기도 쉽습니다. 예를 들어 캐릭터 스프라이트의 왼쪽 상단에 터 레인 타일을 가져 오려면 :

let x,y = character.position
let i,j = getTileIndex(x,y) // <- getTileIndex is the opposite function of getPosition
let tile = Tiles[i][j]

바위 / 나무 등과의 충돌을 확인해야한다고 가정합니다. 타일을 (문자 위치 + 문자 스프라이트 크기 + 현재 방향) 위치에 놓고 걸을 수 있거나 표시 할 수없는 것으로 표시되어 있는지 확인할 수 있습니다.

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