Одной из целью популяризации DIY-робототехники, для меня, является привлечение внимания к IT, к программированию. И в этом плане мне интересны визуальные среды программирования, где простым Drag&Drop можно создавать программы. Для тех кто только начинает изучать компьютер — такой способ программирования может на начальном этапе вызвать интерес (благодаря своей простоте), и дальше уже способствовать к самостоятельному изучению (чего-то более сложного).
Думаю многие слышали про Scratch — это «классика жанра» (созданная в MIT, идея 2003 и выход в релиз 1.0 в январе 2006 году), но для его работы необходимо установка ПО на компьютер (или Flash). Некоторое время назад в University of California at Berkeley была разработана система Snap!, интерфейсе которой близок к Scratch, но работает в браузере, на базе классических html/js/css. То есть для работы с ней — вам достаточно только браузера (и к тому же она open-source).
Вот о веб-системе визуального программирования Snap! я и хочу рассказать.
Изучать что-то новое всегда интересно на каком либо примере из жизни, вот я и решил попробовать задачу рисования и озвучивания азбуки Морзе — этапы решения этой задачи и будет содержимым данной публикации.
Программа будет при нажатии на клавиши — рисовать соответствующие символы, и так же «озвучивать». На КДПВ приведена итоговая программа, и справа написано «HI HABR, HABR HI».
Управление:
"клавиша вверх" — инициализация параметров и очистка (лучше нажать после загрузки — выставится ширина точек)
"клавиша вниз" — перевод строки
клавиши "h", "i", "a", "b", "r" — рисование и озвучивание соотв. буквы с помощью азбуки Морзе.
Начало
Для старта системы Snap! достаточно открыть эту страничку в браузере.
Вот что мы увидим после старта:
Если у вас не было опыта работы со Scratch, то поясним принцип работы с такой системой:
Видим три области (упрощенно):
- слева
- центральная
- справа
Слева отображаются блоки, которые мы с помощью мышки можем переносить на центральную область, и соединять между собой (от этого произошло название программы — «snap»). При нажатии на блоке — происходит его выполнение, и всех соединенных вместе блоков.
Выполнение блоков на центральной области — отображается на правой области, где мы видим «курсор».
Возможно кто-то помнит систему программирования Logo (Черепашка), где подавая команды на перемещение, и рисование — можно было бы рисовать фигуры. С этого примера и начнём.
Первое знакомство
Для первого знакомства с работой в Snap! нарисуем квадрат.
Вверху над блоками отображаются типы блоков (обращаем внимание, что они разного цвета):
- Движение — здесь мы управляем движением и местоположением «курсора»
- Внешность — здесь мы управляем внешним видом «курсора» — который по сути «спрайт»
- Звук — здесь мы можем воспроизводить звуки
- Перо — это функции для рисования
- Управление — с помощью этих блоков мы можем добавлять логику
- Сенсоры — это обратная связь из «мира» где живёт «курсор» — определение касаний и т.п.
- Операторы — это математические функции, условия, циклы
- Переменные — здесь можно определять переменные
Для рисования квадрата напишем программу в свободном стиле:
10. опустить перо 20. повторить 4 раза: 30. двинуться вперёд на 50 пикселей 40. повернуться вправо на 90 градусов
Начнем:
1. выберем раздел «Перо», и перетащим блок "опустить перо" в центральную область.
2. выберем раздел «Движение», и перетащим блок "передвинуться на 10 шагов", после — изменим значение 10, на 50.
3. перетаскиваем блок "повернуться по часовой на 15 градусов" — изменим 15 на 90.
4. соединим блоки «передвижения» и «поворот» — для этого захватим «повернуть» и передвинем его к нижней части блока «передвинуть» до появления светлой полосы — индикатора соединения блоков — и отпускаем блок — после этого два блока становятся соединенными.
Если мы сейчас нажмем на этих блоках — то наш курсор начнёт двигаться и поворачиваться, при каждом нажатии. Но он не рисует, для этого просто нажмем на блоке "опустить перо" — после этого курсор будет рисовать. И нажав 4 раза — нарисуем квадрат.
Теперь очистим зону рисования, для этого выберем раздел «Перо» и нажмем на блоке "убрать всё" (можно не переносить в рабочую зону).
5. выбираем раздел «Управление», и перенесем блок "повторять 10", в рабочую область, и изменим 10 на 4.
6. переносим блоки "опустить перо" и блоки «передвинуть/повернуть», внутрь блока «повторять» — до их автоматического соединения с блоком.
7. так же из раздела «Управления» — перенесём блок "Когда щелкнуть на (зеленый флаг)", в рабочую область, и прикрепляем её к верней части блока «повторять».
Всё мы закончили нашу программу, теперь нажимая на «зелёном флажке», справа вверху (над зоной рисования) — мы будем стартовать нашу программу рисования.
Вот что получилось:
Создание азбуки Морзе
Базовые вещи теперь понятны, теперь приступим к реализации нашей идеи по азбуке Морзе. Вспомним, что кодирование происходит с помощью точки и тире. Поэтому нам надо сделать две функции:
- одна будет рисовать точки
- а вторая тире.
(для нового проекта, если не хотим сохранять текущие изменения — можем просто обновить страничку).
Рисование точки
1. Переходим в раздел «Перо» — переносим блок "установить размер пера 1" — и выставляем его 10. Так будет видно хорошо точку.
2. Из раздела «Движение» переносим блок "передвинуться на 10 шагов" — и выставляем 1 шаг. Так мы нарисуем точку (т.к. кисточка имеет диаметр 10 пикселей — она нарисуем нам окружность).
3. И не забудем перенести блок "опустить перо" из раздела «Перо» — иначе мы ничего не увидим :)
4. Соединяем все блоки, и получается:
Видим, что наш «курсор» закрывает нарисованную точку, для решения этой проблемы — мы просто уменьшим размеры «курсора»:
5. В разделе «Внешность» находим и переносим блок "установить размер в 100" и выставляем его 10. (и прикрепляем его к нашим блокам сверху).
6. Так же сделаем чтобы курсор переходи дальше, но без рисования, для этого перемещаем (и соединяем) блок "поднять перо" из раздела «Перо»
7. Добавляем блок "передвинуть на 10 шагов" из раздела «Движение» — и прикрепляем вниз к нашим блокам, и изменяем 10 шагов на 15.
В итоге получаем (предварительно очистив зону «Перо» — "убрать все"):
Точка справа — это есть наш уменьшенный «курсор» — в этом месте начнется следующее рисование.
Рисование тире
Для рисования тире — нам нужно только увеличить параметр движения с 1 до 10 шагов, а остальное оставить без изменений.
В Snap! есть возможность клонировать блоки, для этого на наших блоках нажимаем правой клавишей мыши, и выбираем «продублировать» — появится дубль, и переносим его вниз. И меняем значение в блоке "передвинуть на 1 шаг", на 15.
Нажимаем на этом сборном блоке, результат:
Видим, что мы нарисовали «тире»!
Обработка нажатий
Теперь мы можем попробовать привязать выполнение наших блоков, не к нажатию по ним, а к нажатию клавиш на клавиатуре.
Например, сделаем: нажатие «0» — точка, нажатие «1» — тире (клавиши на основной клавиатуре).
1. Для этого переходим в раздел «Управление» и выбираем блок "Когда нажать «пробел» клавишу", и прикрепляем его сверху нашей группы блоков (где рисуется точка). И выбираем в выпадающем списке вместо «пробела» — «0»
2. Такой же блок переносим, и прикрепляем сверху группы блоков «тире», и выбираем вместо «пробел» — «1».
Получаем, и проверяем:
Напомню, очистку зоны рисования можно сделать «Перо» — «убрать все», и перемещение курсора в начало: «Движение» — «перейти в точку х [0] y [0]»
Механизм сообщений
В англоязычном варианте азбуки Морзе буква «А» закодирована, с помощью «точка», «тире». Так же после символа должна быть небольшая задержка — отступ (пробел).
Для реализации этой задачи мы будем использовать механизм сообщений в Snap! — мы будем перехватывать нажатие на клавишу «А», и (согласно кодированию этой буквы в азбуке Морзе) последовательно посылать сообщения «точка», «тире» и «пробел» (dot, dash, space).
А в текущих функциях/блоках где происходит рисование по нажатию — мы заменим на выполнение по получению сигнала.
Таким образом у нас будет три сигнала (события):
* dot
* dash
* space
Начнем:
1. перенесем из раздела «Управление» блок "когда я получу []"
2. открепим блоки что рисуют точку, от "когда нажать 0 клавишу" — для этого можно захватить первый блок снизу, у нас это "установить размер в 10", и перенести его в сторону — блоки отсоединятся от верхнего.
3. прикрепляем блок "когда я получу []" к нашим блокам рисующим точку — прикрепляем сверху.
4. удаляем единичный блок «когда нажать 0 клавишу» — для этого переносим его из рабочей зоны, на на левую область блоков.
5. выставляем получаемое сообщение в блоке "когда я получу " — в выпадающем списке выбираем «новый» и вводим "dot"
6. для генерации сообщения — переносим из раздела «Управление» блок — "переслать [] всем и ждать", и в выпадающем списке выбираем сообщение "dot".
Вот что у нас должно получиться:
Сейчас при нажатии на блоке "переслать [dot] всем и ждать" — будет происходить посылка сообщения, и активация/выполнение всех блоков кто «подписаны» на это сообщение, в нашем примере — блок, что рисует точку.
Начальные параметры
Произведём небольшой «рефакторинг».
У нас есть часто повторяемые операции, и их можно вынести в отдельную «функцию», и вызывать её при нажатии на клавишу «вверх». Там будет:
- выставление курсора в начало
- очистка экрана
- выставление размера курсора
- выставление размера точки рисования.
Вынесем эти блоки из наших блоков рисования точки и тире.
Так же доработаем блок «тире», вместо обработки нажатия клавиши — так же будет срабатывать на получение сообщения "dash".
И добавим обработку блока «пробел» — «space» — он будет выполнять только передвижение курсора — для выполнения отступа между «буквами» кода Морзе.
Вот, что у нас получилось:
Кодирование символов
Ну вот, наконец-то мы подошли к самому главному — кодированию символа A. Чтобы при нажатии на «а» — происходило рисование соотв. букве коду Морзе.
Для этого мы используем блок "когда нажать [] клавишу" из Управления, и блоки "переслать всем и ждать" оттуда же. Конкретно, для буквы А, мы должны выслать «точку», «тире», и далее «пробел» (соответственно сигналы: «dot», «dash», «space»).
Вот что получается:
Переменные и перенос строки
В процессе работы я понял, что без переноса строки будет не очень удобно рисовать азбуку морзе. Поэтому сделаем функцию «перенос строки», и назначим её на нажатие клавиши курсора «вниз».
Для выполнения переноса строки необходимо выполнить две задачи:
1. передвинуть курсор на начало по оси X
2. передвинуть курсор на следующую строку (по оси Y) на высоту строки.
Для их реализации я решил ввести две переменные:
* начало текста по оси X (left_border)
* высота строки (line_height)
Значение переменной left_border будет использоваться при выставлении начальной позиции (мы изменим с 0, на -200 чтобы рисование начиналось с левой части экрана).
Для добавления переменной, необходимо нажать слева вверху на разделе «Переменные», и там на "Объявить переменную":
Таким же образом объявим переменную «line_height».
После добавления переменные будут отображены слева (для того чтобы их можно было Drag&Drop и вставить в арифметические операции, условия и т.п.), и так же значение переменной будет транслироваться на экран рисования — чтобы отключить отображение на экране — достаточно нажать слева от переменной (на панели Переменных).
Теперь мы можем выставить значения этим переменным, с помощью блока "придать [] значение [0]" в разделе «Переменные» — перенесём эти блоки в нашу «Функцию инициализации». И выставим для left_border = -200, для line_height = 20.
Вот как выглядит в результате наша функция инициализации и переноса строки:
арифметические команды находятся в разделе «Операторы», а саму переменную мы Drag&Drop из раздела «Переменные» — в соотв. поле функции (обращаем внимание на разные формы).
Кодирование оставшихся букв
По аналогии с буквой А, мы закодируем буквы H, I, B, R:
Звук
Эти блоки будут так же «слушать» сигналы dot, dash и space.
Согласно описанию из азбуки Морзе:
The duration of a dash is three times the duration of a dot. Each dot or dash is followed by a short silence, equal to the dot duration. The letters of a word are separated by a space equal to three dots (one dash)
Открываем раздел «Звук», и нам понадобятся два блока: "сыграть ноту [60] [0.5] тактов", и "пауза [0.2] тактов".
Выбираем частоту 80, и такт 0.1 в качестве «пробела» после точки/тире, и 0.3 такта для «пробела» между символами.
Получим следующие блоки:
Удобство системы событий/подписчиков — что не изменяя самой логики системы, мы просто дополнили механизм (для звукового сопровождения), с помощью создания новых подписчиков на «точку», «тире» — а уже их реализация
Сохранение/экспорт проекта
Сохранение происходит в локальный storage браузера, есть возможность сохранять в облако, после регистрации.
Так же можно экспортировать проект — "Экспорт проект..." — мы получим xml нашей программы. Вот так выглядит эта программа по азбуке Морзе.
В заключении
Конечно, это лишь малая часть возможностей Snap!, и думаю в следующих публикациях мы попробуем на практике другие возможности системы — в частности взаимосвязь с внешними системами, в том числе Arduino.
На мой взгляд наличие такой визуальной системы могло бы добавить интереса в уроки информатики, а если бы ещё были уроки робо-информатики — то думаю программирование было бы интересным и востребованным в школе :)
Ресурсы:
- Официальная страничка Snap! системы (snap.berkeley.edu)
- Руководство пользователя по Snap! v.4.0 (на английском), 77 стр.
- Страничка Snap! проекта на gihub
Если вам интересно поделиться опытом, и быть в курсе — русскоязычная ВК группа по Snap!
Автор: nemilya