Queríamos agregar una interfaz de mapa interactiva para permitir a los usuarios consumir información en la estación espacial que se viera y se sintiera como si viviera en este mundo. Decidimos construir el mapa dentro del espacio 3D en lugar de en una pantalla que se superpuso a la experiencia. Este tipo de visualización diegética permite una mayor inmersión en el mundo, en lugar de sentir que es una experiencia completamente separada.
Diseñar el mapa
Para diseñar el mapa:
Diseñamos la interfaz en una aplicación externa y elaboramos una idea aproximada de cómo queríamos que se viera.

Exportamos las piezas individuales del mapa como .png e importamos en Studio.

Construir el mapa
Construir el mapa dentro de Studio implicó usar Parts y SurfaceGuis.
Para los elementos no interactivos, todo lo que necesitábamos hacer era agregar un objeto SurfaceGui a la parte.
Para los elementos interactivos, el SurfaceGui también debe estar dentro del contenedor StarterGui, con la propiedad Adornee vinculada a la parte apropiada en el espacio de trabajo 3D. Hacerlo permite agregar eventos de botón.
Para lograr un efecto de paralaje, utilizamos tres instancias separadas de ScreenGui asignadas a tres Parts únicos con diferentes valores de X.

Luego agregamos un efecto de resplandor con la propiedad SurfaceGui.LightInfluence. Si configuras el valor de la propiedad a menos de 1, habilita la propiedad SurfaceGui.Brightness. Al ajustar el brillo, puedes aumentar el resplandor que emite la imagen.
Para permitir a los usuarios alternar la visualización del mapa, utilizamos un ProximityPrompt que adjuntamos a un modelo 3D. Esta es una forma fácil de permitir la interacción del usuario con los elementos del mundo.

Finalmente, utilizando un ModuleScript UITweenModule dentro de ReplicatedStorage, animamos el ocultar y mostrar la UI con TweenService y un poco de lógica para determinar el estado. Al rastrear lo que el usuario hizo clic, pudimos ocultar y mostrar elementos al utilizar tween para varias propiedades como alfa, posición y tamaño.
UITweenModule ModuleScriptlocal TweenService = game:GetService("TweenService")local UITween = {}-- para desvanecer imágenesfunction UITween.fadePart(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quad, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay --Tiempo de Delayed)local tween = TweenService:Create(object, tweenAlpha, {Transparency = amount})tween:Play()endfunction UITween.fade(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quad, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay --Tiempo de Delayed)local tween = TweenService:Create(object, tweenAlpha, {ImageTransparency = amount})tween:Play()end-- para desvanecer imágenesfunction UITween.fadeBackground(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quad, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay --Tiempo de Delayed)local tween = TweenService:Create(object, tweenAlpha, {BackgroundTransparency = amount})tween:Play()end-- para desvanecer textofunction UITween.fadeText(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quad, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay --Tiempo de Delayed)local tween1 = TweenService:Create(object, tweenAlpha, {TextTransparency = amount})tween1:Play()end-- para mover texto e imágenesfunction UITween.move(object, position, time, delay)task.wait(delay)object:TweenPosition(position, Enum.EasingDirection.Out, Enum.EasingStyle.Quint, time)end-- para cambiar el tamañofunction UITween.size(object, size, time, delay, override, callback)local tweenSize = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quint, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay, --Tiempo de Delayedoverride,callback)local tween = TweenService:Create(object, tweenSize, {Size = size})tween:Play()endfunction UITween.rotate(object, rotation, time, delay, override, callback)local tweenSize = TweenInfo.new(time, --TiempoEnum.EasingStyle.Quint, --Estilo de EasingEnum.EasingDirection.Out, --Dirección de Easing0, --Repeticionesfalse, --Reversa si es verdaderodelay, --Tiempo de Delayedoverride,callback)local tween = TweenService:Create(object, tweenSize, {Rotation = rotation})tween:Play()end-- para desenfocar la cámara del juegofunction UITween.blur(object, amount, time)local tweenInfo = TweenInfo.new(time, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)local tween = TweenService:Create(object, tweenInfo, {Size = amount})tween:Play()end-- para encender el brillo de la cámara del juegofunction UITween.turnOn(object, amount, time)local tweenInfo = TweenInfo.new(time, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)local tween = TweenService:Create(object, tweenInfo, {Brightness = amount})tween:Play()endreturn UITweenAplicando UI Tween a Objetoslocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- Agregar módulo UITweenlocal UITween = require(ReplicatedStorage.UITweenModule)-- Encontrar Guis del jugador y objetos de UIlocal playerGui = game:GetService('Players').LocalPlayer:WaitForChild('PlayerGui')local screenGuiMapUIFrame = playerGui:WaitForChild("ScreenGuiMapUIFrame").SurfaceGuilocal mapUIFrameStroke = screenGuiMapUIFrame.FrameStrokelocal mapUIFrameFill = screenGuiMapUIFrame.FrameFill-- Tamaños usados para Tweeninglocal frameSizeStart = UDim2.new(0, 0, 0, 0)local frameSizeMid = UDim2.new(1, 0, 0.05, 0)local frameSizeEnd = UDim2.new(1, 0, 1, 0)-- Ejemplo de TweeningUITween.fade(mapUIFrameStroke, 0, 2, 0)UITween.size(mapUIFrameStroke, frameSizeMid, 0.4, 0)UITween.fade(mapUIFrameFill, 0, 2, 0.5)UITween.size(mapUIFrameFill, frameSizeEnd, 0.4, 0.25)task.wait(0.25)UITween.size(mapUIFrameStroke, frameSizeMid, 0.4, 0)UITween.size(mapUIFrameFill, frameSizeMid, 0.4, 0.25)task.wait(0.25)UITween.size(mapUIFrameStroke, frameSizeEnd, 0.4, 0)UITween.size(mapUIFrameFill, frameSizeEnd, 0.4, 0.25)
Aquí está el resultado final del mapa interactivo: