В настоящее время я делаю 2D-игру в Firemonkey для своего телефона Android, используя некоторые элементы управления TImage и контролируя их положение и углы. Просто как тот. Я попытался использовать свой обычный способ зацикливания, который работает хорошо/безупречно в Windows, но не работает на Android.
Способ 1. Бесконечный цикл (плохо)
Моя основная проблема заключается в том, что я хочу избежать нежелательного/неожиданного поведения, используя «бесконечный цикл», подобный этому, где я должен вызывать Application.ProcessMessages()
:
while (Game.IsRunning()) do
begin
{ Update game objects and stuff }
World.Update();
{ Process window messages, or the window will not respond anymore obviously }
Application.ProcessMessages(); { And thats what i want to avoid }
end;
Проблема в том, что, поскольку я застрял в цикле, а также вызываю процедуру для обработки сообщений, я могу столкнуться со многими проблемами, а также я просто не думаю, что это хороший способ.
Способ №2: TTimer (даже не думайте об этом ;-))
Поскольку TTimer ужасен во многих отношениях и не предназначен для таких целей, подход, когда я просто ставлю TTimer с минимальным интервалом, отпадает. Кроме того, я никогда не пробовал другие таймеры, но если есть действительно для игр, я, конечно, попробую :)
Способ №3: OnIdle — как я обычно это делаю в Windows
В Windows я могу использовать Application.OnIdle-Event.
procedure GameLoop(Sender: TObject; var Done: Boolean);
begin
{ Update game objects and stuff }
World.Update();
{ Set done to false }
Done := False;
end;
...
Application.OnIdle := GameLoop;
Он вызывается каждый раз, когда приложение простаивает над сообщениями Windows. Производительность кажется такой же или немного хуже по сравнению с № 1, а общая архитектура намного надежнее, поэтому я обычно использую этот метод. Однако на Android кажется, что он вызывается по-другому в сочетании с TForm.MouseMove. Там, где в Windows OnIdle продолжает работать отлично, на Android он будет зависать/останавливаться, пока TForm.MouseMove вызывается из сенсорного ввода (RAD Studio автоматически компилирует его в сенсорные события)
Однако я могу запустить OnIdle самостоятельно в событии MouseMove, вызвав Application.DoIdle
и "помощь" "Циклу", где, я думаю, он пропускает вызов beimg, но это также работает очень плохо и снова вызывает нежелательное поведение и хуже производительность при работе с сенсорным вводом.
И это возвращает меня к методу № 1, который на данный момент лучше всего работает на Android. Есть ли какой-либо другой способ создания надежного способа (постоянно и быстро вызываемого события, такого как OnIdle или около того) создания такого цикла или любого способа избежать проблем, с которыми я столкнулся в методе № 3 в сочетании с MouseMove-Events? Кажется, что Android-телефон недостаточно мощный, чтобы иметь достаточно «Время простоя» рядом с формами-событиями и мировыми обновлениями.
Кроме того, могу ли я рассмотреть возможность использования потока для мировой логики и рядом с ним метода № 1 в моей основной форме/потоке для обновления рендеринга? Безопасно ли обновлять элементы управления формы бесконечным циклом (с помощью Application.ProcessMessages()) и получать отображаемые данные из другого потока, работающего с миром, объектами и т.д.?