/
Game.cpp
334 lines (275 loc) · 9.53 KB
/
Game.cpp
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
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#include "Game.h"
//initialising the vector
std::vector<Entity*> Game::EntityList;
/**
* Constructor for the Game Class
*/
Game::Game(){
displaySurface = NULL;
running = true;
paused = false;
timeQueued = 0;
scorestring = "";
score = 0;
theend = false;
maxEntities = 10;
currentEntities = 0;
}
/**
* Destructor for the Game Class
*/
Game::~Game(){
}
/**
* Gets called when the game is started, moves everything out of main
* When this function exits the game exits
*/
int Game::Run(){
win = new Window(1280,760);
//The gmae timers start and end
Stopwatch time;
//Calls the init function to initilise everything
if(init() == false){
return -1;
}
//Gets the surface of the screen
displaySurface = win->getGraphics();
//initialises SDLs event handler
SDL_Event event;
//Gets a timestamp for calculating delta times between ticks
double oldTime = GetTime();
//Start the timer
time.start();
//The main game loop
while(running){
//initialises the player entity velocity to 0,
//this resets velocity on each loop to prevent the player from carrying
// on in one direction after the movement keys have stopped being pressed
entity.velocityX = 0;
entity.velocityY = 0;
//Checks to see if an event has occured,
while(SDL_PollEvent(&event)){
onEvent(&event);
}
//Calculates the delta time for dealing with the tick since last loop
const double newTime = GetTime();
double dt = newTime - oldTime;
oldTime = newTime;
//Deals with all game state changes
loop(dt);
//deals with all rendering
win->setText(" Score: " + std::to_string(score) + " Time Left: " + std::to_string(60-(int)(time.read()/1000)) + "s");
render();
if(time.read() > 60000 && !theend){
theend = true;
time.stop();
std::ofstream score;
score.open("score.txt", std::ios::ate | std::ios::out);
score << "Last score: " << this->score << "\n" << scorestring;
score.flush();
score.close();
running=false;
while(SDL_WaitEvent(&event)){
if(event.key.keysym.sym == SDLK_RETURN)
break;
}
}
}
//this is only called when the game is exiting, makes sure the game exits cleanly with all memory cleared correctly
cleanUp();
return 0;
}
/**
* Loads all the graphics and sets some initial conditions in SDL such as allowing for keys held down to retrigger events
*/
bool Game::init(){
//initialises the random seed using the current timestamp
srand(time(NULL));
//Loads the background image
if(background.onLoad("./images/background.bmp", 1280,720,1)==false){
return false;
}
//loads the player image
if(entity.onLoad("./images/player.bmp", 64,64,8)==false){
return false;
}
//pushes the background entity to the back of the Entity vector
EntityList.push_back(&background);
//pushes the player entity to the back of the Entity vector
EntityList.push_back(&entity);
//enables repeat keys so movement keys can be held down
SDL_EnableKeyRepeat(1, SDL_DEFAULT_REPEAT_INTERVAL / 3);
//returns true if initilisation was successful
return true;
}
/**
* Deals with any events that occur
*
* @param SDL_Event event The pointer to the instance of the event handler
*/
void Game::onEvent(SDL_Event * event){
//Deals with pressing the X button on the window causing a quit
if(event->type == SDL_QUIT) {
running = false;
}
//key Left control to pause the game
if(event->type == SDL_KEYDOWN){
if(event->key.keysym.sym == SDLK_LCTRL){
paused = !paused;
}
}
//key Q to quit the game also
if(event->type == SDL_KEYDOWN) {
if(event->key.keysym.sym == SDLK_q) {
running = false;
}
}
//Gets a snapshot of the current keyboard state
Uint8* keystate = SDL_GetKeyState(NULL);
{
//key right arrow or D to move the player right
if(keystate[SDLK_RIGHT] || keystate[SDLK_d]){
entity.AccelerationX+=200.0;
}
//key left arrow or A to move the player left
if(keystate[SDLK_LEFT] || keystate[SDLK_a]){
entity.AccelerationX-=200.0;
}
//key up arrow or W to move the player up
if(keystate[SDLK_UP] || keystate[SDLK_w]){
entity.AccelerationY-=200.0;
}
//key Down arrow or S to move the player down
if(keystate[SDLK_DOWN] || keystate[SDLK_s]){
entity.AccelerationY+=200.0;
}
}
}
/**
* The main loop function for the game, all gamestate changes occur here.
*
* @param double dt the deltatime for
*/
void Game::loop(double dt){
//checks if the game is paused, rendering can still occur even if the game is paused this way
if(!paused){
//queues some time length to calculate the movement under
timeQueued += dt;
//while time queued is greater than a tick do..
while(timeQueued > (1.0/500)) {
//remove 1 tick length from time queue
timeQueued -= (1.0/500);
//Call the loop function for each entity in the entity vector
for(int i = 0; i < EntityList.size(); ++i) {
if(!EntityList[i]) continue;
EntityList[i]->loop(1.0/50);
}
}
//spawns a fresh set of enemy entities
if(currentEntities < maxEntities){
spawnEntity(new EntityEnemy());
currentEntities +=1;
}
//check for any collisions with the player
for( int i = 1; i < EntityList.size(); ++i){
//creates an Axis-Aligned bounding box for the first entity
AABB entityA_AABB;
EntityList[i]->getAABB(entityA_AABB);
//checks for collisions with every entity after the one being checked
for(int j = i + 1; j < EntityList.size(); ++j){
AABB entityB_AABB;
EntityList[j]->getAABB(entityB_AABB);
//if the first entity is a player then..
if(EntityList[i]->isPlayer()){
//checks for a collision
if(AABBinstersect(entityA_AABB, entityB_AABB)){
//tells the entity to despawn
EntityList[j]->despawn();
score++;
}
}
//if the first entity is a player then..
if(EntityList[j]->isPlayer()){
//checks for a collision
if(AABBinstersect(entityA_AABB, entityB_AABB)){
//tells the entity to despawn
EntityList[i]->despawn();
score++;
}
}
}
}
}
//checks all entities to see if they are dead and actually despawns them now
for(int i = 1; i < EntityList.size(); ++i){
if(EntityList[i]->isDead()){
//deletes the instance of the entity
delete EntityList[i];
//removed the null pointer from the vector
EntityList.erase(EntityList.begin() + i);
//decrements the current entities
currentEntities--;
}
}
if(entity.AccelerationX==0){
} else if(entity.AccelerationX<0){
entity.AccelerationX+=50.0;
} else {
entity.AccelerationX-=50.0;
}
if(entity.AccelerationY==0){
} else if(entity.AccelerationY<0){
entity.AccelerationY+=50.0;
} else {
entity.AccelerationY-=50.0;
}
}
/**
* Deals with all the rendering that occurs
*/
void Game::render(){
//draws the screen to black every frame
SDL_Rect rect;
rect.x =0;
rect.y = 0;
rect.w = 1280;
rect.h = 720;
SDL_FillRect(displaySurface, &rect, (displaySurface->format,0,0,0));
//Calls the draw function of every entity
for(int i = 0; i < EntityList.size(); ++i) {
if(!EntityList[i]) continue;
EntityList[i]->draw(displaySurface);
}
//Flips the two surface buffers to actually display the changes
SDL_Flip(displaySurface);
win->renderTextArea();
}
/**
* Deals with exiting the game, cleans up any allocated memory
*/
void Game::cleanUp(){
//calls the cleanup function of every entity
for(int i = 0; i < EntityList.size(); ++i) {
if(!EntityList[i]) continue;
EntityList[i]->onCleanup();
}
//clears the vector of all pointers
EntityList.clear();
//frees the surface of the screen
SDL_FreeSurface(displaySurface);
//this goes out of scope and the progam closes calling any nessasary destructors
}
/**
* Deals with spawning of new enemy entities
*
* @param EntityEnemy entity pointer to a new entity to be spawned
*/
bool Game::spawnEntity(EntityEnemy * entity){
//loads the entitys image
if(entity->onLoad("./images/entity.bmp", 32,32,8)==false){
return false;
}
//pushes the entity to the back of the vector
EntityList.push_back(entity);
return true;
}