-
[009] 플레이어 컨트롤Programming/Dev 2023. 6. 6. 20:13

DevLog 이번 게시글에서는 간단하게 플레이어를 조종하는 것을 구현해보려고 한다.
class Player : public IGameObject { public: class InputComponent { ... }; class PhysicsComponent { ... }; class AnimationComponent { ... }; public: Player(); ~Player() = default; virtual void Update(FLOAT deltaTime); virtual void Render(const ComPtr<ID3D12GraphicsCommandList>& commandList) const; private: InputComponent m_inputComponent; PhysicsComponent m_physicsComponent; AnimationComponent m_animationComponent; };Player 클래스는 위와 같다.
나중에 바꿀지도 모르겠지만 일단 컴포넌트 패턴을 사용해보려고 한다.
void Player::Update(FLOAT deltaTime) { m_inputComponent.Update(deltaTime); // 1. 입력 처리 m_physicsComponent.Update(deltaTime); // 2. 이동 처리 m_animationComponent.Update(deltaTime); // 3. 애니메이션 }코드를 컴포넌트로 분리했기 때문에 Player의 Update 함수에는 크게 내용이 없다.
단, 컴포넌트의 Update 함수 호출의 순서에 따라 결과가 달라지는 것은 주의해야 한다.
void Player::InputComponent::Update(FLOAT deltaTime) { // 좌우 이동 int dir{ 0 }; if (GetAsyncKeyState(VK_LEFT) & 0x8000) --dir; if (GetAsyncKeyState(VK_RIGHT) & 0x8000) ++dir; m_player->m_physicsComponent.Move(static_cast<PhysicsComponent::Direction>(dir)); // 점프 bool isJumped{ false }; if (GetAsyncKeyState('C') & 0x8000) { m_player->m_physicsComponent.Jump(); isJumped = true; } // 애니메이션 재생 auto animationType{ AnimationComponent::AnimationType::NONE }; if (isJumped) animationType = AnimationComponent::AnimationType::JUMP; else if (m_player->m_animationComponent.GetAnimationType() != AnimationComponent::AnimationType::JUMP && m_player->m_animationComponent.GetAnimationType() != AnimationComponent::AnimationType::FALL) { if (dir != 0) animationType = AnimationComponent::AnimationType::RUN; else animationType = AnimationComponent::AnimationType::IDLE; } if (animationType != AnimationComponent::AnimationType::NONE && m_player->m_animationComponent.GetAnimationType() != animationType) m_player->m_animationComponent.PlayAnimation(animationType); }InputComponent에서는 입력에 대한 처리를 담당한다.
위 코드에서 볼 수 있듯이 각 컴포넌트끼리는 직접 접근하여 통신한다. 통신 방법 역시 나중에 바꿀 수도 있을 것 같다.
void Player::PhysicsComponent::Update(FLOAT deltaTime) { FLOAT2 beforePlayerPosition{ m_player->GetPosition() }; FLOAT2 afterPlayerPosition{}; const Platform* beforePlatform{ m_platform }; const Platform* afterPlatform{ nullptr }; // 이동. 현재 플렛폼의 높이와 플레이어의 높이가 같다면 플렛폼 위에 서있다는 것 if (m_speed.y < 0.0f && m_platform && m_platform->GetHeight(beforePlayerPosition.x) == beforePlayerPosition.y) m_speed.y = 0.0f; m_player->Move(FLOAT2{ static_cast<int>(m_direction) * m_speed.x * deltaTime, m_speed.y * deltaTime }); // 현재 위치에서 가장 높은 플렛폼 계산 afterPlayerPosition = m_player->GetPosition(); afterPlatform = GetTopPlatformBelowPosition(afterPlayerPosition); // 움직이기 이전, 이후 플레이어 y좌표 사이에 이전 플렛폼 높이가 있다면 착지한 것 FLOAT platformHeight{ -FLT_MAX }; if (beforePlatform) platformHeight = beforePlatform->GetHeight(beforePlayerPosition.x); if (afterPlayerPosition.y < platformHeight && platformHeight < beforePlayerPosition.y) { afterPlatform = beforePlatform; m_platform = beforePlatform; OnLanding(); } else { m_platform = afterPlatform; } // 이전, 이후 플렛폼이 다르고 이후 플렛폼이 없거나 이전 플렛폼의 높이가 이후 플렛폼의 높이보다 크면 플렛폼을 벗어나 떨어지는 것 if (beforePlatform != afterPlatform && (!afterPlatform || (beforePlatform && afterPlatform && beforePlatform->GetHeight(beforePlayerPosition.x) > afterPlatform->GetHeight(afterPlayerPosition.x)))) OnFalling(); // 중력 적용 m_speed.y -= 980.0f * deltaTime; }PhysicsComponent에서는 이동에 대한 처리를 담당한다.
이동 전, 후를 이용하여 착지했는지, 떨어지는 지를 계산하고 이벤트 함수를 호출한다.
void Player::AnimationComponent::Update(FLOAT deltaTime) { m_timer += deltaTime; FLOAT interval{ DEFAULT_FRAME_INTERVAL }; do { if (auto currFrameInterval{ m_currFrameProp->Get<FLOAT>("interval") }) interval = *currFrameInterval; if (m_timer >= interval) { if (m_frame >= m_currAniProp->GetChildCount() - 1) { // OnAnimationEnd에서 PlayAnimation을 호출하여 m_timer값이 0이되버리므로 저장해줬다가 다시 설정해줌 FLOAT timer{ m_timer }; OnAnimationEnd(); m_timer = timer - interval; continue; } ++m_frame; m_timer -= interval; OnFrameChange(); } } while (m_timer >= interval); }AnimationComponent에서는 애니메이션에 대한 처리를 담당한다.
do-while문을 통해 deltaTime이 아무리 커도 그 사이 프레임에 대해 이벤트 함수를 호출 할 수 있도록 했다.

작동 아직 플렛폼이 보이게 하지는 않았다.
잘 작동하는 것을 볼 수 있다!
'Programming > Dev' 카테고리의 다른 글
[011] 이벤트 매니저 (0) 2023.08.29 [010] 플레이어 컨트롤2 (0) 2023.07.29 [008] 에디트 컨트롤 (0) 2023.03.25 [007] 씬 전환 (0) 2023.03.18 [006] 게임오브젝트 렌더링 (0) 2023.03.05
