Lua для Roblox: основы скриптинга и создание игровых механик

Курс знакомит с языком Lua в контексте Roblox Studio и учит писать скрипты для игровых объектов, интерфейса и простых систем. На практике вы освоите ключевые сервисы Roblox, события, работу с данными и базовые принципы архитектуры кода.

1. Roblox Studio и основы Lua: переменные, таблицы, функции

Roblox Studio и основы Lua: переменные, таблицы, функции

Зачем это нужно в Roblox

Roblox-игры строятся из объектов (деталей, моделей, интерфейсов) и логики поведения. Логику вы пишете на Luau (диалект Lua, используемый в Roblox). В этой статье вы:

  • настроите базовую рабочую среду в Roblox Studio;
  • поймёте, где живут скрипты и как их запускать;
  • разберёте три опоры языка: переменные, таблицы, функции;
  • напишете первые небольшие фрагменты кода, которые реально работают в игре.
  • Официальная документация:

  • Roblox Studio
  • Luau (язык Roblox)
  • Scripts (виды скриптов)
  • Быстрый старт в Roblox Studio

    Где писать и запускать код

    В Roblox Studio чаще всего используют два инструмента:

  • Explorer: дерево объектов (Workspace, Players, ReplicatedStorage и т.д.).
  • Properties: свойства выбранного объекта.
  • Чтобы увидеть их:

  • Откройте вкладку View.
  • Включите Explorer и Properties.
  • Для экспериментов в начале курса удобнее всего:

  • Output (вкладка View): показывает сообщения print() и ошибки.
  • Command Bar (вкладка View): выполняет код один раз (для быстрых проверок).
  • !Расположение ключевых окон, чтобы легко следовать примерам

    Виды скриптов и где они работают

    В Roblox логика делится на серверную и клиентскую. Это критично: сервер авторитетный (доверяемый), клиент (игрок) — нет.

    Таблица ниже — минимальная ориентация, достаточная для старта:

    | Тип | Как создать | Где работает | Типичное место | |---|---|---|---| | Script | Insert Object → Script | Сервер | ServerScriptService, Workspace | | LocalScript | Insert Object → LocalScript | Клиент | StarterPlayerScripts, StarterGui | | ModuleScript | Insert Object → ModuleScript | Там, где его require() | ReplicatedStorage, ServerScriptService |

    На первых шагах:

  • используйте Script в ServerScriptService, чтобы код стабильно запускался на сервере;
  • используйте print() и окно Output, чтобы видеть результат.
  • Переменные в Luau

    Переменная — это имя, под которым хранится значение. В Luau переменные объявляются через local.

    local и глобальные переменные

    Правило на курс:

  • почти всегда пишите local;
  • глобальные переменные (без local) в Roblox-проектах легко приводят к конфликтам и трудно отлаживаются.
  • Пример:

    Основные типы значений

    Luau умеет автоматически понимать тип значения. Вам важно уверенно различать базовые типы:

    | Тип | Пример | Комментарий | |---|---|---| | number | local speed = 16 | Числа (целые и дробные) | | string | local name = "Alex" | Текст в кавычках | | boolean | local isAlive = true | true или false | | nil | local x = nil | «Ничего», часто означает «не задано» | | function | local f = function() end | Функция как значение | | table | local t = {} | Таблица (ключи и значения) |

    Проверить тип можно через typeof() (часто полезно в Roblox):

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

  • Путаница = и ==:
  • - = — присваивание. - == — сравнение.
  • Попытка использовать переменную, которая равна nil.
  • Пример сравнения:

    Таблицы: главный контейнер данных

    В Luau таблица — это универсальная структура данных: список, словарь, объект-конфигурация — всё в одном.

    Таблица как список (массив)

    Список хранит значения по порядку, обычно с числовыми индексами, начиная с 1.

    Чтобы пройтись циклом:

  • ipairs() удобно для «плотных» списков без пропусков.
  • #fruits возвращает длину, но корректнее всего работает, когда элементы идут подряд.
  • Таблица как словарь (ключ → значение)

    Словарь хранит значения по именованным ключам.

    Чтобы пройтись по всем парам ключ-значение:

  • pairs() подходит и для словарей, и для смешанных таблиц.
  • Порядок обхода в pairs() не гарантирован.
  • Вложенные таблицы

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

    Изменение таблиц

    Добавление и удаление:

    В словаре удаление делают через присваивание nil:

    > Таблица в Luau передаётся по ссылке: если вы присвоили одну и ту же таблицу двум переменным, изменения будут видны через обе переменные.

    Пример:

    Функции: переиспользуемая логика

    Функция — это именованный (или безымянный) блок кода, который можно вызывать много раз.

    Объявление и вызов

    Здесь:

  • playerName — параметр (вход функции);
  • .. — склеивание строк;
  • sayHello("Alex") — вызов.
  • return: возвращаем результат

    Несколько возвращаемых значений

    В Luau функция может вернуть несколько значений:

    Функции как значения

    Функцию можно положить в переменную или в таблицу.

    Это полезно для систем команд, обработчиков событий и таблиц настроек.

    Мини-практика в Roblox: скрипт, который меняет объект

    Сделаем простое действие: изменим цвет детали при запуске сервера.

  • В Workspace создайте Part.
  • Переименуйте его в ColorPart.
  • В ServerScriptService создайте Script.
  • Вставьте код:
  • Что здесь важно:

  • workspace:WaitForChild("ColorPart") ждёт объект, если он ещё не доступен.
  • paintRed — функция, которая принимает объект и меняет его свойство.
  • Color3.fromRGB(r, g, b) создаёт цвет из трёх чисел.
  • Как это связано с игровыми механиками

    Игровая механика почти всегда состоит из трёх частей:

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

    2. Объекты и иерархия Roblox: Workspace, Instances, свойства

    Объекты и иерархия Roblox: Workspace, Instances, свойства

    Почему иерархия объектов важна для скриптинга

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

    Любая игра в Roblox — это дерево объектов. Скрипт почти всегда делает одно из двух:

  • находит объект в иерархии и читает или меняет его свойства;
  • создаёт новые объекты, вставляет их в иерархию и настраивает.
  • Чтобы уверенно писать механики, нужно понимать три вещи:

  • что такое Instance (любой объект Roblox);
  • как устроено дерево объектов в Explorer;
  • что такое свойства (Properties) и как их менять из Luau.
  • Документация Roblox:

  • Скриптинг в Roblox
  • Workspace
  • Instance
  • Model
  • BasePart
  • DataModel и Explorer: дерево объектов игры

    Когда вы открываете Explorer в Roblox Studio, вы видите корневой объект игры, который обычно называют DataModel (по сути, «вся игра»). Внутри — сервисы и объекты.

    !Упрощённая схема, где обычно живут объекты и скрипты

    Сервисы как «папки со смыслом»

    Многие верхнеуровневые элементы в Explorer — это сервисы. Их можно воспринимать как специальные контейнеры, у которых есть назначение.

    Ниже — базовая карта, достаточная для старта курса:

    | Сервис | Для чего обычно используют | Где работает логика | |---|---|---| | Workspace | Всё, что находится в 3D-мире: детали, модели, NPC | Сервер и клиент видят (с нюансами репликации) | | ServerScriptService | Серверные Script, игровые правила | Сервер | | ReplicatedStorage | Общие ресурсы: ModuleScript, шаблоны объектов | Сервер и клиент | | ServerStorage | Серверные ресурсы, невидимые клиенту | Сервер | | StarterGui | Шаблоны интерфейса, копируются игроку при спавне | Клиент | | StarterPlayer | Настройки игрока и скрипты игрока | Клиент (StarterPlayerScripts, StarterCharacterScripts) | | Players | Игроки в запущенной игре (появляются при Play) | Сервер и клиент |

    > Практическое правило: если вы не уверены, куда положить первый серверный код, кладите Script в ServerScriptService.

    Workspace: что это и как с ним работать

    Workspace — место, где живут объекты 3D-мира: платформы, стены, интерактивные детали, модели.

    Чаще всего ваши первые механики выглядят так:

  • найти объект в Workspace по имени;
  • изменить его свойства;
  • создать новый объект и поместить его в Workspace.
  • Parts, Models и что такое «объект»

    В Roblox почти всё — это Instance.

  • Part — простая «деталь» в мире.
  • Model — контейнер, который объединяет несколько деталей в одну сущность.
  • Script / LocalScript / ModuleScript — тоже объекты, просто другого типа.
  • Важно: объект определяется не тем, где он лежит, а тем, какого он класса (ClassName) и какие свойства имеет.

    Instance: базовая модель объектов Roblox

    Instance — базовый класс для объектов. У любого объекта есть общие вещи:

  • Name: имя объекта в дереве.
  • Parent: ссылка на «родителя» (контейнер), в котором объект лежит.
  • GetChildren(): список дочерних объектов.
  • Родитель и ребёнок: как устроен путь к объекту

    Если объект лежит внутри другого объекта, говорят, что он дочерний.

    Пример структуры:

  • Workspace
  • Model House
  • Part Door
  • Тогда:

  • Door.Parent — это House
  • House.Parent — это workspace
  • В коде к объектам часто обращаются через «путь»:

    Это работает, только если:

  • объект действительно существует;
  • имя совпадает;
  • объект уже успел загрузиться/появиться.
  • Безопасный поиск: FindFirstChild и WaitForChild

    В реальных проектах объекты могут появляться не мгновенно (особенно у игроков и UI). Поэтому Roblox даёт два важных метода.

    FindFirstChild(name):

  • возвращает объект, если он уже есть;
  • иначе возвращает nil.
  • WaitForChild(name):

  • ждёт, пока объект появится;
  • возвращает найденный объект.
  • Пример (серверный Script в ServerScriptService):

    Практическое правило:

  • используйте WaitForChild, когда объект обязан существовать;
  • используйте FindFirstChild, когда объект может отсутствовать и это нормально.
  • GetService: правильный доступ к сервисам

    Сервисы принято получать через game:GetService():

    Почему так лучше:

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

    У объектов есть свойства: значения, которые настраивают поведение и внешний вид.

    В Studio вы видите их во вкладке Properties, а в коде — читаете и меняете через точку.

    Чтение и запись свойств

    Пример: у Part есть свойства Anchored, Position, Color, Size.

    Важно понимать:

  • тип свойства должен совпадать с ожидаемым типом;
  • если свойство ждёт Color3, нельзя присвоить строку.
  • Частые типы свойств в Roblox

    Ниже — несколько типов, которые вы будете видеть постоянно:

    | Тип | Пример свойства | Пример значения | |---|---|---| | boolean | Anchored | true / false | | number | Transparency | 0, 0.5, 1 | | string | Name | "Door" | | Color3 | Color | Color3.fromRGB(255, 0, 0) | | Vector3 | Position, Size | Vector3.new(0, 10, 0) | | CFrame | CFrame | CFrame.new(0, 5, 0) |

    Если вы сомневаетесь, какой тип у значения, используйте typeof():

    Создание объектов через Luau: Instance.new

    Один из ключевых навыков — создавать объекты кодом.

    Пример: создаём платформу и кладём в Workspace

    Серверный Script в ServerScriptService:

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

  • Instance.new("Part") создаёт объект класса Part в памяти;
  • свойства настраиваются до вставки в мир;
  • platform.Parent = workspace добавляет объект в дерево, и он появляется в мире.
  • Практическое правило:

  • сначала настройте свойства,
  • потом задайте Parent.
  • Так вы избегаете ситуации, когда объект на долю секунды появляется с настройками по умолчанию.

    Parent как «операция вставки в дерево»

    Parent — это не просто поле, а важная часть логики.

  • если Parent = nil, объект существует, но не находится в дереве (его не видно в Explorer);
  • если назначить Parent, объект «вставится» в указанное место;
  • если сменить Parent, объект переместится в другое место дерева.
  • Практика структуры: Model как контейнер

    Model удобен, когда один игровой объект состоит из нескольких деталей.

    Пример: создадим модель из двух деталей.

    Что полезно запомнить:

  • Model помогает держать порядок в Workspace;
  • дочерние части модели можно находить как model.Left и model.Right, если имена уникальны.
  • Имена объектов и стабильные ссылки

    Новички часто упираются в проблему: скрипт не находит объект.

    Почему workspace.Part иногда не работает

    Причины обычно такие:

  • объект называется не так, как вы думаете (ошибка в Name);
  • объект лежит не там, где вы обращаетесь;
  • объект появляется позже (например, персонаж игрока).
  • Поэтому в учебных механиках курса придерживайтесь дисциплины:

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

    Почти любая механика, которую вы будете делать дальше, сводится к комбинации:

  • иерархия: где лежит объект и как его найти;
  • свойства: что менять, чтобы получить эффект;
  • Lua-логика: переменные, таблицы и функции из прошлой статьи.
  • Далее вы сможете строить взаимодействия, где скрипт:

  • ждёт нужный объект;
  • читает/меняет его свойства;
  • создаёт новые Instance по ситуации;
  • организует объекты в Workspace и сервисах так, чтобы проект оставался чистым и расширяемым.
  • 3. События и взаимодействие: клики, касания, RemoteEvents

    События и взаимодействие: клики, касания, RemoteEvents

    Как это связано с предыдущими темами

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

    В Roblox взаимодействие почти всегда строится вокруг событий:

  • игрок кликнул по объекту
  • персонаж коснулся детали
  • клиент (LocalScript) отправил запрос серверу (Script) через RemoteEvent
  • Документация Roblox:

  • События (Events)
  • ClickDetector
  • BasePart.Touched
  • RemoteEvent
  • Что такое событие в Roblox

    Событие — это сигнал, который выстреливает, когда что-то произошло. В коде вы подписываетесь на событие, чтобы выполнить функцию.

    Типичный шаблон:

    Здесь важно:

  • Touched — событие (в Roblox оно имеет тип RBXScriptSignal)
  • :Connect(function(...) ... end) — подписка на событие
  • функция внутри Connectобработчик события (то, что выполнится при срабатывании)
  • Connect возвращает подключение

    Connect возвращает объект-подключение. Его можно отключить, чтобы перестать слушать событие.

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

    Почему нужны задержки и защита от повторов

    Многие события могут срабатывать много раз подряд.

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

    Касания: BasePart.Touched

    Touched — одно из самых популярных событий для механик типа ловушки, кнопки-платформы, чекпоинты, триггеры.

    Мини-механика: платформа, которая меняет цвет при касании игроком

    Подготовка в Studio:

  • В Workspace создайте Part и назовите его TouchPad
  • Установите Anchored = true, чтобы он не падал
  • В ServerScriptService создайте Script
  • Код:

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

  • hit — это деталь, которая коснулась TouchPad (например, нога персонажа)
  • hit.Parent часто является моделью персонажа
  • FindFirstChildOfClass("Humanoid") помогает понять, что это именно персонаж, а не случайный предмет
  • GetPlayerFromCharacter превращает персонажа в Player
  • debounce[player] не даёт одному игроку бесконечно спамить касание
  • Частые ошибки с Touched

  • Считать, что hit — это персонаж. На самом деле это обычно часть персонажа.
  • Забывать, что Touched может срабатывать много раз подряд.
  • Не проверять, что касание сделал именно игрок.
  • Клики по объектам в мире: ClickDetector.MouseClick

    Для кликов по 3D-объектам часто используют ClickDetector.

    Как настроить ClickDetector

  • В Workspace создайте Part и назовите ClickButton
  • Внутрь ClickButton вставьте объект ClickDetector
  • В свойствах ClickDetector можно настроить дистанцию клика через MaxActivationDistance
  • В ServerScriptService создайте Script
  • Пример: игрок кликает по кнопке — кнопка меняет размер

    Что важно запомнить:

  • обработчик MouseClick получает параметр player (кто кликнул)
  • ClickDetector удобен тем, что сразу даёт игрока, в отличие от Touched
  • даже для кликов полезно иметь защиту от спама (busy)
  • > Практическое правило: всё, что даёт награду, меняет валюту или влияет на баланс, делайте на сервере в Script.

    RemoteEvents: связь клиента и сервера

    Когда игрок нажимает кнопку интерфейса или клавишу, это чаще всего происходит на клиенте (в LocalScript). Но менять важное состояние игры должен сервер.

    Для этого используют RemoteEvent:

  • клиент вызывает RemoteEvent:FireServer(...)
  • сервер получает событие RemoteEvent.OnServerEvent
  • сервер при необходимости отвечает RemoteEvent:FireClient(player, ...) или :FireAllClients(...)
  • !Поток сообщений через RemoteEvent между клиентом и сервером

    Где хранить RemoteEvent

    Чаще всего RemoteEvent кладут в ReplicatedStorage, чтобы он был доступен и серверу, и клиенту.

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

    Подготовка в Studio:

  • В ReplicatedStorage создайте RemoteEvent с именем RewardEvent
  • В StarterGui создайте ScreenGui, внутри него TextButton с именем RewardButton
  • Внутрь RewardButton добавьте LocalScript
  • В ServerScriptService создайте Script
  • Код клиента (LocalScript внутри RewardButton):

    Код сервера (Script в ServerScriptService):

    Что здесь важно:

  • в OnServerEvent первый параметр всегда player, который вызвал FireServer
  • сервер не доверяет клиенту: клиент прислал строку "DailyReward", а сервер всё равно проверяет, что это допустимый тип
  • lastRewardTime — таблица-состояние (из прошлой статьи про таблицы), где ключ — UserId
  • Безопасность RemoteEvents

    RemoteEvent — это канал связи, но клиент потенциально может:

  • отправлять любые аргументы
  • отправлять события очень часто
  • пытаться вызвать «невозможные» действия
  • Минимальные правила:

  • проверяйте входные данные (тип, диапазон, допустимые значения)
  • делайте cooldown (как в примере)
  • на сервере проверяйте условия игры (например, действительно ли игрок рядом с кнопкой, действительно ли у него есть предмет)
  • Как выбирать подходящий инструмент

    | Сценарий | Что использовать | Где писать код | |---|---|---| | Игрок наступил на платформу | BasePart.Touched | Обычно сервер (Script) | | Игрок кликает по объекту в мире | ClickDetector.MouseClick | Обычно сервер (Script) | | Игрок нажал кнопку UI или клавишу и нужно действие на сервере | RemoteEvent | Клиент (LocalScript) + сервер (Script) |

    Итог

    Теперь у вас есть три базовых механизма взаимодействия:

  • Touched для физического контакта объектов
  • ClickDetector для кликов по 3D-объектам
  • RemoteEvent для связи клиента и сервера
  • Вместе с навыками из прошлых статей (поиск объектов, свойства, таблицы и функции) этого достаточно, чтобы собирать первые полноценные игровые механики: кнопки, триггеры, простые награды и реакцию мира на действия игрока.

    4. Игровые системы: спавн, инструменты, GUI, простая экономика

    Игровые системы: спавн, инструменты, GUI, простая экономика

    Что вы соберёте в этой статье

    В прошлых материалах вы научились писать базовый Luau-код, находить объекты в иерархии и реагировать на события (Touched, ClickDetector, RemoteEvent). Теперь соберём из этих кирпичиков игровые системы, которые встречаются почти в любом проекте:

  • спавн и респавн игрока в правильных местах
  • инструменты (Tool): предмет в руках, действие по кнопке
  • GUI: кнопки интерфейса и связь с сервером
  • простая экономика: монеты, награды, покупки
  • Ключевая идея статьи: клиент инициирует действие (ввод, GUI), сервер проверяет и применяет изменения (экономика, выдача предметов).

    Полезная официальная документация:

  • Players
  • SpawnLocation
  • Tool
  • RemoteEvent
  • StarterGui
  • !Как клиентские действия превращаются в серверные изменения

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

    Базовый спавн через SpawnLocation

    Самый простой (и часто достаточный) вариант спавна:

  • Добавьте в Workspace объект SpawnLocation.
  • Включите у него Enabled = true.
  • Разместите его там, где игрок должен появляться.
  • Если SpawnLocation несколько, Roblox обычно выбирает подходящую точку автоматически.

    Контрольный код: PlayerAdded и CharacterAdded

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

    Создайте Script в ServerScriptService:

    Что важно:

  • PlayerAdded срабатывает, когда игрок заходит.
  • CharacterAdded срабатывает при каждом спавне персонажа (включая респавн).
  • WaitForChild("Humanoid") безопаснее, чем character.Humanoid.
  • Респавн и события смерти

    Если вы делаете систему наград/штрафов за смерть или хотите логировать события, слушайте Humanoid.Died.

    Практическое правило: всё, что влияет на экономику и прогресс, обрабатывайте на сервере.

    Инструменты (Tool): предметы, которые можно экипировать

    Tool это объект, который Roblox умеет класть игроку в Backpack, показывать в хотбаре и «экипировать» в руках.

    Минимальная настройка Tool

    Чтобы сделать простой инструмент:

  • В StarterPack создайте Tool с именем CoinCollector.
  • Внутрь Tool добавьте Part с именем Handle.
  • Handle нужен многим Tool для корректного отображения и поведения.

    Tool.Activated: действие по клику

    Самый простой интерактив: когда игрок использует инструмент, происходит действие. Внутрь Tool добавьте Script (серверный) или LocalScript (клиентский). Для механик с наградой лучше инициировать запрос с клиента, но применять награду на сервере.

    Надёжная схема:

  • в Tool стоит LocalScript, который ловит Activated и вызывает RemoteEvent:FireServer()
  • на сервере Script проверяет условия и начисляет монеты
  • Подготовка:

  • В ReplicatedStorage создайте RemoteEvent с именем EconomyEvent.
  • Внутрь CoinCollector добавьте LocalScript.
  • LocalScript в Tool:

    Здесь cooldown это простой debounce на клиенте, чтобы не спамить запросами.

    > Клиентский cooldown полезен, но не считается защитой. Сервер всё равно обязан ограничивать частоту.

    GUI: кнопки интерфейса и связь с сервером

    GUI почти всегда живёт на клиенте, потому что:

  • кнопки нажимает игрок локально
  • интерфейс часто персональный
  • Но когда GUI запускает важное действие (покупка, награда), нужно отправить запрос серверу.

    Пример: кнопка «Получить 5 монет»

    Подготовка:

  • В StarterGui создайте ScreenGui.
  • Внутри создайте TextButton RewardButton.
  • Внутрь кнопки добавьте LocalScript.
  • LocalScript (кнопка):

    Важно:

  • GUI вызывает FireServer, но не меняет монеты напрямую.
  • сервер может ответить FireClient сообщением и обновить текст.
  • Простая экономика: монеты, награды, покупки

    Экономика это набор правил:

  • где хранится баланс
  • кто имеет право менять баланс
  • как выдавать награды и списывать стоимость
  • Главное правило: баланс хранится и изменяется на сервере.

    Leaderstats: быстрый способ показать монеты

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

    Скрипт в ServerScriptService:

    Теперь у каждого игрока появится счётчик Coins.

    Серверный обработчик EconomyEvent

    Дальше сделаем единую точку входа для запросов от Tool и GUI.

    Script в ServerScriptService:

    Почему это безопаснее, чем «просто прибавить монеты» на клиенте:

  • сервер не доверяет типам и диапазонам (typeof, лимиты)
  • сервер ограничивает частоту (canAct)
  • изменения происходят только на сервере
  • Покупка предмета: списать монеты и выдать Tool

    Сделаем покупку, которая выдаёт Tool из серверного хранилища.

    Подготовка:

  • В ServerStorage создайте папку ShopTools.
  • Положите туда Tool SpeedCoil (или любой ваш Tool).
  • В Workspace создайте Part с именем ShopButton.
  • Внутрь ShopButton вставьте ClickDetector.
  • Script в ServerScriptService:

    Ключевые моменты:

  • цена задана на сервере (PRICE)
  • монеты списываются только после успешной выдачи
  • Tool хранится в ServerStorage, чтобы игрок не мог подменить шаблон на клиенте
  • Рекомендуемая структура проекта для этих систем

    Когда механик становится больше, порядок в сервисах начинает экономить время.

    Минимальная практичная раскладка:

  • ServerScriptService
  • - SpawnController (логика спавна, события персонажа) - EconomyServer (обработка RemoteEvent, начисления) - ShopServer (покупки через клик в мире)
  • ReplicatedStorage
  • - EconomyEvent (RemoteEvent) - Modules (ModuleScript, если хотите выносить общую логику)
  • StarterGui
  • - ScreenGui (кнопки, отображение сообщений)
  • StarterPack
  • - Tool, которые выдаются всем при старте
  • ServerStorage
  • - шаблоны покупаемых Tool

    Практическое правило: если игрок не должен иметь прямой доступ к объекту до покупки, храните шаблон в ServerStorage.

    Итог: как эти системы складываются в механику

    Теперь вы можете строить базовый игровой цикл:

  • игрок появляется на карте (спавн)
  • получает стартовые инструменты (StarterPack) и может покупать новые (Shop)
  • за действия получает монеты (экономика)
  • управляет действиями через Tool и GUI (клиент), но результат фиксирует сервер
  • Это уже каркас для множества жанров: obby с чекпоинтами и наградами, симулятор с покупками, арена с лутом.

    5. Хранение данных и качество кода: DataStore, модули, отладка

    Хранение данных и качество кода: DataStore, модули, отладка

    Зачем это нужно после экономики и RemoteEvents

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

    В этой статье вы научитесь:

  • сохранять прогресс между сессиями через DataStore;
  • организовывать код через ModuleScript, чтобы проект не превращался в один огромный Script;
  • отлаживать проблемы быстрее: понимать, где сломалось и почему.
  • Полезные официальные ссылки:

  • Data stores
  • DataStoreService
  • DataStore
  • ModuleScript
  • Debugging in Studio
  • Developer Console
  • !Поток данных: от действий игрока до сохранения в DataStore

    DataStore: что это такое и какие есть правила

    DataStore — это облачное хранилище Roblox для сохранения данных между сессиями. Обычно туда кладут прогресс игрока: монеты, уровни, купленные предметы.

    Ключевые правила:

  • DataStore доступен только на сервереScript), клиенту доверять нельзя.
  • Сохраняйте данные реже, чем меняете их в игре (иначе упрётесь в лимиты запросов).
  • Всегда пишите код так, будто запрос может не сработать (ошибка сети, лимиты, временный сбой).
  • Базовые термины

  • DataStoreService — сервис, который выдаёт доступ к хранилищам.
  • DataStore — конкретное хранилище по имени (например, "PlayerData_v1").
  • Key — строковый ключ записи (обычно делается из UserId).
  • Value — значение записи (в Roblox DataStore обычно сохраняют таблицу с примитивами).
  • Пример ключа:

  • "player_123456789"
  • Почему так:

  • UserId стабилен и не меняется при смене ника.
  • префикс player_ помогает не путать ключи разных типов, если вы расширите схему.
  • Важно про тестирование в Studio

    Чтобы DataStore работал в Studio:

  • в настройках игры включают Studio Access to API Services;
  • многие команды тестируют DataStore надёжнее в опубликованной версии (и при запуске через обычный клиент).
  • Настройки находятся в Studio в параметрах проекта (Game Settings), но в разных версиях Studio расположение может отличаться.

    Практика: сохранение и загрузка монет из leaderstats

    Ниже минимальный, но практичный шаблон. Он делает три вещи:

  • при входе игрока загружает данные и выставляет Coins;
  • периодически автосохраняет, чтобы не потерять прогресс при вылете;
  • при выходе и при закрытии сервера сохраняет данные.
  • Подготовка

    Предполагаем, что у вас уже есть leaderstats и Coins как в статье про экономику.

    Создайте Script в ServerScriptService, например DataStoreServer.

    Код: загрузка, сохранение, автосейв

    Что здесь важно:

  • pcall(...) предотвращает падение скрипта из-за ошибки DataStore и даёт вам контролируемый warn.
  • dirty позволяет не спамить сохранениями при каждом +1 монете.
  • UpdateAsync удобен как более безопасный шаблон сохранения (вы обновляете запись через функцию).
  • Version и UpdatedAt помогают позже мигрировать схему данных и дебажить проблемы.
  • ModuleScript: как держать проект чистым

    Когда механик становится больше, один большой Script превращается в проблему:

  • сложно читать;
  • сложно переиспользовать;
  • сложно тестировать;
  • легко сломать случайным изменением.
  • ModuleScript решает это: вы выносите логику в отдельный модуль и подключаете через require.

    Где хранить модули

    Практичная стартовая схема:

  • ServerScriptService/Modules — серверные модули (хранилище, экономика, античит).
  • ReplicatedStorage/Modules — общие модули, которые нужны и серверу, и клиенту.
  • Правило безопасности:

  • если модуль содержит секреты, цены, логику проверки покупок, античит, работу с DataStore, держите его только на сервере.
  • Пример: модуль для работы с монетами

    Создайте ModuleScript в ServerScriptService/Modules с именем CoinsService.

    Теперь в серверных скриптах вы можете подключать модуль:

    Что вы выиграли:

  • проверка типов и правил начисления/списания теперь в одном месте;
  • покупка, награды, Tool-логика используют один и тот же код;
  • меньше риска, что в одном скрипте вы проверяете цену, а в другом забыли.
  • Отладка: как быстрее находить и исправлять ошибки

    Отладка в Roblox почти всегда начинается с ответа на два вопроса:

  • где выполняется код: сервер или клиент;
  • что именно равно nil или имеет неожиданный тип.
  • Базовые инструменты

  • print(...) показывает информацию в Output.
  • warn(...) выделяет сообщение как предупреждение.
  • error(...) останавливает выполнение текущего потока и показывает стек.
  • Developer Console помогает смотреть логи, сеть и информацию по клиенту и серверу.
  • Debugger в Studio позволяет ставить брейкпоинты и смотреть значения переменных.
  • Практические приёмы, которые реально экономят время

  • Печатайте путь объекта, если не уверены, что нашли правильный:
  • Проверяйте тип входных данных, особенно из RemoteEvent:
  • Если вы ожидаете, что объект обязан существовать, используйте WaitForChild, а не обращение через точку.
  • Частые причины багов в проектах с DataStore и RemoteEvents

    | Симптом | Частая причина | Что сделать | |---|---|---| | Данные не грузятся | API сервисы выключены или игра не опубликована | Проверьте настройки API и тест в опубликованной версии | | Монеты иногда откатываются | Сохранения конфликтуют или происходят слишком редко | Автосейв + один поток сохранения на игрока | | Ошибка attempt to index nil | Не дождались leaderstats или объекта в иерархии | WaitForChild, проверки FindFirstChild | | Экономику можно накрутить | Сервер доверяет данным клиента | Проверки на сервере, лимиты, cooldown |

    Итог

    Теперь у вас есть основа для проектов, которые не теряют прогресс и не разваливаются по мере роста:

  • DataStore сохраняет важные данные на сервере и переживает выход игрока.
  • Модули помогают разделить ответственность и переиспользовать код.
  • Отладка становится проще, когда вы проверяете контекст (сервер/клиент), типы и используете правильные инструменты Studio.
  • С таким фундаментом вы можете расширять экономику, добавлять инвентарь, прогрессию и покупки так, чтобы код оставался управляемым.