---
id: game-loop
lang: ru
title: Игровой цикл и время
description: >-
  Отделяем скорость игры от частоты кадров и проверяем поведение при паузах и
  просадках FPS.
category: foundations
level: beginner
minutes: 6
updatedAt: '2026-10-20'
tags:
  - game-loop
  - time
  - simulation
sources:
  - title: 'Robert Nystrom: Game Loop'
    url: 'https://gameprogrammingpatterns.com/game-loop.html'
  - title: 'MDN: requestAnimationFrame'
    url: >-
      https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
  - title: 'Glenn Fiedler: Fix Your Timestep!'
    url: >-
      https://github.com/mas-bandwidth/gafferongames/blob/main/content/post/fix_your_timestep.md
url: 'https://gamemechanics.pro/ru/lessons/game-loop/'
markdownUrl: 'https://gamemechanics.pro/content/ru/game-loop.md'
license: CC-BY-4.0
codeLicense: MIT
attribution: gamemechanics.pro contributors
---

## Что нужно знать

Достаточно понимать переменные, функции и координаты. После урока вы сможете объяснить, кто обновляет мир, в каких единицах задана скорость и почему один нарисованный кадр не всегда равен одному шагу симуляции.

## Принцип

Игровой цикл связывает ввод, изменение состояния и отображение результата. Даже если персонаж стоит, мир может продолжать жить. В готовом движке этот цикл уже существует: ваша задача подключить логику к подходящим точкам обновления. Общая модель разобрана в [главе Game Loop](https://gameprogrammingpatterns.com/game-loop.html).

Запись `x += 3` означает три единицы за вызов. При разной частоте вызовов персонаж проходит разное расстояние. Запись `x += speed * dt` задаёт движение через прошедшее время, где `speed` измеряется в единицах в секунду, а `dt` в секундах. Но это само по себе не делает любую физическую модель устойчивой.

Для чувствительной к шагу симуляции используют фиксированный интервал обновления. Накопленное реальное время расходуется на несколько одинаковых шагов; отрисовка может происходить реже или чаще. Ограничение числа догоняющих шагов требует явного решения: замедлять игровой мир или иначе обрабатывать перегрузку. Подробности есть в [Fix Your Timestep!](https://github.com/mas-bandwidth/gafferongames/blob/main/content/post/fix_your_timestep.md).

## Практический пример

Начните с одного квадрата без столкновений. Пусть он движется со скоростью 120 единиц в секунду. За две секунды непрерывного движения ожидается 240 единиц независимо от количества показанных кадров.

```text
update(dtSeconds, input):
    if input.moveRight:
        player.x += 120 * dtSeconds

render():
    drawSquare(player.x, player.y)
```

Это учебный псевдокод, а не готовый цикл движка. Сначала вызовите `update` 120 раз с шагом `1/60`, затем 60 раз с шагом `1/30`. Сравните координаты с небольшой допустимой погрешностью. Отдельно попробуйте меняющиеся интервалы с той же суммой времени.

В браузере `requestAnimationFrame` вызывает функцию перед перерисовкой и обычно приостанавливается в фоновых вкладках. Его временная метка задана в миллисекундах. Эти условия документирует [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame). При возвращении из фона задайте политику возобновления: например, сбросить предыдущую метку времени и продолжить с паузы.

## Частые ошибки

Не обновляйте координаты одновременно в физическом и визуальном callback (обработчике, который вызывает движок). Не применяйте `dt` дважды, если метод движка уже ожидает скорость. Не запускайте второй цикл при каждом рестарте сцены. Не используйте скрытие вкладки как неявную паузу: звук, сетевые события и таймеры могут иметь другой жизненный цикл.

Сначала проверяйте движение без интерполяции. Когда логика верна, визуальное сглаживание можно добавить отдельно. Иначе плавная картинка способна скрыть ошибку в скорости или порядке обновления.

## Проверка результата

- За одинаковое игровое время квадрат проходит одинаковый путь при разных частотах обновления.
- Пауза останавливает нужные системы, а интерфейс остаётся доступным.
- Возврат из фоновой вкладки не телепортирует персонажа.
- Повторный запуск сцены не удваивает скорость.
- В коде подписаны единицы времени и скорости.

## Задание для ИИ-агента

> Найди владельца игрового цикла и все места изменения координат игрока. Опиши единицы скорости и времени. Предложи минимальное исправление зависимости движения от FPS и проверь путь за две секунды при нескольких последовательностях dt. Отдельно укажи поведение паузы и восстановления фокуса. Не меняй физический backend без доказанной необходимости.
