_Process и _PhysicsProcess: время, включение и пауза
Рабочий счётчик двух callback: delta, отдельное отключение и интерфейс, который продолжает работать на паузе.
Выбрать callback
_Process вызывается в цикле обычного кадра с переменным delta; _PhysicsProcess — в цикле физического шага. Частоту задаёт physics/common/physics_ticks_per_second, но длинный кадр может потребовать несколько шагов, а лимит догоняющей обработки ограничивает работу. Не ожидайте один физический callback на каждый нарисованный кадр.
| Задача | Обычно подходит |
|---|---|
| Управление физическим CharacterBody | _PhysicsProcess и методы движения тела |
| Непрерывная физическая сила | Физический шаг; сила уже интегрируется методом |
| Обновление счётчика/UI | _Process, событие или таймер по требованию |
| Ручная камера по визуальной позе | Выбранная покадровая схема с учётом интерполяции |
| Дорогой HTTP/файл/длительный расчёт | Отдельный асинхронный/фоновый механизм, не блокировка каждого кадра |
delta измеряется в секундах игрового времени и зависит от временных настроек. Для прямого изменения Position прибавляйте speed × delta. Для MoveAndSlide задавайте Velocity без дополнительного delta, для ускорения меняйте Velocity с delta. В callback используйте переданный аргумент; GetProcessDeltaTime/GetPhysicsProcessDeltaTime не являются отдельными часами реального времени.
Запустить счётчики
Добавьте ClockProbe.cs и ProcessingClockDemo.cs. Создайте отдельный уровень с корнем Control, прикрепите ProcessingClockDemo, соберите и запустите F6. Окно — 640×420 или больше. Счётчики показывают вызовы и сумму delta, а не измерение производительности всей игры.
Первая кнопка отключает только _Process у Probe, вторая — только _PhysicsProcess. На паузе оба счётчика Probe стоят, но интерфейс остаётся активен и позволяет снять паузу. У UI установлен Always, у Probe — явный Pausable; наследование здесь намеренно не используется для Probe. При удалении примера прежнее значение EntityTree.Paused восстанавливается.
ClockProbe.cs
using Reckfell;
public partial class ClockProbe : Entity
{
public int Frames { get; private set; }
public int Ticks { get; private set; }
public double FrameSeconds { get; private set; }
public double PhysicsSeconds { get; private set; }
public override void _Process(double delta) { Frames++; FrameSeconds += delta; }
public override void _PhysicsProcess(double delta) { Ticks++; PhysicsSeconds += delta; }
}ProcessingClockDemo.cs
using Reckfell;
public partial class ProcessingClockDemo : Control
{
public ClockProbe Probe { get; private set; } = null!;
public Label Status { get; private set; } = null!;
private bool _initialPause;
public override void _Ready()
{
ProcessMode = ProcessModeEnum.Always; _initialPause = GetTree().Paused;
Probe = new ClockProbe { ProcessMode = ProcessModeEnum.Pausable }; AddChild(Probe);
var box = new VBoxContainer { Position = new Vector2(24,24) }; AddChild(box);
Status = new Label(); box.AddChild(Status);
AddButton(box, Text("Переключить _Process", "Toggle _Process"), () => Probe.SetProcess(!Probe.IsProcessing()));
AddButton(box, Text("Переключить _PhysicsProcess", "Toggle _PhysicsProcess"), () => Probe.SetPhysicsProcess(!Probe.IsPhysicsProcessing()));
AddButton(box, Text("Пауза мира", "Pause world"), () => GetTree().Paused = !GetTree().Paused);
}
private static string Text(string ru,string en) => TranslationServer.GetLocale().StartsWith("ru") ? ru : en;
private static void AddButton(VBoxContainer box,string text,System.Action action)
{
var button = new Button { Text = text }; box.AddChild(button); button.Pressed += action;
}
public override void _Process(double delta)
{
Status.Text = $"_Process: {Probe.Frames} / {Probe.FrameSeconds:F2}s\n_PhysicsProcess: {Probe.Ticks} / {Probe.PhysicsSeconds:F2}s\nPaused: {GetTree().Paused}";
}
public override void _ExitTree() { GetTree().Paused = _initialPause; }
}Включение и эффективная обработка
Переопределённые callback скрипта включаются для обработки автоматически. SetProcess и SetPhysicsProcess переключают разные флаги. IsProcessing/IsPhysicsProcessing показывают флаг включения, но Pause/ProcessMode могут запретить фактический вызов. Если объект не вызывается, проверьте нахождение в дереве, режим, паузу, флаг и наличие правильного override.
Always позволяет работать при паузе, но не делает код независимым от всех временных настроек и не разрешает любой доступ из другого потока. Inherit получает режим родителя; для меню паузы и игрового мира задайте понятные границы. Отключение _Process не отключает сигналы всех дочерних кнопок автоматически; именно поэтому отдельные обработчики могут снова включить счётчик.
Не выводите строку в консоль каждый кадр ради наблюдения: лог сам добавляет нагрузку. Обновляйте компактный индикатор или собирайте ограниченную трассу. Для периодических действий используйте подходящий Timer/событие; для физического движения согласуйте интерполяцию. Паузу, остановку callback и удаление сущности проверяйте как разные состояния.