반응형
타일 맵과 맵 에디터 사용법
타일 맵은 작은 이미지를 배열하여 큰 지도를 만드는 기술입니다. 게임 개발에서 주로 배경이나 맵 디자인에 사용됩니다. 오늘은 타일 맵을 생성하고, 이를 관리하기 위한 맵 에디터 사용법을 학습하겠습니다.
타일 맵 기본 개념
타일 맵은 여러 개의 작은 이미지를 사용하여 큰 맵을 구성합니다. 각 타일은 동일한 크기를 가지며, 타일 맵은 2차원 배열로 표현됩니다.
- 타일(Tile): 맵을 구성하는 기본 단위입니다. 타일은 주로 정사각형이나 직사각형 모양을 가집니다.
- 타일셋(Tileset): 여러 타일 이미지를 하나의 큰 이미지로 모아 놓은 것입니다.
- 타일 맵(Tile Map): 타일을 배열하여 큰 지도를 만든 것입니다. 2차원 배열로 표현됩니다.
SFML을 사용한 타일 맵 구현
타일셋 이미지
먼저, 타일셋 이미지를 준비합니다. 타일셋 이미지는 여러 타일이 하나의 이미지 파일에 모여 있는 형태입니다. 각 타일의 크기와 타일셋 이미지의 크기를 알고 있어야 합니다.
타일 맵 데이터
타일 맵은 2차원 배열로 표현됩니다. 각 타일의 인덱스를 저장하는 배열을 사용하여 타일 맵을 정의합니다.
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <vector>
int main() {
// 창 생성
sf::RenderWindow window(sf::VideoMode(800, 600), "Tile Map Example");
// 타일 텍스처 로드
sf::Texture tileTexture;
if (!tileTexture.loadFromFile("tileset.png")) {
std::cerr << "Error loading texture" << std::endl;
return -1;
}
// 타일 맵 데이터 (0, 1, 2는 타일 인덱스를 의미)
const int tileSize = 32;
const int mapWidth = 10;
const int mapHeight = 10;
int mapData[mapHeight][mapWidth] = {
{0, 0, 1, 1, 2, 2, 1, 1, 0, 0},
{0, 1, 2, 2, 1, 1, 2, 2, 1, 0},
{1, 2, 2, 1, 0, 0, 1, 2, 2, 1},
{2, 2, 1, 0, 0, 0, 0, 1, 2, 2},
{1, 2, 1, 0, 0, 0, 0, 1, 2, 1},
{0, 1, 2, 0, 0, 0, 0, 2, 1, 0},
{0, 0, 1, 1, 2, 2, 1, 1, 0, 0},
{1, 1, 2, 2, 1, 1, 2, 2, 1, 1},
{2, 2, 1, 1, 0, 0, 1, 1, 2, 2},
{1, 1, 0, 0, 1, 1, 0, 0, 1, 1}
};
// 타일 맵 생성
sf::VertexArray tileMap(sf::Quads, mapWidth * mapHeight * 4);
for (int i = 0; i < mapHeight; i++) {
for (int j = 0; j < mapWidth; j++) {
int tileIndex = mapData[i][j];
int tu = tileIndex % 3; // 타일셋 가로 타일 수
int tv = tileIndex / 3; // 타일셋 세로 타일 수
sf::Vertex* quad = &tileMap[(i * mapWidth + j) * 4];
quad[0].position = sf::Vector2f(j * tileSize, i * tileSize);
quad[1].position = sf::Vector2f((j + 1) * tileSize, i * tileSize);
quad[2].position = sf::Vector2f((j + 1) * tileSize, (i + 1) * tileSize);
quad[3].position = sf::Vector2f(j * tileSize, (i + 1) * tileSize);
quad[0].texCoords = sf::Vector2f(tu * tileSize, tv * tileSize);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize, tv * tileSize);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize, (tv + 1) * tileSize);
quad[3].texCoords = sf::Vector2f(tu * tileSize, (tv + 1) * tileSize);
}
}
// 게임 루프
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
// 화면 지우기
window.clear();
// 타일 맵 그리기
sf::RenderStates states;
states.texture = &tileTexture;
window.draw(tileMap, states);
// 화면에 그리기
window.display();
}
return 0;
}
맵 에디터 사용법
맵 에디터는 타일 맵을 쉽게 생성하고 수정할 수 있는 도구입니다. 대표적인 맵 에디터로는 Tiled가 있습니다. 다음은 Tiled를 사용하여 타일 맵을 생성하고, 이를 SFML에서 사용하는 방법입니다.
Tiled 설치 및 사용
- Tiled 설치:
- Tiled 다운로드 페이지에서 Tiled를 다운로드하고 설치합니다.
- 타일셋 추가:
- Tiled를 실행하고, "New Tileset"을 선택합니다.
- 타일셋 이미지를 선택하고, 타일 크기를 설정합니다 (예: 32x32).
- 타일 맵 생성:
- "New Map"을 선택하고, 맵의 크기와 타일 크기를 설정합니다.
- 타일셋을 사용하여 맵을 디자인합니다.
- 맵 저장:
- 맵을
.tmx
파일로 저장합니다.
- 맵을
Tiled 맵을 SFML에서 사용
TMX 파일 파싱
.tmx
파일을 파싱하여 SFML에서 사용할 수 있도록 합니다. 이를 위해 TinyXML2 라이브러리를 사용할 수 있습니다.
- TinyXML2 설치:
- TinyXML2 GitHub 페이지에서 TinyXML2를 다운로드하고 설치합니다.
- TMX 파일 파싱 코드:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <tinyxml2.h>
#include <iostream>
#include <vector>
bool loadTileMap(const std::string& filename, sf::VertexArray& tileMap, sf::Texture& tileTexture) {
tinyxml2::XMLDocument doc;
if (doc.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS) {
std::cerr << "Error loading TMX file" << std::endl;
return false;
}
tinyxml2::XMLElement* map = doc.FirstChildElement("map");
int mapWidth = map->IntAttribute("width");
int mapHeight = map->IntAttribute("height");
int tileSize = map->IntAttribute("tilewidth");
tinyxml2::XMLElement* tileset = map->FirstChildElement("tileset");
std::string textureFile = tileset->FirstChildElement("image")->Attribute("source");
if (!tileTexture.loadFromFile(textureFile)) {
std::cerr << "Error loading texture" << std::endl;
return false;
}
tinyxml2::XMLElement* layer = map->FirstChildElement("layer");
tinyxml2::XMLElement* data = layer->FirstChildElement("data");
std::vector<int> tileData;
for (tinyxml2::XMLElement* tile = data->FirstChildElement("tile"); tile != nullptr; tile = tile->NextSiblingElement("tile")) {
tileData.push_back(tile->IntAttribute("gid") - 1);
}
tileMap.setPrimitiveType(sf::Quads
);
tileMap.resize(mapWidth * mapHeight * 4);
for (int i = 0; i < mapHeight; ++i) {
for (int j = 0; j < mapWidth; ++j) {
int tileIndex = tileData[i * mapWidth + j];
int tu = tileIndex % (tileTexture.getSize().x / tileSize);
int tv = tileIndex / (tileTexture.getSize().x / tileSize);
sf::Vertex* quad = &tileMap[(i * mapWidth + j) * 4];
quad[0].position = sf::Vector2f(j * tileSize, i * tileSize);
quad[1].position = sf::Vector2f((j + 1) * tileSize, i * tileSize);
quad[2].position = sf::Vector2f((j + 1) * tileSize, (i + 1) * tileSize);
quad[3].position = sf::Vector2f(j * tileSize, (i + 1) * tileSize);
quad[0].texCoords = sf::Vector2f(tu * tileSize, tv * tileSize);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize, tv * tileSize);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize, (tv + 1) * tileSize);
quad[3].texCoords = sf::Vector2f(tu * tileSize, (tv + 1) * tileSize);
}
}
return true;
}
int main() {
// 창 생성
sf::RenderWindow window(sf::VideoMode(800, 600), "Tile Map from Tiled");
sf::VertexArray tileMap;
sf::Texture tileTexture;
if (!loadTileMap("map.tmx", tileMap, tileTexture)) {
std::cerr << "Failed to load tile map" << std::endl;
return -1;
}
// 게임 루프
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
// 화면 지우기
window.clear();
// 타일 맵 그리기
sf::RenderStates states;
states.texture = &tileTexture;
window.draw(tileMap, states);
// 화면에 그리기
window.display();
}
return 0;
}
결론
오늘은 타일 맵의 기본 개념과 이를 SFML을 사용하여 구현하는 방법을 학습했습니다. 또한, Tiled 맵 에디터를 사용하여 타일 맵을 생성하고, 이를 SFML에서 사용하는 방법을 알아보았습니다. 질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Day 12: 2D 물리 엔진 기초 (Box2D)"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 게임 개발 시리즈' 카테고리의 다른 글
[C++ 게임 개발 시리즈] Day 13: 충돌 처리와 반응 (0) | 2024.08.01 |
---|---|
[C++ 게임 개발 시리즈] Day 10: 애니메이션 기법 (프레임 기반 애니메이션) (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 8: 2D 그래픽 기본 개념 (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 9: 스프라이트와 텍스처 (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 6: 첫 번째 게임 프로젝트: 간단한 2D 게임 만들기 (3) (0) | 2024.08.01 |