Skip to content

Commit 0e45ec8

Browse files
committed
Турбо режим симуляции
1 parent eb79f57 commit 0e45ec8

7 files changed

+142
-33
lines changed

README.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,27 @@
110110
- **8**: Красный (тип 2).
111111
- **9**: Синий (тип 3).
112112

113+
# Turbo Mode (Experimental Feature)
114+
115+
- **Turbo Mode**
116+
— это экспериментальный режим симуляции, который превращает вашу "Игру Жизни" в настоящий ускоритель частиц! В этом режиме мы выжимаем максимум из GPU, позволяя выполнять несколько шагов симуляции за один кадр рендеринга. Результат? Скорость симуляции взлетает до небес, но стабильность остаётся под вопросом.
117+
- Как это работает?
118+
- Включите Turbo Mode через кнопку в окне "Управление симуляцией" (ищите красную кнопку — её сложно пропустить!).
119+
- Количество шагов симуляции за кадр (Simulation Steps) автоматически подстраивается в зависимости от текущего FPS, пытаясь удерживать рендеринг на частоте вашего монитора (по умолчанию 75 Гц).
120+
- Чем больше шагов, тем быстрее эволюционирует ваша сетка — но и тем выше нагрузка на систему.
121+
- **Предупреждение**: Экспериментальная зона!
122+
- **Стабильность**: Этот режим нестабилен и зависит от размера сетки, мощности вашего GPU и настроек параметров. На больших сетках (например, 10000×10000) возможны просадки FPS, зависания или странные глюки — от "волн" в скорости симуляции до внезапных "турбо-скачков".
123+
- **По умолчанию**: Режим выключен, и игра работает в стандартном стабильном режиме с одной симуляцией на кадр. Включайте Turbo Mode только если готовы к приключениям!
124+
- **Почему это круто**?
125+
- На маленьких сетках вы получите молниеносную симуляцию без потери FPS.
126+
- На больших сетках это как тест на выносливость для вашего GPU — сможете ли вы укротить хаос?
127+
- **Как использовать**?
128+
- Откройте окно "Управление симуляцией".
129+
- Найдите кнопку "Turbo Mode" (красная, как сигнал опасности).
130+
- Нажмите её, чтобы включить/выключить режим.
131+
- Наблюдайте, как ваша симуляция либо взлетает, либо эпично падает — зависит от удачи и настроек!
132+
- **Примечание**: Мы не гарантируем, что ваша видеокарта не начнёт молить о пощаде, а игра — вести себя как космический корабль на автопилоте с пьяным штурманом. Это эксперимент, так что играйте с ним на свой риск и получайте удовольствие от хаоса!
133+
113134
## Установка
114135

115136
Для настройки и запуска проекта:
@@ -190,7 +211,7 @@ git push origin v1.0.0
190211
- `GridRenderer.h`, `GridRenderer.cpp` - Отрисовка навигационной координатной сетки.
191212
- `TextureFieldRenderer.h`, `TextureFieldRenderer.cpp` - Отрисовка игрового поля на дальних расстояниях от самого поля, улучшает производительность не влияя на визуальное отображение.
192213
- `CellsViewportRenderer.h`, `CellsViewportRenderer.cpp` - Отрисовка игрового поля на ближних расстояниях от игрового поля, улучшает визуальное отображение.
193-
- `IRendererProvider.h` - Проводник обеспечивающий обмен данными между разными классами. Это простой интерфейс, паттерн провайдер.
214+
- `IRendererProvider.h` - Проводник для `Renderer` обеспечивающий обмен данными между разными классами. Это простой интерфейс, паттерн провайдер.
194215

195216
- **./mathematics**: Математические утилиты:
196217
- `Matrix4x4.h`, `Matrix4x4.cpp` - Операции с матрицами (на данный момент не используется)
@@ -207,6 +228,7 @@ git push origin v1.0.0
207228
- `ShaderManager.h`, `ShaderManager.cpp` - Создание компиляция проверка шейдеров (GLSL) OpenGL
208229
- `SettingsManager.h`, `SettingsManager.cpp` - Сохранение и загрузка пользовательских настроек.
209230
- `InputHandler.h`, `InputHandler.cpp` - Обработчик пользовательского ввода (клавиатура мыш).
231+
- `PerformanceStats.h`, `PerformanceStats.cpp` - Собирает статистику. ФПС, колличество симуляций и т.д.
210232
- `InputEvent.h` - Сама структура пользовательского ввода.
211233

212234
- **main.cpp**: Точка входа приложения

game/GameController.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ GameController::GameController(int width, int height, float cellSize)
44
: grid(width, height),
55
gpuAutomaton(grid.getWidth(), grid.getHeight()),
66
cellSize(cellSize),
7-
isRunning(false), showGrid(true), showUI(true), isWorldToroidal(true), isPatternPlacementMode(false),
7+
isRunning(false), showGrid(true), showUI(true), isWorldToroidal(true), isPatternPlacementMode(false), isTurboBoost(false),
88
currentPatternRotator(0), isSelectionActive(false),
99
rendererProvider(nullptr)
1010
{
@@ -16,7 +16,6 @@ GameController::GameController(int width, int height, float cellSize)
1616

1717
frameTimeAccumulator = GetTickCount64(); // Инициализация
1818
isRunning = false;
19-
simulationSpeed = 0;
2019

2120
}
2221

@@ -82,7 +81,7 @@ void GameController::update() {
8281
static auto lastUpdate = std::chrono::steady_clock::now();
8382
if (isRunning) {
8483
auto now = std::chrono::steady_clock::now();
85-
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastUpdate).count();
84+
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - lastUpdate).count();
8685

8786
if (elapsed >= simulationSpeed) {
8887
gpuAutomaton.Update();

game/GameController.h

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class GameController {
3232
bool showGrid;
3333
bool showUI;
3434
bool isWorldToroidal;
35+
bool isTurboBoost;
3536
int simulationSpeed = 1; // Значение 1000 может соответствовать одной секунде реального времени
3637
float frameTimeAccumulator = 0.0f;
3738

@@ -132,6 +133,9 @@ class GameController {
132133
bool getShowGrid() const {return showGrid;};
133134
void setShowGrid(bool isShow) {showGrid = isShow;};
134135

136+
void setTurboBoost(bool turboBoost) { isTurboBoost = turboBoost;};
137+
bool getTurboBoost() const { return isTurboBoost; };
138+
135139
bool getShowUI() const { return showUI; };
136140
void setShowUI(bool isShow) { showUI = isShow;};
137141

main.cpp

+49-5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ int GetMonitorRefreshRate() {
167167
return 60; // Значение по умолчанию, если не удалось получить
168168
}
169169

170+
170171
int wWinMain(
171172
_In_ HINSTANCE hInstance,
172173
_In_opt_ HINSTANCE hPrevInstance,
@@ -251,7 +252,14 @@ int wWinMain(
251252
// ===================================================================================
252253
MSG msg;
253254
bool MainLoop = true;
254-
255+
// так как у нас есть вертикальная синхронизация то колличество симуляций не сможет превысить частоту обновление монитора. поэтому мы обошли такие ограничения
256+
int monitorHz = GetMonitorRefreshRate();
257+
float frameIntervalMs = 1000.0f / monitorHz; // Например, 13.33 мс для 75 Гц
258+
PerformanceStats::getInstance().setTargetRefreshRate(monitorHz);
259+
auto lastFrameTime = std::chrono::steady_clock::now();
260+
float targetFPS = static_cast<float>(monitorHz); // Целевая частота монитора
261+
float simulationSteps = 1.0f; // Теперь float для плавности
262+
int needSteps = 1;
255263
while (MainLoop) {
256264
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
257265
TranslateMessage(&msg);
@@ -260,10 +268,46 @@ int wWinMain(
260268
MainLoop = false; // Завершение приложения
261269
}
262270
}
263-
// Здесь вызываем update с deltaTime
264-
gameController.update();
265-
PerformanceStats::getInstance().recordFrame();
266-
renderer.Draw();
271+
if (gameController.getTurboBoost()) { // экстперементальный турбо режим. работает не стабильно может повесить ОС
272+
auto now = std::chrono::steady_clock::now();
273+
auto elapsedFrameNs = std::chrono::duration_cast<std::chrono::nanoseconds>(now - lastFrameTime).count();
274+
float elapsedFrameMs = elapsedFrameNs / 1000000.0f;
275+
276+
// Обновляем статистику один раз за кадр
277+
PerformanceStats::getInstance().updateStats();
278+
float currentFPS = PerformanceStats::getInstance().getFPS();
279+
280+
// Плавная регулировка числа шагов симуляции
281+
float fpsError = targetFPS - currentFPS;
282+
float adjustment = fpsError * 0.05f; // Коэффициент сглаживания (можно настроить)
283+
simulationSteps += adjustment;
284+
285+
// Ограничиваем simulationSteps
286+
if (simulationSteps < 1.0f) simulationSteps = 1.0f;
287+
if (simulationSteps > 20.0f) simulationSteps = 20.0f;
288+
needSteps = static_cast<int>(simulationSteps + 0.5f);
289+
//if (currentFPS < (monitorHz / 2)) {
290+
// needSteps = 1;
291+
//}
292+
if (elapsedFrameMs >= frameIntervalMs) {
293+
// Выполняем симуляцию перед рендерингом
294+
for (int i = 0; i < needSteps; i++) {
295+
gameController.update();
296+
}
297+
renderer.Draw();
298+
lastFrameTime = now;
299+
PerformanceStats::getInstance().recordFrame();
300+
}
301+
}
302+
else {
303+
needSteps = 1;
304+
PerformanceStats::getInstance().updateStats();
305+
gameController.update();
306+
renderer.Draw();
307+
PerformanceStats::getInstance().recordFrame();
308+
}
309+
310+
267311
}
268312

269313
}

rendering/UIRenderer.cpp

+46-17
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ void UIRenderer::DrawMenuBar() {
5858
ImGui::MenuItem("О программе", NULL, &aboutWindowVisible);
5959
ImGui::EndMenu();
6060
}
61-
61+
if (gameController->isSimulationRunning()) {
62+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.5f, 0.3f, 1.0f)); // Красный цвет для "Выход"
63+
ImGui::Text("Симуляция запущена");
64+
ImGui::PopStyleColor();
65+
}
66+
6267
// Получаем статистику
6368
std::string statsText = PerformanceStats::getInstance().getStatsString();
6469

@@ -88,7 +93,7 @@ void UIRenderer::DrawSimulationWindow() {
8893
if (!simulationWindowVisible) return;
8994

9095
ImGui::Begin("Симуляция", &simulationWindowVisible, ImGuiWindowFlags_NoResize);
91-
ImGui::SetWindowSize(ImVec2(0, 300), ImGuiCond_Once);
96+
ImGui::SetWindowSize(ImVec2(0, 350), ImGuiCond_Once);
9297
// Управление симуляцией
9398
if (gameController->isSimulationRunning()) {
9499
if (ImGui::Button("Остановить симуляцию", buttonSize)) {
@@ -125,24 +130,48 @@ void UIRenderer::DrawSimulationWindow() {
125130
if (ImGui::Button("Случайные клетки", buttonSize)) {
126131
gameController->randomizeGrid(0.1f);
127132
}
128-
ImGui::Text("Задержка симуляции");
129-
static float simulateTime = 1;
130-
float minSimulationSpeed = static_cast<int>(PerformanceStats::getInstance().getMinSimulationDelayMs());
131-
ImGui::SetNextItemWidth(buttonSize.x);
132-
if (ImGui::SliderFloat("##simulateTime", &simulateTime, 1, 500)) {
133-
// Здесь код выполнится, если значение слайдера изменилось
134-
gameController->setSimulationSpeed(simulateTime);
135-
}
136-
137133
ImGui::Separator();
138-
ImGui::Text("Необходимо: %.2f мс", minSimulationSpeed);
139134

140-
if (PerformanceStats::getInstance().shouldUpdateSimulationSpeed()) {
141-
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); // Красный (R=255, G=0, B=0, A=255)
142-
ImGui::Text("Необходимо увеличить");
143-
// Возвращаем стандартный цвет текста
144-
ImGui::PopStyleColor();
135+
static float simulateTime = 0;
136+
if (gameController->getTurboBoost()) {
137+
138+
ImGui::Text("Задержка симуляции");
139+
ImGui::SetNextItemWidth(buttonSize.x);
140+
if (ImGui::SliderFloat("##simulateTime", &simulateTime, 0.0f, 100.0f)) {
141+
// Здесь код выполнится, если значение слайдера изменилось
142+
gameController->setSimulationSpeed(simulateTime * 100);
143+
}
144+
if (ImGui::Button("Выключить Turbo Mode", buttonSize)) {
145+
gameController->setTurboBoost(false);
146+
}
147+
float minSimulationSpeed = static_cast<int>(PerformanceStats::getInstance().getMinSimulationDelayMs());
148+
149+
ImGui::Text("Необходимо: %.2f мс", minSimulationSpeed*10);
150+
if (PerformanceStats::getInstance().shouldUpdateSimulationSpeed()) {
151+
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255)); // Красный (R=255, G=0, B=0, A=255)
152+
ImGui::Text("Увеличить !!!");
153+
// Возвращаем стандартный цвет текста
154+
ImGui::PopStyleColor();
155+
}
156+
}
157+
else {
158+
ImGui::Text("Задержка симуляции");
159+
ImGui::SetNextItemWidth(buttonSize.x);
160+
if (ImGui::SliderFloat("##simulateTime", &simulateTime, 0.0f, 5000.0f)) {
161+
// Здесь код выполнится, если значение слайдера изменилось
162+
gameController->setSimulationSpeed(simulateTime * 100000);
163+
}
164+
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(255, 0, 0, 255)); // Красный цвет кнопки
165+
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(255, 50, 50, 255)); // Чуть светлее при наведении
166+
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(200, 0, 0, 255)); // Темнее при нажатии
167+
if (ImGui::Button("Включить Turbo Mode", buttonSize)) {
168+
simulateTime = 0;
169+
gameController->setTurboBoost(true);
170+
gameController->setSimulationSpeed(0);
171+
}
172+
ImGui::PopStyleColor(3); // Сбрасываем три изменения цвета
145173
}
174+
146175
ImGui::End();
147176
}
148177

system/PerformanceStats.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,37 @@ PerformanceStats::PerformanceStats()
1616

1717
void PerformanceStats::recordFrame() {
1818
frameCount++;
19-
updateStats();
19+
//updateStats();
2020
}
2121

2222
void PerformanceStats::recordSimulation() {
2323
simulationCount++;
24-
updateStats();
24+
//updateStats();
2525
}
2626

2727
void PerformanceStats::updateStats() {
2828
LONGLONG currentTime = GetTickCount64();
2929
LONGLONG elapsedTime = currentTime - lastUpdateTime;
3030

3131
if (elapsedTime >= updateInterval) {
32-
// Вычисляем FPS и симуляции в секунду
3332
fps = static_cast<float>(frameCount) * 1000.0f / elapsedTime;
3433
simulationsPerSecond = static_cast<float>(simulationCount) * 1000.0f / elapsedTime;
3534

36-
// Среднее время на кадр и симуляцию
35+
// Считаем среднее время на кадр и симуляцию
3736
avgFrameTimeMs = (frameCount > 0) ? (1000.0f / fps) : 0.0f;
3837
avgSimulationTimeMs = (simulationCount > 0) ? (1000.0f / simulationsPerSecond) : 0.0f;
3938

40-
// Сбрасываем счетчики и время
39+
// Обновляем историю FPS
40+
fpsHistory[historyIndex] = fps;
41+
historyIndex = (historyIndex + 1) % 5; // Циклический индекс
42+
43+
// Считаем сглаженное FPS
44+
smoothedFPS = 0.0f;
45+
for (int i = 0; i < 5; i++) {
46+
smoothedFPS += fpsHistory[i];
47+
}
48+
smoothedFPS /= 5.0f;
49+
4150
frameCount = 0;
4251
simulationCount = 0;
4352
lastUpdateTime = currentTime;

system/PerformanceStats.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class PerformanceStats {
1818
void recordSimulation(); // Для подсчета симуляций (вызов Update)
1919

2020
// Получение текущих значений
21-
float getFPS() const { return fps; }
21+
float getFPS() const { return smoothedFPS; } // Возвращаем сглаженное значение
2222
float getSimulationsPerSecond() const { return simulationsPerSecond; }
2323

2424
float getMinSimulationDelayMs() const; // Минимальная задержка симуляции
@@ -52,7 +52,9 @@ class PerformanceStats {
5252
float avgFrameTimeMs = 0.0f; // Среднее время кадра (мс)
5353
float avgSimulationTimeMs = 0.0f;// Среднее время симуляции (мс)
5454

55-
55+
float fpsHistory[5] = { 75.0f, 75.0f, 75.0f, 75.0f, 75.0f }; // История FPS (5 значений)
56+
int historyIndex = 0; // Индекс для записи
57+
float smoothedFPS = 75.0f; // Сглаженное значение FPS
5658

5759
};
5860

0 commit comments

Comments
 (0)