타일맵
2D맵에는 하나의 커다란 이미지를 사용하는 속칭 "통맵"과 작은 단위의 이미지를 이어붙여 만드는 "타일맵"이 존재한다. 여기서 타일맵은 다양한 형태로 활용이된다. 이미지를 불러들여 맵으로써 활용하기도 하지만 특정 범위를 지정하여 콜리전 범위를 지정할수도 있다. 이번포스팅에서는 이러한 콜리전 범위를 표시하는것을 다루고자 한다.
타일맵 계층구조
- ResourceBase(Load/Save)
- Tilemap(vector<vector<Tile>> _tiles)
- Actor
- TilemapActor(Tilemap* _tile/bool _showDebug)
타일맵 생성
타일맵은 리소스로써 활용될 예정이다. 그렇기에 ResourceBase를 상속받고 ResourceManager에서 관리되어야 한다.
//tilemap.h
class tilemap: public ResourceBase
{
public:
vector<vector<Tile>>& GetTile() { return _tiles; }//타일 전체를 가져온다.
Tile* GetTileAt(Vec2Int pos);//특정위치의 타일맵을 가져온다
private:
Vec2Int _mapSize = {};
int32 _tilesize = 0;
vector<vector<Tile>>_tiles;
}
struct Tile
{
int32 value = 0;//값에 따라 텍스쳐가 다르게 할 목적으로 만들어준다.
};
enum TILE_SIZE
{//텍스쳐의 크기에 맞게 지정해준다
TILE_W=63,
TILE_H=43,
TILE_SIZEX=48,
TILE_SIZEY=48,
};
ResourceManager에 등록한다.
//ResourceManager.h
class ResourceManager
{
public:
tilemap* GetTilemap(const wstring& key) { return _tilemaps[key]; }
tilemap* Createtilemap(const wstring& key);
private:
unordered_map<wstring, tilemap*>_tilemaps;
}
tilemap* ResourceManager::Createtilemap(const wstring& key)
{
if(_tilemaps.find(key)!=_tilemaps.end())return _tilemaps[key];
tilemap* tile = new tilemap();
_tilemaps[key] = tile;
return tile;
}
타일맵 액터 생성
실제 게임에 적용시켜서 생성하기 위해서는 엑터가 필요하다. 현재 타일맵은 리소스이기때문에 이것을 받아서 엑터에 적용시킬 타일맵 액터가 필요하다.
class TilemapActor:public Actor
{
public:
void SetTilemap(tilemap* tile) {_tilemap = tile; }
tilemap* GetTilemap() { return _tilemap; }
void SetShowDebug(bool show) { _showDebug = show; }//타일의 변화를 보여주는 함수
void TilePicking();
protected:
tilemap* _tilemap = nullptr;
bool _showDebug = false;
}
void TilemapActor::Render(HDC hdc)
{
const Vec2Int mapsize = _tilemap->GetMapSize();
const int32 tilesize = _tilemap->GetTileSize();
vector<vector<Tile>>& tiles = _tilemap->GetTile();
Sprite* sprite0=GET_SINGLE(ResourceManager)->GetSprite(L"Tile0");
Sprite* spriteX=GET_SINGLE(ResourceManager)->GetSprite(L"TileX");
Vec2 camerapos = GET_SINGLE(SceneManager)->GetCameraPos();
for (int32 y = 0; y <mapsize.y; y++)
{
for (int32 x = startX; x <mapsize.x; x++)
{
if (x < 0 || x >= mapsize.x || y < 0 || y >= mapsize.y)continue;
switch (tiles[y][x].value)
{
case 0: //val=0이면 spriteO를 랜더링한다.
::TransparentBlt
(
hdc,_pos.x+x*TILE_SIZEX-(camerapos.x-GWinSizeX/2),
_pos.y + y * TILE_SIZEY - (camerapos.y - GWinSizeY / 2),
TILE_SIZEX,TILE_SIZEY,
sprite0->GetDC(),
sprite0->GetPos().x,
sprite0->GetPos().y,
TILE_SIZEX, TILE_SIZEY,
sprite0->GetTransparent()
);
break;
case 1: //val=1이면 spriteX를 랜더링한다.
::TransparentBlt
(
hdc, _pos.x + x * TILE_SIZEX - (camerapos.x - GWinSizeX / 2),
_pos.y + y * TILE_SIZEY - (camerapos.y - GWinSizeY / 2),
TILE_SIZEX, TILE_SIZEY,
spriteX->GetDC(),
spriteX->GetPos().x,
spriteX->GetPos().y,
TILE_SIZEX, TILE_SIZEY,
spriteX->GetTransparent()
);
break;
case 2:
break;
}
}
}
위와 같은 코드를 실행하면 다음과 같이 랜더링된다.
컬링
현재의 타일은 우리의 실제 화면 영역을 넘어서서 게임전체에 랜더링이되고 있다. 이럴 경우 메모리 낭비가 매우 심해지게 되며 게임 플레이에 영향을 줄수 있다. 컬링은 이러한 것을 방지하기 위해서 우리가 보고 있지 않는 영역은 랜더링 하지 않는 것이다.
int32 leftX = (int32)(camerapos.x - GWinSizeX / 2);
int32 leftY = (int32)(camerapos.y - GWinSizeY / 2);
int32 rightX = (int32)(camerapos.x + GWinSizeX / 2);
int32 rightY = (int32)(camerapos.y + GWinSizeY / 2);
int32 startX = (leftX - _pos.x) / TILE_SIZEX;
int32 startY = (leftY - _pos.y) / TILE_SIZEY;
int32 endX = (rightX + _pos.x) / TILE_SIZEX;
int32 endY = (rightY + _pos.y) / TILE_SIZEY;
for (int32 y = startY; y < endY; y++)//컬링효과를 보기위해서 한칸 부족하게 랜더링한다
{
for (int32 x = startX; x < endX; x++)
{
//랜더링
}
}
우리가 화면을 이동하면 타일이 생성되는것을 볼수있다.
타일맵 변화시키기
타일을 변화시키는 방법에는 여러가지가 있다. 본 포스팅에서는 클릭할시 TILE의 value값이 달라지게 함으로써 위에서 생성했던 case를 통해 X과O를 랜더링하도록 구현하고자 한다.
void TilemapActor::TilePicking()
{
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::LeftMouse))
{
Vec2 camerapos = GET_SINGLE(SceneManager)->GetCameraPos();
int32 screenX=camerapos.x - GWinSizeX/2;
int32 screenY=camerapos.y - GWinSizeY/2;
POINT mousepos=GET_SINGLE(InputManager)->GetMousePos();
int32 posX = mousepos.x + screenX;
int32 posY = mousepos.y + screenY;
int32 x = posX / TILE_SIZEX;
int32 y = posY / TILE_SIZEY;
Tile* tile = _tilemap->GetTileAt({x,y});
if(tile)
{
tile->value += 1;
tile->value %= 2;
}
}
}
'게임엔진 > 윈도우API' 카테고리의 다른 글
윈도우API)18.충돌-1 (0) | 2023.01.25 |
---|---|
윈도우API)14.카메라 (0) | 2022.12.30 |
윈도우API)13.플립북 애니메이션 (0) | 2022.12.24 |
윈도우API)12. 모작 (1) | 2022.12.23 |
윈도우API)11. 역삼각함수 (0) | 2022.12.23 |
댓글