Справочник по Roblox


Назначение

Горячие клавиши, команды и форматы Roblox для ежедневной работы. Учебный маршрут: Studioпрактикум "обби"архитектура. Экономика: Внутриигровая экономика Roblox. Справочник API — эта статья.


Краткое пояснение


Справочные таблицы

Содержание справочника


1 — Roblox Lua и базовый класс Instance

1.1 Roblox Lua — среда выполнения

  • Версия Lua: 5.1, с рядом ограничений и расширений.
  • Запрещены стандартные библиотеки:
    • os.*, io.*, debug.*, package.*, loadstring
    • collectgarbage — ограничена (collectgarbage("count") разрешён, остальные вызовы — нет)
  • Добавлены глобальные таблицы/функции:
  game      -- корневой Instance
  workspace -- алиас game.Workspace
  script    -- ссылка на текущий скрипт (Script/LocalScript/ModuleScript)
  shared    -- устарело, не использовать
  settings  -- deprecated, заменено на game:GetService("StarterGui"):GetCore(...)
  • Глобальные сервисы (доступны через game:GetService("Имя")):
    Workspace, Players, ReplicatedStorage, ServerStorage, Lighting, StarterGui, StarterPlayer, TweenService, PathfindingService, DataStoreService, HttpService, MarketplaceService, UserInputService, RunService, Stats, LocalizationService, BadgeService, Chat, CollectionService, ContentProvider, Debris, InsertService, LogService, PhysicsService, SoundService, TestService и др.

  • Типы скриптов:

    Тип Выполняется на Доступ к Основное назначение
    Script Server game.ServerStorage, Workspace, Players, ReplicatedStorage (только чтение в ServerScriptService), DataStoreService Серверная логика, безопасные операции
    LocalScript Client PlayerGui, StarterGui, Players.LocalPlayer, ReplicatedFirst, ReplicatedStorage UI, ввод, рендер-эффекты, предварительная валидация
    ModuleScript Оба Только при require(). Может возвращать таблицу/функцию. Повторное использование кода, инкапсуляция
  • Модель потока выполнения:

    • Сервер создаёт и управляет основной иерархией game.
    • Клиент получает реплицированные объекты (всё, что в Workspace, ReplicatedStorage, Lighting, StarterGui и т.п.).
    • Изменения свойств Instance, помеченных как Replicated, автоматически синхронизируются сервер→клиент.
    • Обратная синхронизация (клиент→сервер) — только через RemoteEvent/RemoteFunction.

1.2 Instance — базовый класс всех объектов

Все объекты в Roblox — наследники Instance.
Нельзя создать Instance напрямую: Instance.new() вызывает ошибку. Используется Instance.new("Part") и т.п.


1.2.1 Свойства Instance
Имя Тип Доступ Описание
Name string RW Имя экземпляра (не уникальное, но влияет на :FindFirstChild() и .-доступ)
Parent Instance | nil RW Родительский объект. При nil — объект отсоединён (Destroy() удаляет поддерево)
ClassName string RO Имя класса (например, "Part"). Неизменяемо.
Archivable boolean RW Указывает, может ли объект быть сериализован (:Clone(), :GetAttribute(), сохранение в .rbxl). По умолчанию true, но для Player, Humanoid и др. — false.
AncestryChanged RBXScriptSignal RO Сигнал: (child: Instance, parent: Instance | nil). Вызывается при изменении Parent.
Changed RBXScriptSignal RO Сигнал: (propertyName: string). Срабатывает при изменении любого свойства (кроме Parent, Name, ClassName).

⚠️ Свойства Anchored, Position, CFrame, Size, Velocity и др. специфичны для наследников (например, BasePart).


1.2.2 Методы Instance
Метод Подпись Контекст Описание
:Clone() → Instance Both Возвращает глубокую копию объекта и всех потомков. Объекты с Archivable = false копируются как пустые заглушки (nilInstance.new("Folder")).
:Destroy() → void Both Удаляет объект и всех потомков. Вызывает AncestryChanged с parent = nil, затем освобождает память. Безопасен к повторным вызовам.
:FindFirstChild(name: string, recursive: boolean = false) → Instance | nil Both Поиск дочернего элемента по Name. Если recursive = true — рекурсивно. Не выдаёт ошибку, если не найдено.
:WaitForChild(name: string, timeout: number = ∞) → Instance Both Блокирует поток до появления дочернего объекта с указанным именем или таймаута (в секундах). При таймауте — ошибка.
:IsA(className: string) → boolean Both Проверяет, является ли объект экземпляром указанного класса (учитывает наследование). typeof(obj) для экземпляров почти всегда возвращает "Instance", а не имя класса — для проверки типа используйте :IsA().
:IsDescendantOf(ancestor: Instance) → boolean Both Проверяет, находится ли объект в поддереве ancestor.
:GetChildren() → {Instance} Both Возвращает таблицу непосредственных потомков (1 уровень вниз).
:GetDescendants() → {Instance} Both Возвращает всех потомков (рекурсивно, в порядке обхода "в глубину").
:GetFullName() → string Both Возвращает путь от корня, например "Workspace.Part.Script". Полезно для логирования.
:ClearAllChildren() → void Both Удаляет всех непосредственных потомков (:Destroy() для каждого).
:GetPropertyChangedSignal(property: string) → RBXScriptSignal Both Возвращает сигнал, который сработает при изменении указанного свойства. Сигнал: (). Позволяет отслеживать изменения без polling.
:GetAttribute(attributeName: string) → any Both Получает значение пользовательского атрибута (хранится в реплицированной таблице).
:SetAttribute(attributeName: string, value: any) → void Server Устанавливает пользовательский атрибут. Поддерживаемые типы: string, number, bool, Vector3, CFrame, UDim, UDim2, Ray, Faces, Axes, BrickColor, Color3, NumberSequence, ColorSequence, NumberRange, Rect, PhysicalProperties, ColorSequenceKeypoint, NumberSequenceKeypoint.
:GetAttributes() → {[string]: any} Both Возвращает копию таблицы всех атрибутов.
:GetTags() → {string} Both (требует CollectionService) Возвращает теги, назначенные через CollectionService:AddTag().
:IsA() — уже выше. Дополнительно: :IsAncestorOf(descendant: Instance) → boolean — зеркально :IsDescendantOf().

1.2.3 События Instance

События — это свойства типа RBXScriptSignal. Подключение:

local connection = instance.Changed:Connect(function(propertyName)
    print("Изменено:", propertyName)
end)
connection:Disconnect() -- отключить вручную
  • AncestryChanged: RBXScriptSignal(child: Instance, parent: Instance \| nil)
  • Changed: RBXScriptSignal(propertyName: string)

Важно: Changed не срабатывает при изменении Parent. Для Parent — только AncestryChanged.


1.3 Основные принципы работы с Instance

  • Родительская привязка (Parent):

    • Установка Parent до Name не влияет на доступ через workspace.PartName — поиск происходит после полной инициализации.
    • Установка Parent = nil не уничтожает объект, но делает его невидимым для :FindFirstChild(), :GetChildren() и рендерера.
    • Объект без Parent не реплицируется клиентам.
  • Репликация:

    • Только объекты в Workspace, ReplicatedStorage, Lighting, StarterGui (и их потомки) реплицируются клиентам.
    • Изменения CFrame, Velocity, Anchored, CanCollide, Transparency у Part реплицируются автоматически (сервер → клиент).
    • Свойства Value (StringValue, NumberValue и др.) реплицируются автоматически.
    • Изменения в ServerStorage, ServerScriptServiceне реплицируются.
  • Производительность:

    • :GetDescendants() — O(N), избегать в hot loop.
    • :FindFirstChild() без recursive = true — O(1) (хэш-таблица по имени).
    • :WaitForChild() с таймаутом — предпочтительнее polling.
    • Избегать game:GetService("Players") в LocalScript (лучше Players = game:GetService("Players") один раз в начале).

2 — Пространственные объекты и физика

Эта часть охватывает пространственную иерархию, геометрию, движение, взаимодействие и навигацию в Roblox.
Все объекты, участвующие в 3D-мире, наследуются от Instance, но ключевая иерархия строится от BasePart.


2.1 Иерархия BasePart

Instance
└── PVInstance
    └── BasePart
        ├── Part
        ├── MeshPart
        ├── TrussPart
        └── UnionOperation (не BasePart напрямую, но создаёт объект, являющийся BasePart)

PVInstance (Physical Volume Instance) — внутренний промежуточный класс, добавляющий базовые физические свойства (Position, Rotation, Velocity). Не документирован официально, но отражён в отладчике.


2.1.1 BasePart — общий интерфейс для физических объектов

Все BasePart участвуют в физике (если Anchored = false) и рендеринге.


Свойства BasePart
Свойство Тип Доступ Контекст Описание
Position Vector3 RW Replicated Позиция центра масс (в мировых координатах). Устанавливать можно, но предпочтительно — через CFrame.
CFrame CFrame RW Replicated Полная поза: позиция + ориентация. Основной способ управления положением и поворотом. Изменение CFrame перезаписывает Position и Rotation.
Size Vector3 RW (но не во время симуляции, если Anchored = false) Replicated Размер по осям X, Y, Z в стадиях (1 стадия = 1 метр). Минимум — 0.001, 0.001, 0.001.
Rotation Vector3 RO Replicated Эйлеровы углы (в градусах) относительно мировой системы координат. Вычисляется из CFrame. Изменять напрямую нельзя — только через CFrame.
Anchored boolean RW Replicated Если true — объект игнорирует гравитацию и физику, остаётся неподвижным. По умолчанию false.
Velocity Vector3 RW Replicated Линейная скорость центра масс (стадий/сек). Изменяется физикой или вручную.
RotVelocity Vector3 RW Replicated Угловая скорость (рад/сек) вокруг осей X, Y, Z в локальной системе.
Mass number RO Replicated Вычисляется как Density × Volume. Зависит от Size и Material.
Density number RW Both Плотность (кг/стадия³). По умолчанию: Wood = 600, Plastic = 1150, Metal = 7850 и др. Изменение Density немедленно меняет Mass.
Material Enum.Material RW Replicated Определяет визуальную текстуру, звук и физические параметры (коэфф. трения, restitution).
Color Color3 RW Replicated Основной цвет поверхности (если BrickColor не установлен). Приоритет ниже BrickColor.
BrickColor BrickColor RW Replicated Цвет из палитры LEGO (999+ значений). Приоритет выше Color.
Transparency number (0.0–1.0) RW Replicated Прозрачность. 0 — непрозрачный, 1 — полностью прозрачный. Влияет на рендер и коллизии (CanCollide).
Reflectance number (0.0–1.0) RW Replicated Коэффициент отражения (0 = матовый, 1 = зеркальный). Только для материалов SmoothPlastic, Neon, Glass, Metal.
CanCollide boolean RW Replicated Включение/выключение коллизий с другими BasePart. Если false — проходит сквозь всё (но Touched/TouchEnded не срабатывают).
CanQuery boolean RW Replicated Участвует ли в Workspace:Raycast(), :FindPartsInRegion3() и т.п. По умолчанию true.
CanTouch boolean RW Replicated Генерировать ли события Touched/TouchEnded. По умолчанию true. Важно: при false коллизии всё ещё возможны (CanCollide = true).
Shape Enum.PartType RO Форма: Block, Ball, Cylinder, CustomMesh, Truss. У Part — читаемое, у MeshPart — всегда CustomMesh.
Locked boolean RW Both Блокировка в Studio (не влияет на рантайм). Игнорируется в игре.
RootPriority number RW (только для Assembly) Replicated Приоритет корня ассемблии (для Humanoid:MoveTo() и IK). Не документирован, используется внутренне.

Методы BasePart
Метод Подпись Контекст Описание
:GetConnectedParts(recursive: boolean = false) → {BasePart} Both Возвращает части, соединённые WeldConstraint, RodConstraint, BallSocketConstraint и др. При recursive = true — транзитивное замыкание.
:GetJoints() → {Constraint} Both Возвращает все Constraint, прикреплённые к части (через Attachment).
:GetMass() → number Both То же, что свойство Mass, но как метод (для совместимости).
:GetRealMass() → number Both Учитывает присоединённые Constraint и другие части в ассемблии.
:GetTouchingParts() → {BasePart} Both Возвращает части, с которыми активно происходит коллизия (контактные точки ≠ 0). Требует CanCollide = true.
:Subtract(part: BasePart) → UnionOperation Server Создаёт UnionOperation, выполняющий булево вычитание: self – part.
:Union(parts: {BasePart}) → UnionOperation Server Объединяет self и parts в UnionOperation.
:Intersect(part: BasePart) → UnionOperation Server Пересечение self ∩ part.
:Resize(extent: Vector3) → void Server Увеличивает Size на extent (в стадиях) относительно центра. Устаревший, предпочтительно Size += extent.
:ApplyImpulse(impulse: Vector3) → void Replicated Прикладывает импульс (в кг·стадий/сек) к центру масс. Эффективно Velocity += impulse / Mass.
:ApplyImpulseAtPosition(impulse: Vector3, position: Vector3) → void Replicated Прикладывает импульс в указанной мировой позиции → вызывает вращение.
:ApplyAngularImpulse(impulse: Vector3) → void Replicated Прикладывает угловой импульс (в кг·стадий²/сек) → изменяет RotVelocity.
:GetBoundingBox() → (Vector3 center, Vector3 size) Both Возвращает осе-выровненный ограничивающий параллелепипед (AABB) части в мировых координатах.
:GetExtents() → (Vector3 min, Vector3 max) Both То же, что GetBoundingBox, но возвращаются углы.
:ToWorldSpace(cf: CFrame) → CFrame Both Преобразует локальную cf (относительно части) в мировую систему координат. Эквивалентно CFrame * cf.
:ToObjectSpace(cf: CFrame) → CFrame Both Обратное: CFrame:Inverse() * cf.
:GetVelocityAtPosition(position: Vector3) → Vector3 Both Линейная скорость точки с мировой координатой position, учитывая вращение (Velocity + RotVelocity × (position – Position)).

События BasePart
Событие Подпись Контекст Описание
Touched (otherPart: BasePart) Replicated Срабатывает при первой коллизии с другой частью (в один кадр — один вызов, даже при множестве контактов).
TouchEnded (otherPart: BasePart) Replicated Срабатывает, когда коллизия с otherPart завершается.
Stepped (dt: number) Server Устаревшее. Заменено на RunService.Stepped. Не использовать.
LocalSpaceMoved (deltaCFrame: CFrame) Client Только для Part в ReplicatedFirst. Используется для предиктивного рендеринга. Редко.

⚠️ Touched/TouchEnded требуют:

  • CanCollide = true у обоих участников
  • CanTouch = true у обоих
  • Физическое пересечение геометрии (точная форма: mesh/collision volume)
  • Один из объектов должен быть Anchored = false или оба — но с движением (иначе срабатывает только при ручном изменении CFrame)

2.1.2 Part — стандартный блок

Наследует BasePart. Добавляет только Shape (доступен для записи у Part, но не у MeshPart).

  • Shape: Enum.PartType.Block | Ball | Cylinder
    • При смене Shape пересчитывается collision mesh и Mass.
    • Ball и Cylinder используют точные формы для коллизий (не AABB).
    • Block — быстрее всего в расчётах.

Пример — создание шара
local sphere = Instance.new("Part")
sphere.Shape = Enum.PartType.Ball
sphere.Size = Vector3.new(2, 2, 2) -- диаметр = 2
sphere.Position = Vector3.new(0, 10, 0)
sphere.Anchored = false
sphere.Parent = workspace

2.1.3 MeshPart
  • Shape фиксирован как CustomMesh.
  • Требует наличие SpecialMesh или DataModelMesh (например, FileMesh) как дочернего объекта для определения геометрии.
  • Если SpecialMesh отсутствует — отображается как пустой Block (но коллизии — только по AABB).
  • Коллизии по умолчанию — AABB, даже если mesh сложный. Для точных коллизий:
    • В Studio: *CollisionFidelity → PreciseConvexDecomposition или Hull
    • Через код — нельзя, только через редактор или загрузку .rbxm.

2.1.4 UnionOperation и NegateOperation
  • Используются для булевых операций над BasePart.
  • Не являются BasePart напрямую, но при вызове :Union(), :Subtract() и т.п. возвращают новый объект типа PartShape = Enum.PartType.Block, но с кастомным collision mesh).
  • Возвращаемый Part имеет CanCollide = true, Anchored = false, Transparency = 0.
  • Удаление исходных частей не ломает union — он автономен.
  • Union нельзя редактировать после создания (только Destroy и пересоздавать).

2.2 Model — контейнер для иерархии

Instance
└── Model
    ├── PrimaryPart (не обязательно, но важно для :MoveTo(), :GetModelCFrame())
    └── другие BasePart, Attachment, Constraint...

Свойства Model
Свойство Тип Описание
PrimaryPart BasePart | nil Часть, относительно которой определяется поза модели. Если не задана — выбирается первая BasePart.
Archivable boolean По умолчанию true, но если в модели есть Player, Humanoid — становится false.

Методы Model
Метод Подпись Описание
:GetModelCFrame() → CFrame Возвращает CFrame модели: позиция = PrimaryPart.Position, ориентация = PrimaryPart.CFrame.Rotation. Если PrimaryPart нет — возвращает CFrame.new().
:SetPrimaryPartCFrame(cf: CFrame) → void Перемещает всю модель, выравнивая PrimaryPart по cf. Остальные части смещаются относительно неё.
:MoveTo(position: Vector3) → void Эквивалентно :SetPrimaryPartCFrame(CFrame.new(position) * PrimaryPart.CFrame.Rotation).
:GetBoundingBox() → (Vector3 center, Vector3 size) AABB всей модели (все BasePart).
:PivotTo(cf: CFrame) → void Новый (2022+) способ: использует Model:PivotOffset и PrimaryPart. Предпочтительнее :SetPrimaryPartCFrame().
:GetPivot() → CFrame Возвращает текущий Pivot CFrame.
:GetDescendantAddedSignal() → RBXScriptSignal Сигнал: (descendant: Instance). Срабатывает при добавлении любого потомка (в т.ч. второго уровня).

:PivotTo() и :GetPivot() — рекомендуемый современный API для позиционирования моделей. Совместим с IK, анимациями, HumanoidRootPart.


2.3 Attachment — точки привязки

Используется для:

  • Привязки Constraint (шарниры, пружины)
  • Определения точек излучения ParticleEmitter, Tool, ProximityPrompt
  • Задания локальных систем координат

Свойства Attachment
Свойство Тип Описание
WorldPosition Vector3 RO. Мировая позиция точки.
WorldCFrame CFrame RO. Полная мировая поза.
Position Vector3 RW. Локальная позиция (относительно ParentBasePart).
Rotation Vector3 RW. Локальный поворот (в градусах, Эйлер).
CFrame CFrame RW. Локальная поза. Приоритет выше Position/Rotation.
Axis Vector3 RO. Нормализованная ось X WorldCFrame.
SecondaryAxis Vector3 RO. Нормализованная ось Y WorldCFrame.

Attachment не рендерится, не участвует в коллизиях. Чисто логический объект.


2.4 Пространственные типы данных

Vector3
  • Конструкторы:
    • Vector3.new(x, y, z)
    • Vector3.zeroVector3.new(0, 0, 0)
    • Vector3.oneVector3.new(1, 1, 1)
  • Операции — +, -, * (скаляр и вектор), /, ==, - (унарный)
  • Методы:
    • :Magnitude() → длина
    • :Unit() → нормализованный вектор
    • :Dot(v) → скалярное произведение
    • :Cross(v) → векторное произведение
    • :Lerp(goal, alpha) → линейная интерполяция
    • :Distance(v)|(self - v)|
    • :DistanceTo(v) → alias :Distance()
    • :Max(other) / :Min(other) → покомпонентные max/min

CFrame
  • Комбинирует позицию (Vector3) и ориентацию (3×3 rotation matrix).
  • Конструкторы:
    • CFrame.new() → identity
    • CFrame.new(x, y, z)
    • CFrame.new(Vector3 pos)
    • CFrame.new(pos, lookAt) → смотрит из pos в lookAt
    • CFrame.new(pos, r00, r01, r02, r10, ..., r22) — прямо матрицу
    • CFrame.Angles(rx, ry, rz) → только поворот (позиция = 0)
    • CFrame.fromMatrix(pos, vX, vY [, vZ]) — из базиса
  • Свойства:
    • .PositionVector3
    • .XVector, .YVector, .ZVector → оси базиса
    • .RightVector, .UpVector, .LookVector — алиасы (Look = Z)
  • Методы:
    • * (умножение) — композиция трансформаций
    • :Inverse()
    • :ToWorldSpace(cf) / :ToObjectSpace(cf)
    • :Lerp(goal, alpha)
    • :GetComponents()(x,y,z, r00,...,r22)
    • :ToEulerAnglesXYZ() / YXZ() / ZYX() → (rx, ry, rz) в радианах
    • :ToAxisAngle()(axis: Vector3, angle: number)
    • :PointToWorldSpace(v)self * v
    • :VectorToWorldSpace(v)self - self.Position * v (без сдвига)

Region3
  • Определён двумя Vector3: CFrame + SizeRegion3.new(min, max).
  • min и max — противоположные углы AABB (не обязательно упорядочены; конструктор сам сортирует).
  • Используется в:
    • Workspace:FindPartsInRegion3(region, ignoreDescendant, maxParts = 100)
    • Workspace:FindPartOnRay(ray, ignoreDescendant) — устаревшее, заменено Raycast
  • ⚠️ Не поддерживает поворот — только осе-выровненные регионы.

Region3int16
  • Целочисленная версия Region3, используемая в Terrain:ReadVoxels().
  • Координаты — int16 (от -32768 до 32767).
  • Region3int16.new(min: Vector3int16, max: Vector3int16)

2.5 Расчёт столкновений — Raycasting

Старый API (FindPartOnRay) устарел. Используется Workspace:Raycast() и RaycastParams.


RaycastParams
  • Создаётся через RaycastParams.new().
  • Свойства:
    • .FilterDescendantsInstances = {Instance} — список объектов, которые игнорируются
    • .FilterType = Enum.RaycastFilterType.Whitelist \| Blacklist
      • Whitelist: проверяются только объекты из FilterDescendantsInstances
      • Blacklist: проверяются все, кроме указанных
    • .IgnoreWater = boolean
    • .CollidableOnly = boolean — учитывать только CanCollide = true
  • Методы: нет (immutable после передачи в Raycast)

Workspace:Raycast(origin: Vector3, direction: Vector3, params: RaycastParams)
  • Возвращает RaycastResult \| nil.
  • directionне позиция цели, а вектор направления (длина = длина луча).
  local origin = Vector3.new(0, 5, 0)
  local target = Vector3.new(10, 5, 0)
  local result = workspace:Raycast(origin, target - origin)

RaycastResult
Свойство Тип Описание
Instance BasePart Часть, в которую попал луч
Position Vector3 Точка пересечения
Normal Vector3 Нормаль поверхности в точке пересечения
Distance number Расстояние от origin до Position
Material Enum.Material Материал поверхности
Face Enum.NormalId Грань блока (Top, Bottom, Front, Back, Left, Right)

2.6 Навигация — PathfindingService

Требует настройки PathfindingLink и NavMesh (в Studio → Pathfinding).


Основные шаги
  1. Получить PathfindingService = game:GetService("PathfindingService")
  2. Создать path = PathfindingService:CreatePath()
  3. Настроить параметры path:
    • AgentRadius, AgentHeight, AgentCanJump, WaypointSpacing
  4. Вызвать path:ComputeAsync(startPos, endPos)yield-функция
  5. Проверить path.Status == Enum.PathStatus.Success
  6. Получить точки: local waypoints = path:GetWaypoints()

PathWaypoint

Таблица:

  • .Position: Vector3
  • .Action: Enum.PathWaypointActionWalk, Jump, WalkToPart, Stop
  • .Label: string — для PathfindingLink
  • .IsRisky: boolean — если путь ведёт в опасную зону (вода, лава)

3 — Персонаж — Humanoid, Animator, Animation и связанные компоненты

Эта часть описывает стандартную модель персонажа Roblox, включая анимационную систему, физику движения, состояние и взаимодействие.
Акцент — на стабильность, безопасность и соответствие официальной архитектуре (StarterPlayer → Character).


3.1 Иерархия персонажа

Стандартный персонаж — Model, создаваемый автоматически из StarterPlayer.StarterCharacterScripts и StarterPlayer.StarterCharacter.
Типичная структура (упрощённо):

Character (Model)
├── HumanoidRootPart (Part)    ← PrimaryPart модели
├── Humanoid (Humanoid)        ← логика состояния и движения
├── Animator (Animator)        ← управление анимациями
├── Head (Part)
│   └── FaceCenterAttachment (Attachment)
├── Torso (Part)
│   ├── RootAttachment (Attachment)
│   ├── Waist (Motor6D)
│   └── [другие Motor6D]
├── [Left/Right] Arm/Leg (Part)
│   └── [Shoulder/Hip/Elbow/Knee] (Motor6D)
├── [Left/Right] Grip (Attachment) — для Tool
└── [Hat, Tool] — динамически добавляются

⚠️ Изменение этой структуры (например, замена HumanoidRootPart) ломает стандартное поведение (Humanoid:MoveTo(), Animator, анимации). Для кастомных персонажей используйте R15/Rthro и Humanoid:BuildRigFromAttachments().


3.2 Humanoid — ядро персонажа

Humanoid управляет:

  • Состоянием (Health, MaxHealth, Sit, Jump, PlatformStand)
  • Движением (MoveDirection, WalkSpeed, JumpPower)
  • Анимацией (через Animator)
  • Воскрешением
  • Синхронизацией между сервером и клиентом

3.2.1 Свойства Humanoid
Свойство Тип Доступ Контекст Описание
Health number RW Replicated Текущее здоровье. При ≤ 0:TakeDamage(), затем BreakJoints() и Dead = true.
MaxHealth number RW Replicated Максимум здоровья. По умолчанию 100.
WalkSpeed number RW Replicated Скорость ходьбы (стадий/сек). По умолчанию 16. Максимум 100 (ограничение клиента).
JumpPower number RW Replicated Импульс прыжка (стадий/сек). По умолчанию 50. Максимум 200.
AutoJumpEnabled boolean RW Client Разрешить автоматический прыжок при столкновении с препятствием (если MoveDirection.Y > 0).
AutoRotate boolean RW Replicated Повернуть персонажа в направлении MoveDirection (если true). По умолчанию true.
MoveDirection Vector3 RW Client Направление движения (нормализовано, локальная система координат персонажа). Устанавливается StarterPlayerScripts из ввода.
Sit boolean RW Replicated Если true — персонаж садится (игнорирует гравитацию, MoveDirection игнорируется).
Jump boolean RW Client → Server Запрос прыжка. Устанавливается в true клиентом, сервер реплицирует и применяет физику. Автоматически сбрасывается в false.
PlatformStand boolean RW Replicated Игнорировать гравитацию, но оставаться в воздухе (для платформеров).
State Enum.HumanoidStateType RO Replicated Текущее состояние: None, Dead, GettingUp, Jumping, Freefall, FallingDown, Climbing, Seated, PlatformStanding, Swimming, Flying, Running.
RootPart BasePart | nil RO Replicated Часть, используемая как точка опоры (по умолчанию HumanoidRootPart).
RigType Enum.HumanoidRigType RO R6 (6 частей), R15 (15 частей), Rthro. Задаётся при создании.
DisplayName string RW Replicated Отображаемое имя (не Player.Name).
DisplayDistanceType Enum.HumanoidDisplayDistanceType RW Replicated Viewer, Subject, None — управляет отображением имени.
BreakJointsOnDeath boolean RW Server Разрушать ли Motor6D при смерти (по умолчанию true).
HealthDisplayDistance number RW Replicated Дистанция, на которой видна полоска здоровья (в стадиях). 0 — всегда, -1 — никогда.

3.2.2 Методы Humanoid
Метод Подпись Контекст Описание
:TakeDamage(amount: number) → void Server Наносит урон. Вызывает событие TakeDamage, затем проверяет Health ≤ 0.
:Heal(amount: number) → void Server Восстанавливает здоровье (не выше MaxHealth).
:MoveTo(position: Vector3, target: Instance = nil) → void Server Асинхронное движение к позиции. Использует PathfindingService, если доступен. Останавливается при StateRunning.
:Move(direction: Vector3, ignoreAutoRotate: boolean = false) → void Client Устанавливает MoveDirection. Устаревший (до 2019), предпочтительно прямая запись в MoveDirection.
:ChangeState(state: Enum.HumanoidStateType) → boolean Server Принудительно меняет состояние. Возвращает true, если успешно. Опасно — может нарушить консистентность.
:BuildRigFromAttachments(definition: R15HumanoidDescription | nil) → void Server Перестраивает скелет по Attachment (требует RigType = R15). Используется для кастомных R15-моделей.
:GetState() → Enum.HumanoidStateType Both То же, что свойство State.
:GetPlayingAnimationTracks() → {AnimationTrack} Both Возвращает активные треки анимаций.
:LoadAnimation(animation: Animation) → AnimationTrack Both Загружает анимацию для проигрывания. Возвращает AnimationTrack.
:ReplaceFace(faceId: number) → void Server Меняет лицо (для R6). Для R15 — используйте FaceCenterAttachment.
:GetAccessories() → {Accessory} Both Возвращает одетые аксессуары (шляпы и др.).
:RemoveAccessories() → void Server Снимает все аксессуары.

3.2.3 События Humanoid
Событие Подпись Контекст Описание
Died () Replicated Срабатывает при Health ≤ 0. После BreakJoints().
Seated (active: boolean, seatPart: BasePart) Replicated При посадке/вставании.
Jumping () Replicated При начале прыжка (не в апексе).
FreeFalling () Replicated При входе в состояние Freefall.
Landed (fallDistance: number) Replicated При приземлении после падения. fallDistance — высота падения.
Running (isRunning: boolean) Replicated При начале/остановке бега.
TakeDamage (amount: number, source: Instance, projectile: BasePart) Server Перед Health -= amount. Можно отменить через return false в BindAction.
HealthChanged (newHealth: number) Replicated При любом изменении Health (включая Heal).
Touched (hitPart: BasePart) Replicated Только если hitPart имеет Touched-обработчик и CanTouch = true.

⚠️ Died не срабатывает, если Humanoid уничтожен до Health ≤ 0 (например, :Destroy()).
Для надёжного отслеживания смерти используйте HealthChanged:Connect(...) + проверку health ≤ 0.


3.3 Animator и анимации

Animator — неотъемлемая часть Humanoid. Доступен как humanoid.Animator.


3.3.1 Animation
  • Хранит данные анимации (позы ключевых кадров).
  • Создаётся через Instance.new("Animation").
  • Основное свойство:
    • AnimationId: string — ссылка на ассет:
      • rbxassetid://123456789
      • http://www.roblox.com/asset/?id=123456789
      • rbxasset://anim.rbxl (локально, редко)

3.3.2 AnimationTrack

Результат humanoid:LoadAnimation(animation). Управляет проигрыванием.


Свойства AnimationTrack
Свойство Тип Описание
Length number Длительность анимации (сек).
Looped boolean Повторять ли анимацию.
Priority Enum.AnimationPriority Core, Movement, Action, Idle. Определяет, какая анимация "побеждает" при конфликте.
Weight number (0.0–1.0) Вес смешивания (для слоёв).
IsPlaying boolean Играет ли трек сейчас.

Методы AnimationTrack
Метод Подпись Описание
:Play(fadeTime: number = 0, weight: number = 1, playbackRate: number = 1) → void Запуск анимации. fadeTime — наложение при смене.
:Stop(fadeTime: number = 0) → void Остановка с затуханием.
:AdjustWeight(goalWeight: number, fadeTime: number = 0) → void Плавное изменение веса.
:AdjustSpeed(goalSpeed: number, fadeTime: number = 0) → void Изменение скорости проигрывания.
:GetMarkerReachedSignal(name: string) → RBXScriptSignal Сигнал: (). Срабатывает при достижении маркера (в Keyframe).
:GetTimePosition() → number Текущая позиция воспроизведения (сек).

События AnimationTrack
Событие Подпись Описание
Stopped () При остановке (включая естественное завершение).
KeyframeReached (name: string) При достижении keyframe с именем.

3.4 KeyframeSequence и Keyframe

  • KeyframeSequence — контейнер для Keyframe.
  • Keyframe — содержит Pose (иерархия CFrame для Attachment).
  • Анимации редактируются в Animation Editor (в Studio).
  • Через код можно создавать программно, но это редко и сложно.

Пример программного создания (не для продакшена):

local seq = Instance.new("KeyframeSequence")
local kf = Instance.new("Keyframe")
kf.Time = 0.5
local pose = Instance.new("Pose")
pose.Name = "Root"
pose.CFrame = CFrame.Angles(0, math.pi/4, 0)
pose.Parent = kf
kf.Parent = seq

3.5 Motor6D — суставы персонажа

  • Наследует Constraint.
  • Соединяет две части через Attachment: Part0.Attachment0Part1.Attachment1.
  • Свойства:
    • C0, C1 — локальные CFrame для Attachment0 и Attachment1.
    • Transform — дополнительное смещение (устаревшее, не использовать).
  • При Humanoid:BreakJoints() все Motor6D удаляются.

3.6 StarterPlayer и конфигурация персонажа

Объект Расположение Назначение
StarterCharacter StarterPlayer Копируется в Character при спавне. Если пуст — используется стандартный R6/R15.
StarterCharacterScripts StarterPlayer Копируются в Character. Должны содержать LocalScript для движения и Script для серверной логики.
StarterPlayerScripts StarterPlayer Копируются в PlayerScripts (дочерний Player). Для клиентской логики вне персонажа.
CharacterAdded Player Событие: (character: Model). Гарантирует, что персонаж загружен.
CharacterRemoving Player Событие: (character: Model). Перед уничтожением.

⚠️ Никогда не обращайтесь к player.Character напрямую — он может быть nil. Всегда используйте:

player.CharacterAdded:Connect(function(character)
    local humanoid = character:WaitForChild("Humanoid")
    -- ...
end)

3.7 Best practices для персонажа

  1. Сервер не должен управлять MoveDirection — это клиентская ответственность. Сервер может корректировать (WalkSpeed = 0 при заморозке), но не задавать направление.
  2. Анимации — клиентская логика. Сервер может запускать AnimationTrack, но только через RemoteEvent (или если анимация влияет на геймплей, например, каст).
  3. Не используйте Humanoid:MoveTo() в реальном времени — только для ИИ или автопилота. Для игрока — MoveDirection.
  4. Сохраняйте Humanoid.Health только на сервере — клиент может подделать Heal().
  5. Для кастомных персонажей:
    • Используйте R15.
    • Создавайте Attachment по стандартным именам (Root, Waist, LeftShoulder и др.).
    • Вызывайте humanoid:BuildRigFromAttachments().

4 — Пользовательский интерфейс (UI) — GuiObject, CoreGui, безопасность и оптимизация

Эта часть описывает графическую подсистему интерфейса Roblox, включая иерархию GuiObject, ограничения рендеринга, безопасность и рекомендации по производительности.
Акцент — на корректное использование StarterGui, изоляцию клиента/сервера и избегание распространённых ошибок.


4.1 Иерархия GuiObject

Все UI-элементы наследуются от GuiObjectInstance:

Instance
└── GuiObject
    ├── GuiButton
    │   ├── TextButton
    │   └── ImageButton
    ├── GuiLabel
    │   └── TextLabel
    ├── Frame
    │   └── ScrollingFrame
    ├── ImageLabel
    ├── TextBox
    ├── CanvasGroup
    └── BillboardGui (в 3D-мире)
        └── WorldBillboardGui

⚠️ UI существует только на клиенте. Сервер не имеет доступа к PlayerGui, CoreGui, StarterGui (кроме StarterGui как шаблона).


4.2 Базовый класс GuiObject

4.2.1 Свойства GuiObject
Свойство Тип Доступ Описание
Size UDim2 RW Размер: UDim2.new(scaleX, offsetX, scaleY, offsetY). scale — доля родителя (0.0–1.0), offset — пиксели.
Position UDim2 RW Позиция относительно родителя (левый верхний угол).
AnchorPoint Vector2 RW Точка привязки (0,0 = левый верх, 0.5,0.5 = центр). Смещает Position относительно неё.
AbsoluteSize Vector2 RO Фактический размер в пикселях.
AbsolutePosition Vector2 RO Фактическая позиция в пикселях.
Visible boolean RW Отображение элемента и всех потомков.
Active boolean RW Обрабатывать ли ввод (нажатия, наведение). Если false — клики проходят "сквозь".
Selectable boolean RW Можно ли выбрать элемент (для TextBox, ImageButton).
BackgroundColor3 Color3 RW Цвет фона.
BackgroundTransparency number (0.0–1.0) RW Прозрачность фона. 1 = полностью прозрачный.
BorderColor3 Color3 RW Цвет границы.
BorderSizePixel number RW Толщина границы (в пикселях). 0 = без границы.
ClipsDescendants boolean RW Обрезать ли потомков за пределами AbsoluteSize.
ZIndex number (1–10) RW Глубина отрисовки (чем выше — тем "ближе"). Максимум 10.
LayoutOrder number RW Порядок для UIListLayout, UIGridLayout.
AutoLocalize boolean RW Использовать ли систему локализации (LocalizationService).

4.2.2 Методы GuiObject
Метод Подпись Описание
:TweenSize(size: UDim2, easingDirection: Enum.EasingDirection, easingStyle: Enum.EasingStyle, time: number, override: boolean, callback: function) Tween Плавное изменение Size.
:TweenPosition(position: UDim2, easingDirection: Enum.EasingDirection, easingStyle: Enum.EasingStyle, time: number, override: boolean, callback: function) Tween Плавное изменение Position.
:TweenSizeAndPosition(size, position, ...) Tween Комбинированная анимация.
:GetChildren() {Instance} Только прямые потомки (не рекурсивно).
:FindFirstChild(name, recursive) Instance | nil Аналогично Instance.

4.2.3 События GuiObject
Событие Подпись Описание
InputBegan (input: InputObject, gameProcessed: boolean) Нажатие внутри элемента. gameProcessed = true, если ввод перехвачен (например, движение мыши).
InputEnded (input: InputObject, gameProcessed: boolean) Отпускание.
MouseButton1Click () Клик ЛКМ (вызывается только если MouseButton1DownMouseButton1Up без движения).
MouseButton1Down () Нажатие ЛКМ.
MouseButton1Up () Отпускание ЛКМ.
MouseEnter () Наведение курсора.
MouseLeave () Уход курсора.
MouseMoved (x: number, y: number) Перемещение мыши над элементом.
MouseWheelBackward () Колёсико вниз.
MouseWheelForward () Колёсико вверх.

⚠️ MouseButton1Click не срабатывает, если курсор вышел за пределы элемента до Up. Для надёжного клика используйте InputBegan + InputEnded с проверкой UserInputType == Enum.UserInputType.MouseButton1.


4.3 Основные UI-элементы

Frame
  • Контейнер для группировки. По умолчанию BackgroundTransparency = 1, Active = false.
  • Используется с UIListLayout, UIPadding, UIScale.

TextLabel / TextButton
Свойство Тип Описание
Text string Текст (поддерживает \n).
TextSize number Размер шрифта (в пикселях). Максимум 100.
Font Enum.Font Legacy, SourceSans, Gotham, RobotoMono и др.
TextColor3 Color3 Цвет текста.
TextWrapped boolean Перенос по словам.
TextXAlignment / TextYAlignment Enum.TextXAlignment / Y Left, Center, Right / Top, Center, Bottom.
RichText boolean Включить форматирование: <b>, <i>, <font color="#FF0000">.
TextScaled boolean Автомасштабирование текста под размер фрейма.

⚠️ RichText не поддерживает изображения (<img>), только стили.


ImageButton / ImageLabel
Свойство Тип Описание
Image string rbxassetid://, http://, rbxasset://.
ImageColor3 Color3 Цвет наложения (умножение).
ImageTransparency number Прозрачность изображения.
ScaleType Enum.ScaleType Stretch, Crop, Fit, Slice (для 9-slice).
SliceCenter Rect Область для ScaleType.Slice (в пикселях исходного изображения).
ImageRectOffset / ImageRectSize Vector2 Для спрайт-листов (смещение и размер кадра).

ScrollingFrame
  • Прокручиваемый контейнер.
  • Требует CanvasSize: UDim2 — размер содержимого (в пикселях: UDim2.new(0, width, 0, height)).
  • Автоматически добавляет скроллбары при ScrollBarThickness > 0.
  • События — CanvasPositionChanged, VerticalScrollBarInset, HorizontalScrollBarInset.

TextBox
Свойство Тип Описание
Text string Текущий ввод.
ClearTextOnFocus boolean Очищать при фокусе.
PlaceholderText string Подсказка (серый текст).
TextColor3 / PlaceholderColor3 Color3 Цвет текста / подсказки.
TextEditable boolean Можно ли редактировать.
MaxLength number Ограничение длины (0 = без ограничения).
MultiLine boolean Многострочный ввод.

⚠️ Text не реплицируется серверу. Для валидации — RemoteEvent.


4.4 UI-ограничения и компоновка

Объект Назначение
UIListLayout Вертикальное/горизонтальное выравнивание потомков (FillDirection, HorizontalAlignment, VerticalAlignment, Padding, SortOrder).
UIPadding Отступы внутри фрейма (PaddingLeft, Top, Right, Bottom).
UIScale Масштабирование всего поддерева (Scale).
UIAspectRatioConstraint Фиксированное соотношение сторон (AspectRatio).
UITextSizeConstraint Ограничение размера шрифта (MinTextSize, MaxTextSize).
UICorner Скругление углов (CornerRadius).
UIStroke Обводка (Color, Thickness, Transparency).

Пример: центрированный фрейм

local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 200, 0, 100)
frame.AnchorPoint = Vector2.new(0.5, 0.5)
frame.Position = UDim2.new(0.5, 0, 0.5, 0)

4.5 Иерархия UI в игре

PlayerGui (в Player)
├── ScreenGui (основной слой)
│   ├── Frame (меню)
│   └── TextLabel (очки)
├── BillboardGui (в 3D-мире)
└── StarterGui (только шаблон, копируется в ScreenGui при спавне)
  • StarterGui — шаблон. При входе игрока его содержимое копируется в Player.PlayerGui.
  • CoreGui — системные элементы (чёрный экран, меню паузы, чат).
    • Доступ только для чтения (game:GetService("CoreGui")).
    • Можно скрыть: StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.All, false).
    • Запрещено удалять или модифицировать напрямую.

4.6 Безопасность и валидация

  1. UI — клиентская зона ответственности

    • Сервер не должен доверять данным из TextBox.Text, ImageButton.Image, и т.п.
    • Все действия (покупки, ввод команд) должны передаваться через RemoteEvent с валидацией на сервере.
  2. Ограничения ввода

    • TextBox не защищает от XSS — RichText не исполняет JS, но можно обмануть визуально.
    • Для фильтрации чата используйте Chat:FilterStringAsync().
  3. Скрытие UI от читеров

    • Не храните конфиденциальные данные (Health, Gold) в TextLabel.Text.
    • Используйте :SetAttribute() + RemoteEvent для обновления.

4.7 Производительность UI

Проблема Решение
Слишком много TextLabel Объединяйте текст в один элемент.
Частые :TweenPosition() Используйте TweenService:Create() один раз, затем :Play().
Сложные ScrollingFrame с 1000+ элементами Виртуализируйте: отрисовывайте только видимые.
MouseMoved на каждом фрейме Дебаунсинг через tick() или RunService.Heartbeat.
RichText с большим объёмом Избегайте — рендеринг очень дорогой.

⚠️ Не используйте wait() в обработчиках InputBegan — блокировка потока ввода вызывает лаги.


5 — Сетевое взаимодействие — RemoteEvent, RemoteFunction, валидация и безопасность

Эта часть описывает механизмы межконтекстного взаимодействия в Roblox — клиент ↔ сервер, а также best practices по безопасности, производительности и отказоустойчивости.
Акцент — на корректное использование RemoteEvent/RemoteFunction, защиту от читерства и обработку ошибок.


5.1 Общая архитектура взаимодействия

  • Клиент (LocalScript) может:
    • Отправлять данные на сервер через RemoteEvent:FireServer(...)
    • Вызывать функции на сервере через RemoteFunction:InvokeServer(...)
    • Получать данные от сервера через RemoteEvent.OnClientEvent:Connect(...)
  • Сервер (Script) может:
    • Рассылать данные клиентам через RemoteEvent:FireAllClients(...), :FireClient(player, ...)
    • Отвечать на вызовы через RemoteFunction.OnServerInvoke = function(...) → return ... end
    • Вызывать функции на клиенте через RemoteFunction:InvokeClient(player, ...)

⚠️ Запрещено:

  • Пытаться вызвать FireServer из Script (ошибка времени выполнения)
  • Вызывать FireClient без проверки player:FindFirstChild("PlayerGui") (клиент может быть не загружен)
  • Передавать Instance, userdata, function, thread — только сериализуемые типы (см. 5.4)

5.2 RemoteEvent — односторонняя асинхронная передача

5.2.1 Создание и размещение
  • Создаётся в ReplicatedStorage (рекомендуется) или ServerStorage (если клиент не должен знать о его существовании до момента передачи).
  • Пример иерархии:
  ReplicatedStorage
  └── Remotes
      ├── PlayerAction
      ├── ChatMessage
      └── ToolUse

5.2.2 Методы и события
Контекст Метод / Событие Подпись Описание
Клиент :FireServer(...) → void Отправляет аргументы на сервер.
Клиент .OnClientEvent RBXScriptSignal Сигнал: (...). Получение данных от сервера.
Сервер :FireAllClients(...) → void Рассылка всем подключённым игрокам.
Сервер :FireClient(player: Player, ...) → void Отправка конкретному игроку.
Сервер .OnServerEvent RBXScriptSignal Сигнал: (player: Player, ...). Получение данных от клиента.

5.2.3 Пример — безопасный выстрел
-- LocalScript (в StarterPlayerScripts)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")

local ToolUse = ReplicatedStorage.Remotes.ToolUse

UserInputService.InputBegan:Connect(function(input, gameProcessed)
    if gameProcessed then return end
    if input.UserInputType == Enum.UserInputType.MouseButton1 then
        local mouse = game.Players.LocalPlayer:GetMouse()
        ToolUse:FireServer(mouse.Hit.Position)
    end
end)

5.3 RemoteFunction — двусторонний синхронный вызов

5.3.1 Особенности
  • Блокирует поток до получения ответа (yield-функция).
  • Максимальное время ожидания — 3 секунды (если клиент не ответит — nil).
  • Не рекомендуется для частых вызовов (например, каждый кадр).

5.3.2 Методы и события
Контекст Метод / Событие Подпись Описание
Клиент :InvokeServer(...) → ... Блокирует, возвращает результат с сервера.
Сервер .OnServerInvoke function(player: Player, ...) → ... Обработчик вызова от клиента.
Сервер :InvokeClient(player: Player, ...) → any | nil Блокирует, возвращает результат от клиента (или nil при таймауте).
Клиент .OnClientInvoke function(...) → ... Обработчик вызова от сервера.

5.3.3 Пример — запрос данных профиля
-- Server (Script)
local GetProfile = ReplicatedStorage.Remotes.GetProfile
GetProfile.OnServerInvoke = function(player)
    local success, data = pcall(function()
        return {
            level = 5,
            gold = 1250,
            equipped = {"Sword", "Shield"}
        }
    end)
    return success and Данные or nil
end
-- Client (LocalScript)
local profile = GetProfile:InvokeServer()
if profile then
    print("Уровень:", profile.level)
else
    warn("Не удалось загрузить профиль")
end

⚠️ InvokeClient не следует использовать для критичных операций — клиент может намеренно не отвечать.


5.4 Поддерживаемые типы данных

Roblox сериализует только следующие типы:

Тип Поддержка Примечания
nil Передаётся как nil.
boolean
number Только double (64-bit float). Целые > 2⁵³ теряют точность.
string UTF-8, до 32 KB на строку.
Vector3, CFrame, UDim, UDim2, Ray, Color3, BrickColor, Rect Встроенные типы Roblox.
Enum.* Передаётся как (Enum, value), восстанавливается автоматически.
Instance Заменяется на nil.
function, thread, userdata Заменяются на nil.
table ✅ (ограниченно) Только массивы и словари с ключами-строками/числами. Циклические ссылки — обрезаются. Метатаблицы игнорируются.

⚠️ Передача таблицы с 10 000 элементов может вызвать превышение лимита пакета (1 MB). Используйте HttpService:JSONEncode() + сжатие, если нужно много данных.


5.5 Лимиты и ограничения

Параметр Значение Последствия превышения
Размер пакета ≤ 1 MB Ошибка: Remote function/event payload too large
Частота вызовов ≤ 200 / сек на игрока Пакеты дропаются, RemoteEvent — lossy.
Глубина таблицы ≤ 100 уровней Обрезается.
Длина строки ≤ 32 767 символов Обрезается.
Количество аргументов ≤ 200 Ошибка при вызове.

Совет: для потоковой передачи (например, прогресс загрузки) используйте несколько FireServer() с небольшими порциями.


5.6 Best practices

  1. Валидация на сервере — обязательно

    • Проверяйте:
      • player ~= nil
      • player.Character ~= nil
      • player == game.Players:GetPlayerFromCharacter(script.Parent) (для Tool)
      • Диапазоны (WalkSpeed ≤ 100, Health ≥ 0)
      • Временные окна (cooldown, double-spend)
  2. Используйте паттерн "запрос-подтверждение" для критичных действий

   -- Клиент: FireServer("buyItem", itemId)
   -- Сервер: проверяет баланс → FireClient(player, "confirmBuy", itemId, price)
   -- Клиент: показывает диалог → FireServer("confirmBuy", itemId)
   -- Сервер: списывает деньги
  1. Не передавайте состояние UI на сервер

    • Например, не отправляйте frame.Visible — сервер должен сам решать, что открыто.
  2. Избегайте FireAllClients для частых обновлений

    • Используйте BindableEvent для локальной синхронизации внутри клиента.
  3. Обрабатывайте ошибки

    • Оборачивайте pcall в OnServerEvent, OnServerInvoke.
    • Логируйте подозрительные вызовы (warn("Player", player.Name, "sent invalid Данные")).

6 — Сохранение данных — DataStoreService, OrderedDataStore, квоты и отказоустойчивость

Эта часть описывает механизмы постоянного хранения данных игроков и игры в Roblox, включая типы DataStore, ограничения, обработку ошибок и промышленные паттерны.
Акцент — на надёжность, соответствие лимитам платформы и защиту от потери данных.


6.1 Общая архитектура DataStore

  • Все операции выполняются только на сервере (Script).
  • Клиент не имеет доступа к DataStoreService (попытка вызова → ошибка).
  • Данные хранятся в облаке Roblox, реплицируются между серверами.
  • Нет гарантии мгновенной синхронизации между разными DataModel (серверами).

6.1.1 Глобальные сервисы
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

6.1.2 Типы DataStore
Тип Создание Назначение Ограничения
Standard DataStore DataStoreService:GetDataStore("Name") Хранение таблиц (до 4 MB на ключ) 64 ключа/мин/сервер, 4000 чтений/мин/сервер
OrderedDataStore DataStoreService:GetOrderedDataStore("Name") Ранжированные данные (числа, до 10⁹) Только number, string (ключ); 64 ключа/мин/сервер
GlobalDataStore DataStoreService:GetGlobalDataStore() Устаревший. Не использовать. Заменён Standard.
ProfileService (не встроенный) Через require(ReplicatedStorage.ProfileService) Промышленный менеджер профилей (рекомендуется) Сторонняя библиотека от DevForum

⚠️ Standard и Ordered — изолированы: GetOrderedDataStore("Scores")GetDataStore("Scores").


6.2 Standard DataStore

6.2.1 Основные методы
Метод Подпись Возвращает Примечания
:GetAsync(key: string) → value | nil, isLoaded: boolean Значение (любой сериализуемый тип) или nil isLoaded = false, если ключ не существует.
:SetAsync(key: string, value: any) → boolean true при успехе, false при квоте Блокирует до подтверждения (yield).
:UpdateAsync(key: string, transformFunction: function) → newValue | nil Результат функции Атомарное обновление (см. 6.3).
:RemoveAsync(key: string) → value | nil Значение до удаления Редко используется (лучше SetAsync(nil)).
:IncrementAsync(key: string, delta: number = 1) → number Новое значение Только для числовых данных. Устаревшее — используйте UpdateAsync.

6.2.2 Типичный цикл сохранения профиля

⚠️ PlayerRemoving не вызывается при краше сервера. Для защиты используйте BindToClose (см. 6.5).


6.3 Атомарное обновление — UpdateAsync

Предотвращает гонку при одновременном изменении данных.


Пример — безопасное добавление золота
local success, newGold = pcall(function()
    return DS:UpdateAsync("Player_" .. player.UserId, function(oldData)
        oldData = oldData or { gold = 0 }
        oldData.gold += reward
        return oldData -- возвращаем новое значение
    end)
end)
  • Функция transformFunction вызывается на сервере Roblox, не в вашем скрипте.
  • Может быть вызвана несколько раз при конфликтах — делайте её идемпотентной.
  • Не используйте замыкания — только локальные переменные.

6.4 OrderedDataStore — рейтинги и счётчики

6.4.1 Основные методы
Метод Подпись Описание
:GetValueAsync(key: string) → number | nil Получение значения.
:SetValueAsync(key: string, value: number) → void Установка значения.
:IncrementAsync(key: string, delta: number = 1) → number Атомарное увеличение.
:GetSortedAsync(ascending: boolean, pageSize: number = 100) → DataStorePages Постраничная выборка.

6.4.2 Работа с пагинацией
local ODS = DataStoreService:GetOrderedDataStore("Leaderboard")

-- Запись
ODS:IncrementAsync("Player_" .. player.UserId, 100)

-- Чтение топ-100
local pages = ODS:GetSortedAsync(false, 100) -- descending
local top = {}
for _, entry in ipairs(pages:GetCurrentPage()) do
    table.insert(top, { userId = entry.key:match("_(%d+)"), score = entry.value })
end

⚠️ Ключи в OrderedDataStoreтолько string, значения — только number.
Для хранения имён используйте отдельный Standard DataStore.


6.5 Обработка ошибок и отказоустойчивость

6.5.1 Типичные ошибки
Код ошибки Описание Решение
404 (KeyNotFound) Ключ не существует Обрабатывать как nil, инициализировать по умолчанию.
429 (TooManyRequests) Превышены квоты Реализовать экспоненциальную задержку.
500 (InternalServerError) Ошибка на стороне Roblox Повторить через 2–5 сек.
DataStore key too long Ключ > 50 символов Хэшировать (HttpService:MD5(key)).

6.5.2 Паттерн — экспоненциальная задержка

6.5.3 BindToClose — сохранение при выключении сервера
game:BindToClose(function()
    warn("Server shutting down — saving all players...")
    for _, player in ipairs(Players:GetPlayers()) do
        local data = player:GetAttribute("PlayerData")
        if Данные then
            DS:SetAsync("Player_" .. player.UserId, Данные) -- blocking
        end
    end
    warn("All Данные saved. Shutting down.")
end)

⚠️ BindToClose даёт 30 секунд на завершение. Если не уложиться — данные потеряются.


6.6 Промышленные паттерны

6.6.1 Версионирование данных

6.6.2 Throttling сохранения
  • Не сохраняйте при каждом изменении.
  • Используйте Debounce или task.delay.

6.6.3 Резервное копирование (fallback)
  • Храните копию в leaderstats (для отладки):
  player.leaderstats.Gold.Value = data.gold
  • Используйте HttpService:JSONEncode() + game:GetService("HttpService"):PostAsync() в свой бэкенд (если разрешено политикой).

6.7 Квоты и лимиты (2025)

Параметр Лимит Единица Комментарий
Чтение 4000 /мин/сервер Standard DataStore
Запись 64 /мин/сервер Standard DataStore
OrderedDataStore запись 64 /мин/сервер
Размер значения 4 MB на ключ Standard DataStore
Длина ключа 50 символов
Ключей в OrderedDataStore 1 000 000 на игру
Срок хранения Но данные могут быть удалены при нарушении ToS

⚠️ Лимиты суммируются по всем DataStore в одной игре.
Для высоконагруженных игр используйте шардирование ключей:

local shard = player.UserId % 10
local key = ("Shard_%d_Player_%d"):format(shard, player.UserId)

7 — Звук, частицы, свет и атмосферные эффекты

Эта часть описывает визуальные и аудиальные компоненты, используемые для создания иммерсивной среды — Sound, ParticleEmitter, Fire, Smoke, Trail, Beam, а также источники света (PointLight, SpotLight, SurfaceLight) и глобальные эффекты (Sky, Lighting, Fog).
Акцент — на параметры, производительность, репликацию и ограничения платформы.


7.1 Sound — аудиосистема

7.1.1 Иерархия и размещение
  • Sound может быть дочерним для:
    • BasePart (привязан к позиции части, движется вместе с ней)
    • Workspace (глобальный звук)
    • PlayerGui (UI-звуки, не затрагиваются 3D-параметрами)
  • Для 3D-звука обязательно наличие BasePart в качестве родителя или Sound.Parent = workspace.

7.1.2 Свойства Sound
Свойство Тип Доступ Описание
SoundId string RW rbxassetid://, http://, rbxasset://. Поддерживает OGG (рекомендуется), MP3 (устаревшее).
Volume number (0.0–10.0) RW Громкость. 1.0 = номинальная. Максимум 10.0 (усиление).
PlaybackSpeed number (0.1–10.0) RW Скорость воспроизведения (и тональность).
TimePosition number RW Текущая позиция (сек). Можно устанавливать для seek.
Looped boolean RW Повторять ли звук.
RollOffMode Enum.RollOffMode RW Inverse, Linear, Constant. Управляет затуханием по расстоянию.
RollOffMaxDistance number RW Макс. дистанция слышимости (стадий). По умолчанию 100.
RollOffMinDistance number RW Мин. дистанция (внутри неё громкость постоянна).
EmitterSize number (0.0–1000.0) RW Размер источника (для пространственного звука). 0 = точечный.
Pitch number (0.5–2.0) RW Только для совместимости. Используйте PlaybackSpeed.
Archivable boolean RO Всегда true, если SoundId задан.

7.1.3 Методы Sound
Метод Подпись Контекст Описание
:Play() → void Both Запуск воспроизведения. Если уже играет — перезапускает.
:Stop() → void Both Остановка.
:Pause() → void Both Пауза (можно продолжить через :Resume()).
:Resume() → void Both Продолжение после паузы.
:IsLoaded() → boolean Both Загружен ли аудиофайл в память.
:GetInfo() → table Both Метаданные: { Duration = number, SampleRate = number, Channels = number }.

7.1.4 События Sound
Событие Подпись Описание
Played () После начала воспроизведения (включая seek).
Stopped () При остановке (включая естественное завершение).
LoadingFailed (errorMessage: string) При ошибке загрузки (SoundId недоступен).

7.1.5 Best practices
  • Используйте OGG (меньше размер, лучше совместимость).
  • Для фоновой музыки — RollOffMode = Enum.RollOffMode.Constant, RollOffMaxDistance = 1000.
  • Не вызывайте :Play() чаще, чем раз в 0.1 сек — возможны артефакты.
  • Для UI-звуков размещайте Sound в StarterGui → копируется в PlayerGui.

7.2 ParticleEmitter — система частиц

7.2.1 Свойства
Свойство Тип Описание
Texture string rbxassetid:// изображение (рекомендуется PNG с альфа-каналом).
EmissionDirection Enum.NormalId Top, Bottom, Front, Back, Left, Right, AllFaces.
SpreadAngle Vector2 Угол рассеяния по X и Y (в градусах).
VelocityInheritance number (0.0–1.0) Наследование скорости родителя (0 = игнорировать, 1 = полное).
Rate number Частиц/сек. Максимум 1000.
Lifetime NumberRange Диапазон жизни частицы (сек). Например, NumberRange.new(1, 2).
Size NumberSequence Изменение размера во времени.
Transparency NumberSequence Изменение прозрачности (0 = непрозрачный, 1 = прозрачный).
Color ColorSequence Изменение цвета.
Rotation NumberRange Начальный угол поворота.
RotSpeed NumberRange Скорость вращения (град/сек).
Acceleration Vector3 Постоянное ускорение (например, гравитация: Vector3.new(0, -196.2, 0)).
Drag number Сопротивление среды.
LockedToPart boolean Двигать эмиттер вместе с Parent (для Part).
ZOffset number Смещение по Z для рендеринга (обход глубины).

7.2.2 Производительность
  • Одна сцена поддерживает до 10 000 частиц (ограничение клиента).
  • Rate > 500 + Lifetime > 1 → 500+ частиц/сек — может вызвать лаги на слабых устройствах.
  • Используйте Debris:AddItem(emitter, 5) для автоудаления.

7.3 Специализированные эффекты

Объект Назначение Ключевые свойства
Fire Имитация пламени Heat, Size, Color, SecondaryColor, Enabled
Smoke Дым Color, Opacity, RiseVelocity, Size, Enabled
Sparkles Искры Color, Enabled, SparkleColor
Trail След за движущейся частью Attachment0, Attachment1, Color, Transparency, Lifetime, FaceCamera, MinLength
Beam Лазер/энергетический луч Attachment0, Attachment1, Color, CurveSize0/1, Texture, Width0/1, Segments

⚠️ Trail и Beam требуют двух Attachment (в разных BasePart или одной).
Пример Trail:

local trail = Instance.new("Trail")
trail.Attachment0 = tool.Grip
trail.Attachment1 = tool.Grip
trail.Lifetime = 0.5
trail.Enabled = true
trail.Parent = tool

7.4 Источники света

7.4.1 PointLight
  • Точечный источник (как лампочка).
  • Свойства:
    • Brightness (0.0–10.0)
    • Range (стадий, до 100)
    • Color
    • CastShadows (требует GraphicsMode = 2 в Lighting)
    • ShadowSoftness (0.0–1.0)

7.4.2 SpotLight
  • Конусообразный свет.
  • Дополнительно:
    • Angle (угол конуса, градусы)
    • Face (Enum.NormalId) — направление излучения
    • Falloff (0.0–1.0) — резкость края

7.4.3 SurfaceLight
  • Плоский источник (например, подсветка панели).
  • Требует BasePart в качестве родителя.
  • Свойства:
    • Angle (угол рассеяния)
    • Face — грань части
    • Thickness — глубина излучения

⚠️ Все источники света реплицируются автоматически.
Максимум 64 активных источника на сцену (ограничение движка).


7.5 Глобальные настройки — Lighting

Свойство Тип Описание
Brightness number (0.0–10.0) Общая яркость сцены.
ClockTime number (0–24) Время суток (влияет на OutdoorAmbient).
FogStart / FogEnd number Дистанция начала/конца тумана.
FogColor Color3 Цвет тумана.
OutdoorAmbient Color3 Цвет окружения (небо → объекты).
GlobalShadows boolean Тени от солнца.
Shadows boolean Тени от источников света.
Technology Enum.Technology Voxel, ShadowMap — влияет на качество теней.
EnvironmentDiffuseScale / SpecularScale number Интенсивность отражений.
GeographicLatitude number (-90–90) Влияет на положение солнца.

7.5.1 Sky
  • Дочерний Lighting.
  • Свойства:
    • SkyboxBk, Dn, Ft, Lf, Rt, Uprbxassetid:// для граней кубмапы
    • CelestialBodiesShown (Enum.CelestialBody) — Sun, Moon, Both, None
    • StarCount — количество звёзд (до 1000)

Для динамического неба используйте Lighting.ClockTime = math.clamp(tick() % 86400 / 3600, 0, 24).


7.6 Производительность и оптимизация

Компонент Совет
Звук Используйте SoundGroup для управления громкостью категорий (музыка/эффекты).
Частицы Ограничьте Rate × Lifetime ≤ 500. Используйте ParticleEmitter:Clear() при скрытии.
Свет Отключайте CastShadows для некритичных источников. Избегайте Range > 50.
Туман FogEnd – FogStart < 100 — предотвращает артефакты на мобильных.
Небо Используйте 512×512 текстуры для Skybox (1024×1024 — только для ПК).

8 — Модули и инструменты разработки — ModuleScript, CollectionService, Binders и инфраструктурные паттерны

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

Важно: CollectionService и ModuleScript — встроенные API движка. Паттерны Binder, Janitor и Signal ниже — не часть Roblox, а распространённые решения сообщества (часто копируются в ReplicatedStorage как собственные ModuleScript). Примеры показывают типичную реализацию, а не официальный класс движка.


8.1 ModuleScript — основа модульной системы

8.1.1 Создание и использование
  • Наследует Instance, но не имеет визуального представления.
  • Возвращает любое значение через return.
  • Кэшируется: require(module) возвращает один и тот же объект при повторных вызовах.
-- ReplicatedStorage/Utils/Math.lua
local Math = {}

function Math.clamp(x, min, max)
    return math.min(math.max(x, min), max)
end

return Math
-- Script
local Math = require(game.ReplicatedStorage.Utils.Math)
print(Math.clamp(15, 0, 10)) -- 10

8.1.2 Best practices
  • Возвращайте таблицу интерфейса, а не отдельные функции.
  • Избегайте глобальных переменных внутри модуля.
  • Используйте local module = {} ... return module — не return { ... }.
  • Для инициализации с параметрами — возвращайте конструктор:
  return function(config)
      local obj = {}
      obj.config = config
      function obj:run() ... end
      return obj
  end

⚠️ require() блокирует до завершения модуля. Не используйте wait(), task.wait(), :WaitForChild() в корне ModuleScript.


8.2 CollectionService — тегирование объектов

Позволяет динамически группировать Instance по тегам (string), без иерархии.


8.2.1 Методы CollectionService
Метод Подпись Описание
:AddTag(instance: Instance, tag: string) → void Добавляет тег. Идемпотентен.
:RemoveTag(instance: Instance, tag: string) → void Удаляет тег.
:HasTag(instance: Instance, tag: string) → boolean Проверка наличия.
:GetTagged(tag: string) → {Instance} Все объекты с тегом (на момент вызова).
:GetTags(instance: Instance) → {string} Все теги объекта.

8.2.2 События
Событие Подпись Описание
InstanceAdded (tag: string, instance: Instance) При добавлении тега.
InstanceRemoved (tag: string, instance: Instance) При удалении тега.

8.2.3 Пример — система дверей

⚠️ Теги не сохраняются в .rbxl. Инициализируйте их при запуске сервера.


8.3 Binder — управление жизненным циклом компонентов

Промышленный паттерн для связывания Instance с логикой (например, EnemyEnemyController).
Реализуется через CollectionService + события.


8.3.1 Простая реализация Binder

8.3.2 Использование
-- ServerScript
local Binder = require(ReplicatedStorage.Binder)
local EnemyController = require(ReplicatedStorage.Controllers.EnemyController)

local enemyBinder = Binder.new("Enemy", function(part)
    return EnemyController.new(part)
end)

enemyBinder:Start()

game:BindToClose(function()
    enemyBinder:Stop()
end)

Преимущества:

  • Автоматическая привязка/отвязка при добавлении/удалении объекта
  • Централизованное управление жизненным циклом
  • Поддержка горячей замены (для Studio plugins)

8.4 Janitor — управление ресурсами

Класс для автоматической очистки соединений, таймеров, дочерних объектов.


8.4.1 Реализация

8.4.2 Пример использования

Используется в PlayerRemoving, CharacterRemoving, BindToClose.


8.5 Signal — кастомные события

Встроенные RBXScriptSignal нельзя создавать вручную. Используйте Signal.


8.5.1 Реализация

8.5.2 Применение

Преимущества перед BindableEvent:

  • Нет ограничений на количество слушателей
  • Полный контроль над жизненным циклом
  • Поддержка отладки (можно логировать :Fire())

8.6 Тестирование — TestService и MockDataStoreService

8.6.1 TestService
  • Доступен только в Studio (не в игре).
  • Методы:
    • :Check() — завершить тест успешно
    • :Fail(message: string) — завершить с ошибкой
    • :Warn(message: string) — предупреждение
    • :Start() / :Stop() — управление временем

8.6.2 MockDataStoreService (сторонний)
  • Имитирует DataStoreService в Studio.
  • Устанавливается как Plugin или через require.
  • Позволяет тестировать сохранение без квот.
-- Только в Studio
if game:GetService("RunService"):IsStudio() then
    local MockDataStore = require(game.ReplicatedStorage.MockDataStore)
    game:GetService("DataStoreService"):SetBackend(MockDataStore.new())
end

8.7 Рекомендации по архитектуре

Проблема Решение
Спагетти-код в Script Вынести логику в ModuleScript + Binder
Утечки памяти Использовать Janitor в каждом компоненте
Глобальные события Заменить BindableEvent на Signal
Зависимости от иерархии Использовать CollectionService + теги
Сложность тестирования Разделять Server/Client/Shared логику, использовать Mock

9 — Внешние интеграции — MarketplaceService, HttpService, GamePass, Developer Products и телепортация

Эта часть описывает механизмы взаимодействия с экосистемой Roblox — монетизация, внешние API, телепортация между серверами и загрузка ассетов.
Акцент — на безопасность, валидацию, обработку ошибок и соответствие политике платформы.


9.1 MarketplaceService — монетизация и виртуальные товары

9.1.1 Поддерживаемые типы
Тип Описание Методы
Game Pass Разовый доступ к функции (скин, способность) :PlayerOwnsGamePassAsync(), :PromptPurchase()
Developer Product Покупка с возвратом значений (золото, ресурсы) :PromptProductPurchase(), :ProcessReceipt
Badge Достижения :AwardBadge(), :GetGameBadgeInfoAsync()

9.1.2 Проверка владения Game Pass

⚠️ PlayerOwnsGamePassAsync() блокирует (yield). Используйте spawn() при массовой проверке.


9.1.3 Developer Products — безопасная обработка покупок
  1. Настройка в Creator Dashboard

    • Создать Product → указать Price, Description, Icon.
    • Включить "Process Receipts" → указать Script в ServerScriptService.
  2. Серверный обработчик (ProcessReceipt)

⚠️ Критически важно:

  • Использовать PurchaseId как уникальный идентификатор (не ProductId!).
  • Всегда возвращать PurchaseGranted после успешной обработки — иначе Roblox повторит вызов.
  • Не доверять player в ProcessReceipt — игрок может выйти до вызова.

9.1.4 Запрос покупки с клиента
-- LocalScript
local MarketplaceService = game:GetService("MarketplaceService")

buyButton.MouseButton1Click:Connect(function()
    MarketplaceService:PromptProductPurchase(
        game.Players.LocalPlayer,
        987654321, -- productId
        false,     -- включить ли бесплатную пробную версию (не для Developer Products)
        "Gold Pack" -- optional context
    )
end)

⚠️ PromptProductPurchase() и PromptGamePassPurchase() не возвращают результат. Успех/отказ отслеживается только через ProcessReceipt.


9.2 BadgeService — система достижений

9.2.1 Выдача бейджа

⚠️ AwardBadge() может вернуть false, если:

  • Бейдж отключён в настройках
  • Игрок уже имеет его
  • Превышена квота (10 бейджей/мин/сервер)

9.3 HttpService — внешние HTTP-запросы

9.3.1 Ограничения
  • Только HTTPS (http:// → ошибка).
  • Доступно только на сервере.
  • Требует включения в Game Settings → Безопасность → Allow HTTP Requests.
  • Лимит: 10 запросов/сек/сервер, 500 байт/сек/сервер (ограничение полосы).
  • Запрещено обращение к roblox.com, roblox.net, localhost, частным IP.

9.3.2 Методы
Метод Подпись Описание
:GetAsync(url: string, nocache: boolean = false) → string GET-запрос. Блокирует.
:PostAsync(url: string, Данные: string, contentType: Enum.HttpContentType) → string POST-запрос.
:JSONEncode(value: any) → string Сериализация в JSON.
:JSONDecode(json: string) → any Десериализация из JSON.

9.3.3 Пример — вебхук в Discord

⚠️ Никогда не передавайте player.UserId, IP, DeviceId в сторонние сервисы без согласия пользователя.


9.4 TeleportService — межсерверная телепортация

9.4.1 Типы телепортации
Метод Назначение
:Teleport(placeId, players, teleportData) Один игрок → другой Place
:TeleportToPrivateServer(placeId, reservedServerAccessCode, players, teleportData) В приватный сервер
:TeleportPartyAsync(placeId, players, teleportData) Группа игроков вместе
:GetPlayerTeleportData(player) Получить teleportData при входе

9.4.2 Передача данных (teleportData)
  • Тип: table (только сериализуемые типы, ≤ 1 KB).
  • Доступен через TeleportService:GetPlayerTeleportData(player) только при первом входе в новый сервер.
-- Сервер A: отправка
TeleportService:Teleport(123456789, {player}, {
    level = 5,
    checkpoint = "castle"
})

-- Сервер B: приём
Players.PlayerAdded:Connect(function(player)
    local data = TeleportService:GetPlayerTeleportData(player)
    if Данные then
        print("Телепортирован из другого сервера:", data.checkpoint)
    end
end)

⚠️ teleportData теряется после первого PlayerAdded. Сохраняйте нужное в Player:SetAttribute().


9.4.3 Respawn в том же сервере
player:LoadCharacter() -- без телепортации
-- или
player:Kick() -- переподключение к тому же серверу

9.5 AssetService — динамическая загрузка ассетов

9.5.1 Получение информации об ассете
local AssetService = game:GetService("AssetService")

-- Получить имя и описание
local success, info = pcall(function()
    return AssetService:GetAssetInfoAsync(123456789)
end)

if success then
    print(info.Name, info.Description, info.Created, info.Updated)
end

9.5.2 Поиск ассетов
local results = AssetService:SearchAsync("sword", Enum.AssetType.Mesh, 1)
for _, asset in ipairs(results.CurrentPage) do
    print(asset.Id, asset.Name)
end

Используется редко — преимущественно в инструментах Studio.


9.6 Безопасность и соответствие политике

Риск Мера
Подделка покупок Всегда проверяйте PurchaseId, используйте ProcessReceipt
Утечка данных Не передавайте UserId в HTTP без шифрования
Спам телепортацией Ограничьте частоту через Debounce
Нарушение ToS Не используйте HttpService для читов, манипуляции рейтингом

🔒 Все денежные операции должны обрабатываться только на сервере.
Клиент не должен знать ProductId, GamePassId — передавайте через RemoteEvent по семантическим именам ("buyGoldPack").


10 — Тестирование и отладка — TestService, LogService, Stats, профилировка и инструменты Studio

Эта часть описывает методы верификации корректности и производительности Roblox-проектов — юнит-тестирование, логирование, сбор метрик, профилирование и разработка плагинов.
Акцент — на воспроизводимость, автоматизацию и соответствие промышленным стандартам.


10.1 TestService — встроенная система тестирования

Доступна только в Roblox Studio, не существует в запущенной игре.


10.1.1 Основные методы
Метод Подпись Описание
:Check() → void Успешное завершение теста. Останавливает выполнение сценария.
:Fail(message: string) → void Провал теста с сообщением. Останавливает выполнение.
:Warn(message: string) → void Предупреждение (не останавливает).
:Start() → void Запуск таймера (для замера времени выполнения).
:Stop() → number Остановка таймера, возврат времени в секундах.

10.1.2 Структура тестового скрипта

Размещается в ServerScriptService или TestService (специальная папка, поддерживаемая плагинами).

⚠️ Тесты не запускаются автоматически. Используйте плагин TestEZ или Rojo + selene + TestEZ для CI.


10.2 LogService — централизованное логирование

10.2.1 Методы и уровни
Метод Уровень Описание
:GetLogHistory() → {LogInfo} — последние 100 сообщений.
message Message Информационное сообщение.
warning Warning Предупреждение.
error Error Ошибка (не прерывает выполнение).

Каждое сообщение — таблица LogInfo:

{
    Message = "текст",
    Timestamp = DateTime,
    Level = Enum.MessageType.Message,
    MessageId = "string"
}

10.2.2 Пример — логгер с метаданными

Используйте теги ("DataStore", "Сеть") для фильтрации в Studio → View → Output.


10.3 Stats — сбор системных метрик

Доступен через game:GetService("Stats").
Возвращает древовидную структуру Int64, Double, Object (для группировки).


10.3.1 Ключевые метрики
Путь Тип Описание
Сеть.IncomingKB Double Входящий трафик (KB)
Сеть.OutgoingKB Double Исходящий трафик (KB)
Physics.StepTime Double Время шага физики (мс)
Render.Fps Double Кадров/сек (только клиент)
Memory.Physics Int64 Память физики (байт)
Memory.Script Int64 Память скриптов (байт)
TaskScheduler.Threads Int64 Количество потоков сервера

10.3.2 Чтение метрик
local Stats = game:GetService("Stats")

local function getMetric(path: string)
    local obj = Stats
    for part in path:gmatch("[^.]+") do
        obj = obj[part]
        if not obj then return nil end
    end
    return typeof(obj) == "Double" and obj.Value or obj.Count
end

print("FPS:", getMetric("Render.Fps"))
print("Physics Step:", getMetric("Physics.StepTime"), "ms")

⚠️ Некоторые метрики (Render.*) доступны только на клиенте.


10.4 Профилировка производительности

10.4.1 Встроенный профайлер Roblox Studio
  1. Запустите игру в Studio.
  2. View → MicroProfiler.
  3. Нажмите Record, выполните сценарий, остановите запись.
  4. Анализируйте:
    • Script — время выполнения Lua (включая yield)
    • Physics — расчёты коллизий, constraints
    • Render — рендеринг геометрии, UI, частиц
    • Сеть — сериализация, отправка пакетов

10.4.2 Программная профилировка
-- Замер времени выполнения участка кода
local start = os.clock()
-- ... код ...
local elapsed = os.clock() - start
print(("Выполнено за %.4f сек"):format(elapsed))

os.clock() — высокоточный таймер (микросекунды), но не учитывает время ожидания (wait, :WaitForChild).


10.5 Debug — низкоуровневая отладка

10.5.1 Методы
Метод Описание
Debug.profilebegin(name: string) Начало именованного профилировочного блока (отображается в MicroProfiler)
Debug.profileend() Конец блока
Debug.setmemorycategory(category: string) Установка категории памяти для последующих аллокаций (для анализа утечек)

10.5.2 Пример
Debug.profilebegin("LoadPlayerData")
local data = DS:GetAsync("Player_" .. player.UserId)
Debug.profileend()

Debug.setmemorycategory("PlayerData")
local cache = {} -- все аллокации пойдут в категорию "PlayerData"

Категории памяти видны в View → MemoryAllocations by Category.


10.6 Studio Plugin API — автоматизация разработки

Плагины работают только в Studio, имеют доступ к редактору.


10.6.1 Основные сервисы
Сервис Назначение
Plugin Управление жизненным циклом плагина
PluginGui Создание окон в Studio
ChangeHistoryService Отмена/повтор действий (Ctrl+Z)
Selection Получение/установка выделенных объектов
StarterGui, Workspace, и др. Прямой доступ к иерархии

10.6.2 Пример — плагин для стандартизации Part

Плагины не публикуются в игру — только для разработки.


10.7 Best practices для отладки

Сценарий Решение
Сложно воспроизвести баг Используйте LogService + :GetLogHistory() при PlayerRemoving
Подозрение на утечку памяти Debug.setmemorycategory() + анализ в Memory
Низкий FPS на клиенте MicroProfiler → фильтр Render / Script
Задержки синхронизации Stats.Сеть.OutgoingKB, ReplicationLagNetworkServerStats)
Ошибки DataStore Логируйте pcall + err в LogService:error()

🔧 Для CI/CD используйте:

  • Rojo — синхронизация кода между Studio и Git
  • Selene — линтер Lua
  • TestEZ — фреймворк для юнит-тестов
  • Tarmac — форматирование кода

11 — Производительность и оптимизация — углублённый анализ движка Roblox

Эта часть охватывает системные аспекты производительности:

  • профилировку;
  • лимиты;
  • оптимизацию физики;
  • рендеринга;
  • сети;
  • памяти. Акцент — на измеримые метрики, количественные ограничения и проверенные методы повышения стабильности.

11.1 Архитектура движка и частоты обновления

Подсистема Частота Контекст Описание
Render 60–240 Гц Клиент Зависит от монитора и RunService:IsHeartbeatStepping(). Не регулируется скриптами.
Heartbeat ~60 Гц Клиент RunService.Heartbeat:Connect(...) — для UI, анимаций, предиктивного рендеринга.
RenderStepped ~60 Гц Клиент RunService.RenderStepped:Connect(...) — для привязки к кадру (устаревшее, предпочтительно Heartbeat).
Stepped 240 Гц Сервер RunService.Stepped:Connect(function(time, deltaTime) ...) — физика, перемещение.
Physics 240 Гц Сервер/Клиент Внутренний шаг симуляции (фиксированный). Не зависит от FPS.
Сеть 20–30 Гц Сервер→Клиент Частота репликации состояния (адаптивная, зависит от NetworkServerStats.OutgoingReplicationLag).

⚠️ SteppedHeartbeat:

  • Stepped — серверный, синхронизирован с физикой (240 Гц).
  • Heartbeat — клиентский, синхронизирован с рендером (~60 Гц).
    Никогда не используйте Heartbeat для физики или перемещения персонажа.

11.2 Профилировка — MicroProfiler и метрики

11.2.1 Ключевые слои в MicroProfiler
Слой Норма (мс/кадр) Критично Рекомендации
Script ≤ 1.0 > 3.0 Оптимизировать hot path, избегать :GetDescendants(), ipairs вместо pairs
Physics ≤ 2.0 > 5.0 Уменьшить CanCollide, использовать CollisionFidelity = Hull, ограничить Constraint
Render.Geometry ≤ 2.0 > 4.0 LOD, Transparency = 1 для невидимых частей, :ClearAllChildren() вместо :Destroy() по одной
Render.UI ≤ 0.5 > 1.0 Избегать RichText, виртуализировать ScrollingFrame, не обновлять TextLabel.Text каждый кадр
Сеть.Encode ≤ 0.3 > 1.0 Сократить количество RemoteEvent, объединять данные в таблицы

11.2.2 Программный доступ к лагам
local RunService = game:GetService("RunService")

-- Только на сервере
if RunService:IsServer() then
    RunService.Heartbeat:Connect(function()
        local stats = game:GetService("Stats")
        local lag = stats.Сеть:FindFirstChild("OutgoingReplicationLag")
        if lag and lag.Value > 0.1 then -- 100 мс
            warn("Высокая сетевая задержка:", lag.Value)
        end
    end)
end

11.3 Физика — оптимизация и ограничения

11.3.1 Иерархия ограничений (Constraint)
Constraint
├── AlignOrientation
├── AlignPosition
├── BallSocketConstraint
├── CylindricalConstraint
├── HingeConstraint
├── LineForce
├── PrismaticConstraint
├── RopeConstraint
├── SpringConstraint
├── RodConstraint
├── SlipConstraint
├── TwistConstraint
└── WeldConstraint

11.3.2 Рекомендации
  • Максимум 100 активных Constraint на сцену (иначе падает Physics.StepTime).
  • WeldConstraint быстрее Motor6D (в 2–3 раза). Для статичных соединений — использовать WeldConstraint.
  • RopeConstraint и SpringConstraint — самые дорогие. Заменять на Attachment + BodyPosition при возможности.
  • Отключать Active = false у неиспользуемых Constraint.

11.3.3 PhysicsService — управление коллайдерами
Метод Описание
:GetCollisionGroups() Список групп коллизий.
:CreateCollisionGroup(name: string) Создание группы.
:CollisionGroupSetCollidable(groupA, groupB, collidable: boolean) Настройка взаимодействия групп.

Пример: игрок не сталкивается с декором:

PhysicsService:CreateCollisionGroup("Player")
PhysicsService:CreateCollisionGroup("Decor")
PhysicsService:CollisionGroupSetCollidable("Player", "Decor", false)

character:SetAttribute("CollisionGroup", "Player")
decorPart.CollisionGroup = "Decor"

⚠️ CollisionGroup работает только для BasePart, не для Model.


11.4 Рендеринг — геометрия, UI, частицы

11.4.1 Геометрия
Параметр Оптимизация
Количество частей ≤ 10 000 на сцену (рекомендовано ≤ 5 000)
MeshPart Использовать CollisionFidelity = Hull (не Precise)
Текстуры 512×512 для мобильных, 1024×1024 — только для ПК; общая сумма VRAM ≤ 512 MB
Прозрачность Избегать Transparency ∈ (0, 1) — только 0 или 1. Промежуточные значения → alpha sorting → лаги.

11.4.2 UI
Проблема Решение
TextLabel с TextWrapped = true Кэшировать размер через TextService:GetTextSize()
Частые :TweenPosition() Использовать TweenService:Create() один раз, затем :Play()
ScrollingFrame с 1000+ элементами Виртуализация: отрисовывать только ViewportSize / ItemSize + 2 элементов

11.4.3 Частицы
Компонент Лимит Совет
ParticleEmitter ≤ 10 активных Останавливать через Enabled = false, не удалять
Общее число частиц ≤ 10 000 Rate × Lifetime ≤ 500 на эмиттер
Trail, Beam ≤ 50 Использовать MinLength, FaceCamera = false для оптимизации

11.5 Сеть — репликация и лимиты

11.5.1 Что реплицируется автоматически
Тип Примеры Частота
Свойства Instance CFrame, Velocity, Transparency, Color у BasePart Адаптивно (до 30 Гц)
Value-объекты StringValue, NumberValue, BoolValue При изменении
Sound TimePosition, Playing При изменении
Humanoid Health, MoveDirection, Jump До 20 Гц

11.5.2 Что не реплицируется
  • LocalScript, PlayerGui, CoreGui
  • Свойства с ReadOnly на клиенте
  • Пользовательские атрибуты, установленные через :SetAttribute() на клиенте
  • Изменения в ServerStorage, ServerScriptService

11.5.3 Оптимизация трафика
  • Объединять данные:
  -- Плохо:
  Remote:FireServer("move", x)
  Remote:FireServer("move", y)
  Remote:FireServer("move", z)
  
  -- Хорошо:
  Remote:FireServer("move", Vector3.new(x, y, z))
  • Использовать Debounce для MoveDirection:
  if (newDir - lastDir).Magnitude > 0.1 then
      Remote:FireServer("dir", newDir)
      lastDir = newDir
  end
  • Для частых обновлений (например, HP) — использовать NumberValue вместо RemoteEvent.

11.6 Память — анализ и утечки

11.6.1 Мониторинг
  • View → Memory в Studio:
    • Allocations — новые объекты за последние 5 сек
    • Instances — количество Instance по классам
    • Lua Memory — использование кучи Lua

11.6.2 Признаки утечек
Симптом Причина Решение
Instance count растёт линейно Не вызван :Destroy() Использовать Janitor
Lua Memory > 50 MB Замыкания, глобальные таблицы Избегать global = {}, использовать local
Debris не удаляет объекты Циклические ссылки Не сохранять Instance в замыканиях

11.6.3 Debris — отложенное удаление
local Debris = game:GetService("Debris")

-- Автоудаление через 5 сек
Debris:AddItem(part, 5)

-- Удаление при изменении родителя (защита от утечек)
part.AncestryChanged:Connect(function(_, parent)
    if not parent then
        Debris:AddItem(part, 0.1)
    end
end)

⚠️ Debris работает только для Instance, не для соединений или таймеров.


11.7 RunService — управление выполнением

Свойство/Метод Контекст Назначение
:IsServer() / :IsClient() Both Определение среды
:IsStudio() Both Проверка запуска в Studio
:IsRunning() Both Игра запущена (не в Studio idle)
Heartbeat Client Для UI, анимаций, предиктивных эффектов
RenderStepped Client Устаревшее. Используйте Heartbeat.
Stepped Server Для физики, перемещения, синхронных расчётов
BindToRenderStep(name, priority, func) Client Вставка в pipeline рендеринга (редко)

⚠️ Никогда не используйте while true do wait() ... end — заменяйте на события (Stepped, Heartbeat).


11.8 NetworkServerStats и NetworkClientStats

Доступны через Stats:

Метрика Описание
IncomingReplicationLag Задержка получения данных от сервера (клиент)
OutgoingReplicationLag Задержка отправки данных клиентам (сервер)
PacketLoss Доля потерянных пакетов (%)
BytesPerSecond Скорость трафика (байт/сек)

При PacketLoss > 5% или Lag > 0.2 — снижать частоту обновлений, упрощать геометрию.


Ошибки

Ситуация Что проверить
Команда не найдена PATH, установка пакета, alias
Permission denied пользователь, группа, sudo, ACL
Неверная версия см. "Совместимость", --version

В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

СправочникиСправочник по Kubernetes, Справочник по Unity, Справочник по Docker, Справочник по Adobe Photoshop, Справочник по Apache Kafka, Справочник по RabbitMQ.