*** 공부 방법 ***
1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. 처
hyrule.tistory.com
- 보통 2D 애니메이션을 구현하는 방법으로는 두 가지가 있다.
-1. 스프라이트 아틀라스
-> 이런 식으로 연속적인 이미지를 한 장의 파일에 다 때려박은 뒤, 좌표를 이용하여 한장씩 로딩하는 방식이다.
-2. 프레임
-> 이런 식으로 한장 한장 로딩해서 재생하는 방식이다.
- 이 두가지 방식 모두 가능하게 구현을 해보자.
- 가장 먼저, 들어온 이미지 파일이 둘 중 어떤 타입인지를 구분할 수 있도록 해주어야 한다.
- Flags.h 헤더 파일을 만들고, 거기에 로드할 이미지 파일이 어떤 타입인지를 구분할 수 있는 열거체를 선언 및 정의한다.
- 이 헤더파일을 GameInfo.h 헤더 파일에 포함시켜준다.
//flags.h
#pragma once
enum class ETexture_Type
{
Sprite,
Frame
};
- 그리고 CTexutre도 여러 장의 텍스처 파일을 저장할 수 있게 전체적인 수정을 해주어야 한다.
-- 우선, 방금 선언한 열거체를 변수로 들고있게 해준다.(m_TextureType) 기본값은 Sprite
-- 그리고, 기존의 이미지 정보를 들고있던 변수들을 구조체로 묶는다.(struct ImageInfo)
--> 변수 초기화 및 소멸도 구조체 안에서 진행한다.
struct ImageInfo
{
HDC hMemDC;
HBITMAP hBmp;
HBITMAP hPrevBmp;
BITMAP BmpInfo;
ImageInfo() :
hMemDC(0),
hBmp(0),
hPrevBmp(0),
BmpInfo{}
{
}
~ImageInfo()
{
// 도구를 원래대로 돌려준다.
SelectObject(hMemDC, hPrevBmp);
DeleteObject(hBmp);
DeleteDC(hMemDC);
}
};
-- 이렇게 해주고 CTexture 안에서는 해당 구조체를 배열에 들고있게 해주면 이미지 파일을 동시에 여러개 들고있을 수 있게 된다.
private:
ETexture_Type m_Type;
std::vector<ImageInfo*> m_vecImageInfo;
- 클래스 내부의 모든 메소드도 여러가지 수정 및 추가가 필요하다.
-- 우선 모든 메소드는 위의 변경에 맞게 수정해주어야 한다.
-- GetDC() 메소드는, 이제 인자로 배열 번호를 집어넣어서 해당 배열 번호에 해당하는 hMemDC를 반환받는다.
public:
HDC GetDC(int Index = 0) const
{
return m_vecImageInfo[Index]->hMemDC;
}
-- LoadTexture()은, LoadTexture() 메소드와 LoadTextureFullPath() 메소드로 분활한다.
--- LoadTexture()에서 파일 이름과 경로를 인자로 받으면, Full Path를 만들어 LoadTextureFullPath에 전달한다.
--- LoadTextureFullPath()에서는 해당 경로를 가지고 그대로 로드하면 된다.
---- 그냥 LoadTexture() 메소드를 반으로 자르면 됨
bool CTexture::LoadTexture(const TCHAR* FileName,
const std::string& PathName)
{
const PathInfo* Path = CPathManager::GetInst()->FindPath(PathName);
TCHAR FullPath[MAX_PATH] = {};
if (Path)
lstrcpy(FullPath, Path->Path);
lstrcat(FullPath, FileName);
return LoadTextureFullPath(FullPath);
}
bool CTexture::LoadTextureFullPath(const TCHAR* FullPath)
{
// 화면DC를 넣고 메모리 DC를 얻는다.
HDC hDC = CreateCompatibleDC(CGameManager::GetInst()->GetWindowDC());
// 비트맵을 로딩한다.
HBITMAP hBmp = (HBITMAP)LoadImage(CGameManager::GetInst()->GetWindowInstance(),
FullPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBmp)
return false;
// 읽어온 비트맵을 메모리 DC에 지정한다.
// 기존에 DC가 가지고 있던 도구를 반환한다.
HBITMAP hPrevBmp = (HBITMAP)SelectObject(hDC, hBmp);
BITMAP BmpInfo;
GetObject(hBmp, sizeof(BITMAP), &BmpInfo);
ImageInfo* Info = new ImageInfo;
Info->hMemDC = hDC;
Info->hBmp = hBmp;
Info->hPrevBmp = hPrevBmp;
Info->BmpInfo = BmpInfo;
m_vecImageInfo.push_back(Info);
return true;
}
-- 또한, 아까 설명했던 Frame 형식의 애니메이션 이미지 여러 장을 동시에 로드할 수 있는 LoadTexture() 기능도 구현해야 한다.
--- 이 LoadTexture() 메소드를 호출한 경우, 이미지 여러장을 애니메이션화 시키겠다는 의미이므로 ETextureType을 기본값인 Sprite에서 Frame으로 변경해주어야 한다.
--- 이 경우, LoadTexture()은 파일 이름에 대한 인자로 위처럼 TCHAR이 아닌 '문자열이 담긴 벡터의 레퍼런스'를 받는다.
---> 해당 벡터에는 애니메이션에 쓰일 파일들의 이름이 순차적으로 넣어서 전달한다.
---- 이 때, 문자 집합이 유니코드인지 멀티바이트인지 #ifdef로 확인하고, 해당 문자 집합에 따라 '문자열이 담긴 벡터의 레퍼런스'를 다르게 받도록 메소드를 나눠놓는 작업도 필요하다.
----- UNICODE -> wstring, else -> string
--- 받은 파일명의 문자열 벡터를 순회돌면서 경로를 집어넣는다.
CF) std::(w)string은 문자열의 대입과 덧셈이 가능하므로 활용하자
((w)stirng 변수).c_str -> 기존의 char 형식으로 문자열을 반환해주는 함수
#ifdef UNICODE
bool CTexture::LoadTexture(const std::vector<std::wstring>& vecFileName,
const std::string& PathName)
{
m_Type = ETexture_Type::Frame;
const PathInfo* Path = CPathManager::GetInst()->FindPath(PathName);
std::vector<std::wstring> vecFullPath;
size_t Size = vecFileName.size();
// 미리 개수만큼 push 해놓는 효과이다.
vecFullPath.resize(Size);
// 미리 배열 공간을 확보하여 꽉 찼을때 공간 재할당이 일어나는것을 방지해주는
// 역할을 할때 사용한다.
//vecFullPath.reserve(Size);
for (size_t i = 0; i < Size; ++i)
{
if (Path)
vecFullPath[i] = Path->Path;
vecFullPath[i] += vecFileName[i];
}
return LoadTextureFullPath(vecFullPath);
}
bool CTexture::LoadTextureFullPath(const std::vector<std::wstring>& vecFullPath)
{
m_Type = ETexture_Type::Frame;
size_t Size = vecFullPath.size();
for (size_t i = 0; i < Size; ++i)
{
// 화면DC를 넣고 메모리 DC를 얻는다.
HDC hDC = CreateCompatibleDC(CGameManager::GetInst()->GetWindowDC());
// 비트맵을 로딩한다.
// string 이나 wstring 클래스의 c_str() 함수는 문자열 포인터를 얻어온다.
HBITMAP hBmp = (HBITMAP)LoadImage(CGameManager::GetInst()->GetWindowInstance(),
vecFullPath[i].c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBmp)
return false;
// 읽어온 비트맵을 메모리 DC에 지정한다.
// 기존에 DC가 가지고 있던 도구를 반환한다.
HBITMAP hPrevBmp = (HBITMAP)SelectObject(hDC, hBmp);
BITMAP BmpInfo;
GetObject(hBmp, sizeof(BITMAP), &BmpInfo);
ImageInfo* Info = new ImageInfo;
Info->hMemDC = hDC;
Info->hBmp = hBmp;
Info->hPrevBmp = hPrevBmp;
Info->BmpInfo = BmpInfo;
m_vecImageInfo.push_back(Info);
}
return true;
}
#else
bool CTexture::LoadTexture(const std::vector<std::string>& vecFileName,
const std::string& PathName)
{
m_Type = ETexture_Type::Frame;
const PathInfo* Path = CPathManager::GetInst()->FindPath(PathName);
std::vector<std::string> vecFullPath;
size_t Size = vecFileName.size();
// 미리 개수만큼 push 해놓는 효과이다.
vecFullPath.resize(Size);
// 미리 배열 공간을 확보하여 꽉 찼을때 공간 재할당이 일어나는것을 방지해주는
// 역할을 할때 사용한다.
//vecFullPath.reserve(Size);
for (size_t i = 0; i < Size; ++i)
{
if (Path)
vecFullPath[i] = Path->Path;
vecFullPath[i] += vecFileName[i];
}
return LoadTextureFullPath(vecFullPath);
}
bool CTexture::LoadTextureFullPath(const std::vector<std::string>& vecFullPath)
{
m_Type = ETexture_Type::Frame;
size_t Size = vecFullPath.size();
for (size_t i = 0; i < Size; ++i)
{
// 화면DC를 넣고 메모리 DC를 얻는다.
HDC hDC = CreateCompatibleDC(CGameManager::GetInst()->GetWindowDC());
// 비트맵을 로딩한다.
// string 이나 wstring 클래스의 c_str() 함수는 문자열 포인터를 얻어온다.
HBITMAP hBmp = (HBITMAP)LoadImage(CGameManager::GetInst()->GetWindowInstance(),
vecFullPath[i].c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBmp)
return false;
// 읽어온 비트맵을 메모리 DC에 지정한다.
// 기존에 DC가 가지고 있던 도구를 반환한다.
HBITMAP hPrevBmp = (HBITMAP)SelectObject(hDC, hBmp);
BITMAP BmpInfo;
GetObject(hBmp, sizeof(BITMAP), &BmpInfo);
ImageInfo* Info = new ImageInfo;
Info->hMemDC = hDC;
Info->hBmp = hBmp;
Info->hPrevBmp = hPrevBmp;
Info->BmpInfo = BmpInfo;
m_vecImageInfo.push_back(Info);
}
return true;
}
#endif // UNICODE
- 이 메소드는 CResourceManager에서 타고 들어가는 구조이므로,
CTextureManager과 CResourceManager에서도 동일한 작업을 반복해주어야 한다.
- 현재 작업이 완료되지 않았기 때문에 컴파일은 되지 않음!
'WIN32API FrameWork > 한단계씩 직접 구현' 카테고리의 다른 글
35. 더블 버퍼링 (0) | 2022.05.25 |
---|---|
34. 씬 단위의 리소스 관리 (0) | 2022.05.25 |
32. 이미지 등의 리소스 관리자 (0) | 2022.05.24 |
31. 이미지 로딩을 위한 준비 - 경로 관리자 (0) | 2022.05.24 |
30. 스킬 구현 2 - 아우렐리온 솔 W (0) | 2022.05.23 |