본문 바로가기

Win32 api

Win32 api 강의 37 - 38화.

- 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