Blitzmax
Пятница, 17.05.2024, 09:51
Приветствую Вас Гость | RSS
 
Главная СтатьиРегистрацияВход
Меню сайта
Категории каталога
Разное [2]
BlitzMax [5]
Доки/Уроки [8]
Игровое программирование [1]
Наш опрос
Оцените скорость работы с сайтом
Всего ответов: 112
Главная » Статьи » Игровое программирование

Оптимальная синхронизация главного цикла

Как я и обещал в своем блоге, напишу небольшую статью про синхронизацию главного игрового цикла с учетом особенностей Blitzmax. Это, в общем, не должно составлять больших проблем, но моей целью был не простой цикл, а динамический, с подстройкой частоты обновления под конфигурацию. Так, чтобы на более медленных машинах частота обновления (прохода главного цикла) уменьшалась до приемлимого минимума и не грузила процессор, а на быстрых – поднималась до оптимального значения. Код должен быть максимально совместим с учетом мультиплатформенности, в дебри не лезть и своих модулей на С/С++ не писать (не царское это дело, да еще под три платформы – трижды не царское).

Итак, цели: использовать только стандартные возможности языка для совместимости; максимальное снижение ненужной нагрузки на систему; независимость скорости анимации; управление частотой обновления для снижения нагрузок на слабые системы. Скажу сразу – эта задача в идеале решена не была. Зато было достигнуты почти все цели и еще одна: минимизация используемого кода и ресурсов. Теперь подробнее.

Я не буду приводить всех листингов (чтобы просто не набирать их заново), приведу только последний выбранный вариант. Использованные тупиковые варианты, думаю, можно для интереса будет написать и самому при желании.

Итак: как синхронизировать главный цикл? Типичное решение – это ввести цикл ожидания на основе счетчика времени одного прохода и использовать его для паузы в главном цикле. При достижении значения, определяемого частотой обновления, продолжать главный цикл. Все работает вполне отлично. Даже можно дописать код регуляции частоты обновления на основе разницы времени на отрисовку и обновление сцены и номинальной частоты обновления, если эта разница есть, конечно. Возникает одно но – все процессорное время жрет наша игра. Ну почти все, т.к. все никто ей не отдаст. Какой здесь выход? Выход в том, что в цикле ожидания надо отдавать время системе, причем желательно на определенны период времени, который можно рассчитать. Но такой возможности в Blitzmax я не нашел. Есть команда WaitSystem, которая и передает время системе, но в ней нельзя указать на сколько, - и возврат в наше приложение происходит только при посылке ему какого-либо сообщения (мышкой там провели над ним и т.п.). Т.е. – никакой анимации и плавного движения мы не получаем.

Второй способ состоял в использовании таймера. Делается таймер с нужной частотой обновления и в главный цикл добавляется команда WaitTimer, заменяющая цикл ожидания. Плюс способа один: WaitTimer передает управление системе, отъедая минимум системного времени, что нам и надо. Минус: в стандартном таймере мы не можем никак регулировать частоту – она задается только один раз при его создании. Небольшое копание в WinApi, привело к выводам, что все это решаемо, но в Blitzmax не сделано. Возможно из-за совместимости с другими ОС, хотя мне кажется странной невозможность изменения интервала ожидания по ходу работы таймера. Есть конечно промежуточное решение – пересоздавать каждый раз в главном цикле таймер с нужным нам интервалом для синхронизации. Но у него недостаток в избыточном потреблении ресурсов. Было бы прекрасно, если бы была просто команда, отдающая управление системе на какой-то отрезок времени. Ее можно реализовать на том же АПИ – timeSetEvent (для Windows, по крайней мере) и не потреблять лишних ресурсов для класса таймера. Для достижения одной из целей – равномерности движения вне зависимости от скорости надо просто добавить коэффициент, который будет рассчитываться в главном цикле, и корректировать скорость анимации объектов.

Третий способ, на котором я остановился, основан на внимательном рассмотрении функций Blitzmax Graphics и Flip. У Graphics есть аргумент hertz, который определяет частоту обновления созданного окна. А у Flip – флаг со значением -1, который привязывает отрисовку к частоте обновления окна, созданного Graphics. Используя это в связке, нам не нужно создавать лишний таймер для синхронизации. Но как и в случае с таймером, мы не можем регулировать скорость обновления.

Вот полученный код:

Strict

Local bExit% = False

Const fBaseFPS# = 50
Const
cTimeDelta% = 1000/fBaseFPS '1000 - milisec in second / fps

Local
fps%= -1

Global fSpeedMul# = 1;

Graphics 800 , 600 , 0 , fBaseFPS

While Not bExit

bExit = KeyDown(KEY_ESCAPE) | AppTerminate()

Local startTime = MilliSecs();

DrawScene()

'draw info

DrawText "FPS: " + fps , 8 , 8
DrawText
"K: "+Round(fSpeedMul), 100,8
DrawText
"Mem: "+GCMemAlloced(), 300,8

'animate scene

UpdateScene()

'Delay(30)

Flip(-1)'by Graphics refresh rate

fps = 1 / Float(MilliSecs() - startTime) * 1000
fSpeedMul = fBaseFPS / fps

Wend

Global x#=0, y#=300

Function UpdateScene()
x :+ 0.5 * fSpeedMul
If
x > GraphicsWidth() Then x = 0
End Function

Function DrawScene()
Cls
DrawOval
(x,y, 50, 50)
End Function

Function Round$(value!, nDecimals%=2)

Local str$ = value
Local
pos% = Instr(str , ".")
str = str[..pos + nDecimals]
Return
str

End Function

End

Итоги: получен главный цикл, отъедающий время пропорционально своим усилиям, учитывающий задержки при отрисовке и обновлении, максимально совместимый и наименее ресурсоемкий как со стороны написания (меньше кода), так и со стороны системных ресурсов (лишний таймер не создается). Недостаток – на слабых платформах, не укладывающихся в номинальное время прохода цикла, будет забираться все время системы (отведенное на процесс естественно), тогда как понизив частоту отрисовки, можно было бы его уменьшить, снизив общую нагрузку.

Еще в процессе выявлено несколько недостатков языка:

- не обновляется содержимое окна при таскании его за заголовок (с тем-же фреймвоком от Поп-Кап таких проблем нет).
- нет нужных команд для временной передачи лишнего времени системе. В Win и PalmOS это вполне возможно, в других ОС, думаю, тоже.
- нет возможности изменять частоту таймера в процессе его работы.

Категория: Игровое программирование | Добавил: oxid (25.06.2007) | Автор: oxid
Просмотров: 3257 | Комментарии: 5 | Рейтинг: 5.0/1 |

Всего комментариев: 5
25.06.2007
1. nLc.
Неплохо в целом и дизайн ничего... smile

25.06.2007
2. oxid
Спс. Только дизайн - стандартный шаблон юкоза.

26.06.2007
3. nLc.
Цвет фона в смайлах надо изменить под цвет фона мессаджей...

26.06.2007
4. oxid
Я наоборот сделал biggrin - поменял цвет фона комментов

27.06.2007
5. nLc.
Тоже выход wink

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Поиск
Ссылки
Статистика
Copyright Oxid © 2024
Сайт создан в системе uCoz