- ResourceMgr 수정.
// CResourceMgr.h
#pragma once
class CTexture;
class CResource;
class CResourceMgr
{
SINGLETON(CResourceMgr);
private:
map<wstring, CResource*> m_mapResources;
public:
void init();
public:
CTexture* LoadTexture(const wstring& _strKey, const wstring& _strRelativePath);
};
map 의 value 형을 CTexture* → CResource* 로 변경. 또 CResource 의 생성-소멸자도 public 으로 변경.
// CResourceMgr.cpp
...
CResourceMgr::~CResourceMgr()
{
SafeDeleteMap<wstring, CResource*>(m_mapResources);
}
...
CTexture* CResourceMgr::LoadTexture(const wstring& _strKey, const wstring& _strRelativePath)
{
map<wstring, CResource*>::iterator iter = m_mapResources.find(_strKey);
if (iter != m_mapResources.end())
{
return dynamic_cast<CTexture*>(iter->second);
}
...
}
그럼 이렇게 SafeDeleteMap 범용 함수로 코드를 간결화할 수 있음.
- Animator 추가 구현.
// CAnimator.h
#pragma once
#include "CComponent.h"
...
class CAnimator : public CComponent
{
private:
map<wstring, CAnimation*> m_mapAnimations; // 애니메이션들을 이름으로 관리하는 맵.
CAnimation* m_pCurAnimation; // 현재 재생 중인 애니메이션.
CObject* m_pOwner;
public:
void CreateAnimation(CTexture* pTexture, const wstring& strName,
const Vector2& vStart, const Vector2& vSize,
UINT iFrameCount, float fDuration, bool bLoop = true);
CAnimation* FindAnimation(const wstring& strName);
...
};
중요한 CreateAnimation 함수를 구현함.
// CAnimator.cpp
...
void CAnimator::CreateAnimation(CTexture* pTexture, const wstring& strName,
const Vector2& vStart, const Vector2& vSize, UINT iFrameCount,
float fDuration, bool bLoop)
{
assert(!FindAnimation(strName) &&
L"이미 동일한 이름의 애니메이션이 존재합니다.");
assert(pTexture &&
L"애니메이션 생성 실패: 유효하지 않은 텍스처 포인터입니다.");
// 새로운 애니메이션 생성.
CAnimation* pNewAnimation = new CAnimation(this, pTexture,
vStart, vSize, iFrameCount, fDuration, bLoop);
// 애니메이션 맵에 추가.
m_mapAnimations.insert(make_pair(strName, pNewAnimation));
}
대상 텍스쳐, 시작 위치, 프레임 사이즈, 프레임 수, 재생 시간 등을 입력받아 애니메이션을 생성함.
- Animation 구현.
// CAnimation.h
...
struct tAnimationFrame
{
Vector2 vStart; // 프레임의 시작 위치.
Vector2 vSize; // 프레임의 크기.
float fFrameDuration; // 프레임의 지속 시간.
};
class CAnimation
{
private:
CAnimator* m_pAnimator; // 애니메이션을 소유한 애니메이터.
CTexture* m_pTexture; // 애니메이션에 사용되는 텍스처.
UINT m_iFrameCount; // 애니메이션 프레임 수.
float m_fDuration; // 애니메이션 재생 시간.
bool m_bLoop; // 애니메이션 반복 여부.
float m_fFrameElapsedTime; // 현재 프레임이 시작된 후 경과된 시간.
UINT m_iCurFrame; // 현재 재생 중인 프레임 인덱스.
bool m_bFinished; // 애니메이션 종료 여부.
vector<tAnimationFrame> m_vecFrames; // 애니메이션 프레임들.
public:
inline bool IsLoop() const { return m_bLoop; }
inline bool IsFinished() const { return m_bFinished; }
void SetFrame(UINT iFrame);
public:
void update();
void render(HDC hDC, Vector2 vPos);
...
};
애니메이션의 각 프레임마다 대상 Texture 에서 출력할 이미지의 Left-Top 위치, 크기, 프레임 시간을
구조체에 저장하고 이걸 m_vecFrames 벡터에 모아둠.
// CAnimation.cpp
...
CAnimation::CAnimation(CAnimator* pAnimator, CTexture* pTexture,
const Vector2& vStart, const Vector2& vSize, UINT iFrameCount,
float fDuration, bool bLoop)
: m_pAnimator(pAnimator)
, m_pTexture(pTexture)
, m_iFrameCount(iFrameCount)
, m_fDuration(fDuration)
, m_bLoop(bLoop)
, m_fFrameElapsedTime(0.f)
, m_iCurFrame(0)
, m_bFinished(false)
, m_vecFrames{}
{
// 각 프레임의 지속 시간을 계산하여 벡터에 저장.
float frameDuration = m_fDuration / static_cast<float>(m_iFrameCount);
for (UINT i = 0; i < m_iFrameCount; ++i)
{
tAnimationFrame frame = {};
frame.vStart = Vector2(vStart.x + i * vSize.x, vStart.y);
frame.vSize = vSize;
frame.fFrameDuration = frameDuration;
m_vecFrames.push_back(frame);
}
}
...
void CAnimation::SetFrame(UINT iFrame)
{
m_fFrameElapsedTime = 0.f;
m_iCurFrame = iFrame;
m_bFinished = false;
}
void CAnimation::update()
{
if(m_bFinished)
return;
// 경과 시간 업데이트.
m_fFrameElapsedTime += DELTATIMEF;
// 현재 프레임의 지속 시간을 초과했는지 확인.
if (m_fFrameElapsedTime >= m_vecFrames[m_iCurFrame].fFrameDuration)
{
// 다음 프레임으로 전환.
// 초과한 시간이 있다면 다음 프레임으로 넘어가기 전에 빼줌.
m_fFrameElapsedTime -= m_vecFrames[m_iCurFrame].fFrameDuration;
m_iCurFrame++;
if (m_iCurFrame >= m_iFrameCount)
{
// 애니메이션 끝에 도달. 마지막 프레임으로 고정.
m_bFinished = true;
m_iCurFrame = m_iFrameCount - 1;
}
}
}
void CAnimation::render(HDC hDC, Vector2 vPos)
{
if (!m_pTexture)
return;
// 현재 프레임의 사각형 영역 계산.
tAnimationFrame& frame = m_vecFrames[m_iCurFrame];
// 텍스처에서 현재 프레임을 hDC에 렌더링.
TransparentBlt(hDC,
static_cast<int>(vPos.x - frame.vSize.x * 0.5f), static_cast<int>(vPos.y - frame.vSize.y * 0.5f),
static_cast<int>(frame.vSize.x), static_cast<int>(frame.vSize.y),
m_pTexture->GetDC(),
static_cast<int>(frame.vStart.x), static_cast<int>(frame.vStart.y),
static_cast<int>(frame.vSize.x), static_cast<int>(frame.vSize.y),
RGB(255, 0, 255)); // 마젠타 색상을 투명색으로 사용.
}
기존의 Player 의 render 기능을 이 애니메이션의 render 함수에서 대체함.
애니메이션이 종료되면 m_bFinished 를 true 로 설정하고, m_iCurFrame 을 마지막 프레임으로 고정하여
render 함수에서 반복적으로 그릴 수 있도록 함.
해당 애니메이션이 loop 라면 Animator 측에서 반복 재생할 수 있도록
// CAnimator.cpp
...
void CAnimator::update()
{
if (m_pCurAnimation)
{
m_pCurAnimation->update();
// 현재 애니메이션이 종료되었고 반복 재생이면
if (m_pCurAnimation->IsFinished() && m_pCurAnimation->IsLoop())
{
m_pCurAnimation->SetFrame(0); // 첫 프레임으로 되돌림.
}
}
}
...
Animator 측의 update 문에서 처리해줌.
'Win32 api' 카테고리의 다른 글
| Win32 api 강의 41 - 42화. (0) | 2025.09.23 |
|---|---|
| Win32 api 강의 39 - 40화. (0) | 2025.09.22 |
| Win32 api 강의 35 - 36화. (0) | 2025.09.21 |
| Win32 api 강의 34화. (0) | 2025.09.20 |
| Win32 api 강의 31 - 33화. (0) | 2025.09.19 |