Repository navigation
Expand file tree
/
Copy pathWorld.cpp
More file actions
106 lines (93 loc) · 4.92 KB
/
Copy pathWorld.cpp
File metadata and controls
106 lines (93 loc) · 4.92 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
#include "World.hpp"
#include "Painter.hpp"
#include <fstream>
// Длительность одного тика симуляции.
// Подробнее см. update()
// Изменять не следует
static constexpr double timePerTick = 0.001;
/**
* Конструирует объект мира для симуляции
* @param worldFilePath путь к файлу модели мира
*/
World::World(const std::string& worldFilePath) {
std::ifstream stream(worldFilePath);
/**
* TODO: хорошее место для улучшения.
* Чтение границ мира из модели
* Обратите внимание, что здесь и далее мы многократно
* читаем в объект типа Point, последовательно
* заполняя координаты x и у. Если что-то делаем
* многократно - хорошо бы вынести это в функцию
* и не дублировать код...
* TODO не пойму, вроде всё прекрасно в коде тут...
*/
stream >> topLeft.x >> topLeft.y >> bottomRight.x >> bottomRight.y;
physics.setWorldBox(topLeft, bottomRight);
/**
* TODO: хорошее место для улучшения.
* (x, y) и (vx, vy) - составные части объекта, также
* как и (red, green, blue). Опять же, можно упростить
* этот код, научившись читать сразу Point, Color...
* TODO потом доделаю. Просто - нужно перегрузить оператор >> методом
* копирования из std::in в классt Point и Color
*/
double x;
double y;
double vx;
double vy;
double radius;
double red;
double green;
double blue;
bool isCollidable;
// Здесь не хватает обработки ошибок, но на текущем
// уровне прохождения курса нас это устраивает
while (stream.peek(), stream.good()) {
// Читаем координаты центра шара (x, y) и вектор
// его скорости (vx, vy)
stream >> x >> y >> vx >> vy;
// Читаем три составляющие цвета шара
stream >> red >> green >> blue;
// Читаем радиус шара
stream >> radius;
// Читаем свойство шара isCollidable, которое
// указывает, требуется ли обрабатывать пересечение
// шаров как столкновение. Если true - требуется.
stream >> std::boolalpha >> isCollidable;
// добавьте его в конец контейнера вызовом
balls.push_back(Ball{Point{x, y}, radius, Velocity{Point{vx, vy}},
Color{red, green, blue}, isCollidable});
}
}
/// @brief Отображает состояние мира
void World::show(Painter& painter) const {
// Рисуем белый прямоугольник, отображающий границу
// мира
painter.draw(topLeft, bottomRight, Color(1, 1, 1));
// Вызываем отрисовку каждого шара
for (const Ball& ball : balls) {
ball.draw(painter);
}
}
/// @brief Обновляет состояние мира
void World::update(double time) {
/**
* В реальном мире время течет непрерывно. Однако
* компьютеры дискретны по своей природе. Поэтому
* симуляцию взаимодействия шаров выполняем дискретными
* "тиками". Т.е. если с момента прошлой симуляции
* прошло time секунд, time / timePerTick раз обновляем
* состояние мира. Каждое такое обновление - тик -
* в physics.update() перемещаем шары и обрабатываем
* коллизии - ситуации, когда в результате перемещения
* один шар пересекается с другим или с границей мира.
* В общем случае время не делится нацело на
* длительность тика, сохраняем остаток в restTime
* и обрабатываем на следующей итерации.
*/
// учитываем остаток времени, который мы не "доработали" при прошлом update
time += restTime;
const auto ticks = static_cast<size_t>(std::floor(time / timePerTick));
restTime = time - double(ticks) * timePerTick;
physics.update(balls, ticks);
}