Найти в Дзене

Аналоговые часы на Бейсике. Часть 1

Всем привет! Сегодня мы будем создавать аналоговые часы (со стрелками). Вот как это выглядит: Технология создания такова: сначала рисуем циферблат, потом запускаем бесконечный цикл, в котором раз в секунду получаем текущее время, разделяем его на составляющие (часы, минуты, секунды) и отрисовываем стрелки часов. Чтобы получить эффект анимации, затираем старые стрелки перед рисованием новых. Кто не знаком с основными операторами графического режима, читаем эту статью. Полный список уроков по Бейсику для начинающих - здесь. Окружность циферблата рисуем с помощью CIRCLE - это понятно. Но вот создание самих цифр, точнее, их расположение, потребует от нас новых знаний. Если посмотрите внимательно и подумаете, то становится понятно, что стандартным LOCATE для их правильного положения воспользоваться не получится, т.к. LOCATE может указать положение только относительно нужной строки и позиции в тексте (подробности работы с LOCATE можно изучить тут). А в нашем случае цифры могут располагаться
Оглавление

Всем привет! Сегодня мы будем создавать аналоговые часы (со стрелками). Вот как это выглядит:

Технология создания такова: сначала рисуем циферблат, потом запускаем бесконечный цикл, в котором раз в секунду получаем текущее время, разделяем его на составляющие (часы, минуты, секунды) и отрисовываем стрелки часов. Чтобы получить эффект анимации, затираем старые стрелки перед рисованием новых.

Кто не знаком с основными операторами графического режима, читаем эту статью. Полный список уроков по Бейсику для начинающих - здесь.

Создаем циферблат

Окружность циферблата рисуем с помощью CIRCLE - это понятно. Но вот создание самих цифр, точнее, их расположение, потребует от нас новых знаний. Если посмотрите внимательно и подумаете, то становится понятно, что стандартным LOCATE для их правильного положения воспользоваться не получится, т.к. LOCATE может указать положение только относительно нужной строки и позиции в тексте (подробности работы с LOCATE можно изучить тут). А в нашем случае цифры могут располагаться и между строк (ну, если представить, где могли бы располагаться строки в текстовом режиме). В общем, нужно какое-то другое решение, такое, которое позволило бы размещать цифры в координатах графического режима, а не текстового.

Такое решение есть, но только для QB64. Напоминаю, что мы с самого начала пользуемся этим компилятором. О том, где его взять я писал в самом начале.

В QB64 есть специфические операторы, начинающиеся на знак подчеркивания. В нашем случае нам понадобится _PRINTSTRING. Из его названия можно понять, что он печатает символьную информацию. Формат записи:

_PRINTSTRING(x,y), $text

где х и у - координаты, а $text - собственно, выводимый текст.

Нам необходимо вывести цифры от 1 до 12, поэтому придется их предварительно перевести в строки - чтобы можно было бы воспользоваться этим оператором. Кроме того, раз это простой ряд цифр, то нам ничего не мешает воспользоваться циклом. Осталось решить вопрос с координатами каждой цифры.

Определяем координаты цифр

Точка в координатной плоскости, которая остается неизменной - это центр циферблата. Поэтому все координаты в часах (цифр и концов стрелок) будем вычислять относительно центра.

Давайте в качестве примера определим координаты положения цифры 2. Для этого нам понадобится знание геометрии.

-2

Здесь Xc и Yc - координаты центра часов/циферблата, X2 и Y2 - координаты цифры 2, dx и dy - расстояние от координат центра до координат цифры (приращение), α - угол между горизонтальным катетом и гипотенузой, R - радиус циферблата (расстояние от центра до цифр).

Тут нужно отметить, что угол считается от горизонтали по часовой стрелке. Следовательно, угол у цифры 3 будет равен 0, у цифры 4 - так как она находится по ходу часовой стрелки - положительное значение, а у цифр 1 и 2 - отрицательное (потому что против часовой стрелки). Этот нюанс нам надо будет в будущем учесть. То есть начинать придется не с нуля, а с какой-то отрицательной величины угла - т.к. цифры начинаются не с трех, а с одного. Надеюсь, понятно изложил мысль.

Итак, чтобы получить координаты X2 и Y2, необходимо найти dx и dy. А для этого необходимо знать угол α. Радиус нам известен. Также нам известно, что:

cos α = dx/R,

sin α = dy/R

Следовательно, мы из этих выражений можем получить dx и dy:

dx = cos α * R,

dy = sin α * R

Теперь мы можем найти X2 и Y2:

X2 = Xc + dx = Xc + cos α * R,

Y2 = Yc + dy = Yc + sin α * R

В Бейсике углы меряют в радианах, а не градусах. Из геометрии мы помним, что 1 град = π/180. Следовательно, выражения принимают такой вид:

X2 = Xc + cos π/180 * R,

Y2 = Yc + sin π/180 * R

Угол будет меняться на одинаковую величину - это понятно. Значит, можно будет зациклить - чтобы не рисовать отдельно каждую цифру. Осталось найти эту величину. Но это просто. Полный оборот - это 360 градусов. Цифр - 12. Значит, величина приращения угла составляет 360/12=30 град.

Повторюсь. Так как угол должен считаться не так, как нам удобно было бы - от вертикали (от цифры 12) - а от горизонтали (от цифры 3), то на самом деле 0 град - это горизонталь вправо (цифра 3), а цифры 1 и 2, соответственно, отрицательный угол, потому что против часовой стрелки. Может быть и не отрицательный, а 300 град и 330 град, соответственно. Но нам же надо запускать часы не с цифры три, а с 12. Поэтому придется начинать с некоего отрицательного значения угла.

Если бы углы шли от вертикали, то цифра 1 была под углом 30 град - т.к. 360/12=30. Но так как углы идут по часовой стрелке от горизонтали, то угол цифры 1 не 30 град, а минус 60 град. Угол цифры 2 - минус 30 град. Угол цифры 3 - ноль градусов. Следовательно, надо придумать, как в цикле получать нужные углы от -60 до 270 - вместо логичных от 30 до 360.

Путем недолгих размышлений мы понимаем, что, если угол цифры 3 равен 0 град, но по ходу часов это вообще-то 90 град. А цифра 12 имеет угол 270 град, но, т.к. с нее все начинается, то это -90 град. Значит, чтобы получить нужный (логичный) угол из реального, необходимо отнять 90:

X2 = Xc + cos ( (α - 90) * π/180 ) * R

Y2 = Yc + sin ( (α - 90) * π/180 ) * R

Пробуем рисовать

Давайте для начала нарисуем внешнюю окружность часов и, для простоты эксперимента, точки (маленькие круги) вместо цифр. Радиус циферблата примем 100 пикс, часы разместим строго по центру окна. Цвет всего пока белый. Точки (которые вместо цифр) разместим ближе к центру, например, расстояние от центра 90 пикс.

Вот что у нас получается:

-3

Код:

-4

Обратите внимание, как мы получаем текущий угол: цифру просто умножаем на 30 - т.к. значения углов у нас кратны тридцати (см. выше).

Добавляем цифры

Теперь, когда эксперимент с вычислениями координат прошел успешно, вернемся к оператору _PRINTSTRING и попробуем вместо точек вставить наши цифры:

-5

Обратите внимание, координаты X2 и Y2 мы поменяли на более понятные X и Y. И т.к. этот оператор работает только со строковыми значениями, то преобразуем наши числа в строки с помощью функции STR$. Результат:

-6

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

Для того, чтобы увидеть возможные пробелы, нам нужно закрасить фон и цифр. Для этого перед _PRINTSTRING добавляем COLOR с фоновым цветом:

-7

Получаем:

-8

Посмотрите: слева от каждого числа есть пустой пробел. Для этого мы фон и сделали - чтобы заметить это. Чтобы четко позиционировать циферблат, необходимо очистить его от лишнего. Уберем пробелы слева с помощью функции LTRIM$:

LTRIM$(STR$(i))

Результат:

-9

Что и требовалось доказать, как говорится.

Теперь можно убрать фон и поработать над центровкой циферблата. По вертикали нам нужно поднять его, а по горизонтали - сдвинуть влево. Соответственно, для текущих координат по осям X и Y надо отнимать какое-то значение. Для начала просто отнимем и там, и там по 5 пикселей.

Код:

-10

Результат:

-11

Уже неплохо. Но если внимательно посмотреть, то видно, что по горизонтали мы немного переборщили - надо бы на 1 пикс правее сделать. А по вертикали еще на 1 пикс выше. Пробуем:

-12

Вот теперь - правильно. Думаю, на сегодня хватит информации. И так много времени потратил. Рисовать стрелки часов и пуск их в работу читайте во второй части.

Комменты приветствуются, за палец вверх - отдельное спасибо. Удачи!