summary refs log tree commit diff stats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp549
1 files changed, 549 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..2fc610b --- /dev/null +++ b/src/main.cpp
@@ -0,0 +1,549 @@
1#include <SDL.h>
2#include <stdexcept>
3#include <memory>
4#include <vector>
5#include <random>
6#include <fov.h>
7#include <deque>
8
9class sdl_error : public std::logic_error {
10public:
11
12 sdl_error() : std::logic_error(SDL_GetError())
13 {
14 }
15};
16
17class window_deleter {
18public:
19
20 void operator()(SDL_Window* ptr)
21 {
22 SDL_DestroyWindow(ptr);
23 }
24};
25
26using window_ptr = std::unique_ptr<SDL_Window, window_deleter>;
27
28class renderer_deleter {
29public:
30
31 void operator()(SDL_Renderer* ptr)
32 {
33 SDL_DestroyRenderer(ptr);
34 }
35};
36
37using renderer_ptr = std::unique_ptr<SDL_Renderer, renderer_deleter>;
38
39enum class Tile {
40 Floor,
41 Wall,
42 Dark,
43 Dust,
44 Lamp
45};
46
47const int GAME_WIDTH = 640;
48const int GAME_HEIGHT = 480;
49const int TILE_WIDTH = 8;
50const int TILE_HEIGHT = 8;
51const int VIEW_WIDTH = GAME_WIDTH / TILE_WIDTH;
52const int VIEW_HEIGHT = GAME_HEIGHT / TILE_HEIGHT;
53
54class Map {
55public:
56
57 Map() :
58 tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor),
59 lighting(VIEW_WIDTH*VIEW_HEIGHT, false)
60 {
61 }
62
63 std::vector<Tile> tiles;
64 std::vector<bool> lighting;
65 std::deque<std::tuple<int, int>> playerLocs;
66};
67
68int player_x = VIEW_WIDTH / 2;
69int player_y = VIEW_HEIGHT / 2;
70
71void render(
72 SDL_Renderer* ren,
73 const Map& map,
74 bool drawDark = true)
75{
76 SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255);
77 SDL_RenderClear(ren);
78
79 for (int y = 0; y < VIEW_HEIGHT; y++)
80 {
81 for (int x = 0; x < VIEW_WIDTH; x++)
82 {
83 bool draw = true;
84
85 if (player_x == x && player_y == y)
86 {
87 SDL_SetRenderDrawColor(ren, 255, 255, 0, 255);
88 } else if (!map.lighting.at(x+VIEW_WIDTH*y))
89 {
90 if (drawDark)
91 {
92 SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
93 } else {
94 draw = false;
95 }
96 } else {
97 switch (map.tiles.at(x+y*VIEW_WIDTH))
98 {
99 case Tile::Floor:
100 {
101 SDL_SetRenderDrawColor(ren, 210, 210, 210, 255);
102 break;
103 }
104
105 case Tile::Wall:
106 case Tile::Dark:
107 {
108 SDL_SetRenderDrawColor(ren, 100, 100, 100, 255);
109 break;
110 }
111
112 case Tile::Dust:
113 {
114 SDL_SetRenderDrawColor(ren, 128, 40, 255, 255);
115 break;
116 }
117
118 case Tile::Lamp:
119 {
120 SDL_SetRenderDrawColor(ren, 0, 255, 255, 255);
121 break;
122 }
123 }
124 }
125
126
127 if (draw)
128 {
129 SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
130 SDL_RenderFillRect(ren, &rect);
131 }
132
133
134 }
135 }
136
137 SDL_RenderPresent(ren);
138}
139
140void incrementIfSet(Map& map, int& count, int x, int y, int w, int h, Tile val = Tile::Dark)
141{
142 if ((x >= 0) && (x < w) && (y >= 0) && (y < h) && (map.tiles[x+w*y] == val))
143 {
144 count++;
145 }
146}
147
148void tick(Map& map, int x1 = 0, int y1 = 0, int x2 = VIEW_WIDTH, int y2 = VIEW_HEIGHT)
149{
150 std::vector<Tile> temp(map.tiles);
151
152 for (int y = std::max(y1, 0); y < std::min(y2, VIEW_HEIGHT); y++)
153 {
154 for (int x = std::max(x1, 0); x < std::min(x2, VIEW_WIDTH); x++)
155 {
156 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp)
157 {
158 continue;
159 }
160
161 int count = 0;
162
163 incrementIfSet(map, count, x-1, y-1, VIEW_WIDTH, VIEW_HEIGHT);
164 incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT);
165 incrementIfSet(map, count, x-1, y+1, VIEW_WIDTH, VIEW_HEIGHT);
166 incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT);
167 incrementIfSet(map, count, x , y , VIEW_WIDTH, VIEW_HEIGHT);
168 incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT);
169 incrementIfSet(map, count, x+1, y-1, VIEW_WIDTH, VIEW_HEIGHT);
170 incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT);
171 incrementIfSet(map, count, x+1, y+1, VIEW_WIDTH, VIEW_HEIGHT);
172
173 if (count >= 5)
174 {
175 temp[x+VIEW_WIDTH*y] = Tile::Dark;
176 } else {
177 temp[x+VIEW_WIDTH*y] = Tile::Floor;
178 }
179 }
180 }
181
182 map.tiles = temp;
183}
184
185void movePlayer(int x, int y, Map& map)
186{
187 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT) &&
188 map.tiles[x+VIEW_WIDTH*y] == Tile::Floor)
189 {
190 if (map.tiles[player_x+player_y*VIEW_WIDTH] == Tile::Floor)
191 {
192 map.tiles[player_x+player_y*VIEW_WIDTH] = Tile::Dust;
193 map.playerLocs.emplace_front(player_x, player_y);
194
195 if (map.playerLocs.size() > 5)
196 {
197 map.playerLocs.pop_back();
198 }
199 }
200
201
202
203
204 player_x = x;
205 player_y = y;
206 }
207}
208
209void setIfValid(Map& map, int x, int y, Tile val)
210{
211 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT))
212 {
213 map.tiles[x+VIEW_WIDTH*y] = val;
214 }
215}
216
217void recalculateLighting(Map& map, fov_settings_type* fov)
218{
219 map.lighting = std::vector<bool>(VIEW_WIDTH*VIEW_HEIGHT, false);
220
221 fov_settings_set_opacity_test_function(
222 fov,
223 [] (void* map, int x, int y) {
224 return
225 x >= 0 &&
226 x < VIEW_WIDTH &&
227 y >= 0 &&
228 y < VIEW_HEIGHT &&
229 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark;
230 });
231
232 fov_settings_set_apply_lighting_function(
233 fov,
234 [] (void* map, int x, int y, int, int, void*) {
235 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT))
236 {
237 static_cast<Map*>(map)->lighting[x+VIEW_WIDTH*y] = true;
238 }
239 });
240
241 for (int y = 0; y < VIEW_HEIGHT; y++)
242 {
243 for (int x = 0; x < VIEW_WIDTH; x++)
244 {
245 if ((player_x == x && player_y == y) || map.tiles[x+VIEW_WIDTH*y] == Tile::Dust || map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp)
246 {
247 fov_circle(fov, static_cast<void*>(&map), nullptr, x, y, 8);
248 }
249
250 if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp)
251 {
252 map.lighting[x+VIEW_WIDTH*y] = true;
253 }
254 }
255 }
256}
257
258int main(int, char**)
259{
260 std::random_device randomEngine;
261 std::mt19937 rng(randomEngine());
262
263 if (SDL_Init(SDL_INIT_VIDEO) != 0)
264 {
265 throw sdl_error();
266 }
267
268 try
269 {
270 window_ptr win(
271 SDL_CreateWindow("Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN));
272
273 if (!win)
274 {
275 throw sdl_error();
276 }
277
278 renderer_ptr ren(
279 SDL_CreateRenderer(
280 win.get(),
281 -1,
282 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
283
284 if (!ren)
285 {
286 throw sdl_error();
287 }
288
289 //std::vector<Tile> tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor);
290 //std::vector<bool> lighting(VIEW_WIDTH*VIEW_HEIGHT, false);
291 Map map;
292
293 std::unique_ptr<fov_settings_type> fov(new fov_settings_type());
294 fov_settings_init(fov.get());
295
296
297 for (int y = 0; y < VIEW_HEIGHT; y++)
298 {
299 for (int x = 0; x < VIEW_WIDTH; x++)
300 {
301 if (std::bernoulli_distribution(0.5)(rng))
302 {
303 map.tiles[x+y*VIEW_WIDTH] = Tile::Dark;
304 }
305 }
306 }
307
308 tick(map);
309 tick(map);
310 tick(map);
311
312 bool quit = false;
313 SDL_Event e;
314 while (!quit)
315 {
316 //SDL_PumpEvents();
317 bool input = false;
318 int presses = 0;
319 while (SDL_PollEvent(&e))
320 {
321 if (e.type == SDL_QUIT)
322 {
323 quit = true;
324 } else if (e.type == SDL_KEYDOWN)
325 {
326 presses++;
327
328 switch (e.key.keysym.sym)
329 {
330 case SDLK_SPACE:
331 {
332 input = true;
333
334 setIfValid(map, player_x-1, player_y , Tile::Floor);
335 setIfValid(map, player_x+1, player_y , Tile::Floor);
336 setIfValid(map, player_x , player_y , Tile::Lamp);
337 setIfValid(map, player_x , player_y-1, Tile::Floor);
338 setIfValid(map, player_x , player_y+1, Tile::Floor);
339
340 auto locs = map.playerLocs;
341 while (!locs.empty())
342 {
343 movePlayer(std::get<0>(locs.front()), std::get<1>(locs.front()), map);
344 locs.pop_front();
345
346 tick(
347 map,
348 player_x - 7,
349 player_y - 7,
350 player_x + 8,
351 player_y + 8);
352
353 render(ren.get(), map, false);
354 SDL_Delay(30);
355 }
356
357 break;
358 }
359 }
360 } else if (e.type == SDL_KEYUP)
361 {
362 presses++;
363 }
364 }
365
366 if (presses > 0)
367 {
368 for (int y = 0; y < VIEW_HEIGHT; y++)
369 {
370 for (int x = 0; x < VIEW_WIDTH; x++)
371 {
372 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Dust)
373 {
374 map.tiles[x+y*VIEW_WIDTH] = Tile::Floor;
375 }
376 }
377 }
378 }
379
380 const Uint8* state = SDL_GetKeyboardState(NULL);
381
382 for (int i = 0; i < presses; i++)
383 {
384 //switch (e.key.keysym.sym)
385 {
386 //case SDLK_UP:
387 if (state[SDL_SCANCODE_UP])
388 {
389 movePlayer(player_x, player_y-1, map);
390 input = true;
391 //break;
392 }
393
394 //case SDLK_DOWN:
395 if (state[SDL_SCANCODE_DOWN])
396 {
397 movePlayer(player_x, player_y+1, map);
398 input = true;
399 //break;
400 }
401
402 //case SDLK_LEFT:
403 if (state[SDL_SCANCODE_LEFT])
404 {
405 movePlayer(player_x-1, player_y, map);
406 input = true;
407 //break;
408 }
409
410 //case SDLK_RIGHT:
411 if (state[SDL_SCANCODE_RIGHT])
412 {
413 movePlayer(player_x+1, player_y, map);
414 input = true;
415 //break;
416 }
417
418
419 }
420
421 if (input)
422 {
423 //render(ren.get(), tiles, false);
424 //SDL_Delay(1);
425 }
426
427 //}
428 }
429
430 bool checkForDust = true;
431
432 while (checkForDust)
433 {
434 checkForDust = false;
435
436 for (int y = 0; y < VIEW_HEIGHT; y++)
437 {
438 for (int x = 0; x < VIEW_WIDTH; x++)
439 {
440 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp)
441 {
442 int count = 0;
443
444 incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
445 incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
446 incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
447 incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
448
449 if (count > 0)
450 {
451 checkForDust = true;
452
453 map.tiles[x+y*VIEW_WIDTH] = Tile::Dust;
454
455 /*for (int i = 0; i < 4; i++)
456 {
457 tick(
458 map,
459 x - 7,
460 y - 7,
461 x + 8,
462 y + 8);
463
464 for (int l = 0; l < (i*2+1); l++)
465 {
466 int px = x - i + l;
467 int py = y - i + l;
468
469 auto fillInDust = [&] (int sx, int sy) {
470 if (sx > 0 && sx < VIEW_WIDTH &&
471 sy > 0 && sy < VIEW_HEIGHT &&
472 map.tiles[sx+sy*VIEW_WIDTH] == Tile::Floor &&
473 !(player_y == sy && player_x == sx))
474 {
475 map.tiles[sx+sy*VIEW_WIDTH] = Tile::Dust;
476 }
477 };
478
479 fillInDust(px , y - i);
480 fillInDust(px , y + i);
481 fillInDust(x - i, py );
482 fillInDust(x + i, py );
483 }
484
485 render(ren.get(), map, false);
486 SDL_Delay(30);
487 }*/
488
489
490 /*
491
492 for (int py = std::max(0, y - 7); py < std::min(VIEW_HEIGHT, y + 8); py++)
493 {
494 for (int px = std::max(0, x - 7); px < std::min(VIEW_WIDTH, x + 8); px++)
495 {
496 if ((map.tiles[px+py*VIEW_WIDTH] == Tile::Floor) &&
497 !(player_y == py && player_x == px))
498 {
499 map.tiles[px+py*VIEW_WIDTH] = Tile::Dust;
500 }
501 }
502 }*/
503
504 std::unique_ptr<fov_settings_type> dusty(new fov_settings_type);
505 fov_settings_set_opacity_test_function(
506 dusty.get(),
507 [] (void* map, int x, int y) {
508 return
509 x >= 0 &&
510 x < VIEW_WIDTH &&
511 y >= 0 &&
512 y < VIEW_HEIGHT &&
513 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark;
514 });
515
516 fov_settings_set_apply_lighting_function(
517 dusty.get(),
518 [] (void* map, int x, int y, int, int, void*) {
519 if ((x >= 0) && (x < VIEW_WIDTH) &&
520 (y >= 0) && (y < VIEW_HEIGHT) &&
521 (static_cast<Map*>(map)->tiles[x+VIEW_WIDTH*y] == Tile::Floor))
522 {
523 static_cast<Map*>(map)->tiles[x+VIEW_WIDTH*y] = Tile::Dust;
524 }
525 });
526
527 fov_circle(dusty.get(), static_cast<void*>(&map), nullptr, x, y, 8);
528
529 render(ren.get(), map, false);
530 SDL_Delay(50);
531 }
532 }
533 }
534 }
535 }
536
537
538 recalculateLighting(map, fov.get());
539 render(ren.get(), map, true);
540 SDL_Delay(10);
541 }
542 } catch (const sdl_error&)
543 {
544 }
545
546 SDL_Quit();
547
548 return 0;
549} \ No newline at end of file