Часть 1 | Часть 2 | Часть 3

Rooms.xyz — это не совсем фэнтезийная консоль (тема, о которой я написал несколько статей в прошлом), но она во многом разделяет те же принципы: поскольку это инструмент, который позволяет вам очень легко создавать мини-игры и интерактивные взаимодействия на основе вокселей, используя воксельные объекты и сценарии Lua.

Раскрытие информации: я сотрудник компании «Things, Inc.» стартап из трех человек, стоящий за Rooms.xyz. Вся часть «, Inc» может показаться немного корпоративной, но на самом деле мы всего лишь 3 человека, которые не знают, что они делают, но хотят создать что-то классное.

Эта статья представляет собой (очень поверхностный) обзор модели программирования и основ написания кода Lua в Rooms для настройки поведения объектов.

В части 1 мы рассмотрим основы:

  • Комнаты и вещи
  • Базовое программирование
  • Перемещение вещей
  • Последовательность действий

Я должен программировать?

Ну, ты обязательно ешь десерт? Предпосылкой для этой статьи является то, что вы занимаетесь программированием, а программирование — это весело. На самом деле мы с вами знаем, что потребуются некоторые усилия, чтобы удержать вас от программирования. Вы бы запрограммировали тостер, если бы у него был API. Возможно, у него есть API. Прекратите программировать тостер. Вернись.

Все это к тому: нет, вам не обязательно программировать в Rooms, вы можете просто делать красивые комнаты на основе уже существующих объектов (в библиотеке их много!), коих много уже приходят с существующим поведением. Но если вы хотите достичь этого высокого потолка и создать что-то необычное и необычное, программирование — это то, что вам нужно!

Что такое комната?

Комната — это небольшая интерактивная трехмерная среда. Это то, что вы строите. Если вы не увлекаетесь комнатами или интерактивными трехмерными средами, о боже, вам не понравится Rooms.xyz. Комната может быть мини-игрой или просто приятным (или нет, но мы надеемся, что это так) опытом, к которому пользователь может получить доступ.

Это пример мини-игры. Это мини-игра в боулинг, в которой вы можете играть в боулинг, нажимая на шар для боулинга. Я думаю, так работает боулинг.

Что такое вещь?

Вещь — это объект. Правда, Вещь? Могли ли мы выбрать более общее название? Ну да, object был бы еще более общим. Иногда мы тоже называем их объектами, когда нам не хватило кофе.

Итак, каждый из предметов в комнате — это Вещь. В комнате наверху шар для боулинга — это Вещь, каждая кегля — Вещь, стол — Вещь, музыкальный автомат — Вещь. Ты понял. Все есть вещь (*).

(*) Стены и пол тоже являются Вещами, но никому об этом не говорите, потому что это странная часть нашего дизайна, и я пока не знаю, имеет ли это смысл.

Что заставляет Вещь вести себя именно так?

Спойлер: это код. Как вы думаете, что это будет?

Если вы щелкнете вещь в режиме редактирования и нажмете кнопку «Код», вы увидите редактор кода.

В редакторе кода вы можете ввести код Lua. Lua — прекрасный скриптовый язык, созданный бразильцем. Не я. Еще один бразилец. Нас там много.

В любом случае, думайте о Lua как о Javascript без раздражающих частей.

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

Обратите внимание, что у нас также есть полная документация по всем функциям API, поэтому после прочтения этого руководства (или во время) вы сможете узнать обо всем, что может делать API.

Прежде чем мы перейдем к кодированию…

Обратите внимание: если вы хотите сохранить свою работу в Rooms.xyz, вам необходимо создать учетную запись. Поскольку (на момент написания этой статьи) Rooms.xyz находится в альфа-версии, вам необходимо запросить ранний доступ через домашнюю страницу (просто нажмите кнопку Запросить ранний доступ).

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

Поздороваться

Хорошо, когда вы нажимаете на шаблон Hello, вы получаете этот предварительно написанный для вас код. Это действительно увлекательный скрипт, который заставляет объект говорить «Привет» при нажатии.

Теперь запустите его либо в окне предварительного просмотра (нажмите «Обновить предварительный просмотр»), либо выйдите из редактора кода и войдите в режим предварительного просмотра.

Эта вещь вверху — это то, как вы переключаетесь из режима редактирования в режим предварительного просмотра (то есть воспроизведения). Вы, наверное, уже поняли это, но на всякий случай, это здесь:

Вы также можете переключаться между редактированием и предварительным просмотром с помощью клавиши ESC.

Теперь перейдите в режим воспроизведения и нажмите на стол. Это то, что ты получаешь:

Не любите болтливую мебель? Не беспокойтесь, мы скоро перейдем к чему-то другому.

С этого момента я перестану делать скриншоты кода (потому что это глупый способ показывать код, и другие разработчики в кофейне уже странно смотрят на меня из-за этого), и вместо этого я буду писать код прямо в маленьких блоках. так:

-- This function runs when the user clicks.
function onClick()
  say("Hello")
end

Конечно, вы можете изменить эту строку, чтобы в таблице было все, что вы можете себе представить, даже совершенно другая фраза, например:

Я уверен, что вы можете найти лучшие вещи для него сказать.

Обработчики (предопределенные функции)

В предыдущем примере наша функция называлась onClick. Это не совпадение: это функция, которая выполняется, когда пользователь что-то щелкает. Каждая вещь может иметь собственную функцию onClick.

Это может показаться излишним, но функцию onClick нужно вызывать onClick. Если вы назовете его "onclick", "ONCLICK" или "clementine", это не сработает, потому что движок ищет именно имя onClick с учетом регистра.

Некоторые другие примеры функций обработчика:

  • onStart(): вызывается при запуске комнаты.
  • onCollision(): вызывается, когда вещь сталкивается с другой вещью.
  • onButtonDown(): вызывается при нажатии кнопки виртуального джойстика.
  • onButtonUp(): вызывается при отпускании кнопки виртуального джойстика.
  • onUpdate(): вызывается один раз за кадр (60 раз в секунду).

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

Функция onStart()

Это полезно, если вы хотите что-то сделать, когда комната запускается независимо от действий пользователя.

-- This function runs when the room starts.
function onStart()
  say("Click me!")
end

-- This function runs when the user clicks.
function onClick()
  say("Thanks for clicking")
end

Вы также можете поместить код инициализации вне каких-либо функций, если хотите, а не внутри onStart(). Это вопрос стиля:

-- This code runs when the room starts.
say("Click me!")

-- This function runs when the user clicks.
function onClick()
  say("Thanks for clicking")
end

Я думаю, будет лучше, если он будет внутри onStart(). Личное предпочтение.

Несколько слов о физике

Если вы следуете и пробуете код, убедитесь, что объект, над которым вы работаете, имеет тип Kinematic в качестве физического типа. Мы объясним подробнее позже, но кинематические объекты делают то, что вы хотите. Динамические (некинематические) объекты делают то, что они хотят. На данный момент мы босс, поэтому установите его на кинематику, чтобы мы могли перемещать их, не задавая нам отношения.

Возьмите его на спину!

Попробуйте этот код на объекте. Если вам нужна отправная точка, просто начните с https://rooms.xyz/btco/tutostart. Нажмите на такси и установите его код следующим образом:

-- This function runs when the user clicks.
function onClick()
  startSpin()
end

Теперь перейдите в режим предварительного просмотра и щелкните его. Он должен начать вращаться! Не пытайтесь повторить это с настоящей машиной. В общем, не принимайте никаких советов по вождению из этого руководства.

Проверьте результат на: https://rooms.xyz/btco/tutospin.

Мгновенное перемещение (без анимации)

Если вы просто хотите переместить Вещь в новое место, используйте функцию setPosition() и сообщите ей новые координаты:

function onClick()
  -- Move it to the center of the room.
  setPosition(0, 0, 0)
end

Нажмите на нее и хлопните, она внезапно переместится в центр комнаты (вероятно, это будет очень неприятно для пассажиров машины).

Проверьте результат на: https://rooms.xyz/btco/tutosetpos.

Движение плавно (с анимацией)

Круто, теперь давайте сделаем так, чтобы этот объект плавно двигался на определенную величину, а не просто телепортировался. Просто используйте функцию startMoveBy(), которая принимает дельту (x, y, z) и общее время и перемещает объект в соответствии с запросом.

-- This function runs when the user clicks.
function onClick()
  say("Here we go")
  -- Move 30 units south in 1 second.
  startMoveBy(0, 0, -30, 1)
end

Почему 0, 0, -30? Ну, это из-за того, как работает наша система координат:

Итак, +Z — к левой стене, +X — к правой стене. Что касается сторон света, то установим, что:

  • Когда мы говорим север, мы имеем в виду направление +Z
  • Когда мы говорим на восток, мы имеем в виду направление +X
  • Когда мы говорим юг, мы имеем в виду направление -Z
  • Когда мы говорим запад, мы имеем в виду направление -X
  • Когда мы говорим «вверх», мы имеем в виду «в сторону +Y».
  • Когда мы говорим вниз, мы имеем в виду направление -Y

Кстати, центр комнаты (0, 0, 0). Это точка на полу в центре комнаты. Поверхность комнаты имеет размер примерно 95x95 и высоту 75 единиц, поэтому это означает, что координаты X и Z изменяются примерно от -47,5 до +47,5, а координата Y изменяется от 0 до 75.

Проверьте результат на: https://rooms.xyz/btco/tutomove

Автомобиль, который заводится и останавливается

Лучшие автомобили на рынке сегодня способны как двигаться, так и останавливаться. Посмотрим, сможем ли мы это сделать. Сделаем так, что если щелкнуть по нему, он начинает двигаться, а если щелкнуть еще раз, то останавливается, и так далее, и тому подобное. Вот код:

moving = false

-- This function runs when the user clicks.
function onClick()
  if moving then
    stopMove()
    moving = false
  else
    startMoveBy(0, 0, -48, 10)
    moving = true
  end
end

Здесь показано, как вызвать stopMove() для остановки движения, запущенного с помощью startMoveBy(), а также показано, как использовать логическую переменную, позволяющую отслеживать состояние автомобиль (движется или не движется). Это также показывает, что переменные могут существовать вне функций, поэтому они могут сохранять свое значение при вызовах функций (чего не было бы, если бы они были объявлены внутри функции).

Проверьте результат на: https://rooms.xyz/btco/tutostartstop

Последовательность действий

Одна вещь, которая может быть не интуитивно понятной, заключается в том, что такие функции, как say(), startMoveBy() и т. д., являются асинхронными, что означает, что они будут работать в фоновом режиме во время выполнения вашего кода. продолжается. Поэтому, если вы вызовете более одного из них, они будут работать одновременно, а не один за другим. Например:

-- WARNING: This doesn't do what it seems to do
function onClick()
  -- Move 20 units south, in 1 second.
  startMoveBy(0, 0, -20, 2)
  -- Move 20 units west, in 1 second.
  startMoveBy(-20, 0, 0, 2)
  -- Say we're done.
  say("Done")
  -- Start to spin around.
  startSpin()
end

Вы можете подумать, что машина сначала переместится на 20 единиц на юг, затем на 20 единиц на запад, а затем скажет «Готово» и начнет вращаться. Но на самом деле он пытается сделать все одновременно, и это полный беспорядок.

Как вы это делаете? Мы должны добавить еще одну функцию в наш репертуар, в том числе потому, что репертуар — классное французское слово, которое я хотел использовать в этом тексте. Это функция wait(). Он будет ждать заданное количество секунд, а затем вызовет другую функцию. Мы можем использовать это для секвенирования.

function onClick()
  -- Move 20 units south, in 1 second.
  startMoveBy(0, 0, -20, 1)
  -- This waits 1 second (the time it takes to move)
  -- and then calls moveWest
  wait(1, moveWest)
end

function moveWest()
  -- Move 20 units west, in 1 second.
  startMoveBy(-20, 0, 0, 1)
  -- This waits 1 second (the time it takes to move)
  -- and then calls sayDone
  wait(1, sayDone)
end

function sayDone()
  say("Done")
  -- Start to spin around.
  startSpin()
end

Это работает. Ну, кроме того, что машину заносит вбок и не поворачивает, но я уже говорил тебе не слушать моих советов по вождению.

Проверьте результат на: https://rooms.xyz/btco/tutoseq

Делать что-то периодически

Если вы хотите, чтобы функция вызывалась периодически каждый заданный интервал, вы можете использовать every().

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

В этом примере овца имеет такой код:

c = 0

function onStart()
  -- Call the count() function every 1 second.
  every(1, count)
end

function count()
  c = c + 1
  say(c .. " sheep")  
end

Итак, в onStart() мы говорим, что хотим, чтобы функция count() вызывалась каждую 1 секунду. Таким образом, движок будет вызывать нашу функцию count() каждую секунду, в которой мы увеличиваем значение счетчика и заставляем овец произносить текущий счет.

Проверьте результат: https://rooms.xyz/btco/tutocount

Примечание. Из соображений производительности интервал не может быть меньше 0,25 с. Однако вы все равно можете снизить производительность другими способами, так что не расстраивайтесь.

Конец части 1

Большой! Вы зашли так далеко и терпели мое чувство юмора и стиль письма. Во второй части ситуация не улучшилась, но, пожалуйста, нажмите на ссылку ниже, чтобы продолжить.

Перейти к части 2 →