<div align="center">
<img src="https://raw.githubusercontent.com/riebel/pixi-tiledmap/master/assets/logo.svg" width="96" height="96" alt="" />
pixi-tiledmap
pixi-tiledmap은 PixiJS v8용 완전한 Tiled 맵 런타임입니다. 이는 내장 파싱, 런타임 편집, 절차적 생성(procedural generation), 그리고 Tiled JSON 내보내기 기능을 갖춘 고성능 렌더러로, Tiled Map Editor의 맵 파일(.tmj / .tmx)을 다루며 TypeScript와 JavaScript를 위해 구축되었습니다.
.tmj 및 .tmx 맵 파일을 로드하고, 배치 처리된 GPU 타일을 렌더링하며, 런타임에 맵을 편집하고 생성한 후, PixiJS 외 추가적인 런타임 종속성 없이 Tiled JSON으로 다시 내보낼 수 있습니다.
[![CI][ci-image]][ci-url]
[![npm version][npm-image]][npm-url]
[![npm downloads][downloads-image]][npm-url]
![runtime dependencies][deps-image]
[![TypeScript types][types-image]][npm-url]
[![license][license-image]][license-url]
[![checked with Biome][biome-image]][biome-url]
Showcase · Map viewer · Quick Start · Performance · API Reference · Documentation
<a href="https://pixi-tiledmap-showcase.vercel.app()"><img src="https://raw.githubusercontent.com/riebel/pixi-tiledmap/master/assets/showcase.webp" width="880" alt="The showcase: a wordmark built from map tiles over an animated packed tile layer, running at 144 fps with 7891 quads and 13.2k setTile calls per second" /></a>
<sub>실시간으로 실행되는 쇼케이스: 이 프레임에서 애니메이션된 패키지 타일 레이어 하나에 7,891개의 사각형(quads)이 144 fps로, 초당 13.2k <code class="language-text">setTile</code> 호출과 함께 작동합니다.</sub>
</div>
Quick Start
npm install pixi-tiledmap pixi.js
로더 확장(loader extension)을 한 번 등록한 다음, Assets를 통해 .tmj (JSON) 또는 .tmx (XML) 파일을 로드합니다:
import { Application, extensions, Assets } from 'pixi.js';
import { tiledMapLoader } from 'pixi-tiledmap';
...
⚠️ [참고]
로더가 파일 확장자를 통해 형식을 자동 감지합니다: .tmj → JSON, .tmx → XML.
PixiJS는 로드된 에셋을 캐시하므로, 동일한 URL을 반복적으로 로드해도 복사본이 아닌 같은 container를 반환합니다. 한 맵을 여러 번 렌더링하거나 로드된 텍스처를 직접 관리하기 전에 에셋 로딩 및 생명 주기 섹션을 참조하세요.
pixi-tiledmap을 사용해야 하는 이유?
Tiled가 여러분의 맵 에디터이고, 맵 파일부터 렌더링되고 편집 가능하며 내보낼 수 있는 맵까지 전체 과정을 처리하길 원한다면 pixi-tiledmap을 선택하세요.
정적 타일은 PixiJS 메시(meshes)로 배치되며, 타일 레이어는 움직이는 카메라가 다시 업로드하지 않는 렌더 그룹(render groups)이며, 호환되는 런타임 편집은 레이어를 재구축하는 대신 버퍼를 제자리에서 업데이트합니다. 이 라이브러리는 모든 Tiled 레이어 유형과 방향, 애니메이션 타일, 오브젝트 및 템플릿, 패럴랙스 스크롤링, 무한 맵을 지원합니다. 성능 섹션에서는 디자인을 설명하고 그 배경이 되는 측정값을 기록합니다.
이 패키지는 자체 TMJ 및 TMX 파서, 포괄적인 TypeScript 타입, 절차적 맵 도구, 그리고 Tiled JSON 내보내기를 함께 제공합니다. 피어 의존성(peer dependency)으로 제공되는 PixiJS 외에는 추가적인 런타임 의존성이 없습니다.
pixi-tiledmap은 TMX/TMJ 형식을 읽는 라이브러리 중 하나로 Tiled 자체 지원 문서에 등재되어 있습니다.
타일 배치기 그 이상
@pixi/tilemap은 자신을
pixi-tiledmap을 사용해야 하는 경우 PixiJS v8이 렌더러이고, 직접 구현하기보다는 Tiled의 의미론적(semantics) 처리를 받고 싶을 때입니다. 특히 대형 지도, 런타임 타일 변경, 절차적으로 생성된 지도, 또는 왕복 내보내기(round-trip export)가 필요한 경우에 그렇습니다.
사용할 필요가 없는 경우는 그리드 위에 임의의 직사각형 스프라이트만 그리고 .tmx나 .tmj 파일을 전혀 건드릴 일이 없을 때입니다.
라이브 데모
- Showcase (위에 그림) - 이 라이브러리가 렌더링하는 일곱 가지 장면을 보여줍니다: 사분면(quad) 단위로 애니메이션되는 패킹 타일, 파라랙스 월드, 지도 타일이 되는 낙하 블록, 등각 투영 높이장(isometric heightfield), 육각형 생물군계 웨이브, Conway의 생명 게임(Conway's Game of Life), 그리고 액체 아틀라스 지형 비행. 이 장면들에는 초당 약 10k
setTile 호출을 포함하는 런타임 편집 기능이 포함됩니다.
- 맵 뷰어 (Map viewer) - 검색 가능한 선택기 뒤에
.tmx 지도를 모아 놓은 카탈로그로, 팬/줌 카메라, 레이어 트리, 타일 그리드 오버레이, 마우스 오버된 타일 검사기(inspector), 그리고 FPS 카운터가 있습니다. 또한 사용자 자신의 .tmx 또는 .tmj 지도를 업로드하여 생성된 링크와 공유할 수도 있습니다.
<a href="https://pixi-tiledmap-viewer.vercel.app/"><img src="https://raw.githubusercontent.com/riebel/pixi-tiledmap/master/assets/viewer.webp" width="880" alt="레이어 트리, 비활성화된 충돌 레이어, 마우스 오버된 타일이 273, 116으로 보고되는 350x250 크기의 타일 마을 지도를 보여주는 맵 뷰어" /></a>
기능 (Features)
라이브러리가 Tiled 지도와 함께 처리하는 내용과 지원하지 않는 부분이 포함되어 있습니다:
| Tiled 기능 | 지원 여부 |
|---|
| TMJ 및 TMX 지도 | 예시 |
| ... | |
| What the table does not show: | |
- 배치 타일 렌더링 (Batched tile rendering) - 정적(static) 타일은 배치 가능한 PixiJS 메시를 사용하고 애니메이션 타일은 개별 타일 재생을 유지합니다. 타일이 셀을 넘어설 때도 렌더 순서가 올바르게 유지됩니다.
- 런타임 편집 및 생성 (Runtime editing and generation) - 로드된 지도를 제자리에 편집하거나 절차적으로(procedurally) 지도를 구축할 수 있습니다. 호환되는 편집은 레이어를 재구축하는 대신 패킹된 메시 버퍼를 업데이트합니다.
- 객체 및 템플릿 (Objects and templates) - Tiled 드로우 순서에 따라 모양(shapes), 텍스트, 애니메이션 타일 객체를 렌더링하며, 자동 객체-템플릿 상속과 GID 재매핑을 지원합니다.
- Tiled JSON 내보내기 (Tiled JSON export) - 로드되거나 생성된 지도를 TMJ로, 독립적인 타일셋은 TSJ로 작성할 수 있습니다. 타일 레이어 인코딩을 보존하며,
exportMapAsync를 통해 gzip/zlib 압축이 가능합니다. 라운드 트립(round-trip) 보장과 런타임 전용 제외 사항에 대해서는 지도를 다시 쓰기 (Writing Maps Back Out)을 참조하세요.
- 데이터 전용 도구 (Data-only tools) -
parseMap, 내보내기(export), 절차적 지도(procedural-map), 조회(lookup), 및 지도 기하학(map-geometry) API는 PixiJS 없이 번들링됩니다. XML 파싱은 PixiJS의 DOMAdapter를 사용하지만 렌더러가 필요하지 않습니다.
- TypeScript 우선 패키징 (TypeScript-first packaging) - 포괄적인 Tiled 타입, ESM 및 CJS 빌드, 트리 쉐이킹(tree-shakable) 모듈을 제공하며 PixiJS 피어 의존성 외에 추가 런타임 종속성이 없습니다.
이 라이브러리에서 가장 많은 주목을 받는 부분은 렌더러입니다. 왜냐하면 Tiled 지도가 보통 화면에서 가장 큰 요소이기 때문입니다.
한눈에 보기. 단일 타일셋 이미지로 그려진 정적 256x256 레이어는 65,536개의 디스플레이 객체 대신 몇 개의 메시 형태로 GPU에 도달합니다. 카메라를 이동하는 것은 사각형(quads)을 순회하는 것이 아니라 변환 업데이트 비용만 발생시킵니다. 타일 하나를 편집하는 것은 레이어를 재작성하는 것이 아니라 하나의 사각형 버퍼만 다시 쓰는 것입니다. 애니메이션 레이어는 몇 개의 타일이 움직이든 단일 티커 리스너(ticker listener) 비용만 발생합니다. 무한 지도는 기록된 벤치마크에서 1024 청크에 대해 좌표를 해당 청크로 약 32ns 만에 해결합니다. 오직 지도 파싱이나 생성만을 수행하는 소비자(consumer)는 아예 렌더러를 번들링하지 않습니다.
이 섹션의 나머지 부분은 어떻게 그렇게 하는지, 그리고 무엇과 비교하여 측정했는지에 대한 내용입니다.
-
정적 타일은 개별 스프라이트가 아닌 배치(batched)됩니다. 타일 레이어는 정적 타일을 텍스처 소스와 런타임 알파 값으로 그룹화하여 배치 가능한 PixiJS Mesh 자식 요소로 묶습니다. 따라서 일반적인 레이어는 타일당 하나의 디스플레이 객체 대신, 텍스처와 알파 값별로 메시(mesh) 하나를 갖게 됩니다. 이 그룹화는 위에 그려지는 내용물을 변경하지 않습니다: 타일이 기존 메시에 합쳐지는 경우는 그 타일이 겹치는 영역에 아무것도 그려지지 않을 때뿐입니다. 배치된 메시(Packed meshes)는 기본적으로 16000개의 사각형(quads)을 담을 수 있으며 (tileMeshBatchSize), 이는 렌더 객체 수를 낮게 유지하면서도 16비트 인덱스 제한보다 낮은 수준에 머무릅니다. 또한, 이들의 사각형 인덱스는 사각형 개수별로 캐시되며 메시 인스턴스 간에 공유됩니다.
-
타일 편집은 레이어가 아닌 버퍼(buffers)에 작성합니다. setTile과 clearTile 함수는 기존 메시 지오메트리 내의 영향을 받은 사각형을 다시 쓰기(rewrite)하며, 해당 영역의 직사각형(rect)과 UV가 변경되지 않았다면 업로드를 건너뛰고, 배치 용량 증가 전에 이전에 클리어된 공간에서 해제된 슬롯을 재사용합니다. 타일 레이어를 재구축하는 경우는 런타임 편집 및 절차적 맵에 나열된 경우뿐입니다.
-
카메라 이동은 타일에 영향을 주지 않습니다. 타일 및 오브젝트 레이어는 PixiJS 렌더 그룹(render groups)이므로, 패닝(panning), 줌(zooming) 또는 applyParallax를 적용할 때마다 PixiJS가 매 프레임 CPU에서 모든 배치된 사각형을 재변환하지 않고, 레이어당 하나의 변환만 업데이트합니다. 데스크톱 CPU에서 네 개의 레이어를 가진 패닝되는 256x256 맵의 경우, 이전에 약 4~6ms가 소요되었으나, 렌더 그룹을 사용하면 (npm run measure:camera) 프레임당 분수 밀리초만 소요됩니다. Tiled 블렌드 모드가 normal이 아닌 레이어는 단순 컨테이너로 유지되는데, 이는 PixiJS가 렌더 그룹에 블렌드 모드를 적용하지 않기 때문입니다.
-
레이어당 하나의 티커 리스너(ticker listener)를 사용합니다. 타일 레이어는 개별 스프라이트의 autoUpdate 대신 단일한 Ticker.shared 리스너에서 모든 애니메이션 타일 시각 효과를 진행시킵니다. 4096개의 스프라이트를 개별적으로 연결하는 것은 그들을 생성하는 것보다 더 많은 비용이 들었으며, 이는 애니메이션 64x64 레이어를 구축하는 데 걸린 64ms 중 약 55ms에 달했습니다. 따라서 이러한 레이어의 구축 속도가 이제는 약 8배 빨라졌습니다.
-
룩업(Lookups)이 인덱싱됩니다. 무한 레이어는 레이어당 한 번 구축되는 청크 그리드를 통해 좌표를 청크로 해석하며, 1024개의 청크에서 약 32ns의 시간이 소요되어 이전보다 훨씬 빠릅니다 (기존 780ns). 또한, TiledMap은 캐시된 인덱스를 통해 타일 레이어를 해석하므로, 편집 시 다른 레이어의 렌더 자식(render children)을 순회할 필요가 없습니다. 레이어 구축 및 편집 과정에서 문자열 셀 키나 UV 코너 배열과 같은 타일별 할당(per-tile allocations)이 방지됩니다.
-
사용하지 않는 것은 배포되지 않습니다. 외부 타일맵 의존성이나 PixiJS를 넘어서는 추가 런타임 의존성이 없습니다. PixiJS의 고급 블렌드 모드는 해당 기능을 사용하는 지도에서 필요할 때만 가져오며, parseMap, 지도 내보내기(map export), 절차적 지도(procedural maps), 룩업, 그리고 지도 지오메트리(map geometry)는 pixi.js가 필요 없으므로 데이터 전용 소비자(data-only consumer)는 렌더러를 포함하지 않습니다.
npm run bench는 렌더러의 주요 경로(hot paths): 레이어 구축, 애니메이션 레이어 한 번 업데이트(tick), 그리고 지도 크기, 점유율, 작업 혼합에 따른 런타임 편집 시간을 측정합니다. docs/BENCHMARKS.md에는 현재 기준선이 기록되어 있으며, 패킹된 레이어와 증분 편집 방식의 작동 원리 및 여전히 레이어를 재구축해야 하는 편집 목록을 설명하고 있습니다. 이 수치들은 기기별로 다르므로, 변경 사항은 동일한 장비에서 같은 세션에 측정된 기준선과 비교해야 합니다.
애니메이션 타일은 의도적으로 여전히 스프라이트(still sprites)입니다. npm run measure:animated는 헤드리스 Chrome 환경에서 PixiJS 자체로 두 가지 형태의 성능을 측정합니다: 패킹된 애니메이션 사각형(packed animated quads)과 타일당 하나의 AnimatedSprite를 사용하는 경우입니다. RTX 3080 기준으로, 약 천 개의 애니메이션 타일이 동시에 작동하는 상황에서는 그 차이가 16ms 프레임 내에서 반올림 오차 수준이며, 이 숫자가 16384개에 달하면 프레임 예산의 약 8%를 차지합니다. 지도가 해당 성능을 요구하기 전까지는 애니메이션 타일이 개별 스프라이트 재생 제어를 유지하고 패킹된 방식은 간단하게 유지됩니다.
튜닝 체크리스트 (앱 통합 개발자를 위한)
게임/애플리케이션에서 최고의 런타임 동작을 원한다면: