Выход из игры: подтверждение и отмена
Не закрывать игру до подтверждения и завершения сохранения.
Закрытие окна, кнопка «Выход» и прямой вызов Quit() — разные пути. По умолчанию EntityTree.AutoAcceptQuit и EntityTree.QuitOnGoBack включены. Для собственного подтверждения отключите оба автоматических выхода и направляйте запросы одному контроллеру.
Контроллер выхода
Создайте C#-проект Reckfell 1.0.0. Сохраните код в ExitController.cs и прикрепите к Entity, которая остаётся в дереве, пока работает меню подтверждения. Для нескольких уровней подойдёт автозагрузка.
using Reckfell;
public partial class ExitController : Entity
{
[Signal] public delegate void ConfirmationRequestedEventHandler();
public bool ConfirmationPending { get; private set; }
public override void _Ready()
{
GetTree().AutoAcceptQuit = false;
GetTree().QuitOnGoBack = false;
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest || what == NotificationWMGoBackRequest)
RequestExit();
}
public void RequestExit()
{
if (ConfirmationPending) return;
ConfirmationPending = true;
EmitSignal(SignalName.ConfirmationRequested);
}
public void CancelExit() => ConfirmationPending = false;
public void ConfirmExit()
{
if (!ConfirmationPending) return;
ConfirmationPending = false;
GetTree().Quit();
}
}Сам скрипт не рисует окно. Подключите его к своему интерфейсу:
- Сигнал
ConfirmationRequestedоткрывает меню с кнопками «Выйти» и «Остаться». - Кнопка «Выход» в основном меню вызывает
RequestExit(). - Кнопка «Остаться» вызывает
CancelExit()и скрывает меню. - Кнопка «Выйти» вызывает
ConfirmExit(). Если нужно сохранение, сначала завершите его и проверьте результат; при ошибке оставьте меню открытым и не вызывайтеConfirmExit().
Повторный запрос при открытом подтверждении не создаёт второй диалог. ConfirmExit() без ожидающего запроса ничего не делает. Сам контроллер не сохраняет игру: законченный пример записи, резервной копии и загрузки есть в сохранении данных.
Что делает движок
| Действие | Результат |
|---|---|
| Запрос закрытия окна | Окно распространяет NotificationWMCloseRequest и выдаёт CloseRequested. Автоматический выход основного окна зависит от AutoAcceptQuit. |
| Запрос Back | Выдаётся NotificationWMGoBackRequest; автоматический выход зависит от QuitOnGoBack. Отключение только AutoAcceptQuit недостаточно. |
GetTree().Quit(23) | Запрашивает завершение с кодом 23. Сам не посылает уведомление закрытия, не открывает подтверждение и не сохраняет данные. |
Root.PropagateNotification(...) | Синхронно уведомляет корень и потомков. Само распространение не завершает процесс; обработчик может вызвать Quit(). |
Не делайте await после Quit() с расчётом на завершение сохранения. Сначала дождитесь операции, затем запрашивайте выход. Не рассылайте уведомление закрытия из каждого обработчика: это повторно вызовет те же обработчики.
Проверка и ошибки
- Нажмите «Выход» дважды: подтверждение должно открыться один раз. Выберите «Остаться»: игра продолжает работать.
- Повторите запрос и подтвердите: процесс завершается. Для собственного меню используйте
RequestExit(), а не прямойQuit(). - Игра закрывается раньше подтверждения: проверьте оба флага дерева и другие вызовы
Quit(); контроллер должен успеть войти в дерево. - Сохраняется не всё: найдите асинхронную операцию, после которой вызывается
Quit()без ожидания, и обработайте ошибку записи.
На мобильных устройствах и при принудительном завершении нельзя полагаться на подтверждение выхода. Делайте контрольные сохранения в ходе игры; обработку ухода в фон проверяйте на целевой платформе. Здесь не обещается гарантированный последний вызов перед уничтожением процесса.
Проверено в установленном движке: точный контроллер, уведомления, повторный запрос, отмена, подтверждение, стандартные подключения сигналов основного окна и код завершения 23. Проверка использует искусственные сигналы и уведомления в headless-режиме; нажатие системной кнопки окна, вид диалога, мобильный жизненный цикл и экспортированные сборки отдельно не проверены.