2D 게임에서 임의로 큰 이미지를 처리하는 방법은 무엇입니까?


13

질문

하드웨어에서 지원할 수있는 것보다 큰 이미지를 사용하는 2D 게임을 사용하는 경우 어떻게해야합니까? 어쩌면 전에 나에게 결코 발생하지 않은이 문제에 대한 흥미로운 해결책이있을 수 있습니다.

저는 기본적으로 일종의 그래픽 어드벤처 게임 메이커에서 일하고 있습니다. 목표 대상은 게임 개발 (및 프로그래밍) 경험이 거의 또는 전혀없는 사람들입니다. 이러한 응용 프로그램으로 작업하는 경우 "이미지를 분할하십시오"라고 말하는 대신 내부적으로 문제를 처리하기를 원하지 않습니까?

문맥

그래픽 카드는 사용할 수있는 텍스처의 크기에 제한을 가하는 것으로 잘 알려져 있습니다. 예를 들어, XNA로 작업 할 때 선택한 프로파일에 따라 최대 텍스처 크기는 2048 또는 4096 픽셀로 제한됩니다.

2D 게임에서는 대개 작은 개별 조각 (예 : 타일 또는 변형 된 스프라이트)으로 구성 할 수있는 레벨이 있기 때문에 이것은 큰 문제가되지 않습니다.

그러나 몇 가지 고전적인 point'n'click 그래픽 어드벤처 게임 (예 : Monkey Island)에 대해 생각해보십시오. 그래픽 어드벤처 게임의 객실은 일반적으로 풍경을 작업하는 화가처럼 반복 가능한 섹션이 거의 또는 전혀없는 전체로 설계됩니다. 또는 사전 렌더링 된 큰 배경을 사용하는 Final Fantasy 7과 같은 게임 일 수도 있습니다.

이 방들 중 일부는 꽤 넓어서 종종 3 개 이상의 너비의 화면에 걸쳐 있습니다. 이제 현대적인 고화질 게임의 맥락에서 이러한 배경을 고려하면 지원되는 최대 텍스처 크기를 쉽게 초과 할 수 있습니다.

이제 이에 대한 확실한 해결책은 배경을 요구 사항에 맞는 작은 섹션으로 나누고 나란히 그리는 것입니다. 그러나 당신 (또는 당신의 예술가)은 당신의 모든 질감을 나누는 사람이어야합니까?

높은 수준의 API로 작업하는 경우이 상황을 처리하고 내부적으로 텍스처를 분할하고 조립할 준비가되어 있지 않아야합니까 (XNA의 Content Pipeline과 같은 사전 프로세스 또는 런타임)?

편집하다

XNA 구현 관점에서 내가 생각한 것은 다음과 같습니다.

내 2D 엔진에는 아주 작은 Texture2D 기능의 하위 집합 만 필요합니다. 실제로이 인터페이스로 줄일 수 있습니다.

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

Texture2D에 의존하는 유일한 외부 메소드는 SpriteBatch.Draw ()이므로 확장 메소드를 추가하여 그들 사이에 브리지를 만들 수 있습니다.

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

이렇게하면 전에 Texture2D를 사용할 때마다 ITexture를 서로 바꿔 사용할 수 있습니다.

그런 다음 RegularTexture와 LargeTexture와 같은 두 가지 다른 ITexture 구현을 만들 수 있습니다. 여기서 RegularTexture는 단순히 일반 Texture2D를 래핑합니다.

반면에 LargeTexture는 분할 된 전체 이미지 조각 중 하나에 해당하는 Texture2D 목록을 각각 유지합니다. 가장 중요한 부분은 LargeTexture에서 Draw ()를 호출하면 모든 변형을 적용하고 마치 하나의 연속 이미지 인 것처럼 모든 조각을 그릴 수 있어야한다는 것입니다.

마지막으로 전체 프로세스를 투명하게하기 위해 팩토리 메소드 역할을하는 통합 텍스처 로더 클래스를 작성합니다. 텍스처의 경로를 매개 변수로 사용하고 이미지 크기 제한을 초과하는지 여부에 따라 RegularTexture 또는 LargeTexture 인 ITexture를 반환합니다. 그러나 사용자는 어느 것을 알 필요가 없었습니다.

약간 과잉이거나 괜찮습니까?


1
이미지 분할과 함께 사용하려면 콘텐츠 파이프 라인을 확장하여 프로그래밍 방식으로 수행하십시오. 모든 단일 시나리오를 포괄하는 모든 기능이있는 것은 아니며 어느 시점에서 직접 확장해야합니다. 타일 ​​맵과 같은 종류의 이미지를 처리 ​​할 수 ​​있으므로 가장 간단한 솔루션처럼 사운드를 개인적으로 분리하면 수많은 리소스가 있습니다.
DMan

콘텐츠 파이프 라인에서이를 수행하는 것이 가장 합리적인 방법입니다. 그러나 제 경우에는 런타임에 이미지를로드해야했고 이미 런타임 솔루션을 생각해 냈습니다 (그래서 어제이 질문을했습니다 ). 그러나 진정한 아름다움은이 "타일 맵"을 가져 와서 일반 텍스처처럼 동작하게 만드는 것입니다. 즉 당신은 여전히 그릴의 SpriteBatch에 전달할 수 있고, 당신은 여전히 등의 위치, 회전, 크기, SRC / 이명 령 사각형을 지정할 수 있습니다 I 약 절반이 지금 쯤 :) 해요
데이비드 Gouveia의

그러나 진실은 이미 가치가있는 모든 것이 있는지 또는 사용자에게 최대 지원 이미지 크기가 2048x2048이며 그와 함께 끝났다는 경고를 표시 해야하는지 궁금합니다.
David Gouveia

디자인에 대한 것은 당신에게 달려 있습니다. 프로젝트를 끝내고 방 사이를 스크롤 할 수 없다면 큰 텍스처를 스크롤 할 수있는 편집기를 끝내지 않는 것이 좋습니다 : D
Aleks

API에 숨기는 것은 게임 제작자의 삶을 편하게 만드는 좋은 방법 인 것 같습니다. 아마도 Polygon (sprite) 및 Texture 클래스에서 구현하고 작은 이미지를 특수한 경우가 아니라 1x1 크기의 타일로 만듭니다. 따라서 텍스처 클래스는 모든 타일과 행 / 열 수를 설명하는 텍스처 그룹입니다. 그런 다음 Polygon 클래스는이 정보를보고 자체를 분할하고 적절한 텍스처로 각 타일을 그립니다. 그런 식으로, 그것은 이다 같은 클래스. 스프라이트 클래스가 보이는 타일 만 그리고 텍스처 그룹은 필요할 때까지 텍스처를로드하지 않는 경우 보너스 포인트입니다.
uliwitness

답변:


5

나는 당신이 올바른 길을 가고 있다고 생각합니다. 이미지를 더 작은 조각으로 분할해야합니다. 게임 메이커를 만들었으므로 XNA의 콘텐츠 파이프 라인을 사용할 수 없습니다. 제작자가 엔진과 비슷하지 않으면 개발자가 Visual Studio를 계속 사용해야합니다. 따라서 분할을 수행하는 자체 루틴을 빌드해야합니다. 플레이어가 가져야 할 비디오 메모리의 양을 제한하지 않도록 조각을 조금 전에 스트리밍하는 것이 좋습니다.

모험 게임을 위해 특별히 할 수있는 몇 가지 요령이 있습니다. 나는 모든 고전 어드벤처 게임처럼이 텍스처의 레이어가 거의 없어서 캐릭터가 나무 나 건물 뒤를 걸을 수 있다고 상상합니다 ...

이 레이어에 시차 효과를 주려면 타일을 분할 할 때 모든 반투명을 한 번만 건너 뜁니다. 여기에서는 타일의 크기를 고려해야합니다. 작은 타일은 오버 헤드 관리 및 호출 호출을 추가하지만 더 큰 타일은 GPU에 친숙하지만 반투명도가 많은 데이터는 더 적습니다.

시차 효과가 없다면 32 비트 깊이를 가진 2-4 개의 거대한 이미지로 전체 장면을 덮어 쓰는 대신 하나의 32 비트 깊이 만 만들 수 있습니다. 그리고 픽셀 당 8 비트의 스텐실 또는 깊이 레이어를 가질 수 있습니다.

게임 개발자가 아닌 사람이 자산을 관리하기가 어렵다는 것을 알고 있지만 실제로는 그렇지 않아도됩니다. 예를 들어 나무가 3 개인 거리가 있고 플레이어가 2 개 뒤에 있고 3 번째 나무와 나머지 배경 앞에있는 경우 ... 편집기에서 원하는 방식으로 장면 레이아웃을 만든 다음 게임 제작자로부터 단계를 구축하면이 거대한 이미지 (큰 이미지의 작은 타일)를 구울 수 있습니다.

고전 게임이 어떻게 지 냈는지에 대해. 나는 그들이 아마도 간단한 트릭을했는지 확신하지 못하지만 화면이 320x240이었을 때 게임은 16 색으로되어있어 구식 질감을 사용할 때 2 바이트를 단일 바이트로 인코딩 할 수 있음을 기억해야합니다. 그러나 이것이 현재 아키텍처가 작동하는 방식은 아닙니다.

행운을 빕니다


감사합니다. 여기에 매우 흥미로운 아이디어가 많이 있습니다! 실제로 Adventure Game Studio에서 이전에 사용 된 스텐실 레이어 기술을 보았습니다. 내 응용 프로그램에 관해서는 조금 다르게하고 있습니다. 객실에 반드시 하나의 배경 이미지가있는 것은 아닙니다. 대신 사용자가 가져온 이미지 팔레트와 배경 / 전경 레이어가 있습니다. 사용자는 룸으로 조각을 끌어서 놓아 자유롭게 만들 수 있습니다. 만약 그가 원한다면 그는 게임 오브젝트를 비 대화식으로 만들 필요없이 작은 조각으로도 구성 할 수있었습니다. 그러나이 두 레이어 만 있기 때문에 시차는 없습니다.
David Gouveia

그리고 Monkey Island Special Edition (HQ 리메이크)의 데이터 파일을 살펴 보았습니다. 모든 배경은 정확히 1024x1024 조각으로 분할됩니다 (이미지의 많은 부분을 사용하지 않은 경우에도). 어쨌든, 전체 프로세스를 투명하게 만들기 위해 내 편집 내용을 확인하십시오.
David Gouveia

아마도 256x256과 같은 합리적인 것을 선택했을 것입니다. 이렇게하면 리소스를 낭비하지 않으며 나중에 스트리밍을 구현하기로 결정하면보다 합리적인 청크가로드됩니다. 어쩌면 나는 충분히 설명하지 않았지만 작은 정적 게임 객체를 모두 큰 질감으로 구울 수 있다고 제안했습니다. 저장할 배경은 큰 배경 질감이있는 경우 정적 객체가 덮은 모든 픽셀이 위에있는 것입니다.
Aleks

모든 정적 객체 배경 으로 병합 한 다음 텍스처 아틀라스를 분할하고 만듭니다. 나는 그 생각의 기차를 따라 다른 모든 것을 텍스처 아틀라스로 구울 수도 있습니다. 좋은 생각이기도합니다. 그러나 지금은 "빌드"단계가 없으므로 에디터와 게임 클라이언트가 동일한 엔진과 동일한 데이터 형식으로 실행되기 때문에 나중에 그대로 두겠습니다.
David Gouveia

나는 스텐실 접근법을 좋아하지만 모험 게임 에디터를 만들고 있다면 아마 그것을 사용하지 않을 것입니다 ... 어쩌면 내가 그런 도구를 만들고 있다면 게임 개발자를위한 것입니다. 그것은 장단점이 있습니다. 예를 들어, 비트 당 픽셀 당 트리거를 정의 할 수있는 다른 이미지를 사용하거나 물이 생기면 쉽게 스텐실로 만들 수 있습니다. 참고 : 하나의 이상한 관련 제안이 스크립팅을 위해 UML 상태 / 활동 다이어그램을 살펴 봅니다.
Aleks

2

당신이 말하는 것처럼 더 이상 임의로 자르지 않도록 잘라내십시오. 마법이 없습니다. 이 오래된 2D 게임은 그렇게하거나 소프트웨어로 렌더링되었는데,이 경우 RAM 크기 이외의 하드웨어 제한은 없었습니다. 주목할 점은 많은 2D 게임에는 실제로 큰 배경이 없었으며 천천히 스크롤되어 크게 느꼈다는 것입니다.

그래픽 어드벤처 게임 제작자에서하고 싶은 것은 게임을 패키지화하기 전에 일종의 "빌드"또는 "통합"단계에서 큰 이미지를 사전 처리하는 것입니다.

직접 작성하는 대신 기존 API 및 라이브러리를 사용하려면 "빌드"중에 큰 이미지를 타일로 변환하고 2D 타일 엔진을 사용하는 것이 좋습니다.

자신의 3D 기술을 사용하려면 여전히 타일로 분할하고 잘 알려져 있고 잘 설계된 2D API를 사용하여 자신의 3D 라이브러리를 작성해야 할 수 있습니다. 좋은 API 디자인과 적은 디자인이 필요합니다.


빌드 타임에하는 것이 이상적입니다 ...하지만 제 에디터는 렌더링을 위해 XNA도 사용합니다. 단지 엔진이 아닙니다. 즉, 일단 사용자가 이미지를 가져 와서 룸으로 드래그하면 XNA는 이미 이미지를 렌더링 할 수 있어야합니다. 따라서 내 큰 딜레마는 내용을로드 할 때 메모리에서 또는 내용을 가져올 때 디스크에서 분할을 수행할지 여부입니다. 또한 이미지를 여러 파일로 물리적으로 분할하면 이러한 파일을 다르게 저장하는 방법이 필요하지만 런타임에 메모리에서 이미지를 저장하는 경우 게임의 데이터 파일을 변경할 필요가 없습니다.
David Gouveia

1

쿼드 트리가 시각적으로 어떻게 보이는지 잘 알고 있다면, 쿼드 트리의 증거 / 시각화와 비슷한 세부적인 큰 이미지를 작은 이미지로 자르는 방법을 사용했습니다. 그러나 광산은 색에 따라 다르게 인코딩되거나 압축 될 수있는 영역을 구체적으로 잘라내는 방식으로 만들어졌습니다. 이 방법을 사용하고 설명 된대로 할 수도 있습니다.

실행 시간을 줄이면 일시적으로 더 많은 메모리가 필요하고로드 시간이 느려집니다. 나는 그것이 당신이 물리적 스토리지에 대해 더 관심이 있는지 또는 에디터로 만든 사용자 게임의 로딩 시간에 더 관심이 있는지에 달려 있습니다.

로드 / 런타임 : 로드에 관한 방법은로드를 비례적인 크기로 자르는 것입니다. 홀수 픽셀 인 경우 가장 오른쪽에있는 한 픽셀을 고려하십시오. 특히 이미지를 자르는 것을 좋아하는 사람은 아무도 없습니다. 사각형이나 4 섹션 (2 행 2 열)이 아닌 이유는 너비의 절반 또는 높이의 절반 (또는 3, 4 등)을 만드십시오 .x와 y에 대해 걱정하지 않기 때문에 타일링 메모리가 더 작아지기 때문입니다. 동시에 (그리고 얼마나 많은 이미지가 큰지에 따라 매우 중요 할 수 있습니다)

수작업 전 / 자동으로 : 이 경우 사용자에게 이미지를 하나의 이미지로 저장하거나 별도의 조각으로 저장하도록 선택할 수 있다는 아이디어가 마음에 듭니다 (하나의 이미지가 기본값이어야 함). 이미지를 .gif로 저장하면 효과적입니다. 이미지는 하나의 파일에 있으며 각 프레임은 애니메이션이 아니라 동일한 이미지의 압축 된 아카이브와 비슷합니다 (기본적으로 .gif가 무엇인지). 실제 파일 전송 및 로딩이 용이합니다.

  1. 하나의 파일입니다
  2. 모든 파일의 형식은 거의 동일합니다
  3. 언제 그리고 개별 텍스처로자를 것인지를 쉽게 선택할 수 있습니다
  4. 메모리에 이미지 파일이 많이 필요하지 않으므로 이미로드 된 단일 .gif 파일에 개별 이미지에 액세스하는 것이 더 쉬울 수 있습니다.

아 그리고 .gif 메서드를 사용하는 경우 .gif 파일이 손상된 파일처럼 애니메이션으로 표시 될 때 혼동을 줄이려면 파일 확장명을 다른 것으로 변경해야합니다 (.gif-> .kittens). (그 합법성에 대해 걱정하지 마십시오. .gif는 공개 형식입니다)


의견을 보내 주셔서 감사합니다. 내가 잘못 이해했지만 압축 및 저장과 관련하여 주로 쓴 것이 아닌 경우 죄송합니다. 모두 정말 약을 걱정하고있어이 경우 가져올 수있는 내 응용 프로그램의 사용자 인 모든 이미지 및 (XNA)에 엔진 로딩 할 수있는 및 표시 어떤 에서 이미지를 런타임 . 나는 GDI를 사용하여 이미지의 다른 섹션을 별도의 XNA 텍스처로 읽고 일반 텍스처와 같이 작동하는 클래스 내에 래핑하여 (즉, 그리기 및 변환을 전체적으로 지원) 간단히 해결했습니다.
David Gouveia

그러나 호기심을 가지고 이미지의 각 영역에 어떤 영역을 적용 할 것인지 선택하는 기준에 대해 좀 더 자세히 설명해 주시겠습니까?
David Gouveia

이미지 처리에 익숙하지 않은 경우 일부는 머리 위에있을 수 있습니다. 그러나 본질적으로 이미지를 세그먼트로 자르는 것을 설명했습니다. .gif 포인트는 스토리지와 로딩을 모두 설명했지만 이미지를 잘라낸 다음 컴퓨터에 이미지를 저장하는 방법을 의미합니다. gif로 저장하면 개별 이미지로 잘라서 애니메이션 GIF로 저장할 수 있으며 각 이미지 컷이 별도의 애니메이션 프레임으로 저장됩니다. 잘 작동하고 도움이 될 다른 기능도 추가했습니다.
Joshua Hedges

내가 설명한 쿼드 트리 시스템은 내가 생각한 곳이므로 전적으로 참조로 언급됩니다. 비슷한 문제가있을 수있는 독자에게는 유용한 질문으로 가득 차기보다는 자세한 내용을 알고 싶다면 개인 메시지를 사용해야합니다.
Joshua Hedges

로저, GIF 프레임을 일종의 아카이브로 사용하는 것에 대해 알게되었습니다. 그러나 GIF가 제한된 색상 팔레트로 색인 형식이 아닌지 궁금합니다. 각 프레임에 32bpp RGBA 이미지 전체를 저장할 수 있습니까? 그리고 XNA는 아무것도 지원하지 않기 때문에 로딩 프로세스가 훨씬 더 복잡해집니다.
David Gouveia

0

이것은 분명하게 들리 겠지만 방을 더 작은 조각으로 나누지 않는 이유는 무엇입니까? 1024x1024 이상인 그래픽 카드에 머리를 부딪치지 않는 임의의 크기를 선택하고 방을 여러 조각으로 나눕니다.

나는 이것이 문제를 피한다는 것을 알고 있으며, 솔직히 이것은 매우 흥미로운 문제입니다. 어쨌든, 이것은 일종의 사소한 해결책이며 약간의 시간이 걸릴 수 있습니다.


이 스레드 어딘가에 이유를 언급했을 수도 있지만 확실하지 않기 때문에 반복 할 것입니다. 기본적으로 게임이 아니라 일반인을위한 게임 메이커이기 때문에 (RPG 메이커와 같은 범위에서 무언가를 생각하십시오) 사용자가 자신의 자산을 가져올 때 텍스처 크기 제한을 강요하는 대신 처리하는 것이 좋습니다 텍스처 크기 제한에 대한 기술적 세부 사항으로 인해 방해받지 않고 장면 뒤에서 자동으로 분할 및 스티칭.
David Gouveia

알겠습니다. 미안, 나는 그것을 놓친 것 같아요.
ashes999
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.