Основы программирования на Lua для Roblox

Этот курс предназначен для новичков, желающих освоить скриптинг в Roblox. Вы изучите основы языка Lua и научитесь создавать интерактивные игровые механики в Roblox Studio.

Знакомство с Roblox Studio и создание первого скрипта

Знакомство с Roblox Studio и создание первого скрипта

Добро пожаловать в курс «Основы программирования на Lua для Roblox»! Это первая статья, с которой начнется ваше путешествие в мир создания игр. Если вы когда-либо задумывались, как работают ваши любимые режимы в Roblox, или хотели создать свой собственный уникальный мир, вы попали по адресу.

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

Что такое Roblox Studio?

Roblox Studio — это движок (программная среда), предоставляемый разработчиками Roblox для создания игр. Если Roblox Player — это приложение, через которое вы играете, то Studio — это мастерская, где эти игры собираются.

Представьте, что вы строите дом. Roblox Player — это возможность зайти в готовый дом и жить в нем. Roblox Studio — это набор инструментов: молоток, пила, чертежи и строительные материалы, которые позволяют возвести этот дом с нуля.

Установка и запуск

Скорее всего, если вы играете в Roblox, Studio уже установлена на вашем компьютере. Она устанавливается автоматически вместе с плеером. Чтобы запустить её:

  1. Найдите синюю иконку Roblox Studio на рабочем столе или в меню «Пуск».
  2. Запустите программу и войдите в свой аккаунт Roblox.
  3. Нажмите на кнопку + New (Новый) в левом верхнем углу и выберите Baseplate (Базовая плита). Это пустой мир, идеальный для обучения.

Обзор интерфейса

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

Давайте разберем четыре ключевые зоны, с которыми программист работает 90% времени:

1. Viewport (Окно просмотра)

Это самое большое окно в центре экрана. Здесь вы видите свой 3D-мир. Вы можете летать камерой, выделять объекты, перемещать их и изменять размер. Управление камерой здесь такое же, как и в самой игре (W, A, S, D и правая кнопка мыши).

2. Explorer (Обозреватель)

Обычно находится справа. Это «дерево» вашей игры. Здесь перечислены все объекты, которые есть в вашем мире: детали (Parts), скрипты, звуки, освещение и интерфейсы.

Самые важные папки для нас сейчас:

  • Workspace: Здесь находится всё, что физически существует в игровом мире (стены, земля, персонажи).
  • ServerScriptService: Лучшее место для хранения серверных скриптов (кода, который управляет логикой игры).

3. Properties (Свойства)

Находится под окном Explorer. Если вы выделите любой объект в Explorer или Viewport (например, деталь), в этом окне отобразятся его характеристики: цвет, размер, прозрачность, позиция и многое другое. Как программисты, мы будем часто менять эти свойства через код.

4. Output (Вывод)

Это окно консоли. Оно находится внизу экрана (если его нет, перейдите во вкладку View сверху и нажмите кнопку Output). Здесь Roblox будет писать нам сообщения, а мы будем искать ошибки в нашем коде. Это главный инструмент общения скрипта с разработчиком.

Создание первого скрипта

Теперь, когда мы ориентируемся в пространстве, давайте напишем нашу первую программу. В программировании традиционно первой программой является вывод фразы «Hello, World!» на экран.

Шаг 1: Создание файла скрипта

  1. В окне Explorer найдите папку ServerScriptService.
  2. Наведите на неё курсор и нажмите на появившийся плюсик (+).
  3. В выпадающем меню начните вводить слово Script и выберите объект Script (иконка свитка с кодом).

Поздравляем! Вы создали свой первый файл с кодом. Roblox Studio автоматически откроет его в редакторе. Если этого не произошло, дважды кликните по созданному скрипту в Explorer.

Шаг 2: Написание кода

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

Введите следующий код:

print("Привет, Roblox!")

Разберем, что мы написали:

  • print — это функция. Команда компьютеру: «Напечатай что-нибудь в консоль».
  • () — круглые скобки. В них мы помещаем то, что именно нужно напечатать.
  • "" — кавычки. Они показывают, что внутри находится текст (строка), а не команда или число.

Шаг 3: Запуск и проверка

Чтобы увидеть результат, нам нужно запустить игру.

  1. На верхней панели перейдите во вкладку Home или Test.
  2. Нажмите кнопку Play (или маленькую стрелочку под ней и выберите Run, чтобы запустить игру без загрузки персонажа — это быстрее).
  3. Посмотрите в окно Output внизу экрана.

Вы должны увидеть надпись: Привет, Roblox!

Если вы её видите — вы официально стали программистом на Lua!

Переменные и простая математика

Программирование — это не только текст, но и вычисления. Lua отлично справляется с математикой. Давайте попробуем использовать скрипт как калькулятор.

Измените ваш скрипт на следующий:

local a = 10
local b = 5
local sum = a + b
print(sum)

Здесь мы использовали ключевое слово local. Оно создает переменную — ячейку памяти, в которой мы храним данные. Мы создали ячейку a и положили туда число 10, затем ячейку b с числом 5.

Математически это можно выразить простой формулой:

c=a+bc = a + b

где cc — это сумма (в нашем коде переменная sum), aa — первое слагаемое (переменная a), а bb — второе слагаемое (переменная b).

Запустите скрипт (Run). В окне Output появится число 15.

Мы можем использовать и более сложные операции. Например, вычисление площади прямоугольника:

S=w⋅hS = w \cdot h

где SS — площадь, ww — ширина (width), а hh — высота (height).

В коде это будет выглядеть так:

local width = 20
local height = 4
local area = width * height -- Звездочка (*) означает умножение
print("Площадь равна:")
print(area)

Обратите внимание на текст после двух дефисов --. Это комментарий. Компьютер игнорирует всё, что написано после --. Комментарии нужны программистам, чтобы оставлять заметки для себя или коллег.

Взаимодействие с игровым миром

Вывод текста в консоль — это полезно, но скучно. Мы ведь в 3D-движке! Давайте заставим наш скрипт изменить что-то в игровом мире.

Подготовка сцены

  1. Вернитесь из редактора скриптов в режим просмотра (вкладка с названием вашего плейса сверху, рядом с вкладкой скрипта).
  2. Во вкладке Home нажмите на иконку Part (Деталь). В центре мира появится кирпичик.
  3. Посмотрите в окно Explorer. В папке Workspace появился новый объект с именем Part.

Обращение к объекту через код

Теперь вернемся в наш скрипт и попробуем изменить прозрачность этой детали.

В Roblox всё организовано иерархически, как папки в компьютере. Главная папка игры называется game. В ней лежит папка Workspace (где находится наш кирпич). А в ней лежит сам Part.

Путь к детали выглядит так: game.Workspace.Part.

Напишем код, который делает деталь полупрозрачной:

-- Ждем 3 секунды, чтобы мы успели заметить изменения после запуска
wait(3)

-- Находим деталь и меняем её свойство Transparency (Прозрачность)
game.Workspace.Part.Transparency = 0.5

print("Деталь стала прозрачной!")

Разбор кода

  • wait(3) — команда, которая останавливает выполнение скрипта на 3 секунды.
  • . (точка) — используется для входа внутрь объекта (из game в Workspace, из Workspace в Part).
  • Transparency — это свойство детали. 0 — полностью видимая, 1 — полностью невидимая. Мы установили 0.5 (50% прозрачности).
  • = — знак присваивания. Мы говорим: «Сделай свойство Transparency равным 0.5».

Запустите игру. Через 3 секунды после старта ваш кирпичик должен стать призрачным. Это ваш первый шаг к созданию динамического мира!

Возможные ошибки

В программировании ошибки неизбежны. Если ваш скрипт не работает, посмотрите в окно Output. Красный текст укажет, что пошло не так.

Частые ошибки новичков:

  1. Регистр букв: Lua чувствителен к регистру. Game, game и GAME — это три разных слова. Правильно писать game, Workspace, Transparency (свойства обычно пишутся с большой буквы).
  2. Забытые кавычки: Текст всегда должен быть в кавычках "текст".
  3. Опечатки в именах: Если деталь называется Part, а вы написали game.Workspace.Part1, скрипт выдаст ошибку, так как не найдет объект.

Заключение

Сегодня вы сделали огромный шаг. Вы не просто установили программу, но и изучили её интерфейс, написали свой первый код, использовали переменные и даже научились управлять физическими объектами через скрипт.

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

Основы синтаксиса Lua: переменные, типы данных и функции

Основы синтаксиса Lua: переменные, типы данных и функции

Приветствуем во второй статье курса «Основы программирования на Lua для Roblox»! В прошлый раз мы научились открывать Roblox Studio, находить окно Output и даже написали свой первый скрипт, который сделал деталь прозрачной. Но чтобы создавать по-настоящему интересные игры — с системой уровней, магазинами, оружием и диалогами — нам нужно разобраться в правилах языка Lua.

Сегодня мы изучим «грамматику» этого языка: как хранить информацию (переменные), какой она бывает (типы данных) и как создавать свои собственные команды (функции).

Переменные: коробки для данных

Представьте, что вы переезжаете. Чтобы перевезти вещи, вы складываете их в коробки. Чтобы не запутаться, вы подписываете каждую коробку маркером: «Книги», «Посуда», «Игрушки». В программировании переменная — это и есть такая подписанная коробка, в которой мы храним данные.

Создание переменной

В Lua создание переменной происходит с помощью ключевого слова local. Это слово говорит компьютеру: «Создай новую коробку только для этого скрипта».

Синтаксис выглядит так:

local myName = "Alex"
local playerHealth = 100

Разберем по частям:

  1. local — команда объявления переменной.
  2. myName — имя переменной (то, что мы пишем маркером на коробке).
  3. = — знак присваивания. Это не математическое равенство, а действие: «Положи то, что справа, в коробку слева».
  4. "Alex" — значение (содержимое коробки).

Правила именования

Имя переменной может быть почти любым, но есть правила:

  • Имя не может начинаться с цифры (1player — ошибка, player1 — верно).
  • Имя не может содержать пробелы (my score — ошибка, myScore — верно).
  • Нельзя использовать зарезервированные слова Lua (например, print, local, function, end).
  • Lua чувствителен к регистру: Score и score — это две разные переменные.

Хорошим тоном считается использование стиля camelCase: первое слово пишется с маленькой буквы, а каждое следующее — с большой. Например: walkSpeed, maxHealth, isDoorOpen.

Типы данных

В наши «коробки» можно класть разные вещи. В Lua есть несколько основных типов данных, с которыми вы будете работать постоянно.

1. Nil (Пустота)

Это особый тип, который означает «ничего». Если вы создали переменную, но ничего в неё не положили, или если вы удалили объект, он становится nil.

local emptyBox = nil

2. Boolean (Логический тип)

Самый простой тип, который может иметь только два значения:

  • true (истина, да, включено)
  • false (ложь, нет, выключено)

Это как выключатель света: он либо включен, либо выключен. Мы будем использовать это для проверок: жив ли игрок? Открыта ли дверь?

local isAlive = true
local isDoorOpen = false

3. Number (Числа)

Lua не делит числа на целые и дробные, для него всё это — number. Вы можете выполнять с ними любые математические операции.

Рассмотрим пример расчета урона. Допустим, у нас есть формула остатка здоровья:

Hcurrent=Hmax−DH_{current} = H_{max} - D

Где HcurrentH_{current} — текущее здоровье, HmaxH_{max} — максимальное здоровье, а DD — полученный урон.

В коде это выглядит так:

local maxHealth = 100
local damage = 15
local currentHealth = maxHealth - damage
print(currentHealth) -- Выведет 85

Вы можете использовать:

  • + (сложение)
  • - (вычитание)
  • * (умножение)
  • / (деление)
  • ^ (возведение в степень)

Например, формула площади круга:

S=π⋅r2S = \pi \cdot r^2

Где SS — площадь, π\pi — число Пи (примерно 3.14), rr — радиус круга.

local pi = 3.14159
local radius = 5
local area = pi * radius^2
print(area)

4. String (Строки)

Строка — это текст. Текст всегда должен быть обернут в кавычки (одинарные ' ' или двойные " ").

local greeting = "Привет, Roblox!"
local name = 'Игрок'

Строки можно склеивать друг с другом. Это называется конкатенация. В Lua для этого используются две точки ...

local firstName = "Roblox"
local lastName = "Developer"
local fullName = firstName .. " " .. lastName
print(fullName) -- Выведет: Roblox Developer

5. Специфические типы Roblox

Помимо стандартных типов Lua, в Roblox есть свои уникальные типы данных, необходимые для 3D-мира.

  • Vector3: Описывает позицию или размер в 3D-пространстве (X, Y, Z).
    local newPosition = Vector3.new(10, 50, 10)
    
  • Color3: Описывает цвет (Красный, Зеленый, Синий).
    local redColor = Color3.fromRGB(255, 0, 0)
    
  • Instance: Ссылка на любой объект в игре (Part, Light, Sound).
    local myPart = game.Workspace.Part
    

Функции: рецепты действий

Мы уже использовали функцию print(). Но что, если мы хотим создать свою команду? Например, команду, которая лечит игрока и одновременно проигрывает звук лечения?

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

Создание функции

Функция объявляется ключевыми словами local function, затем идет имя, скобки () и завершается словом end.

local function sayHello()
    print("Привет!")
    print("Как твои дела?")
end

Этот код сам по себе ничего не сделает. Мы просто «записали рецепт». Чтобы код сработал, функцию нужно вызвать:

sayHello() -- В консоли появятся две строчки текста

Аргументы (Параметры)

Функции становятся мощнее, когда мы передаем им данные. Переменные внутри скобок называются аргументами.

Давайте напишем функцию, которая складывает два числа:

local function addNumbers(a, b)
    local result = a + b
    print("Сумма равна: " .. result)
end

addNumbers(5, 10) -- Выведет: Сумма равна: 15
addNumbers(100, 200) -- Выведет: Сумма равна: 300

Здесь a и b — это временные переменные, которые существуют только внутри функции. Когда мы пишем addNumbers(5, 10), a становится равным 5, а b — 10.

Возврат значений (Return)

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

Представьте формулу расчета площади прямоугольника:

S=w⋅hS = w \cdot h

Где SS — площадь, ww — ширина, hh — высота.

local function calculateArea(width, height)
    local area = width * height
    return area -- Мы "возвращаем" результат наружу
end

local myRoomArea = calculateArea(4, 5)
print(myRoomArea) -- Выведет 20

Если бы мы не написали return, переменная myRoomArea получила бы значение nil.

Область видимости (Scope)

Вы заметили, что мы везде пишем local? Это очень важно. Переменные бывают локальными и глобальными.

  • Локальные (local): Видны только в том блоке кода, где созданы (например, только внутри функции). Это как личный дневник — никто другой его не видит.
  • Глобальные (без local): Видны везде. Это как объявление на столбе.

В Roblox всегда старайтесь использовать local. Глобальные переменные могут конфликтовать друг с другом, замедлять игру и вызывать ошибки, которые трудно найти.

Пример ошибки области видимости:

local function testScope()
    local secret = "Я спрятан!"
    print(secret) -- Сработает
end

testScope()
print(secret) -- ОШИБКА! Переменная secret существует только внутри функции

Практика: Изменяем мир с помощью переменных

Давайте объединим всё, что мы узнали, и напишем скрипт, который изменяет свойства детали, используя переменные и функции.

  1. Создайте в Roblox Studio деталь (Part).
  2. Создайте новый Script в ServerScriptService.
  3. Напишите следующий код:
-- 1. Объявляем переменные для настройки
local targetPart = game.Workspace.Part -- Ссылка на деталь
local newColor = Color3.fromRGB(0, 255, 0) -- Ярко-зеленый цвет
local newTransparency = 0.5 -- Полупрозрачность

-- 2. Создаем функцию для изменения детали
local function changePartProperties(part, color, transparency)
    print("Начинаем изменение детали...")
    part.Color = color
    part.Transparency = transparency
    print("Деталь успешно изменена!")
end

-- 3. Ждем 3 секунды и вызываем функцию
wait(3)
changePartProperties(targetPart, newColor, newTransparency)

Что здесь происходит?

  1. Мы сохранили ссылку на деталь и желаемые параметры в переменные. Если мы захотим поменять цвет на красный, нам нужно будет изменить только одну цифру в начале скрипта.
  2. Мы написали универсальную функцию changePartProperties. Она может покрасить любую деталь в любой цвет, который мы ей передадим.
  3. Через 3 секунды мы вызываем эту функцию, передавая наши подготовленные переменные как аргументы.

Заключение

Поздравляем! Теперь вы знаете, как компьютер хранит данные и как создавать свои собственные команды. Переменные, типы данных и функции — это фундамент, на котором строятся самые сложные скрипты, от инвентаря игрока до искусственного интеллекта врагов.

В следующей статье мы научим наш код «думать» и принимать решения. Мы разберем условные конструкции if и else, чтобы создавать логику вроде: «Если у игрока есть ключ, открыть дверь, иначе — проиграть звук ошибки».

Экспериментируйте с кодом, создавайте свои переменные и функции, и до встречи в следующем уроке!

Управление потоком: условные операторы и циклы

Управление потоком: условные операторы и циклы

Добро пожаловать в третью часть курса «Основы программирования на Lua для Roblox»! В предыдущих уроках мы научились создавать переменные (наши «коробки» с данными) и писать функции (рецепты действий). Но пока наши скрипты были линейными: они выполняли команды строго одну за другой, сверху вниз, как поезд, идущий по рельсам без стрелок.

Сегодня мы научим наш код принимать решения и выполнять рутинную работу за нас. Мы превратим наш «поезд» в умный автомобиль с навигатором. Мы разберем две фундаментальные концепции программирования: условные операторы (как делать выбор) и циклы (как повторять действия).

Условные операторы: Искусство выбора

В жизни мы постоянно принимаем решения на основе условий: «Если на улице дождь, то я возьму зонт, иначе я пойду в футболке». В программировании эта логика реализуется с помощью конструкции if (если), then (то) и else (иначе).

Базовая конструкция if...then

Самая простая проверка выглядит так:

local isRaining = true

if isRaining then
    print("Нужно взять зонт!")
end

Компьютер проверяет то, что написано между if и then. Если это правда (true), он выполняет код внутри. Если ложь (false), он просто пропускает этот блок и идет дальше.

Операторы сравнения

Чаще всего мы проверяем не просто true или false, а сравниваем значения. Например, хватает ли у игрока денег на покупку меча?

В Lua используются следующие знаки для сравнения:

  • == — равно (обратите внимание: два знака равно, так как один знак = — это присваивание переменной).
  • ~= — не равно.
  • > — больше.
  • < — меньше.
  • >= — больше или равно.
  • <= — меньше или равно.

Рассмотрим пример с проверкой здоровья:

local health = 0

if health == 0 then
    print("Игрок погиб!")
end

Математически это условие можно записать так:

h=0h = 0

где hh — это значение переменной здоровья. Если равенство верно, код выполняется.

Конструкция else и elseif

Что, если мы хотим выполнить другое действие, когда условие ложно? Для этого есть слово else (иначе).

local money = 50
local swordPrice = 100

if money >= swordPrice then
    print("Вы купили меч!")
else
    print("Недостаточно монет.")
end

А если условий несколько? Например, светофор. Используем elseif (иначе если).

local lightColor = "Yellow"

if lightColor == "Red" then
    print("Стоп!")
elseif lightColor == "Yellow" then
    print("Приготовиться...")
elseif lightColor == "Green" then
    print("Можно ехать!")
else
    print("Светофор сломан.")
end

Логические операторы: and, or, not

Иногда нужно проверить сразу несколько условий. Для этого мы используем логические связки:

  1. and (И): Оба условия должны быть правдой.
    • Пример: Чтобы открыть сундук, нужно иметь ключ И быть рядом с сундуком.
  2. or (ИЛИ): Хотя бы одно условие должно быть правдой.
    • Пример: Вы выиграли, если убили босса ИЛИ собрали все монеты.
  3. not (НЕ): Переворачивает значение (правду делает ложью, и наоборот).

Пример сложного условия:

local hasKey = true
local isNearDoor = true
local isDoorLocked = true

if hasKey and isNearDoor and isDoorLocked then
    print("Дверь открыта!")
    isDoorLocked = false
end

В математической логике операция И часто обозначается как умножение, а ИЛИ как сложение. Если представить true как 1, а false как 0, то:

R=A⋅BR = A \cdot B

где RR — результат (Result), AA — первое условие, BB — второе условие. Если хотя бы один множитель равен 0 (ложь), то и результат будет 0.

Циклы: Сила повторения

Представьте, что вам нужно создать лестницу из 100 ступенек. Писать 100 раз код для создания одной ступеньки — это долго и неэффективно. Здесь на помощь приходят циклы.

Цикл — это конструкция, которая повторяет блок кода несколько раз.

Цикл While (Пока)

Этот цикл работает до тех пор, пока условие остается истинным (true). Это похоже на if, который повторяет сам себя.

Синтаксис:

local secondsLeft = 10

while secondsLeft > 0 do
    print("Осталось секунд: " .. secondsLeft)
    secondsLeft = secondsLeft - 1
    wait(1)
end

print("Время вышло!")

ВАЖНО: При использовании цикла while всегда добавляйте задержку wait(). Если вы создадите бесконечный цикл без задержки, Roblox Studio зависнет, так как компьютер будет пытаться выполнить миллиарды операций в секунду, не давая игре обновиться.

Цикл For (Для)

Это самый популярный цикл. Он используется, когда мы точно знаем, сколько раз нужно повторить действие (например, от 1 до 10).

Синтаксис:

-- for переменная = старт, финиш, шаг do
for i = 1, 5 do
    print("Это повторение номер " .. i)
end

Разберем параметры:

  1. i = 1: Мы создаем переменную-счетчик i и начинаем с 1.
  2. 5: Мы продолжаем цикл, пока i не станет больше 5.
  3. (Необязательно) Шаг: По умолчанию i увеличивается на 1. Но можно указать шаг третьим числом.

Пример обратного отсчета:

for i = 10, 1, -1 do -- Считаем от 10 до 1 с шагом -1
    print(i)
    wait(1)
end
print("Пуск!")

Математически работу цикла можно описать как арифметическую прогрессию:

an=a1+(n−1)da_n = a_1 + (n-1)d

где ana_n — текущее значение счетчика, a1a_1 — начальное значение (старт), nn — номер шага, а dd — разность прогрессии (шаг цикла).

Практика: Создаем исчезающий мост

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

  1. Создайте деталь (Part) в Roblox Studio.
  2. Добавьте внутрь детали Script.
  3. Напишите следующий код:
local bridge = script.Parent -- Ссылка на саму деталь

-- Бесконечный цикл, так как true всегда правда
while true do
    -- 1. Делаем мост видимым и твердым
    bridge.Transparency = 0
    bridge.CanCollide = true
    print("Мост появился!")

    wait(3) -- Ждем 3 секунды

    -- 2. Делаем мост прозрачным и проходимым насквозь
    bridge.Transparency = 0.8 -- Почти невидимый
    bridge.CanCollide = false -- Игрок провалится
    print("Мост исчез!")

    wait(3) -- Ждем 3 секунды перед повторением
end

Разбор кода

  • while true do: Мы создали бесконечный цикл. Игра будет выполнять этот код вечно, пока сервер работает.
  • script.Parent: Это удобный способ обратиться к объекту, внутри которого лежит скрипт. Если вы переименуете деталь, скрипт не сломается.
  • CanCollide: Это свойство детали, отвечающее за физику. Если оно false, сквозь деталь можно пройти.

Оператор break

Иногда нам нужно экстренно остановить цикл, даже если условие всё еще верно. Для этого используется команда break.

Пример: Ищем число 7 в списке случайных чисел.

for i = 1, 100 do
    if i == 7 then
        print("Мы нашли счастливое число!")
        break -- Прерываем цикл, дальше считать нет смысла
    end
    print(i)
end

Заключение

Сегодня вы получили мощные инструменты управления логикой игры. Теперь ваши скрипты могут:

  1. Принимать решения с помощью if и else.
  2. Проверять сложные условия с помощью and и or.
  3. Повторять действия и создавать таймеры с помощью циклов while и for.

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

Попробуйте поэкспериментировать с домашним заданием: создайте деталь, которая меняет цвет каждую секунду, используя цикл и список цветов!

Работа с игровыми объектами, свойствами и событиями

Работа с игровыми объектами, свойствами и событиями

Добро пожаловать в четвертую часть курса «Основы программирования на Lua для Roblox»! В предыдущих статьях мы проделали большую работу: изучили переменные, научились писать функции и освоили управление потоком с помощью условий и циклов. Наши скрипты уже умеют «думать» и считать, но они всё еще немного изолированы от самого игрового мира.

Сегодня мы вдохнем жизнь в наши творения. Мы научимся не просто менять цвет детали один раз при запуске, а реагировать на действия игрока. Представьте дверь, которая открывается при нажатии кнопки, или пол, который наносит урон, если на него наступить. Всё это возможно благодаря событиям.

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

Иерархия объектов: Семейное древо игры

Roblox Studio организует все объекты в структуру, напоминающую дерево. Вы уже видели окно Explorer (Обозреватель), где папки вложены друг в друга. В программировании это называется иерархией «Родитель-Потомок» (Parent-Child).

Родственные связи

  • Parent (Родитель): Объект, внутри которого находится наш текущий объект. Например, если скрипт лежит внутри детали, то деталь — это Parent скрипта.
  • Children (Дети): Объекты, которые лежат внутри текущего объекта.

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

local myPart = script.Parent

Здесь script — это ключевое слово, обозначающее сам файл с кодом, в котором мы пишем. А .Parent — это ссылка на объект, в который этот скрипт вложен. Это позволяет делать скрипты универсальными: вы можете написать скрипт для лампочки, скопировать его в 100 других лампочек, и каждая будет знать, что управлять нужно именно своим светом.

Свойства: Физика и Геометрия

Мы уже меняли цвет (Color) и прозрачность (Transparency). Но для создания полноценного геймплея нам нужны физические свойства.

Anchored (Якорь)

Это свойство типа Boolean (true/false).

  • Если Anchored = true, деталь застывает в пространстве. Гравитация и толчки других игроков на неё не действуют.
  • Если Anchored = false, деталь подчиняется физике: падает, катится и её можно толкать.

CanCollide (Коллизия)

Определяет, является ли объект твердым.

  • true: Сквозь объект нельзя пройти.
  • false: Объект призрачный, сквозь него можно проходить.

Position (Позиция)

Это свойство определяет, где находится объект в 3D-мире. Для описания позиции используется тип данных Vector3.

Вектор в 3D-пространстве состоит из трех координат: XX, YY и ZZ.

P=(x,y,z)P = (x, y, z)

Где PP — это точка в пространстве, xx — координата по горизонтали (влево-вправо), yy — по вертикали (вверх-вниз), zz — глубина (вперед-назад).

Чтобы переместить деталь в коде, мы создаем новый Vector3:

script.Parent.Position = Vector3.new(0, 50, 0)

Если мы хотим сдвинуть деталь относительно её текущего положения, мы используем сложение векторов:

Pnew=Pold+VmoveP_{new} = P_{old} + V_{move}

Где PnewP_{new} — новая позиция, PoldP_{old} — старая позиция, а VmoveV_{move} — вектор смещения.

В коде это выглядит так:

local part = script.Parent
-- Поднять деталь на 5 студ (единиц измерения Roblox) вверх
part.Position = part.Position + Vector3.new(0, 5, 0)

События: Реакция на мир

До этого момента наш код выполнялся линейно: строка за строкой. Но в игре мы не знаем, когда игрок нажмет кнопку или коснется лавы. Мы не можем использовать wait(), потому что не знаем, сколько ждать.

Здесь на сцену выходят События (Events). Событие — это сигнал, который объект посылает, когда с ним что-то происходит.

Самые популярные события:

  • Touched: Срабатывает, когда чего-то касается детали.
  • Changed: Срабатывает, когда меняется свойство объекта.
  • PlayerAdded: Срабатывает, когда новый игрок заходит на сервер.

Связь события и функции

Чтобы код среагировал на событие, нам нужно «подключить» (Connect) к нему функцию. Это похоже на подписку на уведомления.

Синтаксис выглядит так:

Obiekt.Sobytie:Connect(ImyaFunkcii)

Обратите внимание на двоеточие : перед Connect. Это специальный синтаксис методов в Lua.

Практика 1: Создание «Убивающей плиты» (Kill Brick)

Классический элемент любого Obby (полосы препятствий) — красная деталь, которая убивает игрока при касании. Давайте создадим её, используя событие Touched.

  1. Создайте деталь, покрасьте её в красный цвет и назовите Trap (Ловушка).
  2. Поставьте галочку Anchored, чтобы она не упадала.
  3. Вставьте внутрь детали Script.

Напишем код:

local trap = script.Parent

-- Эта функция запустится, когда кто-то коснется ловушки
local function onTouch(otherPart)
    print("Что-то коснулось ловушки: " .. otherPart.Name)
end

-- Подключаем функцию к событию
trap.Touched:Connect(onTouch)

Если вы запустите игру и коснетесь детали, в консоли (Output) появится много сообщений: «Что-то коснулось ловушки: LeftFoot», «... RightFoot» и т.д.

Аргумент otherPart

Когда срабатывает событие Touched, Roblox автоматически передает в нашу функцию информацию о том, что именно коснулось детали. В нашем примере мы назвали эту переменную otherPart.

Если персонаж наступает на ловушку, otherPart будет ногой персонажа (например, "LeftLeg"). Но сама нога не имеет здоровья. Здоровье (Health) находится в специальном объекте Humanoid, который лежит внутри модели персонажа.

Иерархия персонажа выглядит так:

  • Character (Модель персонажа)
    • Head (Голова)
    • LeftLeg (Нога - это otherPart)
    • Humanoid (Объект, хранящий здоровье)

Значит, чтобы убить игрока, нам нужно:

  1. Узнать, что коснулось ловушки (otherPart).
  2. Найти родителя этой части (otherPart.Parent), то есть модель персонажа.
  3. Поискать внутри модели объект Humanoid.
  4. Если Humanoid найден, сделать здоровье равным 0.

Обновленный код:

local trap = script.Parent

local function killPlayer(otherPart)
    -- 1. Ищем родителя детали (предполагаемого персонажа)
    local character = otherPart.Parent

    -- 2. Ищем внутри персонажа объект Humanoid
    -- FindFirstChild - безопасный способ поиска. Если не найдет, вернет nil.
    local humanoid = character:FindFirstChild("Humanoid")

    -- 3. Проверяем, нашли ли мы гуманоида
    if humanoid then
        humanoid.Health = 0
    end
end

trap.Touched:Connect(killPlayer)

Формула изменения здоровья здесь проста:

Hnew=0H_{new} = 0

Где HnewH_{new} — новое значение здоровья. Если бы мы хотели просто нанести урон, формула была бы такой:

Hnew=Hcurrent−DH_{new} = H_{current} - D

Где HcurrentH_{current} — текущее здоровье, а DD — урон (Damage).

Практика 2: Интерактивная кнопка

Теперь сделаем что-то более позитивное. Кнопку, которая при нажатии включает свет.

  1. Создайте деталь, назовите её Button.
  2. В окне Explorer наведите на деталь, нажмите + и найдите объект ClickDetector. Этот объект позволяет игроку кликать мышкой по детали.
  3. Также добавьте внутрь детали Script.

Код для кнопки:

local button = script.Parent
local clickDetector = button.ClickDetector
local isOn = false -- Переменная для запоминания состояния (включено/выключено)

local function onClick()
    if isOn == false then
        -- Включаем
        button.Color = Color3.fromRGB(0, 255, 0) -- Зеленый
        isOn = true
    else
        -- Выключаем
        button.Color = Color3.fromRGB(255, 0, 0) -- Красный
        isOn = false
    end
end

-- Событие MouseClick принадлежит объекту ClickDetector, а не самой детали
clickDetector.MouseClick:Connect(onClick)

Здесь мы использовали логику переключателя. Переменная isOn хранит состояние. Каждый клик мы меняем состояние на противоположное.

Методы поиска объектов

В примере с ловушкой мы использовали метод :FindFirstChild("Name"). Это очень важный инструмент.

Почему нельзя просто написать character.Humanoid? Потому что, если ловушки коснется обычный мячик или упавшее дерево, у них не будет внутри Humanoid. Попытка обратиться к несуществующему объекту вызовет ошибку, и скрипт сломается.

:FindFirstChild() работает мягче: он ищет объект. Если находит — отдает его нам. Если нет — возвращает nil (пустоту), и мы можем обработать это через условие if.

Еще один полезный метод — :WaitForChild("Name"). Он используется, когда игра только загружается, и некоторые объекты могут еще не успеть появиться. Скрипт «заснет» и будет ждать, пока объект не появится.

Заключение

Сегодня вы перешли важный рубеж. Вы научились работать с событиями — сердцем интерактивности в Roblox. Теперь ваши скрипты не работают сами по себе, а реагируют на мир вокруг.

Мы разобрали:

  1. Иерархию: Как обращаться к родителям и детям (script.Parent).
  2. Свойства: Как работает физика (Anchored, CanCollide) и позиция (Vector3).
  3. События: Как использовать Touched и ClickDetector для запуска функций.
  4. Безопасный поиск: Зачем нужен FindFirstChild.

В следующей статье мы займемся созданием пользовательского интерфейса (GUI). Мы научимся делать кнопки на экране, полоски здоровья и магазины, с которыми игрок сможет взаимодействовать напрямую через экран, а не через 3D-мир. До встречи!

Создание пользовательского интерфейса (GUI) и сохранение данных

Создание пользовательского интерфейса (GUI) и сохранение данных

Приветствуем в пятой части курса «Основы программирования на Lua для Roblox»! Мы уже прошли большой путь: от установки студии до создания интерактивных объектов, реагирующих на касания. Но пока что наши игры выглядят немного «пустыми». Игроку не видно, сколько у него здоровья, сколько монет он собрал, и нет кнопок меню.

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

Что такое GUI?

GUI (Graphical User Interface) — это графический интерфейс пользователя. Это всё, что находится «поверх» 3D-мира: кнопки, полоски здоровья, инвентарь, чат и меню магазина.

В Roblox Studio за интерфейс отвечает специальная папка StarterGui. Всё, что вы положите в эту папку, автоматически копируется на экран каждому игроку, когда он заходит в игру.

Основные элементы GUI

Чтобы создать свой первый интерфейс:

  1. Найдите в окне Explorer папку StarterGui.
  2. Нажмите + и добавьте ScreenGui. Это прозрачный «холст», на котором мы будем рисовать.
  3. Внутри ScreenGui добавьте TextButton (кнопку) или TextLabel (просто текст).

Позиционирование и UDim2

Новички часто путаются в том, как задавать размеры и позицию кнопок. В отличие от 3D-мира, где мы используем Vector3 (X, Y, Z), в 2D-интерфейсе используется UDim2.

UDim2 состоит из четырех чисел. Давайте представим это в виде формулы координат:

P={Sx,Ox,Sy,Oy}P = \{S_x, O_x, S_y, O_y\}

Где:

  • PP — итоговая позиция или размер элемента.
  • SxS_x (Scale X) — масштаб по горизонтали. Это проценты от ширины экрана (от 0 до 1). 0.5 — это середина экрана.
  • OxO_x (Offset X) — смещение по горизонтали в пикселях. Точное значение, не зависящее от размера экрана.
  • SyS_y (Scale Y) — масштаб по вертикали (от 0 до 1).
  • OyO_y (Offset Y) — смещение по вертикали в пикселях.

Если вы хотите, чтобы кнопка всегда была в центре экрана на любом устройстве (телефоне или компьютере), используйте Scale, а не Offset.

Пример создания UDim2 в коде:

-- Позиция: 50% по ширине, 0 пикселей сдвиг, 50% по высоте, 0 пикселей сдвиг
button.Position = UDim2.new(0.5, 0, 0.5, 0)

LocalScript: Код для игрока

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

Для управления GUI мы используем LocalScript.

Главное правило:

  • Script (Сервер): Управляет физикой, сохранением данных, сменой дня и ночи.
  • LocalScript (Клиент): Управляет нажатием кнопок интерфейса, камерой игрока и вводом с клавиатуры.

Давайте оживим кнопку. Создайте LocalScript внутри вашей TextButton и напишите:

local button = script.Parent

-- Функция, которая сработает при клике
local function onButtonClick()
    print("Кнопка нажата!")
    button.Text = "Спасибо!"
    wait(1)
    button.Text = "Нажми меня"
end

-- MouseButton1Click — событие клика левой кнопкой мыши
button.MouseButton1Click:Connect(onButtonClick)

RemoteEvents: Мост между Клиентом и Сервером

Здесь мы сталкиваемся с проблемой безопасности. Если мы напишем в LocalScript код game.Players.LocalPlayer.Leaderstats.Money.Value = 1000000, деньги появятся только на экране у читера. Сервер об этом не узнает, и купить ничего не получится. Это называется FilteringEnabled.

Чтобы игрок мог реально что-то сделать (например, купить предмет), LocalScript должен «попросить» сервер об этом. Для этого используются RemoteEvent (Удаленные события).

Как настроить связь:

  1. В папке ReplicatedStorage (хранилище, доступное всем) создайте RemoteEvent и назовите его GiveMoneyEvent.
  2. В LocalScript (Кнопка):
    local event = game.ReplicatedStorage:WaitForChild("GiveMoneyEvent")
    local button = script.Parent
    
    button.MouseButton1Click:Connect(function()
        -- Отправляем сигнал на сервер: "Я нажал кнопку!"
        event:FireServer()
    end)
    
  3. В Script (ServerScriptService):
    local event = game.ReplicatedStorage:WaitForChild("GiveMoneyEvent")
    
    -- Сервер слушает сигнал
    event.OnServerEvent:Connect(function(player)
        -- Сервер точно знает, КТО нажал кнопку (переменная player)
        print(player.Name .. " хочет денег!")
        -- Тут мы можем добавить деньги (об этом ниже)
    end)
    

Leaderstats: Система статистики

Прежде чем сохранять данные, их нужно где-то хранить во время игры. В Roblox есть стандартная система leaderstats. Если создать папку с таким именем внутри игрока, Roblox автоматически покажет таблицу лидеров в правом верхнем углу экрана.

Создайте Script в ServerScriptService для настройки статистики:

game.Players.PlayerAdded:Connect(function(player)
    -- 1. Создаем папку leaderstats
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    -- 2. Создаем валюту (Gold)
    local gold = Instance.new("IntValue") -- IntValue хранит целые числа
    gold.Name = "Gold"
    gold.Value = 0
    gold.Parent = leaderstats
end)

Теперь, если вы запустите игру, вы увидите свое имя и колонку «Gold» со значением 0.

DataStores: Сохранение прогресса

Самая важная часть для удержания игроков — сохранение их достижений. Для этого используется сервис DataStoreService.

Представьте DataStore как огромный шкаф с ячейками в банке. У каждой ячейки есть уникальный номер (Ключ), и внутри лежат данные (Значение).

Формула доступа к данным выглядит так:

D=f(K)D = f(K)

Где:

  • DD — данные, которые мы получаем (например, количество золота).
  • ff — функция получения данных (GetAsync).
  • KK — уникальный ключ. Обычно это ID игрока (Player.UserId), так как никнейм можно сменить, а ID остается навсегда.

Скрипт сохранения и загрузки

Давайте модифицируем наш серверный скрипт, добавив туда сохранение.

local DataStoreService = game:GetService("DataStoreService")
local myGoldStore = DataStoreService:GetDataStore("PlayerGoldData_v1")

-- 1. Загрузка данных при входе
game.Players.PlayerAdded:Connect(function(player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local gold = Instance.new("IntValue")
    gold.Name = "Gold"
    gold.Parent = leaderstats

    -- Пробуем получить данные из облака
    local success, savedGold = pcall(function()
        return myGoldStore:GetAsync(player.UserId)
    end)

    if success and savedGold then
        gold.Value = savedGold -- Если данные есть, загружаем их
        print("Данные загружены!")
    else
        gold.Value = 0 -- Если данных нет (новичок), даем 0
        print("Новый игрок или ошибка загрузки.")
    end
end)

-- 2. Сохранение данных при выходе
game.Players.PlayerRemoving:Connect(function(player)
    local success, errorMessage = pcall(function()
        -- Сохраняем текущее значение золота по ключу (ID игрока)
        myGoldStore:SetAsync(player.UserId, player.leaderstats.Gold.Value)
    end)

    if success then
        print("Данные сохранены!")
    else
        print("Ошибка сохранения: " .. errorMessage)
    end
end)

Разбор важных моментов:

  1. pcall (Protected Call): Работа с интернетом (облаком) может дать сбой. pcall — это защитная обертка. Если сохранение не удастся (например, сервера Roblox перегружены), скрипт не сломается, а просто вернет false в переменную success.
  2. SetAsync: Функция для записи данных («Положить в ячейку»).
  3. GetAsync: Функция для чтения данных («Взять из ячейки»).
  4. UserId: Мы используем уникальный номер игрока как ключ к его ячейке.

Заключение

Поздравляем! Вы создали полноценный цикл игры. Теперь у вас есть:

  1. Интерфейс, с которым игрок взаимодействует.
  2. Связь, передающая команды от интерфейса к серверу.
  3. Память, сохраняющая прогресс между сессиями.

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