<토이프로젝트>/[C언어 게임]

[C언어 게임] 구글 공룡 게임 만들기 (충돌처리 추가)

BlockDMask 2019. 4. 19. 00:45
반응형

안녕하세요. BlockDMask 입니다.

C언어나 C++을 책만보고 공부만하면 재미가 없잖아요. 그래서 제가 간단한 게임을 만들어서 소개해보려 합니다.

제가 만든 게임이 게임성이 없는 프로그램 일 수 있습니다. 순전히 예제, 연습용 게임들이니 너그럽게 이해해주시면 감사하겠습니다.


오늘은 "C/C++로 게임을 만들어보자" 그 첫번째 게임인 "구글 공룡 게임"을 만들어 보았습니다.

사실 게임이라고 하기도 좀 그런게, 충돌판정이나 게임오버 점수주기 이런게 아무것도 없이, 캐릭터 움직임, 점프, 장애물 이동하기 이 세개만 만들어 보았습니다.


이영상을 통해서 "아 C/C++을 이용해서 이렇게 간단히 게임을 만들 수 있구나"를 보여드리고 싶었습니다.

<목차>

1. 게임 이름 및 설명

2. 게임영상

3. C언어 구글 게임 소스 코드 v1.0 (공룡 움직임, 점프, 나무 움직이기 등 기본 세팅)

4. 공룡 게임 소스코드 v2.0 (충돌, 시간에따른 점수 추가)


1. 게임이름 및 설명


▶ C/C++로 만든 구글 공룡 게임


▶ 구글 공룡게임 v1.0

1. z를 누르면 점프를 할 수 있습니다.

2. 공룡의 발을 번갈아 가며 출력합니다.

3. 장애물이 생성 됩니다.


2. 게임영상 (v1.0)


영상 바로가기 : https://youtu.be/TXSmQ6tpRQ4
영상 댓글에 공룡 모양을 복사할 수 있도록 댓글에 작성해 놓았습니다.


3. 소스코드(v1.0)


코드에 주석을 최대한 자세히 달았으니, 주석을 보고도 이해가 가지 않는다면 댓글 달아주시면 답변 드리겠습니다.


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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//[C/C++ game] very simple google dinosaur.
//BlockDMask. 
#include<stdio.h>
#include<Windows.h>
#include<conio.h>
#define DINO_BOTTOM_Y 12
#define TREE_BOTTOM_Y 20
#define TREE_BOTTOM_X 45
 
//콘솔 창의 크기와 제목을 지정하는 함수
void SetConsoleView()
{
    system("mode con:cols=100 lines=25");
    system("title Google Dinosaurs. By BlockDMask");
}
 
//커서의 위치를 x, y로 이동하는 함수
void GotoXY(int x, int y)
{
    COORD Pos;
    Pos.X = 2 * x;
    Pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}
 
//키보드의 입력을 받고, 입력된 키의 값을 반환하는 함수
int GetKeyDown()
{
    if (_kbhit() != 0)
    {
        return _getch();
    }
    return 0;
}
 
void DrawDino(int dinoY)
{
    GotoXY(0, dinoY);
    static bool legFlag = true;
    printf("        $$$$$$$ \n");
    printf("       $$ $$$$$$\n");
    printf("       $$$$$$$$$\n");
    printf("$      $$$      \n");
    printf("$$     $$$$$$$  \n");
    printf("$$$   $$$$$     \n");
    printf(" $$  $$$$$$$$$$ \n");
    printf(" $$$$$$$$$$$    \n");
    printf("  $$$$$$$$$$    \n");
    printf("    $$$$$$$$    \n");
    printf("     $$$$$$     \n");
    if (legFlag)
    {
        printf("     $    $$$    \n");
        printf("     $$          ");
        legFlag = false;
    }
    else
    {
        printf("     $$$  $     \n");
        printf("          $$    ");
        legFlag = true;
    }
}
 
void DrawTree(int treeX)
{
    GotoXY(treeX, TREE_BOTTOM_Y);
    printf("$$$$");
    GotoXY(treeX, TREE_BOTTOM_Y + 1);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 2);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 3);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 4);
    printf(" $$ ");
}
 
int main(void)
{
    SetConsoleView();
 
    bool isJumping = false;
    bool isBottom = true;
    const int gravity = 3;
 
    int dinoY = DINO_BOTTOM_Y;
    int treeX = TREE_BOTTOM_X;
 
    while (true)
    {
        //z키가 눌렸고, 바닥이 아닐때만 점프가능.
        if (GetKeyDown() == 'z' && isBottom)
        {
            isJumping = true;
            isBottom = false;
        }
 
        //점프중 = y감소
        //점프끝 = y증가
        if (isJumping)
        {
            dinoY -= gravity;
        }
        else
        {
            dinoY += gravity;
        }
 
        //Y가 계속해서 증가하는걸 막기위해 바닥을 지정.
        //Y가 증가한다는 것은 공룡이 아래로 내려온다는 뜻.
        if (dinoY >= DINO_BOTTOM_Y)
        {
            dinoY = DINO_BOTTOM_Y;
            isBottom = true;
        }
 
        //점프의 맨 위를 찍으면 점프가 끝난 상황
        if (dinoY <= 3)
        {
            isJumping = false;
        }
 
        //나무가 왼쪽으로 가도록 하고(x의 음수방향)
        //나무의 위치가 왼쪽 끝으로가면 다시 초기 위치로 소환
        treeX -= 2;
        if (treeX <= 0)
        {
            treeX = TREE_BOTTOM_X;
        }
 
        DrawDino(dinoY);    //draw dino
        DrawTree(treeX);    //draw tree
        Sleep(80);
        system("cls");    //clear
    }
    system("pause");
    return 0;
}
cs


4. 구글 공룡게임 소스코드 충돌처리 및 시간 추가

▶ 구글 공룡게임 v2.0

1. 시간에 따라서 점수가 올라가도록 코드 추가하였습니다.

2. 충돌 처리를 넣어달라는 요청이 있어서 간단하게 한번 넣어 보았습니다.


▶ 충돌 처리 간단 설명

간단하게 충돌을 설명해보겠습니다. 제가 직접 그림을 그려보았습니다.
일단 이 게임에서 x, y는 왼쪽위부터 0,0 이고 
오른쪽으로 갈수록 x가 증가하고
아래쪽으로 갈수록 y가 증가하는 구조 입니다.


우리가 현재 가지고 있는것은 공룡의 Y축 좌표와 나무의 X좌표 뿐입니다. 
따로 좌표를 추가하지않고 우리는 이 두가지 좌표를 통해서 "충돌" 체크를 할 수 있습니다.

말로 한번 설명 드리겠습니다.
나무의 위치X가 공룡몸통에 위치하고 && 공룡의 높이(Y위치)가 적당히 낮을때 충돌이다!
이렇게 판단할 수 있습니다. 그쵸?

그림으로 한번 표현해보겠습니다.

이해가 쑥쑥 가시죠..?

공룡의 머리 기준으로 출력하기 때문에 공룡이 평소에는 y가 12인데 점프를 뛰면 대략 3까지 올라가더군요

그래서 중간 정도인 6정도가 딱 바 에서 나무가 오면 부딪히는걸로 간주하겠다고. 코드를 작성한 것이고


나무의 위치를 보니 공룡쪽으로 오는 X가 4~8 정도가 적당하다고 판단했습니다.

그래서 생겨난 코드가 bool isCollision(const int treeX, const int dinoY) 이 함수입니다.

해당함수 내부를 보면

if (treeX <= 8 && treeX >= 4 && dinoY > 8)

만약에 X(나무)의 위치가 4~8 사이이고 공룡 머머리의 Y가 8보다 높을때(바닥에 가까울때) 충돌했다! 라고 판단하면됩니다.



▶ 구글 공룡게임 v2.0 움짤


공룡이 나무에 부딪히면 게임오버 하는걸 확인할 수 있습니다.


▶ 소스코드
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//[C/C++ game] very simple google dinosaur. (by. BlockDMask)
//2019.12.03 (v2.0)점수 추가, 충돌처리 추가.
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#define DINO_BOTTOM_Y 12
#define TREE_BOTTOM_Y 20
#define TREE_BOTTOM_X 45
 
//콘솔 창의 크기와 제목을 지정하는 함수
void SetConsoleView()
{
    system("mode con:cols=100 lines=25");
    system("title Google Dinosaurs. By BlockDMask.");
}
 
//커서의 위치를 x, y로 이동하는 함수
void GotoXY(int x, int y)
{
    COORD Pos;
    Pos.X = 2 * x;
    Pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}
 
//키보드의 입력을 받고, 입력된 키의 값을 반환하는 함수
int GetKeyDown()
{
    if (_kbhit() != 0)
    {
        return _getch();
    }
    return 0;
}
 
//공룡을 그리는 함수
void DrawDino(int dinoY)
{
    GotoXY(0, dinoY);
    static bool legFlag = true;
    printf("        $$$$$$$ \n");
    printf("       $$ $$$$$$\n");
    printf("       $$$$$$$$$\n");
    printf("$      $$$      \n");
    printf("$$     $$$$$$$  \n");
    printf("$$$   $$$$$     \n");
    printf(" $$  $$$$$$$$$$ \n");
    printf(" $$$$$$$$$$$    \n");
    printf("  $$$$$$$$$$    \n");
    printf("    $$$$$$$$    \n");
    printf("     $$$$$$     \n");
    if (legFlag)
    {
        printf("     $    $$$    \n");
        printf("     $$          ");
        legFlag = false;
    }
    else
    {
        printf("     $$$  $     \n");
        printf("          $$    ");
        legFlag = true;
    }
}
 
//나무를 그리는 함수
void DrawTree(int treeX)
{
    GotoXY(treeX, TREE_BOTTOM_Y);
    printf("$$$$");
    GotoXY(treeX, TREE_BOTTOM_Y + 1);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 2);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 3);
    printf(" $$ ");
    GotoXY(treeX, TREE_BOTTOM_Y + 4);
    printf(" $$ ");
}
 
//(v2.0) 충돌 했을때 게임오버 그려줌
void DrawGameOver(const int score)
{
    system("cls");
    int x = 18;
    int y = 8;
    GotoXY(x, y);
    printf("===========================");
    GotoXY(x, y + 1);
    printf("======G A M E O V E R======");
    GotoXY(x, y + 2);    
    printf("===========================");
    GotoXY(x, y + 5);
    printf("SCORE : %d", score);
 
    printf("\n\n\n\n\n\n\n\n\n");
    system("pause");
}
 
//(v2.0) 충돌했으면 true, 아니면 false
bool isCollision(const int treeX, const int dinoY)
{
    //트리의 X가 공룡의 몸체쪽에 있을때,
    //공룡의 높이가 충분하지 않다면 충돌로 처리
    GotoXY(00);
    printf("treeX : %d, dinoY : %d", treeX, dinoY); //이런식으로 적절한 X, Y를 찾습니다.
    if (treeX <= 8 && treeX >= 4 &&
        dinoY > 8)
    {
        return true;
    }
    return false;
}
 
int main()
{
    SetConsoleView();
 
    while (true)        //(v2.0) 게임 루프
    {
        //게임 시작시 초기화
        bool isJumping = false;
        bool isBottom = true;
        const int gravity = 3;
        
        int dinoY = DINO_BOTTOM_Y;
        int treeX = TREE_BOTTOM_X;
        
        int score = 0;
        clock_t start, curr;    //점수 변수 초기화
        start = clock();        //시작시간 초기화
 
        while (true)    //한 판에 대한 루프
        {
            //(v2.0) 충돌체크 트리의 x값과 공룡의 y값으로 판단
            if(isCollision(treeX, dinoY))
                break;
 
            //z키가 눌렸고, 바닥이 아닐때 점프
            if (GetKeyDown() == 'z' && isBottom)
            {
                isJumping = true;
                isBottom = false;
            }
 
            //점프중이라면 Y를 감소, 점프가 끝났으면 Y를 증가.
            if (isJumping)
            {
                dinoY -= gravity;
            }
            else
            {
                dinoY += gravity;
            }
 
            //Y가 계속해서 증가하는걸 막기위해 바닥을 지정.
            if (dinoY >= DINO_BOTTOM_Y)
            {
                dinoY = DINO_BOTTOM_Y;
                isBottom = true;
            }
 
            //나무가 왼쪽으로 (x음수) 가도록하고
            //나무의 위치가 왼쪽 끝으로가면 다시 오른쪽 끝으로 소환.
            treeX -= 2;
            if (treeX <= 0)
            {
                treeX = TREE_BOTTOM_X;
            }
 
            //점프의 맨위를 찍으면 점프가 끝난 상황.
            if (dinoY <= 3)
            {
                isJumping = false;
            }
 
            DrawDino(dinoY);        //draw dino
            DrawTree(treeX);        //draw Tree
 
            //(v2.0)
            curr = clock();            //현재시간 받아오기
            if (((curr - start) / CLOCKS_PER_SEC) >= 1)    // 1초가 넘었을떄
            {
                score++;    //스코어 UP
                start = clock();    //시작시간 초기화
            }
            Sleep(60);
            system("cls");    //clear
 
            //(v2.0) 점수출력을 1초마다 해주는것이 아니라 항상 출력해주면서, 1초가 지났을때 ++ 해줍니다.
            GotoXY(220);    //커서를 가운데 위쪽으로 옮긴다. 콘솔창이 cols=100이니까 2*x이므로 22정도 넣어줌
            printf("Score : %d ", score);    //점수 출력해줌.
        }
 
        //(v2.0) 게임 오버 메뉴
        DrawGameOver(score);
    }
    return 0;
}
cs

C언어로 구글 공룡게임 만들기 이상입니다.
질문이 있다면 아래 댓글로 남겨주세요.
간단한 공룡게임 특성상 더이상 확장할것은 없을것 같네요.

반응형