타일을 통한 맵을 구현해보겠습니다.
타일 이미지 추가
CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Tile.bmp", L"Tile"); . CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Tile.bmp", L"Tile");
MainApp에서 CBitMap_Manager를 통해 준비된 타일이미지를 추가합니다.
타일 클래스 생성
게임오브젝트를 상속받아 타일 클래스를 만들어줍니다.
Tile.h
#pragma once
#include "GameObject.h"
class CTile :
public CGameObject
{
private:
CTile();
public:
virtual ~CTile();
public:
int Get_DrawID() { return m_iDrawID; }
int Get_Option() { return m_iOption; }
public:
void Set_DrawID(int iDrawID) { m_iDrawID = iDrawID; }
void Set_Option(int iOption) { m_iOption = iOption; }
public:
// CGameObject을(를) 통해 상속됨
virtual int Ready_GameObject() override;
virtual int Update_GameObject() override;
virtual void Late_Update_GameObject() override;
virtual void Render_GameObject(HDC hDC) override;
virtual void Release_GameObject() override;
public:
static CGameObject* Create();
private:
int m_iDrawID; //몇 번쨰 타일을 읽어올지 결정
int m_iOption;
};
Tile.CPP
#include "stdafx.h"
#include "Tile.h"
CTile::CTile()
{
}
CTile::~CTile()
{
Release_GameObject();
}
int CTile::Ready_GameObject()
{
m_tInfo.iCX = 64;
m_tInfo.iCY = 64;
return 0;
}
int CTile::Update_GameObject()
{
return 0;
}
void CTile::Late_Update_GameObject()
{
}
void CTile::Render_GameObject(HDC hDC)
{
CGameObject::Update_Rect_GameObject();
int iScrollX = CScroll_Manager::Get_ScrollX();
int iScrollY = CScroll_Manager::Get_ScrollY();
HDC hMemDC = CBitmap_Manager::Get_Instance()->FindImage(L"Tile");
if (nullptr == hMemDC)
return;
BitBlt(hDC, m_tRect.left + iScrollX,
m_tRect.top + iScrollY,
m_tInfo.iCX,
m_tInfo.iCY,
hMemDC,
m_tInfo.iCX * m_iDrawID, //몇 번쨰 타일을 읽어올지
0,
SRCCOPY);
}
void CTile::Release_GameObject()
{
}
CGameObject * CTile::Create()
{
CGameObject* pInstance = new CTile;
if (0 > pInstance->Ready_GameObject())
Safe_Delete(pInstance);
return pInstance;
}
타일 매니저 클래스 생성
타일 클래스의 생성을 관리한 매니저 클래스를 생성해줍니다.
Tile_Manager.h
#pragma once
class CGameObject;
class CTile_Manager
{
public:
static CTile_Manager* Get_Instance()
{
if (nullptr == m_pInstance)
m_pInstance = new CTile_Manager;
return m_pInstance;
}
static void Destroy_Instance()
{
if (m_pInstance)
{
delete m_pInstance;
m_pInstance = nullptr;
}
}
private:
static CTile_Manager* m_pInstance;
private:
CTile_Manager();
CTile_Manager(const CTile_Manager& rObj) = delete;
void operator=(const CTile_Manager& rhs) = delete;
//복사 생성자와 대입연산자는 안전을위해 미리 막아둡니다.
~CTile_Manager();
public:
void Save_Data_Tile_Manager();
void Load_Data_Tile_Manager();
//각각 그린 타일들을 저정하고 불러오는 함수입니다
void Picking_Tile(const POINT& rMouse, const int& iDrawID, const int& iOption = 0); //현재 마우스가 클릭하고있는 타일을 골라주는 함수입니다.
public:
void Ready_Tile_Manager();
void Render_Tile_Manager(HDC hDC);
void Release_Tile_Manager();
private:
vector<CGameObject*> m_vecTile;
};
Tile_Manager.cpp
#include "stdafx.h"
#include "Tile_Manager.h"
#include "Tile.h"
CTile_Manager* CTile_Manager::m_pInstance = nullptr;
CTile_Manager::CTile_Manager()
{
}
CTile_Manager::~CTile_Manager()
{
Release_Tile_Manager();
}
void CTile_Manager::Save_Data_Tile_Manager()
{
HANDLE hFile = CreateFile(L"../Data/TileData.dat", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == hFile)
return;
//파일 열기에 실패했다면 리턴
DWORD dwbyte = 0;
// 주소값이 들어있기 때문이다.
//wstring도 마찬가지다.안에 주소값 들고 있는 놈ㅇ ㅣ있다.
// 그거 주소값 저장하면 다음번 불러왔을때 주소값은 유효한가?
// ㄴㄴ
//한번에 타일 구조체들을 모두 저장하는것이 아닌 필요한 정보만 모아서 저장
for (auto& pTile : m_vecTile)
{
int iDrawID = dynamic_cast<CTile*>(pTile)->Get_DrawID();
int iOption = dynamic_cast<CTile*>(pTile)->Get_Option();
WriteFile(hFile, pTile->Get_Info(), sizeof(INFO), &dwbyte, nullptr);
WriteFile(hFile, &iDrawID, sizeof(int), &dwbyte, nullptr);
WriteFile(hFile, &iOption, sizeof(int), &dwbyte, nullptr);
}
CloseHandle(hFile);
//모두 저장했다면 핸들 닫음
}
void CTile_Manager::Load_Data_Tile_Manager()
{
HANDLE hFile = CreateFile(L"../Data/TileData.dat", GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (INVALID_HANDLE_VALUE == hFile)
return;
// 주소값이 들어있기 때문이다.
//wstring도 마찬가지다.안에 주소값 들고 있는 놈ㅇ ㅣ있다.
// 그거 주소값 저장하면 다음번 불러왔을때 주소값은 유효한가?
// ㄴㄴ
DWORD dwbyte = 0;
//불러오기전 벡터를 초기화해줌
if (!m_vecTile.empty())
{
for (auto& pTile : m_vecTile)
Safe_Delete(pTile);
m_vecTile.clear();
m_vecTile.shrink_to_fit();
}
m_vecTile.reserve(TILEX * TILEY);
//공간을 미리 예약
while (true)
{
int iDrawID = 0;
int iOption = 0;
INFO tInfo{};
ReadFile(hFile, &tInfo, sizeof(INFO), &dwbyte, nullptr);
ReadFile(hFile, &iDrawID, sizeof(int), &dwbyte, nullptr);
ReadFile(hFile, &iOption, sizeof(int), &dwbyte, nullptr);
//읽어온 바이트가 없을때 까지 파일을 로드 후 저장
if (0 == dwbyte)
break;
CGameObject* pTile = CTile::Create();
pTile->Set_Info(tInfo);
dynamic_cast<CTile*>(pTile)->Set_DrawID(iDrawID);
dynamic_cast<CTile*>(pTile)->Set_Option(iOption);
m_vecTile.emplace_back(pTile);
}
CloseHandle(hFile);
}
void CTile_Manager::Picking_Tile(const POINT & rMouse, const int & iDrawID, const int & iOption)
{
int iIndexX = rMouse.x / TILECX;// x축으로의 현재 타일의 인덱스 구하고
int iIndexY = rMouse.y / TILECY; // y축으로의 현재 타일의 인덱스 구하고
//나는 이 두개만 알고 있으면 현재 타일의 인덱스 번호를 구해 낼 수 있다!!!
int iIndex = iIndexX + (iIndexY * TILEX);
if (0 > iIndex || m_vecTile.size() <= iIndex)
return;
dynamic_cast<CTile*>(m_vecTile[iIndex])->Set_DrawID(iDrawID);
dynamic_cast<CTile*>(m_vecTile[iIndex])->Set_Option(iOption);
}
void CTile_Manager::Ready_Tile_Manager()
{
for (int i = 0 ; i < TILEY; ++i)
{
for (int j = 0 ; j < TILEX; ++j)
{
// 타일 깔자. 규칙은?
//중심점의 좌표을 구해줌
float fX = (j * TILECX) + (TILECX >> 1);
float fY = (i * TILECY) + (TILECY *0.5f);
CGameObject* pTile = CTile::Create();
pTile->Set_Pos(fX, fY);
m_vecTile.emplace_back(pTile);
}
}
}
void CTile_Manager::Render_Tile_Manager(HDC hDC)
{
for (auto& pObject : m_vecTile)
{
pObject->Render_GameObject(hDC);
}
}
void CTile_Manager::Release_Tile_Manager()
{
for (auto& pObject : m_vecTile)
Safe_Delete(pObject);
m_vecTile.clear();
m_vecTile.shrink_to_fit();
}
이렇게하면 타일매니저 클래스를 통해 타일 클래스를 관리하고 저장,불러오기,그리기를 할수있습니다.
에디터 씬 추가
타일 매니저까지 완성했다면 이제 에디터 씬을 구성할수있습니다. 스테이지를 가던것과 마찬가지로 에딧버튼을 클릭하면 에딧씬으로 이동하게 해준뒤 에딧씬을 구성합니다.
Edit.h
#pragma once
#include "Scene.h"
class CEditor final:
public CScene
{
public:
explicit CEditor();
virtual ~CEditor();
public:
// CScene을(를) 통해 상속됨
virtual int Ready_Scene() override;
virtual void Update_Scene() override;
virtual void Render_Scene(HDC hDC) override;
virtual void Release_Scene() override;
public:
static CScene * Create();
};
Edit.cpp
#include "stdafx.h"
#include "Editor.h"
#include "Tile_Manager.h"
CEditor::CEditor()
{
}
CEditor::~CEditor()
{
}
int CEditor::Ready_Scene()
{
CTile_Manager::Get_Instance()->Ready_Tile_Manager();
return 0;
}
void CEditor::Update_Scene()
{
//키보드를 이용해 스크롤을 조종합니다.
if (CKey_Manager::Get_Instance()->Key_Pressing(KEY_LEFT))
CScroll_Manager::Set_ScrollX(5);
if (CKey_Manager::Get_Instance()->Key_Pressing(KEY_RIGHT))
CScroll_Manager::Set_ScrollX(-5);
if (CKey_Manager::Get_Instance()->Key_Pressing(KEY_UP))
CScroll_Manager::Set_ScrollY(-5);
if (CKey_Manager::Get_Instance()->Key_Pressing(KEY_DOWN))
CScroll_Manager::Set_ScrollY(5);
if (CKey_Manager::Get_Instance()->Key_Down(KEY_LBUTTON))
{
POINT pt{};
GetCursorPos(&pt);
ScreenToClient(g_hWnd, &pt);
pt.x -= CScroll_Manager::Get_ScrollX();
pt.y -= CScroll_Manager::Get_ScrollY();
//스크롤값을 구해오고 뺴서 현재 마우스의 위치를 알아낸후 타일의 색을 교체합니다
CTile_Manager::Get_Instance()->Picking_Tile(pt, 1);
}
//각각 s.l키를 누르면 저장과 불러오기를 합니다.
if (CKey_Manager::Get_Instance()->Key_Down(KEY_S))
CTile_Manager::Get_Instance()->Save_Data_Tile_Manager();
if (CKey_Manager::Get_Instance()->Key_Down(KEY_L))
CTile_Manager::Get_Instance()->Load_Data_Tile_Manager();
}
void CEditor::Render_Scene(HDC hDC)
{
CTile_Manager::Get_Instance()->Render_Tile_Manager(hDC);
}
void CEditor::Release_Scene()
{
}
CScene * CEditor::Create()
{
CScene* pInstance = new CEditor;
if (0 > pInstance->Ready_Scene())
Safe_Delete(pInstance);
return pInstance;
}
이렇게 해서 맵을 수정할수있게 되었습니다.