Win32 API/기초

Win32 API 기초 : Scene Manager (2)

시플마 2024. 7. 5. 17:11

CCore 클래스의 멤버 함수 progress를 보시면

 

update와 render 함수를 없애고 각 매니저가 

그 일을 대신 할 수 있도록 하였습니다.

 

이제 CSceneMgr 클래스로 만든 씬 매니저가

씬마다의 update와 render를 진행할 것입니다.

 

 

CSceneMgr.h 파일을 보면

 

15 ~ 16번째 줄에 update와 render 함수가 추가되었습니다.

 

render 함수는 어디에 그릴 것인가에 대한 정보,

즉 목적지가 필요하기 때문에 CCore 클래스의

progress 함수로부터 호출될 때 HDC형 _dc를

인자로 받게 됩니다.

 

 

각 함수의 정의를 살펴보면

 

36번째 줄에서 현재 씬을 저장하고 있는

m_pCurScene의 update 함수를 호출하고 있습니다.

 

 

CScene 클래스의 헤더 파일을 보시면

 

 update 함수는 CScene 클래스로부터 파생된

모든 자식 클래스가 동일하게 작동할 것이므로 

virtual 키워드를 붙이지 않았습니다.

 

즉 m_pCurScene가 어떤 씬을 가리키고 있든

 

무조건 위 코드가 작동하는 것이죠.

 

update와 render 함수 모두

GROUP_TYPE의 개수만큼 반복합니다.

 

바깥 for 문이 한 번 돌 때

안쪽 for 문은 m_arrObj[i]의 개수만큼 돕니다.

 

m_arrObj[i]의 개수는 해당 씬의 오브젝트의

개수와 같을 겁니다.

 

27번째 줄에서는 해당 오브젝트의

update 함수를 호출하고 있습니다.

 

 

정리하면 코어 매니저가 씬 매너지의 update 함수를 호출하면

씬 매니저는 현재 가리키고 있는 씬으로 가서

해당 씬이 보유한 모든 오브젝트의 update 함수를 호출하는 것이죠.

 

이 동작은 render 함수도 완전히 같습니다.

 

 

그럼 CObject 클래스의 update 함수와

render 함수를 보도록 합시다.

 

오브젝트의 update 함수는

W 키가 계속 눌리고 있는 상태라면

오브젝트의 y 좌푯값을 내립니다.

 

그럼 위로 올라가겠죠.

 

 

S 키가 계속 눌리고 있는 상태라면

오브젝트의 y 좌푯값을 올립니다.

 

그럼 아래로 내려갈 겁니다.

 

 

A 키가 계속 눌리고 있는 상태라면

오브젝트의 x 좌푯값을 내립니다.

 

그럼 왼쪽으로 이동할 것이고,

 

 

D 키가 계속 눌리고 있는 상태라면

오브젝트의 x 좌푯값을 올립니다.

 

그럼 오른쪽으로 이동하겠죠.

 

 

render 함수는 오브젝트의 좌푯값과

크깃값을 통해 사각형을 그립니다.

 

만약 update 함수로 인해 좌푯값이 수정되었다면

바뀐 값을 적용해 새로운 위치에 사각형이 그려지겠죠.

 

 

이렇게 그려진 사각형은

씬이 종료될 때 delete를 해 줘야겠죠?

 

이를 각 씬의 소멸자에 구현을 해 주기보다는 

어차피 부모 클래스인 CScene 클래스에서

모든 오브젝트에 접근할 수 있으니,

각 씬이 상속받은 부모 클래스에 있는 소멸자에서

오브젝트를 delete해 준다면 일일이 자식 클래스에

구현해 줄 필요가 없을 겁니다.

 

위와 같이 모든 vector가 가리키고 있는 동적 할당된 모든 공간,

즉 오브젝트가 들어가 있는 공간을 하나씩 다 돌면서

delete를 진행하게 될 겁니다.

 

 

그럼 여기서 오브젝트가 존재하는, 동적 할당된 공간의

주솟값을 저장하고 있는 vector는 delete해 주지 않는지에

대한 의문점이 생길 수 있습니다.

 

이는 따로 delete해 주지 않아도 씬이 종료될 때

CScene 클래스의 소멸자가 호출될 것이고

이는 곧 CScene 클래스로 만든 객체가 갖고 있는

멤버 함수가 소멸될 것임을 의미합니다. vector형 멤버는

vector의 소멸자가 호출되며 스스로 소멸하게 되겠죠.

 

 

 


 

 

 

 

Start 씬은 사각형이 하나 존재하고

STAGE_01 씬은 삼각형이 두 개 존재하는 등,

씬이 실행되었을 때 각각 초기 상태가 있을 겁니다.

 

이를 설정해 주기 위해 CSceneMgr 클래스의

init 함수를 보시면 Enter 함수가 호출되고 있습니다.

 

이것이 현재 가리키고 있는 씬의

초기 상태를 설정해 주는 함수이죠.

 

그리고 25번째 줄에서 Start 씬에

"Start Scene"라는 이름을 붙여주고 있습니다.

 

 

CScene 클래스의 헤더 파일에서

 

18, 19번째 줄에 Enter와 Exit 함수가 보입니다.

 

Exit 함수는 씬이 종료될 때 해야 하는 

동작을 진행하는 함수입니다.

 

update와 render 함수는 CScene 클래스로부터

파생된 자식 클래스가 모두 똑같이 동작합니다.

 

그러나 Enter와 Exit 함수는

각 자식 클래스마다, 즉 씬마다

모두 다르게 작동해야 하죠.

 

씬마다 존재하는 오브젝트의 개수와 

형태 등이 모두 다를 것이기 때문이죠.

 

그래서 virtual 키워드를 붙여 주고 있습니다.

 

각 씬이 Enter와 Exit 함수를 호출하게 되면

부모 클래스인 CScene 클래스의 Enter와 Exit 함수가

호출되는 것이 아닌, 알아서 자신들이 각각 보유하고 있는

Enter와 Exit 함수가 호출되어 실행될 겁니다.

 

 

또한 virtual 키워드가 붙은 가상 함수를 0으로 초기화

해 주면 순수 가상 함수가 됩니다.

 

부모 클래스인 CScene 클래스가 추상 클래스가 되어

순수 가상 함수들을 정의해 줄 필요가 없어집니다.

 

대신 부모 클래스이자 추상 클래스인 

CScene 클래스를 통해 객체를 만들 수 없게 되며,

파생된 자식 클래스들은 모두, 순수 가상 함수로

정의된 함수를 반드시 선언하고 정의하고 있어야 합니다.

 

즉 추상 클래스가 되었다는 것은 오직 상속을 위해

존재하며, 추상 클래스를 상속받은 자식 클래스가

구현해야 할 함수들을 알리는 목적의

클래스라는 의미가 되죠.

 

 

Start 씬을 의미하는 CScene_Start 클래스를 보시면

 

9, 10번째 줄에 부모 클래스에서 순수 가상 함수로

선언해 주었던 Enter와 Exit 함수가 보입니다.

 

CScene_Start 클래스는 CScene 클래스를 상속받은

자식 클래스이므로 순수 가상 함수인 Enter와 Exit 함수를

만들어 주지 않으면 문제가 발생합니다.

 

virtual 키워드를 자식 클래스에는 붙여 주지 않아도

상관없지만 가상 함수임을 명시적으로 표현하기 위해

virtual 키워드를  붙여 주었습니다.

 

 

Enter 함수의 정의를 살펴보죠.

 

10번째 줄에서 CObject형 포인터를 선언하고

CObject형 공간으로 동적 할당해 주고 있습니다.

 

12, 13번째 줄에서는 동적 할당된 공간에

존재하는 오브젝트의 위치와 사이즈를

SetPos와 SetScale 함수를 통해 설정하고 있습니다.

 

15번째 줄에서는 AddObject 함수가 호출되었는데,

 

부모 클래스인 CScene 클래스에 존재하는 함수로 

동적 할당된 공간의 주솟값과 설정하고자 하는 그룹의 값을 받아

동적 할당된 공간에 존재하는 오브젝트를 그룹에 맞는 vector에

삽입하는 함수입니다.

 

이때 AddObject 함수는 protected로 선언이 되었습니다.

 

이는 부모 클래스 자신은 물론, 자신을 상속받은 자식 클래스를

통해 접근이 가능하며 이외의 외부에서는 접근이 불가능하게 만드는

키워드이죠.

 

물론 부모 클래스의 멤버를 protected로 선언하여

자식 클래스에서 접근하여 값을 수정할 수 있도록

할 수도 있습니다. 

 

그러나 이렇게 되면 다양한 자식 클래스들이

모든 함수를 통해, 어느 위치에서나 부모 클래스 

멤버에 접근할 수 있게 됩니다. 

 

즉 부모 클래스의 멤버에 의도하지 않은 값이 

들어왔을 때, 어디서 문제가 발생했는지

자식 클래스의 모든 부분을 탐색해야 하죠.

 

이때 부모 클래스의 값을 수정하는 함수를

protected로 선언해 놓으면 나중에

해당 멤버에 의도하지 않은 값이 들어왔을 때

부모 클래스의 값을 수정하는 함수가 

호출된 부분만 찾아 디버깅해 보면 되겠죠.

 

 

CScene_Start 클래스의 Enter 함수로 인해

동적 할당된 공간에 생성된 오브젝트는

DEFAULT 그룹에 해당하는 vector 공간에 삽입이 

되겠네요.

 

 

Exit 함수는 다음에 구현하도록 하겠습니다.

 

 

프로그램을 실행해 보면 

 

씬은 Start 씬밖에 구현되지 않았으므로

프로그램을 실행했을 때의 화면은

Start 씬일 것이고 사각형이 하나이므로

해당 씬이 가리키는 동적 할당된 공간도

하나일 것입니다. 동적 할당된 공간에는

( 100, 100 ) 사이즈의 사각형 한 개를

멤버로 두고 있겠죠.

 

W를 눌렀을 때 사각형이 위로,

S를 눌렀을 때는 아래로,

A를 눌렀을 때는 왼쪽으로,

D를 눌렀을 때는 오른쪽으로 잘 이동하는 것을

확인할 수 있습니다.

 

update 함수가 코어 매니저 쪽에서 프레임마다 

호출되고 있으므로 키의 입력을 프레임마다 확인하며

키 입력이 발생하면 오브젝트의 update 함수가 호출이 되어

사각형의 좌푯값이 수정될 것입니다.

 

코어 매니저 쪽에서 마찬가지로 프레임마다 render 함수를 

호출하고 있으므로 수정된 사각형의 좌푯값을 통해

다른 위치에 사각형을 다시 그리고 화면에 출력할 것입니다.

(정확히는 수정된 위치에 사각형을 미리 만들어 놓은

'비트맵'에 그린 후 이 비트맵에 다 그려진 사각형을

화면에 띄워진 메인 윈도우에 복사하여 출력하는 거겠죠?)

 

 


강의 출처 : https://www.youtube.com/watch?v=A9eL3p0MfLA