<토이프로젝트>/[C++ SFML 게임]

[C++ SFML 게임] 화살표 디펜스

BlockDMask 2020. 9. 27. 11:10
반응형

안녕하세요. BlockDMask 입니다.
오늘은 제가 SFML C++ 을 이용해서 만들었던 마지막 게임인 Arrow Defense 라는 게임을 저 폴더 구석탱이에 있는걸 발견해서 가지고 왔습니다.

<목차>
1. 간단한 게임 설명
2. 게임 영상
3. 소스코드와 깃허브 주소


1. 간단한 게임 설명


> SFML Arrow Defense 게임 설명

C++ SFML 으로 만든 간단한 게임 입니다. 제가 이름을 화살표 디펜스라고 지었습니다.

이 게임은 화살표가 나오는 순서대로 같은 방향의 화살표를 입력하면 되는 간단한 게임 입니다. 맨 좌측에 있는 빨간색 라인에 화살표가 닿게 되면 게임이 끝납니다.

SFML은 간단히 설명하자면 게임(멀티미디어)를 편하게 만들 수 있게 도와주는 함수들을 모아둔 라이브러리 입니다. C++로 만들어져 있습니다.


> 코드를 보기전에 알면 좋을 지식

1. C++ STL deque [바로가기]
이 게임에서는 화살표들을 담기 위해서 deque 컨테이너를 사용하였습니다. 맨 뒤에 화살표가 계속 채워지고, 유저가 맨앞에 화살표를 맞추면 맨 앞에 화살표가 살아져야 하기 때문에 deque를 이용해서 해당 작업을 편리하게 하였습니다.
deque의 push_back 멤버 함수를 이용해서 맨 뒤에 화살표를 넣어주고
deque의 pop_front 멤버 함수를 이용해서 맨 앞의 화살표를 제거 해주었습니다.
deque에 대해서 궁금하시다면 [바로가기] 에 가시면 더 자세한 포스팅이 준비되어있습니다.

2. 랜덤을 생성 하는 방법 [바로가기]
이 게임에서 화살표의 방향이 4방향으로 랜덤하게 생성을 하기 위해서, 랜덤 함수를 이용했습니다.
srand(static_cast<unsigned int>(time(nullptr))); 을 이용해서 시간 값을 srand의 시드값으로 넣어주고
rand() % 4 를 이용해서 4방향을 랜덤하게 만들 수 있도록 하였습니다.
랜덤함수, 난수 생성에 대해서 더 궁금하시다면 [바로가기] 에 가시면 더 자세한 포스팅이 있습니다.


2. 게임 영상


영상 주소 : https://youtu.be/FmAmkHbaLQU

3. 소스코드와 깃허브 주소


깃허브에는 소스코드와 이미지 파일을 업로드 해두었습니다.

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
//Youtube : https://youtu.be/FmAmkHbaLQU
//Blog : https://blockdmask.tistory.com/431
 
#include<SFML/Graphics.hpp>
#include<iostream>
#include<deque>
#include<time.h>
 
using namespace sf;
using namespace std;
 
#define WIDTH 1000
#define HEIGHT 300
 
struct ArrowShape
{
    int direction;
    int x;
    int y;
};
 
class Arrow
{
private:
    enum Dir
    {
        UP = 0,
        DOWN,
        LEFT,
        RIGHT,
    };
 
    Texture t;
    Sprite s;
    deque<ArrowShape> questions;
 
    float frame;
    float frameSpeed;
    int frameLimit;
    int dir[4= { -90901800 };
private:
    bool CheckArrow(int idx)
    {
        if (questions.empty()) return false;
        if (idx == questions[0].direction)
        {
            cout << "correct" << endl;
            return true;
        }
        return false;
    }
 
public:
    Arrow()
    {
        srand(static_cast<unsigned int>(time(nullptr)));
 
        t.loadFromFile("images/arrow.png");
        s = Sprite(t);
        Rect<float> rect = s.getGlobalBounds();
        s.setOrigin(Vector2f(rect.width / 2, rect.height / 2));
        frame = 20.f;
        frameSpeed = 0.6f;
        frameLimit = 20;
    }
    ~Arrow() {}
 
    void Init()
    {
        questions.clear();
    }
 
    bool CheckKey()
    {
        if (Keyboard::isKeyPressed(Keyboard::Up))
        {
            cout << "UP" << endl;
            return CheckArrow(Dir::UP);
        }
        if (Keyboard::isKeyPressed(Keyboard::Down))
        {
            cout << "DOWN" << endl;
            return CheckArrow(Dir::DOWN);
        }
        if (Keyboard::isKeyPressed(Keyboard::Left))
        {
            cout << "LEFT" << endl;
            return CheckArrow(Dir::LEFT);
        }
        if (Keyboard::isKeyPressed(Keyboard::Right))
        {
            cout << "RIGHT" << endl;
            return CheckArrow(Dir::RIGHT);
        }
        return false;
    }
 
    void ArrowSetting()
    {
        //check frame
        frame += frameSpeed;
        if (frame <= frameLimit) return;
        frame -= frameLimit;
 
        //check arrow number
        if (questions.size() > 10return;
        ArrowShape as;
 
        int dirIdx = rand() % 4;
        as.direction = dirIdx;
        as.x = WIDTH;
        as.y = 100;
        s.setPosition(as.x, as.y);
        questions.push_back(as);
    }
 
    void Move(const int& speed, bool& isGameOver)
    {
        deque<ArrowShape>::iterator iter;
        for (iter = questions.begin(); iter != questions.end(); ++iter)
        {
            iter->-= speed;
            if (iter-><= 0)
            {
                //gameover;
                isGameOver = true;
                break;
            }
        }
    }
 
    void Draw(RenderWindow& _window)
    {
        for (auto iter = questions.begin(); iter != questions.end(); ++iter)
        {
            s.setRotation(dir[iter->direction]);
            s.setPosition(iter->x, iter->y);
            _window.draw(s);
        }
    }
 
    ArrowShape GetFirstArrowPos()
    {
        return questions[0];
    }
 
    void RemoveFirstArrow()
    {
        if (questions.empty()) return;
        questions.pop_front();
    }
 
    bool IsEmpty() const
    {
        return questions.empty();
    }
};
cs

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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
 
class GameManager
{
private:
    enum GameState
    {
        NONE,
        CORRECT,
        WRONG,
    };
    int arrowSpeed;
    bool isGameOver;
    Arrow* pArrow;
 
    Texture tw;
    Texture tl;
    Sprite imgWrong;
    Sprite imgDeadLine;
    GameState state;
    ArrowShape firstArrowPos;
public:
    GameManager() 
    {
        arrowSpeed = 10;
        isGameOver = false;
        pArrow = new Arrow();
        state = NONE;
 
        tw.loadFromFile("images/wrong.png");
        tl.loadFromFile("images/line.png");
        imgWrong = Sprite(tw);
        imgDeadLine = Sprite(tl);
        imgDeadLine.setPosition(045);
 
        Rect<float> rect = imgWrong.getGlobalBounds();
        imgWrong.setOrigin(Vector2f(rect.width / 2, rect.height / 2));
    }
 
    void Init()
    {
        pArrow->Init();
    }
 
    void CheckKey()
    {
        if (pArrow->IsEmpty()) return;
 
        if (pArrow->CheckKey()) 
        {
            //correct
            firstArrowPos = pArrow->GetFirstArrowPos();
            pArrow->RemoveFirstArrow();
            state = CORRECT;
        }
        else
        {
            //wrong
            firstArrowPos = pArrow->GetFirstArrowPos();
            pArrow->RemoveFirstArrow();
            state = WRONG;
        }
    }
 
    void Move()
    {
        pArrow->ArrowSetting();
        pArrow->Move(arrowSpeed, isGameOver);
    }
 
    void Draw(RenderWindow& window)
    {
        switch (state)
        {
        case WRONG:
            //game over.
            state = NONE;
            imgWrong.setPosition(firstArrowPos.x, firstArrowPos.y);
            window.draw(imgWrong);
            isGameOver = true;
            break;
        case CORRECT:
            //score up.
            state = NONE;
            break;
        }
        pArrow->Draw(window);
 
        window.draw(imgDeadLine);
    }
    void CheckGameOver()
    {
        if (isGameOver)
        {
            sleep(seconds(3));
            isGameOver = false;
            Init();
        }
    }
};
 
int main(void)
{
    RenderWindow window(VideoMode(WIDTH, HEIGHT), "Arrow Defense. By BlockDMask.");
    window.setFramerateLimit(60);
 
    GameManager* pGameMgr = new GameManager();
    pGameMgr->Init();
    while (window.isOpen())
    {
        Event e;
        while (window.pollEvent(e))
        {
            if (e.type == Event::Closed)
            {
                window.close();
            }
            if (e.type == Event::KeyPressed)
            {
                pGameMgr->CheckKey();
            }
        }
        //logic.
        pGameMgr->Move();
 
        //draw.
        window.clear(Color::Black);
        pGameMgr->Draw(window);
        window.display();
 
        pGameMgr->CheckGameOver();
    }
    delete(pGameMgr);
    return 0;
}
cs


감사합니다. 이상으로 C++ SFML로 만든 Arrow defense 게임 소개를 마치겠습니다.

반응형