«Я просто хотел подвинуть кубик… а в итоге написал игру на 200 строк» - каждый, кто открыл Roblox Studio
Зачем вообще Lua в Roblox?
Окей, давай разберёмся. Ты наверняка слышал про Roblox - платформу, где миллионы людей играют в игры, которые создали… другие игроки. И вот за всей этой магией стоит Luau - это форк Lua, заточенный под Roblox. Быстрый, простой, с типами (ну, почти).
Если ты уже кодишь на JS, Python или чём-то ещё - Lua покажется тебе подозрительно простым. Никаких {} для блоков, никаких ; в конце строк. Просто local, function, end и поехали.
Факт: массивы в Lua начинаются с 1, а не с 0. Да, мы тоже в шоке. Не благодарите.
Шаг 0: Открываем Roblox Studio
Качаем Roblox Studio
Создаём новый проект → выбираем Baseplate (пустой мир с полом)
Видим 3D-сцену, слева - Explorer (дерево объектов), справа - Properties
Всё. Ты - разработчик игр. Можешь обновлять LinkedIn.
Шаг 1: Кидаем объект на сцену
В меню сверху жмём Part → на сцене появляется серый кирпич. Это наш подопытный.
Переименуем его для порядка:
В Explorer находим
PartКликаем правой кнопкой → Rename → пишем
MovingBlock
Можно поменять цвет в Properties → BrickColor. Чисто для вайба.
Шаг 2: Первый скрипт - двигаем объект
Теперь самое интересное. Кликаем правой кнопкой по MovingBlock в Explorer → Insert Object → Script.
Открывается редактор кода. Удаляем дефолтный print("Hello world!") и пишем:
local block = script.Parent -- это наш MovingBlock
local startPos = block.Position -- запоминаем стартовую позицию
while true do
for i = 0, 10, 0.1 do
block.Position = startPos + Vector3.new(math.sin(i) * 5, 0, 0)
task.wait(0.03)
end
endЧто тут происходит:
script.Parent- это объект, внутри которого лежит скрипт (наш блок)Vector3.new(x, y, z)- координаты в 3D пространствеmath.sin(i) * 5- блок качается туда-сюда по синусоиде с амплитудой 5 юнитовtask.wait(0.03)- пауза между кадрами (≈30 FPS движения)
Жмём Play (зелёная кнопка сверху) и… кубик поехал! Туда-сюда, как маятник. Красота.
Поздравляю, ты только что написал свой первый игровой скрипт. Это уже больше, чем делает 90% людей, которые «хотят делать игры».
Шаг 3: Реагируем на игрока - «не трогай мой кубик!»
Теперь сделаем так, чтобы блок реагировал, когда игрок его касается. Заменяем содержимое скрипта на:
local block = script.Parent
local startPos = block.Position
local isRunning = false
-- Функция: блок убегает вверх при касании
local function onTouch(otherPart)
-- Проверяем, что нас коснулся именно игрок (у него есть Humanoid)
local humanoid = otherPart.Parent:FindFirstChild("Humanoid")
if humanoid and not isRunning then
isRunning = true
-- Блок подпрыгивает
for i = 0, 3, 0.1 do
block.Position = startPos + Vector3.new(0, math.sin(i) * 8, 0)
task.wait(0.02)
end
-- Возвращается на место
block.Position = startPos
-- Кулдаун 1 секунда
task.wait(1)
isRunning = false
end
end
-- Подписываемся на событие касания
block.Touched:Connect(onTouch)Разбор полётов:
Touched- событие, которое срабатывает при физическом контакте с объектом:Connect(функция)- подписка на событие (привет, паттерн Observer!)FindFirstChild("Humanoid")- проверяем, что нас коснулся игрок, а не случайный кирпичisRunning- флаг-дебаунс, чтобы анимация не запускалась 100 раз подряд
Нажми Play, подойди к блоку персонажем, коснись его - и он подпрыгнет. Как кот, которого напугали огурцом.

Шаг 4: Комбо - движение + реакция
А теперь финальный босс. Сделаем блок, который и двигается сам, и реагирует на игрока - меняет цвет и раздувается:
local block = script.Parent
local startPos = block.Position
local originalColor = block.BrickColor
local isReacting = false
-- Движение блока (в отдельном потоке)
task.spawn(function()
while true do
for i = 0, 10, 0.1 do
if not isReacting then
block.Position = startPos + Vector3.new(
math.sin(i) * 5, 0, math.cos(i) * 5
)
end
task.wait(0.03)
end
end
end)
-- Реакция на касание
block.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChild("Humanoid")
if humanoid and not isReacting then
isReacting = true
-- Меняем цвет на случайный
block.BrickColor = BrickColor.Random()
block.Size = block.Size + Vector3.new(1, 1, 1)
task.wait(0.5)
-- Возвращаем как было
block.BrickColor = originalColor
block.Size = block.Size - Vector3.new(1, 1, 1)
task.wait(0.5)
isReacting = false
end
end)
print("🎮 Скрипт запущен! Попробуй коснуться блока.")Что нового:
task.spawn()- запускает функцию асинхронно (как горутина, только в Lua)Блок двигается по кругу:
sinпо X,cosпо Z - круговая траекторияПри касании блок меняет цвет на случайный и «раздувается»
print()выводит сообщение в Output (View → Output в Studio)
Теперь у нас есть блок, который летает по кругу и троллит игрока вспышками цвета при касании. По сути - это уже мини-игра «поймай кубик».
Быстрая шпаргалка
Концепт | Пример |
|---|---|
Переменная |
|
Функция |
|
Условие |
|
Цикл |
|
Таблица (массив) |
|
Таблица (объект) |
|
Событие |
|
Ожидание |
|
Асинхронность |
|
Что учить дальше?
Ты написал свой первый скрипт - респект. Но это только начало:
RemoteEvents - общение между клиентом и сервером (да, в Roblox есть клиент-серверная архитектура!)
DataStoreService - сохранение прогресса игроков
TweenService - плавные анимации без ручных циклов
UI - интерфейсы с помощью ScreenGui
Модули -
ModuleScriptдля чистой архитектуры
📱 Хочешь прокачать навыки программирования?
Если тебя зацепила тема и хочется не просто читать, а реально кодить - попробуй приложение Кодик. Это платформа, где программирование изучается через практику: короткие уроки, задачи с проверкой прямо в приложении и понятные объяснения без воды. Идеально, чтобы подтянуть основы или освоить новый язык в метро, в очереди или перед сном.
А ещё заходи в наш Telegram-канал - там регулярно выходят посты по программированию, разборы задач, шпаргалки и мемы для разработчиков. Отличный способ повторять материал и держать себя в тонусе, даже когда нет времени садиться за комп.
Удачи в геймдеве! И помни: каждая AAA-игра когда-то начиналась с кубика, который кто-то пнул скриптом. 🎮
Вопросы про движущийся блок и Touched
Как заставить деталь двигаться в Roblox Studio?
Деталь двигают скриптом, который меняет её свойство Position в цикле. В примере из статьи блок качается по синусоиде: block.Position = startPos + Vector3.new(math.sin(i) * 5, 0, 0), а task.wait(0.03) держит паузу между кадрами. Стартовую позицию запоминают заранее, иначе блок будет уезжать всё дальше.
Как понять, что детали коснулся именно игрок?
Игрока в обработчике Touched определяют по наличию Humanoid: otherPart.Parent:FindFirstChild("Humanoid"). Если Humanoid найден, касание сделал персонаж. Без такой проверки событие сработает от любого кирпича, который просто упал рядом.
Зачем нужен дебаунс в обработчике Touched?
Дебаунс нужен потому, что Touched срабатывает много раз подряд, пока персонаж соприкасается с деталью. Обычный приём: булев флаг вроде isRunning, который ставят в true в начале реакции и возвращают в false после паузы. Так анимация не запустится сто раз за секунду.
Как объект может двигаться и одновременно реагировать на касание?
Бесконечный цикл движения запускают отдельно через task.spawn(function() ... end), а на Touched вешают свой обработчик. task.spawn выполняет функцию асинхронно, поэтому цикл не блокирует остальной код скрипта. Общий флаг вроде isReacting помогает притормозить движение на время реакции.
Чем Luau отличается от обычного Lua?
Luau это форк Lua, который Roblox заточил под свою платформу: он быстрый, простой и поддерживает типы. Синтаксис остался узнаваемым: фигурные скобки для блоков не нужны, точка с запятой в конце строки тоже, есть local, function и end.
С какого числа начинаются индексы массивов в Lua?
Индексы массивов в Lua начинаются с 1, а не с нуля. После JavaScript или Python об этом легко забыть и промахнуться на один элемент. Поэтому перебор пишут как for i = 1, #arr do.
