게임엔진/윈도우API

윈도우API)13.플립북 애니메이션

PJNull 2022. 12. 24.
728x90
반응형

플립북 애니메이션

 

플립북 애니메이션은 2D전용 애니메이션이다. 상용엔진에서는 특정 툴을 이용하여 범위를 지정하고 그것을 통해 얻은 스프라이트를 합쳐서 애니메이션을 만드는것을 플립북이라고 한다. WindowApi에서는 bmp만을 지원하며 알파 채널이 없어 특정 색상을 무시하는 것을 통해 본래의 이미지를 추출하는 방식을 채택한다.

 

 

TransparentBlt 함수(wingdi.h) - Win32 apps

TransparentBlt 함수는 지정된 원본 디바이스 컨텍스트에서 대상 디바이스 컨텍스트로 픽셀 사각형에 해당하는 색 데이터의 비트 블록 전송을 수행합니다.

learn.microsoft.com

 

TransparentBlt를 이용하여  특정 색을 무시하는것이 가능하다.

TransparentBlt을 사용하기 위해서는 이러한 특정 라이브러리를 추가할 필요하다.

#pragma comment(lib,"msimg32.lib")

 

플립북 생성

 

먼저 이미지 파일들을 애니메이션 처럼 재생시켜줄 플립북 클래스와 그것을 적용할 플립북엑터를 생성해준다.

이 플립북에는 텍스쳐 정보와 이름, x축과 y축 그리고 몇번째 까지 재생할것인지 애니메이션 속도, 루프여부 등의 정보를 가지고 있다.

//Flipbook.h

class Texture;

struct FlipbookInfo
{
	Texture* texture = nullptr;
	wstring name;
	Vec2Int size = {};
	int32 start;
	int32 end;
	int32 line;
	float duration = 1.f;
	bool loop = true;
};

class Flipbook :public ResourceBase
{

public:
	Flipbook();
	virtual ~Flipbook();

	void SetFlipInfo(const FlipbookInfo& Info) { _info = Info; }
	const FlipbookInfo& GetFlipInfo() { return _info; }
private:
	FlipbookInfo _info;
};

 

여러 플립북을 사용할수 있도록 등록한다. 

	Flipbook* GetFlipbook(const wstring& key) { return _flipbook[key]; }
	Flipbook* CreateFlipbook(const wstring& key);
    
    unordered_map<wstring, Flipbook*>_flipbook;
    
    Flipbook* ResourceManager::CreateFlipbook(const wstring& key)
{
	if (_flipbook.find(key) != _flipbook.end())return _flipbook[key];

	Flipbook* fbook = new Flipbook();
	_flipbook[key] = fbook;

	return fbook;
}

 

플립북 엑터생성

 

다음은 플립북을 실행시킬 플립북엑터를 생성한다.

플립북엑터의 동작원리는 Tick에서 일정시간이 지나면 (이미지 순서+1)%이미지 숫자를 계산해주고 Render에서 그 숫자를 토대로 랜더링해주는 것이다.

class Flipbook;

class FlipbookActor:public Actor
{
	using Super = Actor;

public:
	FlipbookActor();
	virtual ~FlipbookActor();

public:
	virtual void BeginPlay()override;
	virtual void Tick()override;
	virtual void Render(HDC hdc)override;

	void SetFlipbook(Flipbook* fbook);
	void Reset();
protected:
	Flipbook* _flipbook=nullptr;
	float _sumTime = 0.f;
	int32 _idx = 0;
};

 

//FlipbookActor.cpp

void FlipbookActor::Tick()
{
	Super::Tick();
	if (_flipbook == nullptr)return;

	const FlipbookInfo& info = _flipbook->GetFlipInfo();

	if (info.loop == false && _idx == info.end)return;

	float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
	_sumTime += deltaTime;
	int32 frame = info.end - info.start - 1;
	float Anispeed=info.duration / frame;
	
	if (_sumTime >= Anispeed)//일정시간이 지났으면 다음이미지로 갱신하라
	{
		_sumTime = 0.f;
		_idx=(_idx+1)%frame;

	}
}

void FlipbookActor::Render(HDC hdc)
{
	Super::Render(hdc);
	if (_flipbook == nullptr)return;

	const FlipbookInfo& info = _flipbook->GetFlipInfo();

	::TransparentBlt
	(
		hdc,
		_pos.x - info.size.x/2,
		_pos.y-info.size.y/2,
		info.size.x,
		info.size.y,
		info.texture->GetDC(),
		_idx*info.size.x,//몇번째 이미지를 출격할것인가
		info.line*info.size.y,//몇번째 줄의 이미지인가
		info.size.x,
		info.size.y,
		info.texture->GetTransparent()
	);


}

void FlipbookActor::SetFlipbook(Flipbook* fbook)
{
	if (_flipbook && _flipbook == fbook)return;
	_flipbook = fbook;
	Reset();
}

void FlipbookActor::Reset()
{
	_sumTime = 0.f;
	_idx = _flipbook->GetFlipInfo().start;

}

 

플레이어에 적용

 

먼저 Scene에서 필요한 플립북 이미지를 등록시키고 플레이어가 특정 키를 누를때 그 플립북을 재생하는 방식으로 적용한다. 본프로젝트의 경우 위/아래/왼쪽/오른쪽 별로 플립북이 재생되게 된다.

//Scene.cpp

void Scene::Init()
{

	{//플립북 UP
		Texture* tx = GET_SINGLE(ResourceManager)->GetTexture(L"PlayerUp");
		Flipbook* fbook = GET_SINGLE(ResourceManager)->CreateFlipbook(L"FB_MoveUp");
		fbook->SetFlipInfo({ tx,L"FB_MoveUp",{200,200},0,9,1,0.5f });
	}

	{//플립북 Down
		Texture* tx = GET_SINGLE(ResourceManager)->GetTexture(L"PlayerDown");
		Flipbook* fbook = GET_SINGLE(ResourceManager)->CreateFlipbook(L"FB_MoveDown");
		fbook->SetFlipInfo({ tx,L"FB_MoveDown",{200,200},0,9,1,0.5f });
	}

	{//플립북 Left
		Texture* tx = GET_SINGLE(ResourceManager)->GetTexture(L"PlayerLeft");
		Flipbook* fbook = GET_SINGLE(ResourceManager)->CreateFlipbook(L"FB_MoveLeft");
		fbook->SetFlipInfo({ tx,L"FB_MoveLeft",{200,200},0,9,1,0.5f });
	}

	{//플립북 Right
		Texture* tx = GET_SINGLE(ResourceManager)->GetTexture(L"PlayerRight");
		Flipbook* fbook = GET_SINGLE(ResourceManager)->CreateFlipbook(L"FB_MoveRight");
		fbook->SetFlipInfo({ tx,L"FB_MoveRight",{200,200},0,9,1,0.5f });
	}
 }

 

//Player.h


	Flipbook* _flipUp = nullptr;
	Flipbook* _flipDown = nullptr;
	Flipbook* _flipLeft = nullptr;
	Flipbook* _flipRight = nullptr;
//Player.cpp


Player::Player()//:SpriteActor(ObjectType::Player)
{
	_flipUp=GET_SINGLE(ResourceManager)->GetFlipbook(L"FB_MoveUp");
	_flipDown = GET_SINGLE(ResourceManager)->GetFlipbook(L"FB_MoveDown");
	_flipLeft = GET_SINGLE(ResourceManager)->GetFlipbook(L"FB_MoveLeft");
	_flipRight = GET_SINGLE(ResourceManager)->GetFlipbook(L"FB_MoveRight");
	
}

void Player::BeginPlay()
{
	Super::BeginPlay();
	SetFlipbook(_flipDown);
}

void Player::Tick()
{
	Super::Tick();
	float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
	// 거리 = 시간 * 속도

	if (GET_SINGLE(InputManager)->GetButton(KeyType::A))
	{
		_pos.x -= 200 * deltaTime;
		SetFlipbook(_flipLeft);
	}

	if (GET_SINGLE(InputManager)->GetButton(KeyType::D))
	{
		_pos.x += 200 * deltaTime;
		SetFlipbook(_flipRight);
	}

	if (GET_SINGLE(InputManager)->GetButton(KeyType::W))
	{
		_pos.y -=200 * deltaTime;
		SetFlipbook(_flipUp);
	}

	if (GET_SINGLE(InputManager)->GetButton(KeyType::S))
	{
		_pos.y += 200 * deltaTime;
		SetFlipbook(_flipDown);
	}


}

 

실행

 

728x90
반응형

'게임엔진 > 윈도우API' 카테고리의 다른 글

윈도우API)17.타일맵  (0) 2023.01.24
윈도우API)14.카메라  (0) 2022.12.30
윈도우API)12. 모작  (1) 2022.12.23
윈도우API)11. 역삼각함수  (0) 2022.12.23
윈도우API)10. 벡터의 외적  (0) 2022.12.22

댓글