Roblox GuidebookБаза знаний
Русский ⌄

Разработка / ROBLOX

ProximityPrompt в Roblox: учебная станция с E, геймпадом и touch

Создайте отдельную закреплённую лампу с Attachment и ProximityPrompt. Понятные подписи, условия видимости, серверная проверка и план испытаний на разных устройствах.

Где находятся станция и скриптОткрыть изображение крупнее ↗
Авторская схема: точные имена нужны коду.
Обновлено:

Одна станция, одно понятное действие #

Представьте отдельный прототип: игрок подходит к небольшой лампе и переключает её свет. Вместо поиска невидимой кнопки он видит имя объекта, действие и подходящую подсказку ввода. Мы используем стандартный ProximityPrompt и обычный серверный Script. Ни наград, ни валюты, ни покупок в примере нет.

Это самостоятельное упражнение, а не исправление Paws and Finds, Cloud Nests или других игр автора. Код ниже написан для описанной структуры. Его статическая проверка не означает запуск в движке Studio. Сначала сохраните отдельный учебный проект, соберите имена точно по схеме и определите ожидаемый результат: меняются общий свет и цвет станции, а не личный инвентарь.

1. Соберите точную структуру в Explorer #

В Workspace добавьте Part с именем PracticeStation. Внутри него нужны Attachment с именем PromptAnchor и PointLight с именем PracticeLight. В PromptAnchor добавьте ProximityPrompt с именем SwitchPrompt. Это две ветки: свет — ребёнок детали, подсказка — ребёнок вложенного Attachment. Не кладите Prompt рядом с Attachment по привычке.

В ServerScriptService создайте обычный Script PracticeStationServer, включите его и установите RunContext в Server. Не заменяйте его LocalScript. Имена объектов в коде чувствительны к написанию. WaitForChild ждёт конкретное имя, а не создаёт недостающий объект. При ожидании сначала сравните дерево Explorer со схемой: исправлять логику расстояния бессмысленно, если SwitchPrompt находится в другой ветке.

2. Закрепите лампу и поставьте точку подсказки #

Для упражнения задайте PracticeStation: Anchored=true, Size=(4,2,4), Position=(0,3,0). Эти размеры и координаты — наши учебные значения, а не требование движка. Поставьте SpawnLocation рядом, вне детали, чтобы персонаж мог подойти. У PromptAnchor задайте Position=(0,2,0): это локальная позиция относительно станции, не самостоятельная мировая координата.

У PracticeLight можно выбрать Brightness=2 и Range=12 как стартовые значения. Скрипт начинает с выключенного света. Не добавляйте сложную модель, подвижные соединения или готовую систему наград ради этой проверки. Закреплённая деталь даёт стабильный ориентир; сервер затем измеряет расстояние до anchor.WorldPosition. Если переставляете Attachment, меняется точка взаимодействия, поэтому повторите проверку границы.

3. Подпишите объект и действие своим языком #

ObjectText отвечает на вопрос «что это?», ActionText — «что я сделаю?». Для русской сцены мы выбрали «Учебная лампа» и «Переключить свет». Код содержит пары для ru/en/de/es/zh/ar. В UI_LANGUAGE выберите язык этой учебной сцены: например, "ru". Названия PracticeStation и SwitchPrompt в Explorer при этом не переводятся.

Это один настроенный язык для всего тестового сервера, а не автоматический язык каждого игрока. AutoLocalize=false оставляет выбранные строки без автоматической подмены. Для настоящей многоязычной игры отдельно проектируют таблицу локализации и проверяют длинные строки. Важнее сохранить смысл действия, чем вписать E в ActionText: клавишу или экранный ввод показывает стандартная подсказка в зависимости от способа управления.

4. Разделите клавиатуру, геймпад и экранное нажатие #

В примере KeyboardKeyCode=E, GamepadKeyCode=ButtonX, ClickablePrompt=true. Не обещайте, что каждый пользователь увидит букву E: актуальный тип ввода влияет на стандартное отображение. На телефоне или планшете подсказка доступна для экранного нажатия; даже ClickablePrompt=false не запрещает мобильное нажатие. Этот параметр не является выключателем touch-доступа.

HoldDuration=0.3 задаёт удержание в обычном интерфейсе; 0 означало бы немедленное срабатывание. Значение 0.3 выбрано для упражнения и не измерено как лучший вариант. Попробуйте короткое и полное удержание, затем отпустите кнопку. Не используйте начало удержания как разрешение выдать результат. Нужное событие завершённого взаимодействия в нашем серверном примере — Triggered.

5. Видимость подсказки и разрешение действия различаются #

MaxActivationDistance=10 задаёт дальность появления подсказки. RequiresLineOfSight=true учитывает ясный путь от камеры к объекту; это не то же измерение, что расстояние от HumanoidRootPart до Attachment. При стене или иной позиции камеры интерфейс может скрыться даже рядом со станцией. Сначала проверяйте одну причину: дистанцию, затем обзор.

Скрытая подсказка не заменяет серверное правило доступа. Свойства интерфейса могут изменяться на клиенте. Этот пример дополнительно проверяет живого персонажа, расстояние и разрешённую станцию, но не реализует серверный запрет взаимодействия через стену. Если такая преграда важна для вашей механики, потребуется отдельная проверка препятствия по выбранным игровым правилам. Не выдавайте RequiresLineOfSight за готовую защиту двери или покупки.

ПараметрЗначение примераЧто проверить
ActionText / ObjectTextПереключить свет / Учебная лампаНазваны действие и объект; UI_LANGUAGE="ru"
KeyboardKeyCode / GamepadKeyCodeE / ButtonXПодсказка соответствует текущему вводу
ClickablePrompttrueКлик и touch; false не запрещает мобильное нажатие
HoldDuration0.3 секундыКороткое/полное удержание и отмена
MaxActivationDistance10Граница появления и отдельная серверная дистанция
RequiresLineOfSighttrueОбзор камеры; не серверное разрешение
COOLDOWN0.5 секунды, общийСлишком быстрый повтор не переключает лампу

6. Подключите один серверный обработчик #

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

Triggered передаёт игрока, завершившего взаимодействие. Сервер находит его персонажа и проверяет условия до изменения лампы. Между проверкой короткого интервала и сменой состояния нет ожидания. Мы не добавляем RemoteEvent, запрос цены или сохранение: всё действие — переключить подготовленную общую лампу. Если вы ещё не различаете место запуска и вид объекта, сначала прочитайте наш материал о расположении Script, LocalScript и ModuleScript.

local Players = game:GetService("Players")
local station = workspace:WaitForChild("PracticeStation")
assert(station:IsA("BasePart") and station.Anchored, "Anchor PracticeStation")
local anchor = station:WaitForChild("PromptAnchor")
assert(anchor:IsA("Attachment"), "PromptAnchor must be an Attachment")
local prompt = anchor:WaitForChild("SwitchPrompt")
assert(prompt:IsA("ProximityPrompt"), "SwitchPrompt must be a ProximityPrompt")
local light = station:WaitForChild("PracticeLight")
assert(light:IsA("PointLight"), "PracticeLight must be a PointLight")

local UI_LANGUAGE = "en" -- Choose one language for this whole test server.
local labels = {
    ru = {action = "Переключить свет", object = "Учебная лампа"},
    en = {action = "Switch light", object = "Practice lamp"},
    de = {action = "Licht umschalten", object = "Übungslampe"},
    es = {action = "Cambiar la luz", object = "Lámpara de práctica"},
    zh = {action = "切换灯光", object = "练习灯"},
    ar = {action = "تبديل الضوء", object = "مصباح التدريب"},
}
local words = assert(labels[UI_LANGUAGE], "Unknown UI_LANGUAGE")
local MAX_DISTANCE = 10
local COOLDOWN = 0.5
prompt.Style = Enum.ProximityPromptStyle.Default
prompt.AutoLocalize = false
prompt.ActionText = words.action
prompt.ObjectText = words.object
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.GamepadKeyCode = Enum.KeyCode.ButtonX
prompt.ClickablePrompt = true
prompt.HoldDuration = 0.3
prompt.MaxActivationDistance = MAX_DISTANCE
prompt.RequiresLineOfSight = true
prompt.Enabled = true

local isOn = false
local lastToggle = -COOLDOWN
light.Enabled = false
station.Color = Color3.fromRGB(70, 80, 95)
station:SetAttribute("PracticeLightOn", false)

prompt.Triggered:Connect(function(player)
    if player.Parent ~= Players or not prompt.Enabled then return end
    if not station:IsDescendantOf(workspace) or not station.Anchored then return end
    local character = player.Character
    if not character or not character:IsDescendantOf(workspace) then return end
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    local root = character:FindFirstChild("HumanoidRootPart")
    if not humanoid or humanoid.Health <= 0 then return end
    if not root or not root:IsA("BasePart") then return end
    local distance = (root.Position - anchor.WorldPosition).Magnitude
    if distance ~= distance or distance > MAX_DISTANCE then return end
    local now = os.clock()
    if now - lastToggle < COOLDOWN then return end
    lastToggle = now
    isOn = not isOn
    light.Enabled = isOn
    station.Color = isOn and Color3.fromRGB(255, 190, 80) or Color3.fromRGB(70, 80, 95)
    station:SetAttribute("PracticeLightOn", isOn)
end)

7. Прочитайте проверки до строки переключения #

Обработчик требует игрока в Players, включённую подсказку и закреплённую станцию в Workspace. Затем нужны персонаж в мире, Humanoid с Health>0 и HumanoidRootPart типа BasePart. Расстояние вычисляется на сервере до PromptAnchor.WorldPosition и сравнивается с теми же 10 единицами, которые выбраны для упражнения. Неизвестные или неподходящие состояния просто не меняют свет.

Документация отдельно указывает: Triggered имеет собственную серверную проверку расстояния, тогда как другие события подсказки её не имеют. Наш явный контроль всё равно выражает правило прототипа. HoldDuration не доказывает, что клиент честно удерживал ввод. Это не полноценная защита любой игровой системы: дополнительные права, препятствия и ресурсы зависят от задачи, которой здесь нет.

От ввода к общему светуОткрыть изображение крупнее ↗
Схема примера; не отчёт испытаний движка.

8. Поймите общее состояние и короткую паузу #

isOn — одно состояние станции на этом сервере. При принятом действии меняются PointLight.Enabled, цвет Part и атрибут PracticeLightOn. Другой клиент, которому доступна эта станция, должен наблюдать то же общее состояние. Это не персональное включение для каждого игрока. В другом сервере или после нового запуска пример начинает с выключенного света, поскольку сохранения нет.

COOLDOWN=0.5 — общая короткая пауза станции, выбранная для демонстрации. Слишком быстрый следующий запрос не переключает свет. Она отличается от времени удержания и не обещает универсального ограничения нагрузки. Во время проверки двух клиентов оставьте паузу между действиями: А включает, Б видит, Б переключает, А видит. Не считайте действие Б доказательством сбоя у А.

9. Когда нужен ProximityPromptService #

Для одной станции достаточно prompt.Triggered. ProximityPromptService позволяет слушать взаимодействия разных подсказок из общего места; у PromptTriggered аргументы начинаются с самой подсказки, затем идёт игрок. При расширении сначала определите, какие станции допускаются, вместо выполнения одной операции для любого найденного Prompt.

Не подключайте обработчик экземпляра и глобальный обработчик к той же лампе без причины: одно действие может обработаться дважды. События показа и скрытия используют при клиентском оформлении, особенно собственном UI. В этом уроке Style=Default уже даёт стандартный интерфейс, поэтому отдельный рисующий LocalScript не требуется. Кастомный стиль лучше разбирать после работающей структуры и понятной серверной операции.

10. Найдите конкретную причину, если ничего не видно #

Если подсказки нет, проверьте дерево, Enabled, расстояние, Style и положение камеры. В перегруженной сцене несколько подсказок могут конкурировать по правилам Exclusivity; наша первая проверка специально содержит одну станцию. Не переключайте все параметры сразу. Сначала подойдите ближе при открытом обзоре, затем меняйте одну настройку и записывайте результат.

Если подсказка видна, но свет не меняется, проверьте Output сервера, тип и RunContext Script, точные имена и принятую паузу. Если цвет меняется, а окружение не освещается, отдельно посмотрите PointLight, Range, Brightness и условия сцены. Отказы в обработчике используют тихий return без печати причины; сопоставьте условия персонажа и станции с кодом. Серверный атрибут помогает отличить результат логики от впечатления о яркости. Таблица сценариев ниже оставляет результаты пустыми до вашей реальной проверки.

СценарийОжидание для примераУстройство / версия / результат
Живой персонаж рядом, полный вводСвет, цвет и атрибут меняются один раз—
Короткое удержание и отпусканиеВ обычном UI завершённое действие не ожидается—
Дальняя или мёртвая фигура; Prompt выключенОбработчик не меняет состояние—
Быстрый повтор раньше паузыСостояние не переключается снова—
Два клиента, действия после паузыОба наблюдают общую станцию—
Телефон/геймпад и нужный языкПравильный ввод и читаемые подписи—

11. Отделите проверенный текст от проверки движка #

Для этого материала проверены структура статьи и используемые API по официальной справке. Пример прошёл компиляцию Luau и 13 изолированных проверок обработчика с заменителями объектов движка. Код не запускался в Roblox Studio и не проверялся на реальном телефоне или геймпаде. В отдельном учебном проекте выполните первый запуск с игроком, затем испытайте расстояние, отмену удержания, отключение Prompt и быстрое повторение.

Для взаимодействия используйте Test/F5 с персонажем; Run/F8 без персонажа его не заменяет. Для двух клиентов выберите Server & Clients; завершайте испытание через End Session. После этого проверьте нужные устройства, сохранив версию проекта и наблюдения. Эмуляция помогает увидеть компоновку, но не заменяет испытание реального ввода и производительности. Если хотите перенести идею на выдачу питомца или покупку, это будет другая система с правами, согласованной выдачей и отдельными тестами. Сначала добейтесь понятного результата у одной безопасной учебной лампы; такой образец легче обсуждать с другим разработчиком.

Первоисточники

Roblox Creator Hub — Proximity prompts
ProximityPrompt
ProximityPromptService
Securing the client-server boundary
Studio testing modes