Animation
애니메이션이다. 3D 게임에서는 모델링의 움직임을 파일로 만들지만, 2D에서는 각각 이미지를 교체하는 식으로 애니메이션을 만들기 때문에 이미지를 교체하는 방식으로 만들었다.
Animation.h
#pragma once
enum class RepeatType : uint
{
Once, Loop
};
struct Keyframe final
{
Keyframe() = default;
Keyframe(const D3DXVECTOR2& offset, const D3DXVECTOR2& size, const double& time)
: offset(offset)
, size(size)
, time(time)
{}
D3DXVECTOR2 offset{ 0.0f, 0.0f };
D3DXVECTOR2 size{ 0.0f,0.0f };
double time{ 0.0 };
};
class Animation final
{
public:
Animation(class Context* const context);
~Animation();
const RepeatType& GetRepeatType() { return repeat_type; }
void SetRepeatType(const RepeatType& repeat_type) { this->repeat_type = repeat_type; }
const D3DXVECTOR2 GetSpriteTextureSize() { return sprite_texture_size; }
void SetSpriteTextureSize(const D3DXVECTOR2& size) { this->sprite_texture_size = size; }
const std::shared_ptr<class D3D11_Texture>& GetSpriteTexture() const { return sprite_texture; }
void SetSpriteTexture(const std::shared_ptr<class D3D11_Texture>& sprite_texture) { this->sprite_texture = sprite_texture; }
void SetSpriteTexture(const std::string& path);
const std::vector<Keyframe>& GetKeyframes() const { return keyframes; }
void SetKeyframes(const std::vector<Keyframe>& keyframes) { this->keyframes = keyframes; }
const Keyframe* GetKeyframeFromIndex(const uint& index);
const uint GetKeyframeCount() const { return keyframes.size(); }
void AddKeyframe(const Keyframe& keyframe);
void AddKeyframe(const D3DXVECTOR2& offset, const D3DXVECTOR2& size, const double& time);
private:
class Context* context = nullptr;
RepeatType repeat_type = RepeatType::Loop;
D3DXVECTOR2 sprite_texture_size = D3DXVECTOR2(1.0f, 1.0f);
std::shared_ptr<class D3D11_Texture> sprite_texture;
std::vector<Keyframe> keyframes;
};
하나하나 살펴보자
enum class RepeatType : uint
{
Once, Loop
};
지금 이 애니메이션이 한번 실행할건디 계속해서 실행할건지 결정한다. 보통 공격은 한번하고 뛰거나 대기상태일땐 무한으로 도니까 나눠놨다.
struct Keyframe final
{
Keyframe() = default;
Keyframe(const D3DXVECTOR2& offset, const D3DXVECTOR2& size, const double& time)
: offset(offset)
, size(size)
, time(time)
{}
D3DXVECTOR2 offset{ 0.0f, 0.0f };
D3DXVECTOR2 size{ 0.0f,0.0f };
double time{ 0.0 };
};
각 키프레임마다 어떤 스프라이트를 갖고올지 그리고 얼마나 실행시킬지에 관한 구조체이다.
void Animation::SetSpriteTexture(const std::string& path)
{
sprite_texture = std::make_shared<D3D11_Texture>(context->GetSubsystem<Graphics>());
sprite_texture->Create(path);
}
스프라이트 텍스쳐를 경로에 따라 갖고온다.
const Keyframe* Animation::GetKeyframeFromIndex(const uint& index)
{
assert(index < keyframes.size());
return &keyframes[index];
}
void Animation::AddKeyframe(const Keyframe& keyframe)
{
keyframes.emplace_back(keyframe);
}
void Animation::AddKeyframe(const D3DXVECTOR2& offset, const D3DXVECTOR2& size, const double& time)
{
keyframes.emplace_back(offset, size, time);
}
각 키프레임 추가하거나 갖고오는 함수이다.
하지만 Get부분을 보면 assert로 한번 막아주는 모습을 보인다.
이 부분은 if문을 줄이려고 사용했다 어차피 assert는 debug모드에서만 작동하니 완성품엔 없을 수 있으므로 막아뒀다.
Timer
매 프레임마다 얼마나 지났는지 확인하는 클래스이다.
Timer.h
class Timer final : public ISubsystem
{
public:
Timer(class Context* const context);
~Timer() = default;
bool Initialize() override;
void Update() override;
const float GetDeltaTimeMS() const { return static_cast<float>(delta_time_ms); }
const float GetDeltaTimeSEC() const { return static_cast<float>(delta_time_ms / 1000.0); }
private:
double delta_time_ms = 0.0f;
std::chrono::time_point<std::chrono::high_resolution_clock> previous_time;
};
매 프레임마다 시간을 밀리세컨드나 일반 세컨드로 갖고온다.
Timer.cpp
void Timer::Update()
{
auto current_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ms = current_time - previous_time;
previous_time = std::chrono::high_resolution_clock::now();
delta_time_ms = ms.count();
}
매 업데이트마다 시간을 측정!