posted by REDFORCE 2017. 5. 18. 22:14

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData

 + Layer  

 + Input (현재 글)

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


이번글에서 설명 할 내용은 Input Class 입니다.


Input 클래스는 엔진에서의 모든 키입력 처리에 대한 것을 담당하는 클래스입니다.


일반적인 키보드 입력, 마우스 입력 부터 XBox Pad의 입력에 대한 처리를 담당합니다.




먼저 헤더에서의 주요 내용들을 살펴보도록 하겠습니다.


헤더에서 다룰 내용 목록은 다음과 같습니다.


1. 키 입력을 위한 주요 변수들

2. Input 클래스의 주요 함수 목록 


본 글에서는 자세한 게임패드 입력처리에 대한 설명은 하지 않습니다.

게임패드 입력처리에 대한 자세한 내용은 다음에 기회가 되면 다루도록 하겠습니다.

(#include <XInput>제목으로 별도의 포스팅을 통해 다룰 예정입니다.)




1. 먼저 Input.h 의 상단에 위치한 내용들을 보도록 하겠습니다.



 (1) namespace inputNS를 보시면 사용 될 모든 키들에 대한 값들을 위해 KEYS_ARRAY_LEN이 있습니다. 사용 할 키들의 사이즈 크기라 보시면 됩니다. (즉, 256 개의 키를 지원)

 (2) 다음 키다운 이나 눌러졌다를 판단할 용도의 KEYS_DOWN / KEYS_PRESSED 플래그

 (3) 마우스에 대한 플래그 값 MOUSE와 텍스트 입력에 대한 플래그 값 TEXT_IN 플래그

 (4) 모든 키들을 Clear시킬 용도로 각 플래그 값들을 합친 KEYS_MOUSE_TEXT 플래그


그리고 그 아래에는 게임 패드를 사용하는 것들에 대한 키 플래그값들이 나열되어 있습니다.

게임패드에 대한 입력을 처리할 목적으로 선언되어 있으나 패드를 지원하는 게임을 만들 게 아니라면 딱히 사용할 일은 없습니다.


게임 패드에 대한 선언은 본 글에서는 생략하고 추후 XInput에 대한 것을 다룰 때 다시 설명하도록 하겠습니다.



다음, Input 클래스에서 키 입력 처리를 위해 사용 되어지는 주요 변수들 입니다.


(private: 접근한정자 안에 선언 된 주요 변수들을 먼저 코드로 올렸습니다. 실제 전체 코드는 public: 영역도 포함하여 최 하단에 업로드 되어있습니다.)



 (1) keysDown[KEYS_ARRAY_LEN] / keysPressed[KEYS_ARRAY_LEN] (키 입력 여부를 판단할 목적의 bool 변수)

 (2) bool mouseWheelRoll / Rollup/ RollDown (마우스 휠을 굴렸을 때의 이벤트 판단목적)

 (3) std::string textIn (텍스트 입력값들을 저장할 목적)

 (4) char charIn (텍스트 입력 시 한 글자 값들을 저장)

 (5) bool newLine (줄바꿈 여부를 판단할 목적)

 (6) int mouseX / Y (현재 마우스 커서의 x,y 위치)

 (7) int mouseRawX / Y (현재 마우스커서의 고감도 x, y 위치)

 (8) RAWINPUTDEVICE Rid[1] (고감도 마우스 지원 여부 판단 목적의 변수)

 (9) bool mouseCaptured (마우스 위치 캡쳐 목적의 플래그 값)

 (10) bool mouseL/M/RButton (마우스 좌/우/중앙 키 입력 플래그 값)

 (11) bool mouseX1/X2Button (마우스 특수버튼 1,2 키 플래그 값)

 (12) ControllerState controllers[MAX_CONTROLLERS] (게임 패드 이용 시 사용하는 플래그 값)


들로 주요 변수들이 이루어져 있습니다.


일반적인 게임 키처리에 대한 변수들과 동일한 구조 형태라 아마 이름만봐도 아 저변수가 무슨용도구나 하고 이해하시는데는 불편함이 없을거라 생각합니다.



그럼 마지막으로 각 키입력에 대한 함수들의 구조를 보겠습니다.


2. 주요 함수 목록



지금 위에 언급된 함수 외에도 게임패드관련 함수가 상당히 많이 있습니다만, 분량이 너무 길어지는 관계로 위 코드에는 올리지 않았습니다. 최하단 전체 코드에는 게임패드 관련 함수도 같이 들어있습니다.


헤더에서 함수가 뭐 이렇게 많아!? 하고 겁먹으실 필요는 없습니다.

어짜피 엔진을 쓰면서 사용하게 될 함수는 8~90% isKeyDown / wasKeyPressed 밖에 없으니까요. 게임패드 관련 함수를 뺏음에도 상당히 부담이 가신다면 아래와 같이 간단히 이런 게 있다 라고만 보시면 될 것 같습니다.


 (1) 생성자 / 소멸자

 (2) KeyDown / Up / In (키입력에 대한 판단 함수)

 (3) isKeyDown (키가 눌러졌냐~? 라고 물어보는 함수)

 (4) wasKeyPressed (최근 프레임 1~2사이에 키가 눌려졌냐~? 라고 물어보는 함수)

 (5) anyKeyPressed (아무키나 눌러졌었냐~? 라고 물어보는 함수)

 (6) clearKeyPressed (눌려진적이 있는 키를 다시 false로 초기화 하는 함수)

 (7) mouseWheel In / Up / Down (마우스 휠이 굴려졌을때 위로굴렸냐 아래로 굴렸냐 체크하는 함수)

 (8) clear / clearAll / clearTextIn 각각 키 입력에 대한 Clear 함수

 (9) getTextIn / getCharIn (문장 / 한 글자 입력 시 내용 받아오는 함수)

 (10) set/ get Mouse L/M/R/X Button (마우스 키 입력 또는 받아오는 함수)

 (11) getMouseX / Y , getMouseRawX /Y (마우스 좌표 받아오는 함수)


키 입력에 대한 처리를 하는 함수들은 위와 같이  11가지가 있습니다.

결과적으로는 모두 다 사용하는 함수들이기 때문에 대충 어떤목적에 사용한다 라는 것만 알고 넘어간 뒤 엔진을 사용하면서 쓰다보면 자연스레 본인이 쓰고 있는 모습을 볼 수 있습니다.


자세한 각 함수들에 구현 내용은 .cpp로 이어서 적도록 하겠습니다.



아래는 전체 헤더파일 내용입니다.



'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #3_LayerManager Class .cpp  (0) 2017.04.21
June_Engine #3_LayerManager Class .h  (0) 2017.04.21
June_Engine #3_Layer Class  (0) 2017.04.21
June_Engine #3_Image Class .cpp (2)  (0) 2017.04.20
June_Engine #3_Image Class .cpp (1)  (0) 2017.04.19
posted by REDFORCE 2017. 4. 21. 20:39

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData

 + Layer  (현재 글)

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


LayerManager Class .cpp 내용을 살펴보도록 하겠습니다.



1. 간단히 생성자와 소멸자 그리고 initialize 함수를 보도록 하겠습니다.



생성자 부분에서는 현재 LayerState 값이 LAYER_NONE 값으로 초기화 됩니다.

소멸자는 release 함수 호출뿐이군요.


initialize 함수에서는 미리 네임스페이스로 만들어두었던 기본 LAYER들 값들에 맞춰서

addLayer 함수를 호출하여 레이어를 등록하도록 되어있습니다.


반복문으로 처리하면 안되~? 라는 생각도 해봤습니다만


= _=아마 당시에 만들면서 귀찮아 그냥 몇개 안되니까 하드코딩으로 만들자

라고 생각했던 것 같네요.


enum Class 타입의 값을 반복문으로 알아서 처리되게끔 고치실 수 있다면 initialize 코드를 개선해보시는것도 좋을 것 같습니다.



release 함수에서는 각각 Layer들이 new 로 할당되어 등록되었기 때문에


해지해주는 과정이 이루어지고 있습니다.

(SAFE_DELETE 매크로를 이용하여 해지합니다. SAFE_DELETE 매크로는 graphics 글에서 언급했습니다.)



initialize 함수의 addLayer 과정을 통해 다음 그림과 같이 Layer가 layerVec에 쌓이게 됩니다.


레이어 순서는 번호 순서대로 위에서 아래로 렌더링 순서가 정해집니다.

enum class 형태의 값 순서대로 읽어 가기 때문인데요. 


여기서 중요한 점은 AddLayer 함수를 호출하면 레이어가 enum Class 값 형식에 맞춰서 정렬됩니다.


만약 같은 Layer 타입이라면 딱히 같은 타입들사이에서는 정렬 될 필요가 없다 느꼈기 때문에


다른 타입들간의 순서만 정렬시켜줍니다.



그럼 이제 AddLayer 함수를 살펴보겠습니다.


2. addLayer


addPlayer 함수는 initialize() 에서 Layer를 등록하면서 호출 되었덩 함수입니다.


코드를 먼저 보겠습니다.



// 레이어 등록이 성공적으로 끝났다면 true값으로 바뀝니다.

Line 3 : bool success = false;   


// 만약 레이어 타입이 네임스페이스LayerManagerNS::none 과 같다면 false를 리턴합니다.

Line 6 : if (layerkey.compare (LayerManagerNS::none) == 0) 


Line 10 ~ 15 : 현재 레이어 리스트에 등록된 같은 레이어가 있는지 확인하여 있다면 false를 리턴합니다.


Line 17 : 여기까지 왔는데 아무이상없었으면 Layer를 등록합니다. 


Line 18 : success 값을 true 로 변경합니다.


Line 20 : 레이어 정렬 함수를 호출합니다.



아마 위에 적어둔 설명을 보시면 아마 AddLayer 함수 내용자체는 별로 어려운 것이 없을 것 입니다.


★주의 할 점은 현재 layerList 라고 하는 MAP 형태의 컨테이너에만 

Layer를 담았다는 것을 꼭 확인하시기 바랍니다.



3. deleteLayer


DeleteLayer() 함수는 AddLayer 함수와 반대로 등록 된 레이어를 삭제하는 함수입니다.



간단히 layerList 에 등록 된 레이어 중에 파라미터로 받은 레이어 이름과 비교하여

등로 된 레이어가 있다면 layerList에서 해당 항목의 레이어를 erase 시킨 후

sortLayer() 함수를 호출하여 줍니다.



4. sortLayer


네 번째로, addLayer과 deleteLayer에서 호출한 sortLayer 함수를 살펴보겠습니다.


sortLayer는 함수명 그대로 레이어들을 정렬시키는 함수입니다.




위에서 주의할 점으로 layerList 라고 하는 Map 타입의 컨테이너에 Layer를 담았었다는 것을 보셨을 겁니다.


그 이유는 바로 layerList (Map 컨테이너)에서 정렬을 수행 한 후

진짜 컨테이너인 layerVec (Vector 타입의 컨테이너) 에 정렬 시킨 후 담아두기 위함입니다.


sortLayer( ) 함수 자체는 간단하게 3줄로 되어있습니다.


1. std::vector<std::pair<std::string, Layer*>> 형태의 벡터 컨테이너를 먼저 만듭니다.

그리고 생성과 동시에 layerList에 담겨있는 Layer들을 그대로 begin 부터 end까지 넣어줍니다.


2. 미리 헤더에 생성해둔 Sort 템플릿을 이용하여 정렬시킵니다.


3. layerVec 의 값을 위에서 정렬 시킨 컨테이너로 넣어줍니다.



그리고 SortLayer에서 중요한 점은 아래의 템플릿을 이해를 하셔야 합니다.




방법은 간단히 좌우 값을 비교하여 작은 값 순서대로 정렬을 시킵니다.


아마 정렬하는 로직은 간단해서 이해하시기 어려움이 없을 것이오나, 템플릿을 사용하는 점에대해서는 스스로 템플릿이 뭔지 알고보셔야 아마 이해하시는데 문제가 없을거라 보입니다.



'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #2_Input .h  (0) 2017.05.18
June_Engine #3_LayerManager Class .h  (0) 2017.04.21
June_Engine #3_Layer Class  (0) 2017.04.21
June_Engine #3_Image Class .cpp (2)  (0) 2017.04.20
June_Engine #3_Image Class .cpp (1)  (0) 2017.04.19
posted by REDFORCE 2017. 4. 21. 07:18

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData

 + Layer  (현재 글)

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------



이어서 LayerManager Class에 대해서 설명하도록 하겠습니다.



Layer Class를 보셨다면 헤더 파일 내용 중에

enum class 타입으로 선언되어있는 Layer 리스트를 보셨을 겁니다.


위 그림은 해당 리스트 내용을 그대로 순서대로 나열한 것 입니다.



다시 뒤로 돌아가서 코드 보기 귀찮으신 분들을 위해 enum Class만 다시 올려드립니다.



보는 바와 같이 LAYER_NONE 부터 LAYER_LAST 까지.


 (1) LAYER_NONE : 초기화용 레이어 타입

 (2) LAYER_FIRST : 첫 번째 레이어

 (3) LAYER_BACKGROUND : 배경 레이어

 (4) LAYER_DEFAULT : 일반 레이어

 (5) LAYER_UI : UI 용 레이어

 (6) LAYER_LAST : 마지막 레이어


순으로 총 6가지의 레이어 타입이 있습니다.


만약 무엇보다 우선순위를 높여서 출력하고 싶으신 것이 있다면 첫 번째 레이어로 이미지 클래스에서 타입을 결정시키면 되고.


일반적인 이미지 출력(캐릭터, 아이템, 애니메이션 등)은 LAYER_DEFAULT 를 이용하시면 됩니다.

그 외에 레이어들은 다른 레이어와 똑같이 직관적이므로 설명은 생략하겠습니다.


만약 어떤 설정을 안한다면 모든 이미지들은 LAYER_DEFAULT 값으로 들어갑니다.



그럼 Layer에 대한 복습이 다시 됐으리라 생각하고, 

LayerManager를 바로 살펴보도록 하겠습니다.


Layer Manager 헤더 내용입니다.



1. LayerManagerNS


먼저 namespace 를 살펴보시면 const std::string 타입으로 미리 구성 된 LAYER의 이름들이 들어가있습니다.



2. 변수들


그리고 private: 에 선언되어있는 변수를 확인해주시기 바랍니다.


 (1) std::map<std::string, layer*> layerList;  (레이어 정렬 전 MAP 컨테이너)

 (2) std::vector<std::pair<std::string, layer*>> layerVec; (레이어 정렬 된 VECTOR 컨테이너)

 (3) enLayerList curLayerState; (현재 렌더링 해야할 레이어)


이렇게 3가지의 변수가 있습니다.



3. 함수들


다음  public: 에 여러가지 함수들이 있습니다만...

역시나 getter/setter함수들이 주로 있을 뿐, 현재 눈여겨 봐야 될 함수는 SortLayer( ) 밖에 없습니다.



4. 정렬용 템플릿


네 번째로 확인할 점은 레이어들을 정렬 시키기 위해 만들어 둔 템플릿 입니다.

std::less를 이용하여 받아온 매개변수를 left / right 비교를 통해 true/false를 뱉어줍니다.




헤더에서 일단 살펴볼 내용들은 위에 언급한 정도이고,

자세한 설명은 .cpp에서 이어가도록 하겠습니다.

'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #2_Input .h  (0) 2017.05.18
June_Engine #3_LayerManager Class .cpp  (0) 2017.04.21
June_Engine #3_Layer Class  (0) 2017.04.21
June_Engine #3_Image Class .cpp (2)  (0) 2017.04.20
June_Engine #3_Image Class .cpp (1)  (0) 2017.04.19
posted by REDFORCE 2017. 4. 21. 04:00

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData

 + Layer  (현재 글)

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


이번 글에서는 Layer Class에 대해 다루도록 하겠습니다.


Layer Class는 Image Class 내부에 들어가서 사용 되는 클래스 입니다.

즉, 어떤 이미지 또는 애니메이션을 돌릴 때 사용되어지는 모듈 입니다.



Q. 그럼 Layer Class가 대체 무엇인가?

A. 포토샵의 레이어와 비슷하다 생각하시면 될 것 같습니다.


흔히 레이어라 하면 겹겹이 쌓여서 출력되어지는 그런 계층 구조의 기능을 상상하실 수 있을 것 입니다.


그러나 보시고 계신 현재 Layer Class 는 Scene의 Render에서 

해당 Layer 단계의 출력 여부(true / false) 를 체크하여 Rendering 해줍니다.


Layer Class 자체는 Layer가 활성화 됐냐 안됐냐 여부만 갖고 있습니다.


그리고 활성화 여부에 맞춰,

씬의 Render 에서는 활성화 된 Layer만 Rendering을 해주게 됩니다.


Layer Class의 헤더 부터 살펴볼까요.



헤더에서 보면 


Class Layer

{

private:

enLayerList layer = enLayerList::LAYER_DEFAULT;

bool bRenderSwitch = TRUE;

}


로 되어있습니다.


첫 번째 enum class 형 layer는 현재 Layer클래스가 어떤 레이어 타입인지를 나타내고,

두 번째 bRenderSwitch 값은 레이어의 활성화 여부를 나타냅니다.


기본적으로 두 값은 Default와 true 값으로 초기화되어 들어갑니다.

클래스가 만들어 진 시점에서 일단 한번 바로 활성화하기 위해서 그렇습니다.


만약 레이어만 만들고 쓰고 싶지 않다면


클래스 생성 후 바로 set함수를 이용하여 비활성화 시키면 됩니다.


.cpp 파일의 내용 또한 별게 없습니다.


다만 주의할 점은 생성자가 enum class 형 enLayerList layerstate값을 받게 되어있습니다.



여기까지 봐서는 무슨 말인지 잘 이해가 안가실 수 있으나


간단히 예제 상황을 들면,


액션 게임을 할 때 캐릭터가 필살기를 쓰면 배경이 검은색으로 바뀌면서 배경이나 UI가 사라지고 캐릭터에 카메라 포커스가 맞춰지는 경우를 보신 적이 있을 것 입니다.


위 경우와 같이 어떤 레이어 계층의 렌더링 자체를 껏다 켰다 하실 때 사용 할 수 있습니다.


별로 이런거 쓸일이 없다. 그러면 딱히 Layer Class를 활용하지 않아도 상관없습니다.



레이어 클래스 자체는 여기까지만 설명드리면 어느정도 목적과 그 이용 사례를 스스로 생각하실 수 있으리라 예상 됩니다.


그럼 다음 글 LayerManager Class 를 이어서 설명하도록 하겠습니다.

posted by REDFORCE 2017. 4. 20. 05:44

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData  (현재 글)

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


Image Class .cpp (1) 번 글에 이어서 (2)번 글 입니다.


이번 글은 주목할 내용이 Update 함수 뿐이라서 짧습니다.



1. Update


Update 라는 함수 이름으로 알 수 있듯이, 이 함수는 게임이 진행 되는


매 프레임마다 호출되는 함수입니다.


왜 Update 라는 함수가 필요한가? 에 대해서 의문이신 분은 Image class가 궁극적으로

무엇을 하기 위한 클래스 였는지 한번 상기해볼 필요가 있습니다.


이유인즉, Image Class는 spriteData와 같이 단순한 이미지 출력 용이 아닌,

애니메이션을 돌리기 위한 용도이기 때문입니다.


따라서 매 프레임 어떤 애니메이션 동작이 나올지 계속 갱신해줘야 하기 때문에 Update 함수를 갖고 있습니다.


다음 코드가 update 함수 전체 입니다.



update 내용을 보면,


8 Line : if (endFrame - startFrame > 0) 


만약 끝 프레임에서 시작프레임을 뺐는데 값이 0 보다 크다는 말은

프레임이 1개 이상이라는 뜻이니 애니메이션을 업데이트 해야 한다라고 인식합니다.


10 Line : animTimer += frameTime;


위 뜻은 animation을 돌릴 때 설정해둔 딜레이와 계산해서 

딜레이 보다 작다면 애니메이션을 업데이트 하지 않고 크다면 애니메이션을 업데이트 시킵니다.

즉, 딜레이가 길다는 뜻은 애니메이션 동작을 펼치는데 오래걸린다는 뜻 입니다.


예를 들어서 느릿느릿 움직이게 하고 싶은 애니메이션은 딜레이를 길게 주면됩니다.


13 Line : animTimer -= frameDelay;


조건문 결과 true 값으로 안으로 들어왔다면, 타이머에서 딜레이 값 만큼 빼줍니다.

안그러면은 타이머가 계속 올라가기만 해서 딜레이 보다 무조건 크다 라고 판단하고 조건문을 계속 들어오니까요.


14 Line : currentFrame++;


업데이트를 하게 되었으니, 현재 프레임을 상승시켜줍니다.


15 Line : if (currentFrame < startFrame || currentFrame > endFrame)


위 뜻은 현재 프레임이 시작프레임 보다 작거나 현재 프레임이 끝 프레임보다 크다면

아래의 내용을 수행해라 라는 뜻 입니다.


17 ~ 23 Line : if(loop == true){ } else { }


만약 반복 애니메이션 이라면~? 아래 내용을 수행 / 아니면 현재 프레임을 끝 프레임으로 설정하고 애니메이션이 끝났다 라고 알림 (animComplete = true;)


25 Line : setRect( ) 


다음 출력 해야 할 애니메이션의 spriteData.rect 를 셋업.



여기까지가 Image Class의 Update 내용이었습니다.


혹시나 보시고 응? 잘 이해안가시거나 오류가 있다면 알려주시면

바로 해결하도록 노력하겠습니다.

posted by REDFORCE 2017. 4. 19. 23:09

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData  (현재 글)

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


Image Class의 header 파일을 살펴봤던 것에 이어서, 


.cpp 내용을 살펴보도록 하겠습니다.


1. 생성자 / 소멸자 


간단하게 생성자부터 확인하도록 하겠습니다.



생성자 내엔 역시나 주요 변수들에 대한 초기화가 이루어집니다.


포인터 형태인 변수는 null 값으로 초기화가 됐습니다만,

최근에는 모던 C++을 공부하면서 nullptr을 사용하는 것이 더 낫다 보여집니다.



소멸자 아무 내용도 없어서 여기에 담진 않았습니다.



2. initialize


두 번째 내용은 의미있는 초기화를 담당하고 있는 initialize 함수 입니다.


try - catch 구문으로 감싸져있으며, 어떤 exception이 발생할 시엔 return false 값을 내뱉고 종료합니다.


try 안에서는 매게변수로 받아온 


 (1) Graphics*

 (2) width / height

 (3) cols

 (4) textureManager*


값을 그대로 대입합니다.


아마 이글에서 textureManager (?) 하고 의문이 들수 있습니다.


지금까지 언급했던 내용중에는 textureManager라는 항목이 없었거든요.

많이 궁금하시겠지만 일단은 그냥 그런가보다 하고 넘어가시기 바랍니다.


여기서 꼭 숙지할 점은 받아온 각 파라미터의 값들이 spriteData 안에 대입이 되어진다는 것을 확인하시기 바랍니다.


그리고 Layer 라고 하는 클래스도 갑자기 등장했습니다만, 

추후 Layer 파트에 대한 메뉴얼이 있으므로 그곳에서 설명드리도록 하겠습니다.



3. Draw Functions


세 번째 Draw 함수들 입니다.


Graphics에서 보신것과 같이 기본적인 Image를 Draw 하는 함수와

Image의 Rect가 어느정도 크기인지를 볼 수 있게 도와주는 drawRect 함수입니다.


(drawNine 함수는 현재 제대로 작동하지 않아서 언급하지 않습니다. 추후 버그수정 후 다시 올리도록 하겠습니다)



draw 함수들에 대해서는 의미적으로 이미 바로 알 수 있기 때문에


어렵게 설명할 내용은 없습니다.


현재 Image 클래스에서 갖고있는 spriteData 구조체에 들어가있는 Texture와 각종 값들을 토대로 Texture 이미지를 그대로 graphics 클래스에게 부탁하여 drawSprite 함수를 호출합니다.



나머지 함수부터는 다음 글로 이어서 적도록 하겠습니다.

'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #3_Layer Class  (0) 2017.04.21
June_Engine #3_Image Class .cpp (2)  (0) 2017.04.20
June_Engine #3_Image (Class) & SpriteData (Struct)  (0) 2017.04.19
June_Engine #2_Graphics.cpp (3)  (0) 2017.04.18
June_Engine #2_Graphics.cpp (2)  (0) 2017.04.17
posted by REDFORCE 2017. 4. 19. 04:38

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics

 + Image - SpriteData  (현재 글)

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


이번 글에서는 Image 클래스와 SpriteData 구조체에 대해서 자세히 살펴보도록 하겠습니다.


Image Class 자체는 Graphics 클래스에 비하면


헤더 내용 자체는 양반입니다만 의미 자체는 역시나 Graphics 클래스 못지않게

인게임에서 렌더링을 편하게 할 수 있게 도와주는 클래스 이므로 매우 중요합니다.



그럼 먼저 성격 급하신 분들을 위해 대체 Image Class가 뭐하는 것인지부터 

간략히 설명하도록 하겠습니다.



앞서 우리는 SpriteData 라는 구조체를 봤습니다.

SpriteData 구조체 만으로도 상당히 편하게 In game에서 사용할 이미지를 대충 뿌릴 수 있습니다만...


Image Class는 SpriteData 구조체보다 한 단계 위의 작업을 하기 위해 존재합니다.

결과만 먼저 한 줄로 이야기 해드리자면, 바로 애니메이션! 을 돌리기 위함 입니다.


1. 먼저 헤더 파일의 일부를 살펴보겠습니다.




위와 같이 Protected 접근한정자 영역 안에

이미 SpriteData 구조체가 들어가 있음을 볼 수 있습니다.


즉 Image Class 자체에 텍스쳐 및 이미지 정보를 가지고 있는 SpriteData를 내포하고 있습니다.



위에서 아래로 차례대로 변수들의 목적에 대해서 설명해드리겠습니다.


 (1) *graphics : 이미지가 사용 될 Graphics 클래스 포인터

 (2) *textureManager : SpriteData에 입력 될 Texture 정보

 (3) spriteData : SpriteData 구조체

 (4) colorFilter : 투명화 시킬 컬러 필터 값 ( 아무것도 안주면 WHITE 컬러 = No change)

 (5) cols : 텍스쳐에서 애니메이션화 시킬 프레임의 열 갯수

 (6) startFrame : 시작 프레임

 (7) endFrame : 끝 프레임

 (8) currentFrame : 현재 출력중인 프레임

 (9) frameDelay : 애니메이션 딜레이

 (10) animTimer : 애니메이션 타이머

 (11) hr : 초기화 시 리턴 값

 (12) loop : 반복 애니메이션 여부

 (13) visible : 출력 여부

 (14) initialized : 초기화 성공 여부

 (15) animComplete : 애니메이션 끝났는지 여부

 (16) *layer : Layer 클래스 포인터


이렇게 총 16개의 변수가 있어서 상당히 뭐가 많아 보이긴 합니다만.


그저 Image 클래스를 자주 쓰다보면 저절로 익혀지는 내용들이라 

지금 당장 숨가쁘게 이해하실 필요는 없습니다.



2. 다음, Image Class의 각 함수들 입니다.


코드를 보신다면 아마 헐... 뭐가 이렇게 함수가 많아 라고 하실 분들도 계실텐데


주석의 량 때문에 함수 구간이 길어지다보니 많아보일 뿐

사실 함수 갯수자체로는 각 변수별 필요한 내용들에 대한 Setter/Getter 밖에없습니다.


따라서 함수에 대한 설명은 Setter/Getter 함수들을 제외한


특별한 함수들에 대해서만 설명하겠습니다.


헤더에서 일단 이런게 있구나 살펴볼 함수들은 


 (1) initialize

 (2) draw

 (3) drawLine

 (4) drawRect

 (5) update


이상 5가지 입니다.


(함수에 대한 설명글은 .cpp 에서 잇도록 하겠습니다)


'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #3_Image Class .cpp (2)  (0) 2017.04.20
June_Engine #3_Image Class .cpp (1)  (0) 2017.04.19
June_Engine #2_Graphics.cpp (3)  (0) 2017.04.18
June_Engine #2_Graphics.cpp (2)  (0) 2017.04.17
June_Engine #2_Graphics.cpp (1)  (0) 2017.04.15
posted by REDFORCE 2017. 4. 18. 23:18

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics  (현재 글)

 + Image - SpriteData

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


이번 글에서는 앞서 다룬 DrawSprite 함수에 이어서 적도록 하겠습니다.



1. changeDisplayMode (화면 전환 함수 [창모드/전체화면모드] )


이어서 다룰 첫 번째 함수는 changeDisplayMode 입니다.


이름만봐도 알 수 있듯이 위 함수는 전체화면이나 창모드 화면으로 변경할 시에 사용 되는 함수입니다.


사용빈도 자체는 높진 않지만 일반적인 게임이라면 필수적으로 지원되야하는


기능이라 할 수 있습니다.


우리는 일상에서 많은 게임들이 Alt+Enter 키를 누르면 전체화면이나 창모드로 바뀌는 그런 경우를 볼 수 있었을 것 입니다.


단축키 자체는 별도로 작성해서 이 함수를 호출하도록 하게끔만 만들면 되므로

키 입력에 대한 내용은 추후 Input Class 에서 다루도록 하고 여기서는


어떻게 화면이 변환되는지에 대해서만 언급하겠습니다.


먼저 코드를 살펴보겠습니다.




함수 내용 전체는 try - catch 문으로 감싸져 있습니다.


이유는 미리 우리가 정의해놓은 어떤 디스플레이 모드 상에서 바뀌는 거라면

상관이 없지만 어떤 에러로 인해 제대로 동작이 안될 경우를 대비하여 


안전하게 화면을 바꾸기 위함입니다.



천천히 try 문 부터 살펴보도록 하겠습니다.



switch 문으로 mode 플래그 값을 통해 구분이 되어있는데


동작 원리는 밖에 선언해두었던 fullscreen (bool) 값을 이용하여 단순히 true / false 를 교체해주는 행위를 합니다.


그리고 switch 문에서 나오면 


reset() 함수를 호출하네요.


reset 함수의 내용은 아래와 같습니다.



그리고 fullscreen 값을 체크하여 true 라면

현재 모니터의 전체 화면으로 메인 윈도우를 늘려주고,


아니라면 현재 게임의 width / height 값으로 창화면을 만들어줍니다.


catch 구문으로 갔을 경우의 하는 역할도 마찬가지 입니다.



2. pixelCollision (픽셀 충돌 함수)


두 번째로 다룰 함수는 픽셀 충돌 함수 입니다.


pixelCollision 함수는 저도 꽤 어려운 구역이라 어떻게 설명을 드려야 할지 저도 잘 모르겠습니다. 그래도 아에 스킵하고 넘어갈순 없으므로 어떤 식으로 픽셀 충돌을 검출하는지 확인해보겠습니다.


다음이 픽셀 충돌 함수의 내용입니다.



픽셀 충돌은 먼저 두 개의 spriteData 구조체 파라미터를 받습니다.

그리고 다소 어려운 내용일 수도 있지만 깊이 버퍼 값을 이용하여 픽셀 충돌을 검사합니다.


코드를 보시면, 처음 stencilSupport 여부를 체크하는데요.

이것은 그래픽카드에서 깊이 버퍼를 이용한 기술적 지원을 해주는지 여부를 확인합니다.

(위 stencilSupport 값은 Initialize( ) 에서 true / false 여부가 판단되어 있습니다)


다음, 깊이 버퍼 기술을 이용할 수 있다면


다양한 RenderState를 설정하는 것을 볼 수 있습니다.

이 값들이 의미하는 바에 대해서는 여기서 일일이 설명드리기에 너무 많으므로


MSDN이나 구글링 하시는 것을 통해 알아가시기를 양해드립니다.



첫 번째, 


중요한 요점은 D3DRS_STENCILE 이라 하는 RenderState 값들을 이용한다는 점을 숙지하는 것 입니다.



두 번째,


설정한 RenderState 값들 중에 몇가지는 spriteBegin() 이 호출된 이후에 설정되어야 하는 값들이 있습니다.



세 번째,


pOcclusionQuery (IDirect3DQuery9*)를 이용하여 두 스프라이트의 픽셀 갯수만큼 while 문을 돌고 픽셀 충돌 여부를 검출합니다.


그리고 반환 된 충돌 된 픽셀 갯수가 numberOfPixelsColliding 에 담겨서 리턴되게 됩니다.



만약 이 함수를 이용하여 픽셀 충돌을 검사한다면 numberOfPixelsColliding 값이 0보다 큰지 아닌지만 검사한다면 픽셀 충돌이 이뤄졌는가 아닌가를 알 수 있습니다.



여기까지가 주요 Graphics Class에 대한 내용들이었습니다.


의외로 세 번에 걸쳐서 글을 쓰게 될줄은 몰랐습니다.



처음에는 한번에 다 적을 수 있겠지~~ 했는데, 

코드를 포함하여 적다보니 량이 적지않구나 하는걸 느낀 후로 조금 나눠서 글을 적게 되었습니다.


만약 여기까지 읽어주셨다면 정말 감사드리고, 궁금하신 점 있으시면 답글이나 이메일

redforce01@naver.com 으로 주시면 제가 아는 한에서 꼭 답변해드리겠습니다.




추신. getDeviceState() 함수가 여기서는 다뤄지지 않은 것 같습니다만,

추후에 reset() 함수를 다시 활용할 때 한번 더 정리 하여 올릴 예정입니다.



아래는 Graphics 클래스의 .h 파일과 .cpp 파일 전체 입니다.


헤더 코드입니다.


cpp 코드입니다.


'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #3_Image Class .cpp (1)  (0) 2017.04.19
June_Engine #3_Image (Class) & SpriteData (Struct)  (0) 2017.04.19
June_Engine #2_Graphics.cpp (2)  (0) 2017.04.17
June_Engine #2_Graphics.cpp (1)  (0) 2017.04.15
June_Engine #2_Graphics.h  (0) 2017.04.07
posted by REDFORCE 2017. 4. 17. 21:53

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics  (현재 글)

 + Image - SpriteData

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


Graphics Class의 핵심 내용에 이어서 나머지 함수들에 대해서 정리하도록 하겠습니다.


아래 코드는 Graphics class에서 제공해주는 VertexBuffer / Draw Quad / Draw Line 함수 입니다.



1. createVertexBuffer


VertexBuffer 라는 말에서 볼 수 있듯이


createVertexBuffer 함수는 directX를 공부하셨다면 Vertex 라는 개념을 이해할 수 있습니다.

이때 사용하는 함수인데, 모든 이미지나 어떤 출력물은 vertex라 하는 좌표점들을 통해 구성이 되어집니다.


특히 3D의 모델은 삼각형으로 이루어진 폴리곤의 집합체라 볼 수 있습니다.


마찬가지로 2D 에서도 Vertex를 이용한 Drawing이 필요할 때가 있습니다.


그 예시들은 다음에 기회가 되면 설명드리기로 하고, 지금은 일단 넘어가겠습니다.



2. DrawLine / DrawQuad


DrawLine과 DrawQuad는 Vertex를 이용하여 어떤 선 / 면을 그리는 함수 입니다.

인게임 자체에서 자주 이용할지 여부는 때에 따라 다르나,


맵툴에서의 타일 또는 간단한 테스팅을 위한 UI용도로는 상당히 편리한 함수입니다.




3. showBackBuffer


세 번째 showBackBuffer 함수는 매우 심플하여 별거 없어보이지만

의미 자체는 정말 중요한 함수입니다.


showBackBuffer의 내용을 보면 간단히 코드 한줄로만 이루어져 있습니다.

(return 문은 계산에서 제외..)


device3d->Present(NULL, NULL, NULL, NULL);


가 그 코드인데요.


present(NULL, NULL, NULL, NULL)로 주는 순간. 


Device에서는 "아~ 내가 출력할 것들다 넣어줬어? 그럼 이제 렌더링해야지~"

하고 받아들이게 됩니다.


결국 showbackbuffer 라는 함수는 매 프레임 렌더할 내용들이 끝나는 시점인 마지막에

호출하게 됩니다.



4. isAdapterCompatible


isAdapterCompatible 함수는 원래 initialize 를 다룰때 설명해드렸어야 했으나


제가 실수로 이제와서 언급하게 되었네요.


함수의 내용을 보면 UINT 값 modes 를 통해 현재 모니터의 어댑터 모드를 볼 수 있습니다. DVI라던지...HDMI라던지...그리고 받아온 값을 통해 전체화면으로 출력 할 시


adapter 값을 확인하고 화면의 width height 값 만큼 전체 화면으로 출력 해줍니다.



5. drawSprite


5번째로 설명할 drawSprite 함수는 Graphics 클래스에서 가장 많이 사용 되어지며


결과적으로 Graphics 클래스가 궁극적으로 'rendering' 이라는 역할을 수행하는

함수가 바로 drawSprite 입니다.




drawSprite 함수는 2가지 파라미터 값을 받습니다.


 (1) SprtieData 구조체 타입 값

 (2) 투명 적용시킬 컬러 값


SpriteData 구조체는 앞에서 몇번 언급했듯이 모든 이미지들이 담겨져있는 데이터 구조체 입니다.


SpriteData 구조체를 까먹으신 분들을 위해 다시 한번 SpriteData 구조체안에 어떤 정보들이 담겨있는지 다시 살펴보겠습니다.



구조체 안에 있는 정보들을 보면 


 (1) width / height  (텍스쳐 그림 크기)

 (2) x, y (출력할 x, y 좌표)

 (3) scale (스케일 크기)

 (4) angle (출력 할 그림의 각도)

 (5) rect (텍스쳐 안에서 출력 할 부분)

 (6) 기타..(texture / 반전 여부)


들이 있습니다. 위 항목들을 토대로 drawSprite 함수에서 필요한 내용들이 수행되어집니다.


차례대로 함수안의 내용을 나열해보겠습니다.


 A. spriteCenter : SpriteCenter 값은 출력 할 스프라이트(그림)의 센터를 받아옵니다.

 B. translate : 스크린상의 x, y 좌표로 변환 값

 C. scaling : SpriteData 안에 있는 scale 값을 토대로 이미지에 연산 시킬 스케일 값

 D. 좌우상하 반전 여부를 통해 센터값을 기준으로 상하좌우 반전을 계산합니다.

 E. D3DXMatrixTransformation2D 함수를 통해 연산 값들을 넣어 최종 D3DMATRIX (matrix)에 넣습니다.

 F. 나온 결과 값을 토대로 sprite에 matrix 값을 transform 시킵니다.

 G. 마지막으로 Draw 함수 수행.


위 과정을 간추려 요약하자면  3가지 단계로 이루어지게 됩니다.


 ① SpriteData구조체 값을 통해 출력 할 내용을 D3DMatrix 값으로 변환 

 ② LPD3DXSPRITE 에 SetTransform (위치나 스케일 등 Setup)

 ③ LPD3DXSPRITE Draw


첫 번째 과정이 조금 길게 느껴지실 수 있으나 한번 위와같이 설정해두면 우리는 어떤 그림이든 이제 이 함수 자체만을 통해 바로바로 그림을 출력 할 수 있게 됩니다.


계속해서 적으면 글이 너무 길어지므로, 이번 글에서는 DrawSprite 까지만 다루도록 하겠습니다.

'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #3_Image (Class) & SpriteData (Struct)  (0) 2017.04.19
June_Engine #2_Graphics.cpp (3)  (0) 2017.04.18
June_Engine #2_Graphics.cpp (1)  (0) 2017.04.15
June_Engine #2_Graphics.h  (0) 2017.04.07
June_Engine #1_MainNode  (0) 2017.04.07
posted by REDFORCE 2017. 4. 15. 01:51

#1. Engine System

 + WinMain - EngineSystem

 + EngineCore

 + EngineError

 + MainNode


#2. FrameWork

 + Grahpics  (현재 글)

 + Image - SpriteData

 + Layer

 + Input

 + Game

 + Manager

 + Game Interface

 + Utility


#3. Testing Module

 + 2D Image Test

 + 2D Animation Test

 + Game UI Test


-----------------------------------------------------------------------


이번 글에서는 Graphics 클래스의 cpp 파일을 확인하도록 하겠습니다.


먼저 헤더 내용을 정리하며 가리켰던 3가지 항목


A. struct VertexC

B. struct SpriteData

C. Class Graphics


를 다시 상기해볼 필요가 있습니다.


A. VertexC에 대해서 간략히 다시 설명하자면


앞으로 사용 할 모든 이미지들은 x,y 좌표가 필요한데, DirectX 상에서는 3D 좌표를 이용하므로

z 축 좌표가 하나 더 필요합니다.


그러나 여기서 다룰 2D 게임을 위한 엔진에서는 z 축은 사실 상 필요가 없습니다.

따라서 z 축 자체는 0 값으로 모두 보존됩니다.



B. SpriteData 구조체는 모든 이미지를 사용함에 있어 그 데이터를 가지고 있습니다.

출력할 스크린 상의 x, y 좌표, 텍스쳐(이미지) 정보, 텍스쳐에서 어떤 부분을 사용할 것인지 RECT 값 등.


Graphics 클래스에서는 이 SpriteData 구조체를 주소 값 형식( * 가 아닌 & 연산자)으로 받아옴으로 원하고자 하는 SpriteData 정보를 이용하여 이미지를 출력합니다.



C. Graphics Class의 .cpp 내용을 지금 부터 확인해보겠습니다.



1. 생성자 ( Constructor )와 소멸자


생성자 구역은 헤더에서 선언한 주요 Graphics 클래스의 멤버들을 초기화합니다.

별 다른 특별한 내용은 없습니다.



소멸자는 releaseAll 함수를 호출하여 연결되어있던 내용들을 해지합니다.



releaseAll( ) 에서 사용한 safeRelease( ) 함수는 템플릿 형태로 미리 만들어 둔 매크로 입니다.




2. Initialize


이어서 Graphics Class의 시작인 initialize( )를 살펴보겠습니다.


initialize 의미 자체대로 모든 초기화에 대한 진행을 이곳에서 합니다.



주요 내용을 천천히 살펴보면 먼저 파라미터


 (1) 생성된 윈도우 핸들 값 (HWND) 

 (2) width / height 값 (int)

 (3) fullscreen 여부 (bool)


값들을 받습니다. 

그리고 direct3d 초기화에 들어갑니다.


위에서 보여지는 DirectX 초기화 설정에 대한 내용은 여기서 다루진 않겠습니다.

(추후 DirectX 관련 글을 올리면서 어떤 내용들이었는지 언급하여 다루겠습니다)


어 일단 이거 코드를 활용 해보고 싶은데? 라는 분들은 그대로 가져가셔서 쓰시되 필요한 설정에 대한 부분만 본인에 맞게 바꾸시면 될 것 같습니다.



3. LoadTexture


LoadTexture 함수는 Graphics Class Initialize 중에 생성 한 DirectX Device에

Texture를 올리는 함수입니다.


간단히 비유하여 설명드리자면,


2. Initialize에서 Direct9Device 라는 상자를 만들었고

LoadTexture 함수는 그 상자안에 Texture라는 내용들을 담아주는 거라 보시면 됩니다.



LoadTexture 함수는 파라미터 값으로 다음의 내용들을 받습니다.


 (1) fileName (const char*) - 파일 경로

 (2) transColor ( COLOR_ARGB ) - 걸러 내고싶은 컬러 값

 (3) width / height ( UINT [unsigned int] ) - 불러 올 텍스쳐 크기

 (4) &texture ( LP_TEXTURE ) - 텍스쳐의 주소 값


아래는 LoadTexture 함수 전체입니다.


간단히 설명하자면 


 (1) 파라미터로 받아온 파일 경로를 통해 이미지 정보를 생성

 (2) 텍스쳐 정보 생성 및 device에 입력


순으로 들어갑니다.


위 함수가 기본적인 텍스쳐 정보들을 Device에 담아주는 함수입니다만

아래와 같이 만약 시스템 메모리를 사용하여 텍스쳐를 담고 싶을 경우에는 


로드 텍스쳐 함수를 다음과 같이 이용합니다.



Graphics Class의 주요 핵심 내용은 이렇게 위 3가지로 좁혀집니다만.


다음 글 부터 나머지 Graphics class의 내용에 대해서 정리하도록 하겠습니다.

'MyProject > SephyEngine' 카테고리의 다른 글

June_Engine #2_Graphics.cpp (3)  (0) 2017.04.18
June_Engine #2_Graphics.cpp (2)  (0) 2017.04.17
June_Engine #2_Graphics.h  (0) 2017.04.07
June_Engine #1_MainNode  (0) 2017.04.07
June_Engine #1_EngineError.h  (0) 2017.04.07