Software Development/C, C++

C언어로 게임만들기 - 3. 렌더링 기능 구현

huiyu 2017. 3. 15. 22:50

참고페이지 : C로 게임만들기 3장-게임의 기본


프레임워크란?

 - 소프트웨어 제작이 편리하도록 미리 뼈대를 이루는 클래스와 인터페이스를 제작해놓은 틀/구조


게임 프레임워크란?

 - 게임 제작에 필요한 기본 구조 및 긱능을 만들어 놓는 것을 말한다. 게임을 화면에 표시하기 위한 기본 기능들은 미리 구현해  두고, 실제 게임을 제작할때는 이 틀에 맞게 게임의 기능만 만들면 된다.


C언어 콘솔 게임 프레임워크에 필요한 기능

- ScreenInit() : 화면 버퍼 초기화, 전위버퍼-백버퍼 두개 생성
- ScreenClear() : 하나의 버퍼가 그려지고 있는 동안, 다음 장면을 위한 버퍼는 지워져야 한다.
- ScreenFliping() : 환성화된 버퍼와 비활성화된 버퍼의 상태를바꾸는 함수
- ScreenRelease() :  생성한 두개의 버퍼를  모두 해제하는 함수
- ScreenPrint(int x, int y, char* string) :  x,y 좌표에  string출력
- SetColor(unsigned short color) :  화면에 출력할 문자색상값 지정


기존에 만들어 놓았던  게임 구조에 적용하면, 아래와 같이 작성할 수  있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<stdio.h>
#include<time.h>
#include<conio.h>
 
void Init()
{
}
 
void Update()
{
}
 
void Render()
{
    ScreenClear();
    //출력코드
    ScreenFlipping();
}
 
void Release()
{
}
 
int main()
{
    int nKey;
    clock_t CurTime, OldTime;
    ScreenInit();
    Init();//초기화
 
    while (1)
    {
        if (_kbhit())
        {
            nKey = _getch();
            if (nKey == 'q')
                break;
            switch (nKey)
            {
            case 'j':
                break;
            case 'l':
                break;
            }
        }
        OldTime = clock();
        Update();//데이터 갱신
        Render();//화면 출력
        while (1)
        {
            CurTime = clock();
            if (CurTime - OldTime > 33)
                break;
        }
    }
    Release();//해제
    ScreenRelease();
    return 0;
}

cs

Render() 함수의 내부는 GL과 유사한 구조라고  할 수 있다.

그릴 버퍼를지우고 -> 출력 코드 ->  화면에 그리기

1
2
3
4
5
6
7
8
void Render()
{
    glClear(GL_COLOR_BUFFERR_BIT);
    glBegin(GL_POLYGON);
    //출력코드
    glEnd();
    glFlush();
}
cs


위와 같은 기능을 실제로 하는  Screen.h와 Screen.c는  아래와 같다.

Screen.h

1
2
3
4
5
6
void ScreenInit();
void ScreenFlipping();
void ScreenClear();
void ScreenRelease();
void ScreenPrint(int x, int y, char* string);
void SetColor(unsigned short color);
cs

Screen.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <windows.h>
 
static int g_nScreenIndex;
static HANDLE g_hScreen[2];
 
void ScreenInit()
{
    CONSOLE_CURSOR_INFO cci;
 
    //화면 버퍼 2개를 만든다.
    g_hScreen[0= CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 
0NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    g_hScreen[1= CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 
0NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
 
    //커서 숨기기
    cci.dwSize = 1;
    cci.bVisible = FALSE;
    SetConsoleCursorInfo(g_hScreen[0], &cci);
    SetConsoleCursorInfo(g_hScreen[1], &cci);
}
 
void ScreenFlipping()
{
    SetConsoleActiveScreenBuffer(g_hScreen[g_nScreenIndex]);
    g_nScreenIndex = !g_nScreenIndex;
}
 
void ScreenClear()
{
    COORD Coor = { 0,0 };
    DWORD dw;
    FillConsoleOutputCharacter(g_hScreen[g_nScreenIndex], ' '80 * 25, Coor, &dw);
}
 
void ScreenRelease()
{
    CloseHandle(g_hScreen[0]);
    CloseHandle(g_hScreen[1]);
}
 
void ScreenPrint(int x, int y, char* string)
{
    DWORD dw;
    COORD CursorPosition = { x, y };
    SetConsoleCursorPosition(g_hScreen[g_nScreenIndex], CursorPosition);
    WriteFile(g_hScreen[g_nScreenIndex], string, strlen(string), &dw, NULL);
 
}
 
void SetColor(unsigned short color)
{
    SetConsoleTextAttribute(g_hScreen[g_nScreenIndex], color);
}
cs

간단하게 사용하고 있는  API를 설명하면,(API 이름을 보면 무슨기능인지 유추가 가능하다)

#include <windows.h>-> https://en.wikipedia.org/wiki/Windows
- windows관련  헤더파일로 Windows API의 모든 함수에 대한 선언(매크로, 함수 및 하위  시스템)이 포함되어 있다. 

1.   ScreenInit() :  두개의 버퍼 생성  후, 커서 설정
- CreateConsoleScreenBuffer()->참고
      : Screen Buffer를 생성한다. 여기선 두개의 버퍼를 생성하여,  Flipping을 구현하고 있다.
- CONSOLE_CURSOR_INFO  ->참고
      : 콘솔의 커서에 대한 정보를 갖고 있다.
      : dwSize  :  커서로 채워지는 문자 셀의  비율(1~100)
      : bVisible : 화면  표시 여부
- SetConsoleCursorInfo->
      : 생성한  스크린 버퍼에 정의한 커서의 정보를 설정한다.

2. ScreenFlipping() : 버퍼 교환, 활성화된 버퍼를 화면에 그린다.
- SetConsoleActiveScreenBuffer : 이함수가 위에말한 그 역할, 파라미터로 넘겨주는 버퍼를 콘솔화면에 그린다. ->참고

3. ScreenClear() : 화면을 지워준다.
- FillConsoleOutputCharacter -> 참고
: FillConsoleOutputCharacter(buffer, ' ', 80*25, Coor(0,0), &dw) -> buffe에 0,0(x,y)부터 시작하여 80x25만큼 ' '로 채운다. dw값은 버퍼에 실제 기록된 문자수를 받는 변수 포인터

4. ScreenRelease() : 화면 해제, CloseHandle()

5. ScreenPrrint(int x, int y, char* sting) : x,y 좌표에 string 출력, SetConsoleCursorPosition()으로 좌표 이동, WriteFile()함수로 string입력

6. SetColor() : 색상 변경, SetConsoleTextAttribute()


이제 Screen.h만 포함시켜주면 렌더링 기능은 완료되게 된다.


이제 완성된 소스에 FPS를 출력해보면 아래와 같이 완성된다.
*FPS란, Frame Per Second로 1초당 출력되는 프레임 수를 의미한다.

저의 경우엔 아래 노란 음영과 같이 만들었습니다.
한번 렌더링 될때마다 그리는 프레임의 갯수를 counting 한 후,
1초(1000ms)가 되었을 때 프레임 갯수를 출력합니다. 그 후 다시 초기화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<stdio.h>
#include<time.h>
#include<conio.h>
#include<malloc.h>
#include"screen.h"
 
clock_t FPSCurTime, FPSOldTime;
int FrameCnt;
char *FPSTextBuffer;
 
void Init()
{
    FrameCnt = 0;
    FPSTextBuffer = (char*)malloc(sizeof(char* 10);
    sprintf(FPSTextBuffer, "FPS:%d", FrameCnt);
    FPSOldTime = clock();
}
 
void Update() 
{
}
 
void Render()
{
    ScreenClear();
    //출력코드
    FrameCnt++;
    FPSCurTime = clock();
    if (FPSCurTime - FPSOldTime >= 1000)
    {
        sprintf(FPSTextBuffer, "FPS:%d", FrameCnt);
        FPSOldTime = clock();
        FrameCnt = 0;
    }
 
    ScreenPrint(00, FPSTextBuffer);
 
    //ScreenPrint(0, 0, FPSTextBuffer);
    ScreenFlipping();
}
 
void Release()
{
    free(FPSTextBuffer);
}
 
int main()
{
    int nKey;
    clock_t CurTime, OldTime;
    ScreenInit();
    Init();//초기화
 
    while (1)
    {
        if (_kbhit())
        {
            nKey = _getch();
            if (nKey == 'q')
                break;
            switch (nKey)
            {
            case 'j':
                break;
            case 'l':
                break;
            }
        }
        OldTime = clock();
        Update();//데이터 갱신
        Render();//화면 출력
        while (1)
        {
            CurTime = clock();
            if (CurTime - OldTime > 33)
                break;
        }
    }
    Release();//해제
    ScreenRelease();
    return 0;
}
cs


출력된 화면,



728x90