타일

김주현·2021년 8월 3일
0

Win API

목록 보기
10/14

타일을 통한 맵을 구현해보겠습니다.

타일 이미지 추가

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;
}

이렇게 해서 맵을 수정할수있게 되었습니다.

0개의 댓글

관련 채용 정보