summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/consts.h10
-rw-r--r--src/entity.h31
-rw-r--r--src/level.h52
-rw-r--r--src/main.cpp60
-rw-r--r--src/renderer.cpp97
-rw-r--r--src/renderer.h126
-rw-r--r--src/simulation.cpp115
-rw-r--r--src/simulation.h57
-rw-r--r--src/tileset.h13
-rw-r--r--src/vector.h119
10 files changed, 680 insertions, 0 deletions
diff --git a/src/consts.h b/src/consts.h new file mode 100644 index 0000000..f3a073c --- /dev/null +++ b/src/consts.h
@@ -0,0 +1,10 @@
1#ifndef CONSTS_H_8019F1B3
2#define CONSTS_H_8019F1B3
3
4#include "vector.h"
5
6constexpr vec2s TILE_SIZE { 32, 32 };
7constexpr vec2s LEVEL_SIZE { 16, 16 };
8constexpr vec2s WINDOW_SIZE = TILE_SIZE * LEVEL_SIZE;
9
10#endif /* end of include guard: CONSTS_H_8019F1B3 */
diff --git a/src/entity.h b/src/entity.h new file mode 100644 index 0000000..d99680f --- /dev/null +++ b/src/entity.h
@@ -0,0 +1,31 @@
1#ifndef ENTITY_H_0D6CB29A
2#define ENTITY_H_0D6CB29A
3
4#include "vector.h"
5
6class Entity {
7public:
8
9 // Transform
10 vec2s pos;
11 vec2s size;
12
13 // Grid placement
14 vec2s gridPos;
15
16 // Movement
17 bool moving = false;
18 vec2s destPos;
19 double movementTween = 0.0;
20 double speed = 0.0; // Tiles per second
21
22 // Player
23 bool player = false;
24
25 // Collision
26 bool playerCanPush = false;
27 bool trainCanPush = false;
28
29};
30
31#endif /* end of include guard: ENTITY_H_0D6CB29A */
diff --git a/src/level.h b/src/level.h new file mode 100644 index 0000000..3d6fb87 --- /dev/null +++ b/src/level.h
@@ -0,0 +1,52 @@
1#ifndef LEVEL_H_678CFCCF
2#define LEVEL_H_678CFCCF
3
4#include "consts.h"
5#include "tileset.h"
6
7class Level {
8public:
9
10 Level()
11 {
12 size_ = LEVEL_SIZE;
13
14 tiles_.resize(size_.w() * size_.h());
15
16 for (size_t y = 0; y < size_.h(); y++)
17 {
18 for (size_t x = 0; x < size_.w(); x++)
19 {
20 tiles_[x+y*size_.w()] = rand() % 10;
21 }
22 }
23 }
24
25 const vec2s& getSize() const
26 {
27 return size_;
28 }
29
30 size_t at(vec2s pos) const
31 {
32 return at(pos.x(), pos.y());
33 }
34
35 size_t at(size_t x, size_t y) const
36 {
37 return tiles_.at(x + size_.w() * y);
38 }
39
40 const Tileset& getTileset() const
41 {
42 return tileset_;
43 }
44
45private:
46
47 vec2s size_;
48 std::vector<size_t> tiles_;
49 Tileset tileset_;
50};
51
52#endif /* end of include guard: LEVEL_H_678CFCCF */
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..1b74143 --- /dev/null +++ b/src/main.cpp
@@ -0,0 +1,60 @@
1#include "renderer.h"
2
3#include <random>
4#include "simulation.h"
5#include "level.h"
6
7int main(int, char**)
8{
9 std::random_device randomEngine;
10 std::mt19937 rng(randomEngine());
11
12 Renderer renderer;
13 Level level;
14 Simulation sim(level);
15
16 Simulation::id_type player = sim.emplaceEntity();
17 Entity& entity = sim.getEntity(player);
18 entity.gridPos.x() = 1;
19 entity.gridPos.y() = 5;
20 entity.size = TILE_SIZE;
21 entity.speed = 3.0;
22 entity.player = true;
23
24 bool quit = false;
25
26 SDL_Event e;
27 size_t lastTime = SDL_GetTicks();
28
29 while (!quit)
30 {
31 size_t currentTime = SDL_GetTicks();
32 size_t frameTime = currentTime - lastTime;
33 lastTime = currentTime;
34
35 while (SDL_PollEvent(&e))
36 {
37 if (e.type == SDL_QUIT)
38 {
39 quit = true;
40 } else if (e.type == SDL_KEYDOWN)
41 {
42 switch (e.key.keysym.sym)
43 {
44 case SDLK_ESCAPE:
45 {
46 quit = true;
47
48 break;
49 }
50 }
51 }
52 }
53
54 const Uint8* state = SDL_GetKeyboardState(NULL);
55
56 sim.tick(frameTime / 1000.0, state);
57
58 renderer.render(sim);
59 }
60}
diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..2916dd6 --- /dev/null +++ b/src/renderer.cpp
@@ -0,0 +1,97 @@
1#include "renderer.h"
2#include "simulation.h"
3#include "consts.h"
4#include "level.h"
5
6Renderer::Renderer()
7{
8 win_ = window_ptr(
9 SDL_CreateWindow(
10 "dispatcher",
11 100,
12 100,
13 WINDOW_SIZE.w(),
14 WINDOW_SIZE.h(),
15 SDL_WINDOW_SHOWN));
16
17 if (!win_)
18 {
19 throw sdl_error();
20 }
21
22 ren_ = renderer_ptr(
23 SDL_CreateRenderer(
24 win_.get(),
25 -1,
26 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
27
28 if (!ren_)
29 {
30 throw sdl_error();
31 }
32
33 SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_MOD);
34 SDL_SetRenderDrawColor(ren_.get(), 255, 150, 255, 255);
35 SDL_RenderFillRect(ren_.get(), nullptr);
36}
37
38void Renderer::render(const Simulation& sim)
39{
40 texture_ptr canvas(
41 SDL_CreateTexture(
42 ren_.get(),
43 SDL_PIXELFORMAT_RGBA8888,
44 SDL_TEXTUREACCESS_TARGET,
45 WINDOW_SIZE.w(),
46 WINDOW_SIZE.h()));
47
48 if (!canvas)
49 {
50 throw sdl_error();
51 }
52
53 SDL_SetRenderTarget(ren_.get(), nullptr);
54 SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
55 SDL_SetRenderDrawColor(ren_.get(), 255, 150, rand() % 255, 255);
56 SDL_RenderClear(ren_.get());
57
58 const Level& level = sim.getLevel();
59
60 for (size_t y = 0; y < level.getSize().h(); y++)
61 {
62 for (size_t x = 0; x < level.getSize().w(); x++)
63 {
64 int val = level.at(x, y) * 10;
65
66 SDL_SetRenderDrawColor(ren_.get(), val, val, 0, 255);
67
68 SDL_Rect rect {
69 static_cast<int>(x * TILE_SIZE.w()),
70 static_cast<int>(y * TILE_SIZE.h()),
71 TILE_SIZE.w(),
72 TILE_SIZE.h()
73 };
74
75 SDL_RenderFillRect(ren_.get(), &rect);
76 }
77 }
78
79 for (Simulation::id_type id : sim.getActive())
80 {
81 const Entity& entity = sim.getEntity(id);
82
83 SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, 255);
84
85 SDL_Rect rect {
86 static_cast<int>(entity.pos.x()),
87 static_cast<int>(entity.pos.y()),
88 static_cast<int>(entity.size.w()),
89 static_cast<int>(entity.size.h())
90 };
91
92 SDL_RenderFillRect(ren_.get(), &rect);
93 }
94
95 //SDL_RenderCopy(ren_.get(), canvas.get(), nullptr, nullptr);
96 SDL_RenderPresent(ren_.get());
97}
diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..dd3498f --- /dev/null +++ b/src/renderer.h
@@ -0,0 +1,126 @@
1#ifndef RENDERER_H_6A58EC30
2#define RENDERER_H_6A58EC30
3
4#include <SDL.h>
5#include <SDL_image.h>
6#include <stdexcept>
7#include <memory>
8
9class Simulation;
10
11class sdl_error : public std::logic_error {
12public:
13
14 sdl_error() : std::logic_error(SDL_GetError())
15 {
16 }
17};
18
19class img_error : public std::logic_error {
20public:
21
22 img_error() : std::logic_error(IMG_GetError())
23 {
24 }
25};
26
27class sdl_wrapper {
28public:
29
30 sdl_wrapper()
31 {
32 if (SDL_Init(SDL_INIT_VIDEO) != 0)
33 {
34 sdl_error ex;
35 SDL_Quit();
36
37 throw ex;
38 }
39 }
40
41 ~sdl_wrapper()
42 {
43 SDL_Quit();
44 }
45};
46
47class img_wrapper {
48public:
49
50 img_wrapper()
51 {
52 if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
53 {
54 img_error ex;
55 IMG_Quit();
56
57 throw ex;
58 }
59 }
60
61 ~img_wrapper()
62 {
63 IMG_Quit();
64 }
65};
66
67class window_deleter {
68public:
69
70 void operator()(SDL_Window* ptr)
71 {
72 SDL_DestroyWindow(ptr);
73 }
74};
75
76using window_ptr = std::unique_ptr<SDL_Window, window_deleter>;
77
78class renderer_deleter {
79public:
80
81 void operator()(SDL_Renderer* ptr)
82 {
83 SDL_DestroyRenderer(ptr);
84 }
85};
86
87using renderer_ptr = std::unique_ptr<SDL_Renderer, renderer_deleter>;
88
89class surface_deleter {
90public:
91
92 void operator()(SDL_Surface* ptr)
93 {
94 SDL_FreeSurface(ptr);
95 }
96};
97
98using surface_ptr = std::unique_ptr<SDL_Surface, surface_deleter>;
99
100class texture_deleter {
101public:
102
103 void operator()(SDL_Texture* ptr)
104 {
105 SDL_DestroyTexture(ptr);
106 }
107};
108
109using texture_ptr = std::unique_ptr<SDL_Texture, texture_deleter>;
110
111class Renderer {
112public:
113
114 Renderer();
115
116 void render(const Simulation& game);
117
118private:
119
120 sdl_wrapper sdl_;
121 img_wrapper img_;
122 window_ptr win_;
123 renderer_ptr ren_;
124};
125
126#endif /* end of include guard: RENDERER_H_6A58EC30 */
diff --git a/src/simulation.cpp b/src/simulation.cpp new file mode 100644 index 0000000..3079f56 --- /dev/null +++ b/src/simulation.cpp
@@ -0,0 +1,115 @@
1#include "simulation.h"
2
3#include "consts.h"
4#include "level.h"
5
6void Simulation::tick(
7 double dt,
8 const Uint8* keystate)
9{
10 for (id_type id : active_)
11 {
12 Entity& entity = entities_.at(id);
13
14 // Control
15 if (entity.player &&
16 !entity.moving)
17 {
18 if (keystate[SDL_SCANCODE_LEFT] &&
19 entity.gridPos.x() > 0 &&
20 level_.getTileset().canPlayerMoveTo(
21 level_.at(entity.gridPos - vec2s { 1, 0 })))
22 {
23 entity.moving = true;
24 entity.destPos = entity.gridPos - vec2s { 1, 0 };
25 }
26 else if (keystate[SDL_SCANCODE_UP] &&
27 entity.gridPos.y() > 0 &&
28 level_.getTileset().canPlayerMoveTo(
29 level_.at(entity.gridPos - vec2s { 0, 1 })))
30 {
31 entity.moving = true;
32 entity.destPos = entity.gridPos - vec2s { 0, 1 };
33 } else if (keystate[SDL_SCANCODE_RIGHT] &&
34 entity.gridPos.x() < (level_.getSize().w() - 1) &&
35 level_.getTileset().canPlayerMoveTo(
36 level_.at(entity.gridPos + vec2s { 1, 0 })))
37 {
38 entity.moving = true;
39 entity.destPos = entity.gridPos + vec2s { 1, 0 };
40 }
41 else if (keystate[SDL_SCANCODE_DOWN] &&
42 entity.gridPos.y() < (level_.getSize().h() - 1) &&
43 level_.getTileset().canPlayerMoveTo(
44 level_.at(entity.gridPos + vec2s { 0, 1 })))
45 {
46 entity.moving = true;
47 entity.destPos = entity.gridPos + vec2s { 0, 1 };
48 }
49
50 if (entity.moving)
51 {
52 entity.movementTween = 0.0;
53 }
54 }
55
56
57
58
59 // Collision
60
61
62
63
64 // Movement
65 if (entity.moving)
66 {
67 entity.movementTween += entity.speed * dt;
68
69 if (entity.movementTween >= 1.0)
70 {
71 entity.moving = false;
72 entity.gridPos = entity.destPos;
73 }
74 }
75
76 if (entity.moving)
77 {
78 entity.pos.x() =
79 TILE_SIZE.x() * entity.destPos.x() * entity.movementTween +
80 TILE_SIZE.x() * entity.gridPos.x() * (1.0 - entity.movementTween);
81
82 entity.pos.y() =
83 TILE_SIZE.y() * entity.destPos.y() * entity.movementTween +
84 TILE_SIZE.y() * entity.gridPos.y() * (1.0 - entity.movementTween);
85 } else {
86 entity.pos = TILE_SIZE * entity.gridPos;
87 }
88 }
89}
90
91Simulation::id_type Simulation::emplaceEntity()
92{
93 id_type nextId;
94
95 if (!available_.empty())
96 {
97 nextId = available_.front();
98 available_.pop_front();
99
100 entities_.at(nextId) = Entity();
101 } else {
102 nextId = entities_.size();
103 entities_.emplace_back();
104 }
105
106 active_.insert(nextId);
107
108 return nextId;
109}
110
111void Simulation::deleteEntity(id_type id)
112{
113 available_.push_back(id);
114 active_.erase(id);
115}
diff --git a/src/simulation.h b/src/simulation.h new file mode 100644 index 0000000..bc47642 --- /dev/null +++ b/src/simulation.h
@@ -0,0 +1,57 @@
1#ifndef SIMULATION_H_7BF6EEA4
2#define SIMULATION_H_7BF6EEA4
3
4#include "entity.h"
5#include "renderer.h"
6#include <vector>
7#include <deque>
8#include <set>
9
10class Level;
11
12class Simulation {
13public:
14
15 using id_type = std::vector<Entity>::size_type;
16
17 // Constructor
18 explicit Simulation(const Level& level) : level_(level) {}
19
20 void tick(
21 double dt,
22 const Uint8* keystate);
23
24 id_type emplaceEntity();
25
26 void deleteEntity(id_type id);
27
28 Entity& getEntity(id_type id)
29 {
30 return entities_.at(id);
31 }
32
33 const Entity& getEntity(id_type id) const
34 {
35 return entities_.at(id);
36 }
37
38 const std::set<id_type>& getActive() const
39 {
40 return active_;
41 }
42
43 const Level& getLevel() const
44 {
45 return level_;
46 }
47
48private:
49
50 const Level& level_;
51
52 std::vector<Entity> entities_;
53 std::deque<id_type> available_;
54 std::set<id_type> active_;
55};
56
57#endif /* end of include guard: SIMULATION_H_7BF6EEA4 */
diff --git a/src/tileset.h b/src/tileset.h new file mode 100644 index 0000000..552b2f8 --- /dev/null +++ b/src/tileset.h
@@ -0,0 +1,13 @@
1#ifndef TILESET_H_B89AE7A1
2#define TILESET_H_B89AE7A1
3
4class Tileset {
5public:
6
7 bool canPlayerMoveTo(size_t tile) const
8 {
9 return (tile % 2 == 1);
10 }
11};
12
13#endif /* end of include guard: TILESET_H_B89AE7A1 */
diff --git a/src/vector.h b/src/vector.h new file mode 100644 index 0000000..10fe4da --- /dev/null +++ b/src/vector.h
@@ -0,0 +1,119 @@
1#ifndef COORDINATES_H_A45D34FB
2#define COORDINATES_H_A45D34FB
3
4#include <cstddef>
5
6template <typename T>
7class vec2 {
8public:
9
10 T coords[2];
11
12 constexpr vec2() : coords{0, 0}
13 {
14 }
15
16 constexpr vec2(T x, T y) : coords{x, y}
17 {
18 }
19
20 inline T& x()
21 {
22 return coords[0];
23 }
24
25 constexpr inline const T& x() const
26 {
27 return coords[0];
28 }
29
30 inline T& w()
31 {
32 return coords[0];
33 }
34
35 constexpr inline const T& w() const
36 {
37 return coords[0];
38 }
39
40 inline T& y()
41 {
42 return coords[1];
43 }
44
45 constexpr inline const T& y() const
46 {
47 return coords[1];
48 }
49
50 inline T& h()
51 {
52 return coords[1];
53 }
54
55 constexpr inline const T& h() const
56 {
57 return coords[1];
58 }
59
60 template <typename R>
61 constexpr operator vec2<R>() const
62 {
63 return vec2<R>(x(), y());
64 }
65
66 constexpr vec2 operator+(const vec2& other) const
67 {
68 return vec2(x() + other.x(), y() + other.y());
69 }
70
71 vec2& operator+=(const vec2& other)
72 {
73 x() += other.x();
74 y() += other.y();
75
76 return *this;
77 }
78
79 constexpr vec2 operator-(const vec2& other) const
80 {
81 return vec2(x() - other.x(), y() - other.y());
82 }
83
84 vec2 operator-=(const vec2& other)
85 {
86 x() -= other.x();
87 y() -= other.y();
88
89 return *this;
90 }
91
92 constexpr vec2 operator-() const
93 {
94 return vec2(-x(), -y());
95 }
96
97 constexpr vec2 operator*(T s) const
98 {
99 return vec2(x() * s, y() * s);
100 }
101
102 vec2& operator*=(T s)
103 {
104 x() *= s;
105 y() *= s;
106
107 return *this;
108 }
109
110 constexpr vec2 operator*(const vec2& other) const
111 {
112 return vec2(x() * other.x(), y() * other.y());
113 }
114
115};
116
117using vec2s = vec2<size_t>;
118
119#endif /* end of include guard: COORDINATES_H_A45D34FB */