Поговорим о Луне! #0. Угадываем числа.
На днях я рассказывал об интересном языке для OpenComputers (и не только).
MoonScript
Но одно дело - прочитать об языке где-то. А совсем другое - попробовать язык самому.
Именно этим я и предлагаю заняться.
Для разогрева, начнем с чего-нибудь несложного. Например "Угадай число".
Думаю все знают эту игру. Компьютер загадывает число, мы пытаемся угадать. На каждую нашу попытку, компьютер злорадно сообщает - "больше!", "меньше!" или "у вас закончились попытки!" и "вы проиграли!".
Немного модифицируем исходную идею, и перенесем ее на 2d поле. Просто, чтобы не было скучно.
ТЗ
Что нам потребуется?
1) Отрисовать сетку
Тут мы просто возьмем текущий размер дисплея, и разметим его на клеточки.
2) Загадать число
3) Слушать команды пользователя
Юзер будет тыкать на клеточки. Нам надо будет слушать эвент touch.
4) Обновлять игровое поле в ответ
Собственно после тыка, будем открывать клетку. Если это не та клетка - рисовать на ней стрелочку. Если та - рисовать победный баннер. Если закончились ходы - рисовать что-нибудь обидное.
За дело
Первым делом надо подключить все, что мы будем использовать.
В Lua обычно мы при помощи команды require пишем все в локальные переменные.
В MoonScript все переменные по дефолту локальны. Поэтому использовать ключевое слово local нет необходимости.
Для подключения же, используется ключевое слово import:
import getResolution setForeground setBackground set fill from require('component').gpuimport pull from require 'event'import ceil, random from mathimport rep from string
Мы вытащили из нужных библиотек нужные функции. Ничего лишнего.
Теперь объявим переменные, которые будут использоваться в коде.
- Размеры экранаwidth, height = getResolution()width /= 2 -- потому что по горизонтали наши клетки займут 2 символаheight -= 1 -- потому что внизу будет статус-- Цветаwhite = 0xFFFFFFblack = 0x000000gray = 0x222222green = 0x00BB33yellow = 0xFFC04Cred = 0xFF0000pink = 0xFF0074violet = 0xD600FFblue = 0x4E5AFFcyan = 0x4ED7FFteal = 0x00CC99-- Заготовка для сетки - один ряд клетокgrid_line = rep("▒▒ ", ceil(width / 2))-- Наша цельtarget = { x: 0, y: 0 }-- Количество попытокmaxAttemts = ceil(width * height / 150) -- 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, "[]" elseif x == target.x and y < target.y then white, green, "▼▼" -- по неведомой мне причине, стрелки вниз в новом шрифте ОС 1.6 нету =) 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!.
Это довольно весело смотрится в коде. =)
Ну чтож, все готово.
Давайте соберем все написанное, и запилим немного игровой логики!
-- Поехали!newGame!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!
- 12
6 комментариев
Рекомендуемые комментарии