На днях я рассказывал об интересном языке для OpenComputers (и не только).
MoonScript
Но одно дело - прочитать об языке где-то. А совсем другое - попробовать язык самому.
Именно этим я и предлагаю заняться.
Для разогрева, начнем с чего-нибудь несложного. Например "Угадай число".
Думаю все знают эту игру. Компьютер загадывает число, мы пытаемся угадать. На каждую нашу попытку, компьютер злорадно сообщает - "больше!", "меньше!" или "у вас закончились попытки!" и "вы проиграли!".
Немного модифицируем исходную идею, и перенесем ее на 2d поле. Просто, чтобы не было скучно.
ТЗ
Что нам потребуется?
- Отрисовать сетку Тут мы просто возьмем текущий размер дисплея, и разметим его на клеточки.
- Загадать число
- Слушать команды пользователя
Юзер будет тыкать на клеточки. Нам надо будет слушать эвент
touch
. - Обновлять игровое поле в ответ Собственно после тыка, будем открывать клетку. Если это не та клетка - рисовать на ней стрелочку. Если та - рисовать победный баннер. Если закончились ходы - рисовать что-нибудь обидное.
За дело
Первым делом надо подключить все, что мы будем использовать.
В Lua обычно мы при помощи команды require
пишем все в локальные переменные.
В MoonScript все переменные по дефолту локальны. Поэтому использовать
ключевое слово local
нет необходимости.
Для подключения же библиотек, используется ключевое слово import
:
import getResolution setForeground setBackground set fill from require('component').gpu import pull from require 'event' import ceil, random from math import rep from string
Мы вытащили из нужных библиотек нужные функции. Ничего лишнего.
Теперь объявим переменные, которые будут использоваться в коде.
-- Размеры экрана width, height = getResolution() width /= 2 -- потому что по горизонтали наши клетки займут 2 символа height -= 1 -- потому что внизу будет статус -- Цвета white = 0xFFFFFF black = 0x000000 gray = 0x222222 green = 0x00BB33 yellow = 0xFFC04C red = 0xFF0000 pink = 0xFF0074 violet = 0xD600FF blue = 0x4E5AFF cyan = 0x4ED7FF teal = 0x00CC99 -- Заготовка для сетки - один ряд клеток grid_line = rep("▒▒ ", ceil(width / 2)) -- Наша цель target = { x: 0, y: 0 } -- Количество попыток -- (150 - магический коэффициент сложности, больше - сложнее, меньше - легче) maxAttemts = ceil(width * height / 150) attempts = maxAttemts
Тут тоже присутствует несколько новых фич MoonScript.
Во-первых - это сдвоенные операции. Конструкции a /= b
или a -= b
означают
тоже самое, что a = a / b
и a = a - b
.
Во-вторых это новый синтаксис создания таблиц. Названия полей и их значения отделены двоеточиями. (Такое обозначение будет знакомо тем, кто владеет JavaScript).
Для реализации геймплея и отрисовки всякой всячины, потребуется определить несколько функций.
Тут мы столкнемся еще с несколькими новшествами, по сравнению с Луа.
Первое, в MoonScript нету ключевого слова end
. Блоки кода обозначаются
отступом разной величины.
Так что вам придется тщательно следить за тем, на каком уровне вы пишете команды. (Это чертовски полезно, и вырабатывает красивый стиль написания кода =), а не эти кошмарные простыни, где нельзя разобрать начал и хвостов.)
Второе, функции объявляются конструкцией вида (a, b, c) -> ....
Тут слева -
набор аргументов, потом стрелочка - разделитель и блок кода, который
собственно является телом функции.
-- Очищаем экран clear = () -> setForeground white setBackground black fill 1, 1, width * 2, height + 1, ' ' -- Рисуем сетку grid = -> setForeground gray setBackground black for y = 1, height set (if y % 2 == 0 then 1 else 3), y, grid_line
Пустой набор аргументов можно опустить, как в функции grid
.
Кроме того, как несложно заметить, MoonScript позволяет вызывать функции, не используя скобочки.
Продолжим.
-- Открываем одну клетку sign = (x, y) -> if x == target.x and y == target.y then black, white, "[]" -- по неведомой мне причине, стрелки вниз в новом шрифте ОС 1.6 нету =) elseif x == target.x and y < target.y then white, green, "▼▼" elseif x == target.x and y > target.y then white, violet, "↑↑" elseif x < target.x and y < target.y then white, teal, "↘↘" elseif x < target.x and y == target.y then white, cyan, "→→" elseif x < target.x and y > target.y then white, blue, "↗↗" elseif x > target.x and y < target.y then white, yellow, "↙↙" elseif x > target.x and y == target.y then white, red, "←←" elseif x > target.x and y > target.y then white, pink, "↖↖" cell = (x, y) -> fore, back, text = sign x, y setForeground fore setBackground back set x * 2 - 1, y, text
Здесь функция sign
сконструирована так, чтобы отдавать три переменных разом.
Следует заметить, что в MoonScript можно не пользоваться оператором return
.
Функция автоматически вернет значение последнего оператора в теле.
Кроме функций, значения умеют возвращать и условия. Поэтому в данном случае, функция возвращает значение условия, а условие возвращает три значения из той ветки, которая выполнится.
Функция cell
просто берет эти значения и отрисовывает в нужном месте клетку.
Далее.
-- Рисуем статус status = (state) -> setForeground white setBackground black fill 1, height + 1, width * 2, height + 1, ' ' set 2, height + 1, "[Угадай, где клад!]" switch state when 'win' setForeground green set 24, height + 1, "Вы победили!" when 'lose' setForeground red set 24, height + 1, "Вы проиграли!" else set 24, height + 1, "Попыток осталось: #{attempts}" set width * 2 - 10, height + 1, "[R] [Q]"
Здесь тоже используются две новые конструкции.
Первая - это switch
. Наверняка многие уже знакомы с ним. По сути,
это просто удобный вариант длинных условий, со множеством elseif
.
Свитч получает значение, а потом сравнивает с ним все ветки when
.
Какая совпадет - та и выполнится.
Вторая - это интерполяция строк. В строку в двойных кавычках можно встраивать значения перменных (или даже кусочки кода), используя диез и фигурные скобки, как в функции выше.
Последние приготовления:
-- Генерируем цель setTarget = -> target = { x: random(1, width), y: random(1, height) } -- Инициализируем игру newGame = -> attempts = maxAttemts setTarget! clear! grid! status!
Функция newGame
использует специальный синтаксис для вызова функции,
которой не нужны аргументы.
Вместо того, чтобы писать setTarget()
, MoonScript советует использовать
восклицательный знак. setTarget!
.
Это довольно весело смотрится в коде. =)
Ну чтож, все готово.
Давайте соберем все написанное, и запилим немного игровой логики!
while true -- Ждем события event, _, x, y = pull! -- Обрабатываем его switch event when 'touch' -- Если был клик -- Открываем клетку, если остались попытки if attempts > 0 x = ceil(x / 2) cell x, y attempts -= 1 -- Обновляем инфу if x == target.x and y == target.y attempts = 0 status('win') elseif attempts == 0 status('lose') else status! when 'key_down' switch x when 113 -- Q: выход из игры break when 114 -- R: перезапуск newGame! clear!
Вуаля! Оно работает. И даже можно поиграть. И даже победить =)
Круто, правда?
Не надо делать такое выражение лица, я знаю что на самом деле вы со мной согласны. =)
А вы, да-да, вы! - на задних рядах, хватит кидаться тапками!
Полный код игрушки доступен тут:
http://pastebin.com/M0sxk1QH
Enjoy!