Уроки
Написать нам

Урок 6. Круглый регулятор громкости - Уроки мастерства

На уроках по ММВ уже рассказывалось, как сделать ползунковый регулятор громкости - слайдер. И тут на форуме появился вопрос: «А как сделать круглый регулятор?» Сначала показалось, что это совсем не трудно. Возникли даже две идеи, как реализовать это на практике. Первая заключалась в том, что можно поворачивать нарисованную ручку регулятора, а вторая - нарисовать статический регулятор, а на нём точку, и перемещать эту точку по окружности, тем самым создавая иллюзию поворота ручки. Но после первых практических попыток стало понятно, что средствами ММВ это сделать будет трудно, так как программа не очень "дружит" с математикой. Она не умеет вычислять синусы, косинусы и корни числа, что при движении объекта по окружности просто необходимо уметь вычислять.

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

Но начнём по порядку. Нарисуем в каком-нибудь графическом редакторе будущую ручку регулятора громкости, например, такую:

и сохраним её (желательно в формате *.bmp).

После этого открываем программу Multimedia Builder и начинаем создавать наш проект. Для начала вставим рисунок в проект. Забегая вперёд, скажу, что нам будет нужно знать координаты центра окружности. Для удобства я буду использовать проект размером 200*200 пикселей и нашу ручку помещу ровно в центр страницы. Отсюда понятно, что центр окружности будет находиться в координатах X=100 и Y=100. У вас должно получиться вот что (для наглядности я изменил цвет страницы):

Теперь нужно избавиться от белого квадрата. Для этого зайдём в свойства рисунка и активируем флажок «Прозрачный цвет». Тут же в области просмотра можно увидеть результат. Если белые пикселы удалились недостаточно, нужно нажать кнопку "Безопасный цвет" и увеличить значение допуска.

Далее нужно создать скрипт который будет поворачивать регулятор (то есть нашу картинку) в зависимости от положения курсора мыши. Опять же забегая вперед, скажу, что для удобства расчетов было решено создать четыре скрипта, каждый из которых управляет своей зоной поворота. А общий скрипт, который решает, какому из четырех скриптов передать управление, назовем, например, Main.
Давайте мысленно разделим наш проект на четыре условные зоны. Так, как показано на рисунке:

Итак, скрипт Main должен определять, в какой из четырех областей находится курсор мыши, и исходя из этого решать, какую команду ему выполнять. Подумаем, как это сделать. Нетрудно заметить, что область 1 находится в пределах координат по оси Х от нуля до центра окружности, т.е. до ста, а по оси Y от центра окружности, т.е. от ста до края страницы, т.е. двухсот. Вторая область находится в пределах координат по оси Х от 0 до 100, по оси Y так же от 0 до 100. Раз областей у нас четыре то создадим четыре скрипта (Script1, Script2 …), они будут отвечать каждый за свою область.

В скрипте Main мы пропишем четыре условия:

MMB Script
If (MouseX()<100 & MouseY()>100) Then
  RunScript("Script1")
End
If (MouseX()<100 & MouseY()<100) Then
  RunScript("Script2")
End
If (MouseX()>100 & MouseY()<100) Then
  RunScript("Script3")
End
If (MouseX()>100 & MouseY()>100) Then
  RunScript("Script4")
End

Из этих условий видно, что скрипт оценивает координаты мыши и, исходя из этого, решает, какой скрипт запустить. В первом условии записано:

MMB Script
If (MouseX()<100 & MouseY()>100) Then
  RunScript("Script1")
End

Т.е. если курсор мыши находится в первой области, то надо выполнить Script1, если во второй - то Script2, и т.д.

Теперь нужно обеспечить, чтобы при нажатии левой кнопкой мыши на регуляторе запускался скрипт Main, а при отпускании кнопки скрипт останавливался.

Для запуска скрипта снова откроем свойства рисунка и поставим флажок «Разрешить действие». Затем войдем в редактор скриптов и на вкладке Mouse up напишем такую команду:

MMB Script
mouseup=TRUE

а на вкладке Mouse down напишем:

MMB Script
mouseup=FALSE
ScriptTimer("TimerA=Main","50")

Запустить-то скрипт мы запустили, но еще нужно, чтобы при нажатой кнопке скрипт работал постоянно. Значит, в конце скрипта Main нужно добавить строку:

MMB Script
ScriptTimer("TimerB=Main","50")

Однако если мы обойдемся только этой строкой, то не сможем остановить работу скрипта - даже если будет отпущена кнопка мыши, скрипт Main будет работать. Чтобы этого избежать, надо перед строкой ScriptTimer("TimerB=Main","50") прописать некоторое условие:

MMB Script
MStatus=MouseLButton()
If (MStatus=0) Then
  mouseup=TRUE
  Return()
End

Это условие как раз и остановит работу скрипта Main, а следовательно, и работу всех остальных скриптов.
Итак, окончательное содержание скрипта Main будет таким:

MMB Script
VolumeUp("rotate/2.7")
If (MouseX()<100 & MouseY()>100) Then
  RunScript("Script1")
End
If (MouseX()<100 & MouseY()<100) Then
  RunScript("Script2")
End
If (MouseX()>100 & MouseY()<100) Then
  RunScript("Script3")
End
If (MouseX()>100 & MouseY()>100) Then
  RunScript("Script4")
End
MStatus=MouseLButton()
If (MStatus=0) Then
  mouseup=TRUE
  Return()
End
ScriptTimer("TimerB=Main","50")

В самом начале этого скрипта стоит строка VolumeUp("Rotate/2.7"). Эта строка устанавливает значение громкости. Ведь громкость должна будет регулироваться в зависимости от угла поворота ручки (в дальнейшем этот угол будет обозначен Rotate). А полный угол поворота равен 2700. Однако диапазон регулирования громкости изменяется не до 270, а только до 100. Поэтому в скрипте и записано деление угла на величину 2,7 (кстати, не лишним будет напомнить, что для записи дробных чисел в ММВ используется не запятая, а точка).

Теперь начинается самое сложное. Нужно увязать координаты курсора мыши с углом поворота регулятора. Ну, раз надо увязать - будем увязывать :))) Для начала нужно оценить, какие величины мы знаем и какие можем вычислить. У нас есть координаты мыши - мы их можем получить с помощью команд MouseX() и MouseY(). Также мы знаем координаты центра регулятора - это X=100 и Y=100.

Рассмотрим для примера первую область. В скрипте будем использовать величины от курсора мыши до центра окружности по оси X и оси Y и назовем их katX и katY соответственно (kat - это кусочек от слова катет). То есть мы рассматриваем прямоугольный треугольник, вот он:

Отсюда видно, что:

katX=100-MouseX(),
katY=100-MouseY()

Зная катеты, теоретически мы можем определить угол . Если поделить katY на katX, то получим тангенс угла α. Итак:
tg(α)=katY/katX.

Но, как я говорил в начале статьи, программа ММВ умеет производить только четыре основных арифметических действия. Она не сможет вычислить arctg(α) и предоставить нам значение угла. Поэтому мы пойдем другим путём. Вооружившись калькулятором, будем вычислять значение угла в зависимости от значения tg(α) и получившиеся значения подставлять в скрипты.

Итак, в начальном положении (α) равен 450, тангенс (α) равен 1, громкость в этом положении равна 0. Значит, в Script1 запишем:

MMB Script
katX=100-MouseX()
katY=MouseY()-100
tg=katY/katX
If (tg>1) Then
  rot=0
End
If (tg<1) Then
  rot=5
End

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

Выше было сказано, что минимальное значение угла (α) - это 45 градусов. Если мы повернём ручку на 50, то угол (α) будет равен 400. Вычислим на калькуляторе значение тангенса 400 и получим 0,84. Теперь в Script1 добавим следующее условие:

MMB Script
If (tg<0.84) Then
  rot=10
End

Это означает, что если мы попытаемся повернуть ручку на угол больше 50, то ручка повернётся на 100. Теперь вычислим значение тангенса 350 и получим 0,7. Добавим в Script1 ещё одно условие:

MMB Script
If (tg<0.7) Then
  rot=15
End

И так далее, прибавляя к значению rot по 50, пока не дойдём до 450.

Но это ещё не всё. Нужно ещё поворачивать ручку на величину rot. Значит, в конце всех условий нужно прописать команду поворота ручки, которая выглядит следующим образом:

MMB Script
rotate=rot
RotateImageTo("Ручка","rotate")

Надеюсь, тут всё понятно.
Но и это ещё не всё. Нам ведь надо обеспечить непрерывную работу скрипта Main при нажатой кнопке мыши, и прекратить работу всех скриптов при отпускании кнопки. Как это сделать, я объяснял чуть выше, так что просто добавим в конец скрипта Script1 такое условие:

MMB Script
MStatus=MouseLButton()
If (MStatus=0) Then
  mouseup=TRUE
  Return()
End
ScriptTimer("TimerB=Main","50")

На этом работа над скриптом Script1 закончилась. Вот что у нас получилось в итоге:

MMB Script
katX=100-MouseX()
katY=MouseY()-100
tg=katY/katX
If (tg>1) Then
  rot=0
End
If (tg<1) Then
  rot=5
End
If (tg<0.84) Then
  rot=10
End
If (tg<0.7) Then
  rot=15
End
If (tg<0.57) Then
  rot=20
End
If (tg<0.47) Then
  rot=25
End
If (tg<0.37) Then
  rot=30
End
If (tg<0.27) Then
  rot=35
End
If (tg<0.17) Then
  rot=40
End
If (tg<0.08) Then
  rot=45
End
rotate=rot
RotateImageTo("Ручка","rotate")
MStatus=MouseLButton()
If (MStatus=0) Then
  mouseup=TRUE
  Return()
End
ScriptTimer("TimerB=Main","50")

Теперь нажмём кнопку F5 и посмотрим, как работает наш проект. Ручка поворачивается, но пока ещё слишком мало, она двигается только в первой условной зоне. Ведь мы написали только один скрипт из четырех. Переходим ко второй зоне, за которую должен отвечать скрипт Script2. Здесь мы будем рассматривать уже другой треугольник, и соответственно другие катеты (см.рис.):

В этой зоне значения катетов будут другими. Понятно, что katX равен 100-MouseX(), а katY=100-MouseY(). Начнём без лишних объяснений писать Script2:

MMB Script
katX=100-MouseX()
katY=100-MouseY()
tg=katY/katX

Вычислим чему равен тангенс 50 и получим 0,08. Добавим в Script2 условие:

MMB Script
If (tg>0.08) Then
  rot1=5
End

И так далее, пока не дойдём до значения rot1=900.

Угол поворота во второй зоне будет не просто равен значению rot1, к нему надо прибавить ещё 450. Т.к. при rot1=0 угол общий угол поворота ручки равен 45 градусов. Значит после всех условий запишем:

MMB Script
rotate=(45+rot1)
RotateImageTo("Ручка","rotate")
MStatus=MouseLButton()
If (MStatus=0) Then
  rot1=5
  mouseup=TRUE
  Return()
End
ScriptTimer("TimerB=Main","50")

Для третьей и четвёртой зоны скрипты напишите сами.

После того, как вы это сделаете, регулятор будет вполне работоспособным, но у него обнаружатся два недостатка. Во-первых, при старте проекта он не будет отклоняться на угол, соответствующий уровню громкости в системе, а во-вторых, если вы захватите регулятор мышью и будете тащить его до максимального значения и по достижении его продолжите движение мышью через низ в сторону первой зоны то регулятор проскочит туда и громкость исчезнет, "сорвётся"; то же самое и в обратную сторону. Значит, придётся устранять эти недостатки.

С первым справится несложно. Нужно создать текстовый объект и назвать его CBK_Volume, а в скрипте старта страницы написать такую строчку:

MMB Script
RotateImageTo("Ручка","CBK_Volume*2.7")

И всё. А вот со второй проблемой сложнее, но исправить её возможно. Для начала нам нужно понять, что следует разрешить, а что запретить. Например, для первой зоны можно разрешить работу скрипта, только если мышь пришла из второй зоны, а для второй зоны можно разрешить работу скрипта, только если мышь пришла из третьей или первой зоны, и т.д. Т.е. работу скриптов можно разрешать, только если мышь пришла из соседних зон. Начнём это реализовывать.

Как определить, в какой зоне находится мышь? Да очень просто. Введём какую-нибудь переменную, например q. В Script1 добавим строку q=1, в Script2 - q=2, в Script3 - q=3 и, соответственно, в Script4 - q=4.

Теперь осталось немного подправить скрипт Main. В условие запуска скрипта Script1 надо добавить дополнительное условие, которое разрешит запустить скрипт, только если мышь пришла из второй зоны. Условие будет выглядеть так:

MMB Script
If (MouseX()<100 & MouseY()>100) Then
  If (q<>4 & q<>3) Then
    RunScript("Script1")
  End
End

То же самое проделаем для других условий. Окончательно скрипт Main будет выглядеть так:

MMB Script
VolumeUp("Rotate/2.7")
If (MouseX()<100 & MouseY()>100) Then
  If (q<>4 & q<>3) Then
    RunScript("Script1")
  End
End
If (MouseX()<100 & MouseY()<100) Then
  If (q<>4) Then
    RunScript("Script2")
  End
End
If (MouseX()>100 & MouseY()<100) Then
  If (q<>1) Then
    RunScript("Script3")
  End
End
If (MouseX()>100 & MouseY()>100) Then
  If (q<>1) Then
    RunScript("Script4")
  End
End
MStatus=MouseLButton()
If (MStatus=0) Then
  mouseup=TRUE
  Return()
End
ScriptTimer("TimerB=Main","50")

ВСЁ!!! Теперь запустите проект и - о чудо! - регулятор работает, как будто настоящий!

Ну а если вы так и не смогли разобраться во всех хитросплетениях этого урока, то просто скачайте готовый регулятор с сайта, из раздела "Готовые проекты - Запчасти".

Удачи!

PolN
02 Июля 2005
5181

Всего комментариев: 1


1. Антон

11:20, 15 Января 2010Спам


чет у меня нефига ниче неполучилось, некакая ручка не крутится!! бред=)

Ответ: Если вы себе позволяете так выражаться, но я смело заявляю, что у вас кривые руки. И вообще. Какой это бред, когда вы можете спокойно скачать готовый по ЭТОМУ УРОКУ проект? Вот где действительно бред. Слова человека, который не захотел разобраться.

Добавлять комментарии могут только зарегистрированные пользователи
[ Регистрация | Вход ]