«от нефиг делать / just for lulz» посвящается…
![](https://habrastorage.org/r/w1560/storage1/adc38296/ce5f603d/a9b20179/c2c40e68.png)
Змейка. Игра старая (как утверждает Wikipedia: середины или даже конца 1970х годов), но от того не менее интересная, по крайней мере в качестве примера несложного но интересного алгоритма для иллюстрации возможностей графического программирования на LabVIEW 2009.
В основу игры положим двумерный массив целых чисел, который и будет представлять собою игровое поле. В этом массиве и будет располагаться змея. При движении головы змеи в новое поле массива (в зависимости от направления движения змейки) будет добавляться время жизни конкретной клетки.
Каждый такт игры цикл пробегается по массиву уменьшая значения ненулевых ячеек на единицу. После этого на экране ненулевые ячейки заливаются цветом, а нулевые остаются белыми. Таким образом за двигающейся по полю головой постоянно будет тянуться шлейф из ненулевых ячеек длиной равной времени жизни первой клетки. Таким образом время жизни клетки и определяет длину змейки. А длину можно увеличивать или уменьшать.
Увеличение длины змеи происходит при съедании некоей «еды». Еда — точка на игровом поле, описываемая лишь двумя ее координатами. Как только она съедается, то есть координаты головы змеи совпадают с координатами еды, длина змейки увеличивается на 1, а еда получает новую пару случайно выбранных координат.
Уменьшение длины змеи происходит при откусывании собственного хвоста. Да, я понимаю, что это получается уже не змея, а червяк какой-то, и что в классической змейке следовало бы заканчивать игру гамовером, но не суть. Это делается так же просто: если в какой-то момент голова змеи попадает в ячейку уже занятую её телом, то дина её уменьшается на то значение, которое записано в месте укуса. Оставшийся хвост тихонько долежит на поле, исчерпывая свое время жизни.
Задачка проста и понятна. Обратимся теперь к LabVIEW.
Создадим на форме элемент — массив и простейший из булевых индикаторов «Flat Square Button» с панели инструментов ClassicBoolean.
![](https://habrastorage.org/r/w780q1/storage1/2bd939b8/fb07cb84/23151263/de4793e8.jpg)
У булева индикатора скроем его заголовок и раскрасим его так, чтобы при значении false он сам и его рамка были бы белыми, а при true – темно-зеленым и салатовой соответственно. Размеры индикатора зададим равными 10 х 10 пиксель.
Поместим индикатор в массив. Сделаем массив двумерным, а так же скроем индикаторы индекса массива и его заголовок. Сам же массив растащим так, чтобы он отображал 32 х 24 копии индикатора.
Раскрасим форму в приятные цвета. Этот пункт необязателен, но является моим любимым.
После всех манипуляций, игровое поле со случайным набором true и false значений выглядит так.
![](https://habrastorage.org/r/w780q1/storage1/b6d18c27/ba948536/c87ed31e/6755e8ba.jpg)
В основе программы будет положен цикл While, завершаемый по условию false, то есть никогда. Внутрь цикла поместим терминал нашего массива, а так же подключим к массиву следующие переменные, которые будут хранить основные параметры игры. Это координаты головы змеи, направление ее движения и ее длина, координаты еды, объединенные в соответствующие кластеры, а также целочисленный массив, упоминавшийся в первой главе. Выглядит все это так:
![](https://habrastorage.org/r/w780q1/storage1/170716b2/ea0d34ac/bec52085/4c64e867.jpg)
Внутри цикла добавим Event Structure при помощи которой мы будем впоследствии захватывать события с ц целью обработки сигналов с клавиатуры о нажатии управляющих стрелок, и последовательную структуру, внутри которой шаг за шагом расположим всю последовательность обработки каждого шага змейки. И первым шагом станет пробежка по всему массиву с уменьшением всех ненулевых элементов на 1. Делается это при помощи двух вложенных один в другой циклов for.
![](https://habrastorage.org/r/w780q1/storage1/ee226918/0b60cf3f/7a61bdf1/8eac8f5f.jpg)
Следующий шаг — изменение координат головы в соответствии с направлением движения и изменение длины змеи в случае поедания еды, либо откусывания собственного хвоста. Изменение координат происходит при помощи Case — структуры к терминалу условия которой подключена переменная направление. В зависимости от значения направления выполняется одна из вкладок структуры, на которой на 1 увеличивается либо уменьшается соответствующая координата. Если при этом координата выходит за пределы максимума либо нуля, то она обнуляется, либо устанавливается максимальной, чтобы обеспечить так называемое «прохождение сквозь край экрана».
Если новые координаты попарно равны с координатами еды (два оператора сравнения и один оператор And) то длина увеличивается на 1, а для еды генерируются новые координаты при помощи генератора случайных чисел (от 0 до 1) и коэффициентов. Иначе (вкладка false не показана) все три переменные получают прежние значения.
Если элемент массива с координатами нового положения головы не равен нулю, то от длины змеи отнимается значение этого элемента. Если при этом значение длины змеи становится меньше либо равным нулю, то ему присваивается значение 1, поскольку голова у змеи остается всегда.
Кластеры значений собираются обратно вбирая в себя новые значения. Значения которые на данном шаге не изменялись можно заново не вбирать – они останутся прежними и так.
![](https://habrastorage.org/r/w780q1/storage1/7636338e/cbd88c8a/93da2af8/d1903c1b.jpg)
В следующем шаге, выполняется запись значения длины змеи в новое поле в качестве его времени жизни, генерация булева массива и выгрузка его в индикатор на переднюю панель. Это не трудно. Не забудем только непосредственно перед выгрузкой дополнительно добавить true в ячейку с координатами, равными координатам еды.
![](https://habrastorage.org/r/w780q1/storage1/1a2ce35d/148a7048/bc244185/fac7d6bf.jpg)
Вот и вся, собственно говоря змейка, осталось только прикрутить управление. Для него мы заранее уже определили Event — структуру, или говоря по-русски структуру событий. Эта многовкладочная структура ждет в течение заданного интервала времени наступления одного из предопределенных в ней событий, и выполняет соответствующую вкладку когда дождется (ну или вкладку timeout если не дождется). События могут быть разнообразными, начиная от кликов мышкой по передней панели приложения, и заканчивая системными событиями. Нас же будет интересовать событие «Key down» клавиатуры.
Переместим структуру событий в последний кадр последовательной структуры и заведем в нее проводник, содержащий кластер Змея (поскольку именно его значение будем изменять при нажатии на клавиши клавиатуры).
Добавим событие, в качестве источника события (Event Source) выберем: . А в качестве события: Key -> Key Down.
Из параметров события возвращаемых структурой нас интересует лишь параметр VKey, содержащий код клавиши, спровоцировавшей событие. Добавим Case — структуру, которая будет выдавать 0 если была нажата клавиша влево, 1 — если вниз, 2 — вправо, а 3 — вверх. а в случае нажатия любой другой клавиши значение направления оставалось бы неизменным. дополнительная задержка добавлена, с той целью, чтобы срабатывание структуры event не укорачивало бы интервал между тактами.
![](https://habrastorage.org/r/w780q1/storage1/eddcd039/325d800d/0a7721e0/ce28040b.jpg)
Вот собственно и все. Можно запускать и играться. Конечно неплохо было бы еще выводить на переднюю панель количество набранных очков, уровень сложности, от которого бы зависела скорость игры (величина задержки между тактами) и еще многое другое, ну да улучшать что угодно можно до бесконечности а иллюстративных целей дальнейшие улучшения не несут.
Для желающих, ознакомиться с полной схемой приложения можно тут.
![](https://habrastorage.org/storage1/adc38296/ce5f603d/a9b20179/c2c40e68.png)
Змейка. Игра старая (как утверждает Wikipedia: середины или даже конца 1970х годов), но от того не менее интересная, по крайней мере в качестве примера несложного но интересного алгоритма для иллюстрации возможностей графического программирования на LabVIEW 2009.
Собственно алгоритм.
В основу игры положим двумерный массив целых чисел, который и будет представлять собою игровое поле. В этом массиве и будет располагаться змея. При движении головы змеи в новое поле массива (в зависимости от направления движения змейки) будет добавляться время жизни конкретной клетки.
Каждый такт игры цикл пробегается по массиву уменьшая значения ненулевых ячеек на единицу. После этого на экране ненулевые ячейки заливаются цветом, а нулевые остаются белыми. Таким образом за двигающейся по полю головой постоянно будет тянуться шлейф из ненулевых ячеек длиной равной времени жизни первой клетки. Таким образом время жизни клетки и определяет длину змейки. А длину можно увеличивать или уменьшать.
Увеличение длины змеи происходит при съедании некоей «еды». Еда — точка на игровом поле, описываемая лишь двумя ее координатами. Как только она съедается, то есть координаты головы змеи совпадают с координатами еды, длина змейки увеличивается на 1, а еда получает новую пару случайно выбранных координат.
Уменьшение длины змеи происходит при откусывании собственного хвоста. Да, я понимаю, что это получается уже не змея, а червяк какой-то, и что в классической змейке следовало бы заканчивать игру гамовером, но не суть. Это делается так же просто: если в какой-то момент голова змеи попадает в ячейку уже занятую её телом, то дина её уменьшается на то значение, которое записано в месте укуса. Оставшийся хвост тихонько долежит на поле, исчерпывая свое время жизни.
Задачка проста и понятна. Обратимся теперь к LabVIEW.
Интерфейс игры.
Создадим на форме элемент — массив и простейший из булевых индикаторов «Flat Square Button» с панели инструментов ClassicBoolean.
![](https://habrastorage.org/storage1/2bd939b8/fb07cb84/23151263/de4793e8.jpg)
У булева индикатора скроем его заголовок и раскрасим его так, чтобы при значении false он сам и его рамка были бы белыми, а при true – темно-зеленым и салатовой соответственно. Размеры индикатора зададим равными 10 х 10 пиксель.
Поместим индикатор в массив. Сделаем массив двумерным, а так же скроем индикаторы индекса массива и его заголовок. Сам же массив растащим так, чтобы он отображал 32 х 24 копии индикатора.
Раскрасим форму в приятные цвета. Этот пункт необязателен, но является моим любимым.
После всех манипуляций, игровое поле со случайным набором true и false значений выглядит так.
![](https://habrastorage.org/storage1/b6d18c27/ba948536/c87ed31e/6755e8ba.jpg)
Основной цикл программы.
В основе программы будет положен цикл While, завершаемый по условию false, то есть никогда. Внутрь цикла поместим терминал нашего массива, а так же подключим к массиву следующие переменные, которые будут хранить основные параметры игры. Это координаты головы змеи, направление ее движения и ее длина, координаты еды, объединенные в соответствующие кластеры, а также целочисленный массив, упоминавшийся в первой главе. Выглядит все это так:
![](https://habrastorage.org/storage1/170716b2/ea0d34ac/bec52085/4c64e867.jpg)
Содержимое цикла
Внутри цикла добавим Event Structure при помощи которой мы будем впоследствии захватывать события с ц целью обработки сигналов с клавиатуры о нажатии управляющих стрелок, и последовательную структуру, внутри которой шаг за шагом расположим всю последовательность обработки каждого шага змейки. И первым шагом станет пробежка по всему массиву с уменьшением всех ненулевых элементов на 1. Делается это при помощи двух вложенных один в другой циклов for.
![](https://habrastorage.org/storage1/ee226918/0b60cf3f/7a61bdf1/8eac8f5f.jpg)
Следующий шаг — изменение координат головы в соответствии с направлением движения и изменение длины змеи в случае поедания еды, либо откусывания собственного хвоста. Изменение координат происходит при помощи Case — структуры к терминалу условия которой подключена переменная направление. В зависимости от значения направления выполняется одна из вкладок структуры, на которой на 1 увеличивается либо уменьшается соответствующая координата. Если при этом координата выходит за пределы максимума либо нуля, то она обнуляется, либо устанавливается максимальной, чтобы обеспечить так называемое «прохождение сквозь край экрана».
Если новые координаты попарно равны с координатами еды (два оператора сравнения и один оператор And) то длина увеличивается на 1, а для еды генерируются новые координаты при помощи генератора случайных чисел (от 0 до 1) и коэффициентов. Иначе (вкладка false не показана) все три переменные получают прежние значения.
Если элемент массива с координатами нового положения головы не равен нулю, то от длины змеи отнимается значение этого элемента. Если при этом значение длины змеи становится меньше либо равным нулю, то ему присваивается значение 1, поскольку голова у змеи остается всегда.
Кластеры значений собираются обратно вбирая в себя новые значения. Значения которые на данном шаге не изменялись можно заново не вбирать – они останутся прежними и так.
![](https://habrastorage.org/storage1/7636338e/cbd88c8a/93da2af8/d1903c1b.jpg)
В следующем шаге, выполняется запись значения длины змеи в новое поле в качестве его времени жизни, генерация булева массива и выгрузка его в индикатор на переднюю панель. Это не трудно. Не забудем только непосредственно перед выгрузкой дополнительно добавить true в ячейку с координатами, равными координатам еды.
![](https://habrastorage.org/storage1/1a2ce35d/148a7048/bc244185/fac7d6bf.jpg)
Управление
Вот и вся, собственно говоря змейка, осталось только прикрутить управление. Для него мы заранее уже определили Event — структуру, или говоря по-русски структуру событий. Эта многовкладочная структура ждет в течение заданного интервала времени наступления одного из предопределенных в ней событий, и выполняет соответствующую вкладку когда дождется (ну или вкладку timeout если не дождется). События могут быть разнообразными, начиная от кликов мышкой по передней панели приложения, и заканчивая системными событиями. Нас же будет интересовать событие «Key down» клавиатуры.
Переместим структуру событий в последний кадр последовательной структуры и заведем в нее проводник, содержащий кластер Змея (поскольку именно его значение будем изменять при нажатии на клавиши клавиатуры).
Добавим событие, в качестве источника события (Event Source) выберем: . А в качестве события: Key -> Key Down.
Из параметров события возвращаемых структурой нас интересует лишь параметр VKey, содержащий код клавиши, спровоцировавшей событие. Добавим Case — структуру, которая будет выдавать 0 если была нажата клавиша влево, 1 — если вниз, 2 — вправо, а 3 — вверх. а в случае нажатия любой другой клавиши значение направления оставалось бы неизменным. дополнительная задержка добавлена, с той целью, чтобы срабатывание структуры event не укорачивало бы интервал между тактами.
![](https://habrastorage.org/storage1/eddcd039/325d800d/0a7721e0/ce28040b.jpg)
Вот собственно и все. Можно запускать и играться. Конечно неплохо было бы еще выводить на переднюю панель количество набранных очков, уровень сложности, от которого бы зависела скорость игры (величина задержки между тактами) и еще многое другое, ну да улучшать что угодно можно до бесконечности а иллюстративных целей дальнейшие улучшения не несут.
Для желающих, ознакомиться с полной схемой приложения можно тут.