Pull to refresh

Corona SDK точный таймер

Reading time3 min
Views2.4K
Всем привет. В этой краткой статье я расскажу как сделать в вашем приложении на Corona SDK таймер с приемлемым показателем точности отсчета. Так же рассмотрим в чем заключаются проблемы стандартного таймера.

В статье будет решаться следующая задача: Сделать приложение которое будет показывать время прошедшее с момента включения приложения с его обновлением 1 раз в секунду.

1.Очевидное стандартное решение.


Создаем стандартный таймер и выводим его тики.

timeout = 1000
timer.performWithDelay( timeout,function(event)
	print(event.count)
end,0)

Вроде бы все очевидно, но в работе этого решения есть особенности:

  • Во-первых стандартный таймер способен корректно и достаточно точно отрабатывать таймауты начиная с 300-400мс, а все что ниже этого значения начинает очень существенно отставать, но наш случай другой так как таймаут более указанных пределов. Минимально возможный период тиков таймера (если указать 1 мс) 1/fps, т.е. 16.(6)мс для 60 кадров или 33.(3)мс для 30 кадров.
  • Во-вторых даже на указанном относительно точном периоде имеется случайная погрешность около 5-10 мс с каждого тика, т.е. за час набегает погрешность 15-30секунд. Эту проблему частично можно решить отняв 5 мс от того значение которое указывается в параметре при создании таймер, т.е. вместо 1000 указать 995.
  • В-третьих если в вашем приложении будут возникать мелкие фризы вызванные результатом работы другого кода или нестабильной работой устройства, эти фризы так же будут добавляться в копилку отставания в работе таймера.
  • В четвертых если свернуть приложение на какое-то время и после этого его заново развернуть, все время которое приложение было свернуто будет исключено из количества секунд работы приложения.

2. Хорошее решение.


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

local timeout = 1000--таймаут
socket = require "socket"
local start_time = socket.gettime()*1000--время инициализации таймера(старт приложения)
local good_time = 0
timer.performWithDelay( 1,function(event)
	local new_time = socket.gettime()*1000--новая временная метка
	local total_time = new_time - start_time--прошло времени с момента запуска приложеня
	local num = math.floor(total_time/timeout)--количество прошедших целых периодов размером в timeout
	if num > good_time then--если пришло время нового тика
		good_time = num--новый тик
		print(good_time)
	end
end,0)

Разбираем особенности этого метода. Несмотря на то что мы указываем частоту тиков 1мс как было описано выше реальные кванты тиков будут выполняться с раз в 16(33)-50мс, а это и будет определять максимально возможную погрешность приведенного выше метода, погрешность будет изменяться в диапазоне 0..50мс от тика к тику, т.е. частота следования тиков будет менее стабильной чем в первом методе, но величина этой погрешности на любой дистанции (даже длиной в годы) будет одинаковой, т.е. даже через год наш очередной тик будет иметь погрешность в этих же пределах относительно самого первого тика.

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


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

local timeout = 1000
socket = require "socket"
local start_time = socket.gettime()*1000--время инициализации таймера
local good_time = 0--время сокетного счетчика
local bad_time = 0--время обычного счетчика

--плохой таймер
timer.performWithDelay( timeout,function(event)
	bad_time = event.count
	local bad_delta = (socket.gettime()*1000 - start_time) - (bad_time*timeout)
	print('Bad tick: '..bad_time, 'Delta: '..bad_delta)
end,0)

--хороший таймер
timer.performWithDelay( 1,function(event)
	local new_time = socket.gettime()*1000
	local total_time = new_time - start_time
	local num = math.floor(total_time/timeout)
	if num > good_time then
		good_time = num
			local good_delta = (socket.gettime()*1000 - start_time) - (good_time*timeout)
			print('Good tick: '..good_time, 'Delta: '..good_delta)
	end
end,0)

Всем удачи!
Tags:
Hubs:
Total votes 7: ↑7 and ↓0+7
Comments3

Articles