-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame_engine.cpp
More file actions
120 lines (101 loc) · 3.65 KB
/
game_engine.cpp
File metadata and controls
120 lines (101 loc) · 3.65 KB
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
#include "coordinates_transform_canvas_wrapper.h"
#include "input_manager.h"
#include "box_collider.h"
#include "game_engine.h"
#include "game_object.h"
#include "timer.h"
#include <algorithm>
#include <iterator>
#include <iostream>
namespace breakout {
namespace {
constexpr Seconds kMaxTimeDelta = 0.06s;
template<typename ColliderPtr, typename ColliderIt>
void handle_collisions_range(
ColliderPtr lhs_collider,
ColliderIt rhs_collider_first,
ColliderIt rhs_collider_last) {
while (rhs_collider_first != rhs_collider_last) {
auto& rhs_collider = *rhs_collider_first++;
if (lhs_collider->has_collision(*rhs_collider)) {
lhs_collider->on_collision(rhs_collider.get());
rhs_collider->on_collision(lhs_collider);
}
}
}
} // namespace
GameEngine::~GameEngine() = default;
void GameEngine::run_main_loop() {
stopped_ = false;
Timer timer;
while (!stopped_ && !game_objects_.empty()) {
auto time_delta = std::min(kMaxTimeDelta, timer.get_duration_and_restart());
update(time_delta);
handle_collisions();
remove_dead_objects();
}
}
void GameEngine::draw(Canvas* canvas) const {
std::lock_guard<std::mutex> lock_guard(game_object_removal_mutex_);
CoordinatesTransformCanvasWrapper game_engine_canvas(canvas, kGameFieldWidth, kGameFieldHeight);
for (const auto& game_object : game_objects_) {
game_object->draw(&game_engine_canvas);
}
}
void GameEngine::update(const Seconds& time_delta) {
for (auto& game_object : game_objects_) {
game_object->update(time_delta);
}
}
void GameEngine::reset() {
std::lock_guard<std::mutex> lock_guard(game_object_removal_mutex_);
game_objects_.clear();
dynamic_colliders_.clear();
static_colliders_.clear();
}
void GameEngine::handle_collisions() {
size_t lhs_collider_index = 0;
for (auto& lhs_collider : dynamic_colliders_) {
handle_dynamic_collisions(lhs_collider.get(), lhs_collider_index);
handle_static_collisions(lhs_collider.get());
lhs_collider_index++;
}
}
void GameEngine::handle_dynamic_collisions(DynamicBoxCollider* lhs_collider, size_t rhs_last_index) {
handle_collisions_range(
lhs_collider,
dynamic_colliders_.begin(),
std::next(dynamic_colliders_.begin(), static_cast<ptrdiff_t>(rhs_last_index)));
}
void GameEngine::handle_static_collisions(DynamicBoxCollider* lhs_collider) {
handle_collisions_range(
lhs_collider,
static_colliders_.begin(),
static_colliders_.end());
}
void GameEngine::remove_dead_objects() {
std::lock_guard<std::mutex> lock_guard(game_object_removal_mutex_);
game_objects_.remove_if([] (const auto& game_object) { return game_object->is_dead(); });
static_colliders_.remove_if([] (const auto& game_object) { return game_object->is_dead(); });
dynamic_colliders_.remove_if([] (const auto& game_object) { return game_object->is_dead(); });
}
void GameEngine::register_game_object(std::shared_ptr<GameObject> game_object) {
add_collider_if_needed(game_object);
game_objects_.emplace_back(std::move(game_object));
}
void GameEngine::add_collider_if_needed(const std::shared_ptr<GameObject>& game_object) {
const auto* box_collider = dynamic_cast<const BoxCollider*>(game_object.get());
if (box_collider == nullptr) {
return;
}
switch (box_collider->movement_type()) {
case MovementType::Dynamic:
dynamic_colliders_.emplace_back(std::static_pointer_cast<DynamicBoxCollider>(game_object));
return;
case MovementType::Static:
static_colliders_.emplace_back(std::static_pointer_cast<StaticBoxCollider>(game_object));
return;
}
std::clog << "unknown movement type: " << static_cast<size_t>(box_collider->movement_type());
}
} // namespace breakout