Desarrollo / ROBLOX
ProximityPrompt en Roblox: estación de práctica con E, mando y pantalla táctil
Crea una lámpara anclada independiente con Attachment y ProximityPrompt. Etiquetas claras, visibilidad, comprobaciones del servidor y un plan de pruebas por dispositivo.
Una estación y una acción comprensible #
Imagina un prototipo independiente: la persona se acerca a una lámpara pequeña y cambia su luz. En vez de buscar un botón invisible, ve objeto, acción e indicación de entrada adecuada. Usamos un ProximityPrompt estándar y un Script de servidor normal. No hay recompensas, moneda ni compras.
Es un ejercicio independiente, no un cambio en Paws and Finds, Cloud Nests u otros juegos del autor. El código original requiere la estructura indicada. Una comprobación estática no significa haberlo ejecutado en Studio. Guarda un proyecto de práctica separado, reproduce los nombres y define el resultado: cambia la luz y el color compartidos de la estación, no un inventario personal.
1. Construye la jerarquía exacta en Explorer #
En Workspace crea un Part llamado PracticeStation. Dentro añade un Attachment llamado PromptAnchor y un PointLight llamado PracticeLight. Dentro de PromptAnchor añade un ProximityPrompt llamado SwitchPrompt. Son dos ramas: luz dentro de la pieza, prompt dentro del attachment. No coloques el prompt al lado del attachment por costumbre.
Crea un Script normal llamado PracticeStationServer en ServerScriptService, actívalo y establece RunContext en Server. Un LocalScript no lo sustituye. Los nombres deben coincidir exactamente. WaitForChild espera ese nombre, no crea objetos ausentes. Ante una espera, compara Explorer y diagrama antes de cambiar distancias. Si SwitchPrompt está en otra rama, es un problema de estructura, no de alcance, y aumentar un número no lo resuelve.
2. Ancla la lámpara y sitúa el punto del prompt #
Para el ejercicio establece PracticeStation: Anchored=true, Size=(4,2,4), Position=(0,3,0). Son valores de nuestro ejemplo, no requisitos del motor. Coloca un SpawnLocation cerca y fuera de la pieza para poder acercarte. PromptAnchor.Position=(0,2,0) es una posición local respecto a la estación, no una coordenada mundial independiente.
Puedes comenzar PracticeLight con Brightness=2 y Range=12. El script empieza con la luz apagada. No añadas modelos complejos, uniones móviles o un sistema de recompensas existente para esta prueba. La pieza anclada ofrece una referencia estable; el servidor mide después hasta anchor.WorldPosition. Si mueves el attachment, cambia el punto de interacción: repite la comprobación del límite en lugar de confiar en el aspecto anterior.
3. Nombra el objeto y la acción en tu idioma #
ObjectText responde «¿qué es?» y ActionText «¿qué haré?». Para la escena española elegimos «Lámpara de práctica» y «Cambiar la luz». El código contiene pares para ru/en/de/es/zh/ar. Elige el idioma de esta escena con UI_LANGUAGE, por ejemplo "es". No traduzcas los nombres de Explorer PracticeStation y SwitchPrompt.
Esto configura un idioma para todo el servidor de prueba, no automáticamente el de cada jugador. AutoLocalize=false conserva las cadenas seleccionadas sin sustitución automática. Un juego publicado multilingüe necesita su propio diseño de localización y pruebas de textos largos. Conserva el significado en vez de escribir E dentro de ActionText: el prompt estándar muestra la indicación según la entrada actual. El diccionario es una configuración de ejercicio, no localización completa.
4. Distingue teclado, mando y pulsación en pantalla #
El ejemplo usa KeyboardKeyCode=E, GamepadKeyCode=ButtonX y ClickablePrompt=true. No prometas una letra E a todos: la entrada activa influye en la presentación estándar. Teléfonos y tabletas pueden interactuar pulsando en pantalla; incluso ClickablePrompt=false no prohíbe esa pulsación móvil. La propiedad no es un interruptor general del acceso táctil.
HoldDuration=0.3 pide mantener pulsado en la interfaz normal; 0 activaría inmediatamente. Elegimos 0.3 para practicar, no como valor óptimo medido. Prueba una pulsación corta, una completa y soltar. El inicio del mantenimiento no es permiso para producir el resultado. El evento de interacción completada usado en nuestro servidor es Triggered, no el evento de empezar a mantener la entrada.
5. Visibilidad y permiso de acción son distintos #
MaxActivationDistance=10 determina el alcance de aparición. RequiresLineOfSight=true considera el trayecto libre entre cámara y objeto; no equivale a medir entre HumanoidRootPart y Attachment. Una pared o posición de cámara puede ocultar la interfaz incluso cerca de la estación. Comprueba una causa cada vez: distancia y después vista.
Un prompt oculto no sustituye una regla de acceso del servidor. Las propiedades de interfaz pueden cambiar en el cliente. El ejemplo comprueba personaje vivo, distancia y estación prevista, pero no implementa una prohibición del servidor de interactuar a través de paredes. Si el obstáculo importa, diseña una comprobación adicional según tus reglas. No presentes RequiresLineOfSight como protección completa para una puerta o compra.
| Ajuste | Valor del ejemplo | Qué comprobar |
|---|---|---|
| ActionText / ObjectText | Cambiar la luz / Lámpara de práctica | Acción y objeto nombrados; UI_LANGUAGE="es" |
| KeyboardKeyCode / GamepadKeyCode | E / ButtonX | Indicación adecuada a la entrada actual |
| ClickablePrompt | true | Clic y touch; false no prohíbe la pulsación móvil |
| HoldDuration | 0.3 segundos | Pulsación corta/completa y cancelación |
| MaxActivationDistance | 10 | Límite de aparición y distancia separada del servidor |
| RequiresLineOfSight | true | Vista de cámara, no permiso del servidor |
| COOLDOWN | 0.5 segundos, compartido | Repetición rápida no cambia la lámpara |
6. Conecta un único controlador del servidor #
Pega el ejemplo original siguiente en PracticeStationServer. Primero encuentra cuatro objetos, comprueba clases, elige etiquetas y configura propiedades. Después establece la luz apagada. No ejecutes otra copia a la vez: dos controladores pueden cambiar el estado dos veces y aparentar que no pasó nada.
Triggered entrega el jugador que completó la interacción. El servidor encuentra su personaje y comprueba condiciones antes de cambiar la lámpara. No hay espera entre comprobar el intervalo y cambiar el estado. No añadimos RemoteEvent, solicitud de precio ni guardado: solo cambiamos una lámpara compartida. Si confundes clase y ubicación de ejecución, lee primero la guía sobre Script, LocalScript y ModuleScript antes de ampliar el ejercicio.
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. Lee las condiciones anteriores al cambio #
El controlador requiere jugador en Players, prompt activo y estación anclada en Workspace. Después necesita personaje en el mundo, Humanoid con Health>0 y HumanoidRootPart de tipo BasePart. El servidor calcula la distancia a PromptAnchor.WorldPosition y compara con las mismas diez unidades del ejemplo. Estados ausentes o inadecuados dejan la luz igual.
La documentación señala que Triggered tiene comprobación propia de distancia en el servidor, mientras que otros eventos del prompt no. Nuestra comprobación explícita expresa además la regla del prototipo. HoldDuration no demuestra un mantenimiento honesto en el cliente. No es protección completa para cualquier sistema: permisos, obstáculos y recursos adicionales dependen de la acción, que aquí no necesita condiciones de recompensa.
8. Comprende el estado compartido y la pausa #
isOn es un estado de estación en este servidor. Una acción aceptada cambia PointLight.Enabled, el color del Part y el atributo PracticeLightOn. Otro cliente con esta estación disponible debería observar el mismo estado compartido. No es una luz personal para cada jugador. Otro servidor o un inicio nuevo comienza apagado porque no existe guardado.
COOLDOWN=0.5 es una pausa común elegida para demostrar. Una solicitud siguiente demasiado rápida no cambia la luz. Es distinta del tiempo de mantenimiento y no promete controlar toda carga posible. En la prueba de dos clientes deja la pausa: A enciende, B observa, B cambia, A observa. La acción aceptada de B no demuestra que se rompiera el estado de A.
9. Cuándo sirve ProximityPromptService #
Para una estación basta prompt.Triggered. ProximityPromptService puede observar varios prompts desde un lugar común; PromptTriggered recibe primero el prompt y luego el jugador. Al ampliar, decide qué estaciones se admiten, en lugar de realizar una operación para cualquier prompt encontrado en el mundo.
No conectes sin motivo un controlador de instancia y otro global a la misma lámpara: una acción podría procesarse dos veces. Los eventos de aparición y desaparición sirven para presentación del cliente, especialmente con UI propio. Style=Default ya ofrece la interfaz estándar, así que no hace falta un LocalScript que la dibuje. Estudia estilos personalizados después de una estructura funcional y una operación clara. Centralizar no elimina la validación de cada acción.
10. Identifica una causa cuando no aparece nada #
Si falta el prompt, comprueba jerarquía, Enabled, distancia, Style y cámara. En escenas densas varios prompts pueden competir según Exclusivity; la primera prueba usa deliberadamente una estación. No cambies todas las propiedades a la vez. Acércate con vista libre, modifica un ajuste y anota el resultado.
Si aparece pero no cambia la luz, comprueba Output del servidor, clase del Script, RunContext, nombres y pausa. Si cambia el color sin iluminar, revisa por separado PointLight, Range, Brightness y la escena. Los rechazos usan return sin imprimir el motivo; compara personaje y estación con las condiciones del código. El atributo del servidor distingue estado lógico e impresión de brillo. La tabla de escenarios conserva resultados vacíos hasta una comprobación real; un resultado esperado todavía no es una observación.
| Escenario | Expectativa del ejemplo | Dispositivo / versión / resultado |
|---|---|---|
| Personaje vivo cercano, entrada completa | Luz, color y atributo cambian una vez | — |
| Mantener poco y soltar | No se espera acción completada en UI normal | — |
| Personaje lejano/muerto o prompt desactivado | El controlador conserva el estado | — |
| Repetir antes de terminar la pausa | Sin segundo cambio | — |
| Dos clientes y acciones tras la pausa | Ambos observan la estación compartida | — |
| Teléfono/mando e idioma elegido | Entrada correcta y textos legibles | — |
11. Separa el texto comprobado de una prueba del motor #
Comprobamos la estructura del material y las API frente a referencias oficiales. El ejemplo pasó el compilador Luau y 13 comprobaciones aisladas del controlador con objetos simulados. El código no se ejecutó en Roblox Studio ni en teléfono o mando reales. En el proyecto independiente inicia primero con un jugador; prueba distancia, mantener y cancelar, desactivar el prompt y repetir rápidamente.
Usa Test/F5 con personaje; Run/F8 sin personaje no sustituye esta prueba de interacción. Para dos clientes elige Server & Clients y termina con End Session. Después comprueba los dispositivos necesarios, guardando versión y observaciones. La emulación ayuda con la distribución, pero no sustituye entrada ni rendimiento reales. Aplicarlo a entregar mascotas o comprar sería otro sistema con permisos, entregas coherentes y pruebas propias. Primero consigue un resultado comprensible en una lámpara sencilla. Un ejemplo pequeño y concreto resulta más fácil de explicar y transferir a otro desarrollador.
Fuentes originales
Roblox Creator Hub — Proximity promptsProximityPrompt
ProximityPromptService
Securing the client-server boundary
Studio testing modes