Queríamos adicionar uma interface de mapa interativa para permitir que os usuários consumissem informações na estação espacial de uma forma que parecesse e se sentisse como parte deste mundo. Decidimos criar o mapa dentro do espaço 3D em vez de em uma tela que sobrepõe a experiência. Este tipo de visualização diegética permite uma maior imersão no mundo, em vez de parecer que é uma experiência completamente separada.
Projetar o mapa
Para projetar o mapa:
Nós mockamos a interface em um aplicativo externo e chegamos a uma ideia inicial de como queríamos que ela parecesse.

Exportamos as peças individuais do mapa como .png e as importamos para o Studio.

Construir o mapa
Construir o mapa dentro do Studio envolveu usar Parts e SurfaceGuis.
Para elementos não interativos, tudo o que precisávamos fazer era adicionar um objeto SurfaceGui à parte.
Para elementos interativos, o SurfaceGui também precisa estar dentro do contêiner StarterGui, com a propriedade Adornee vinculada à parte apropriada no espaço 3D. Ao fazer isso, você pode adicionar eventos de botão.
Para conseguir um efeito de paralaxe, usamos três instâncias separadas de ScreenGui atribuídas a três Parts únicos com diferentes valores de X.

Em seguida, adicionamos um efeito de brilho com a propriedade SurfaceGui.LightInfluence. Se você definir o valor da propriedade para qualquer coisa menor que 1, isso ativa a propriedade SurfaceGui.Brightness. Ajustando o brilho, você pode aumentar o brilho emitido pela imagem.
Para permitir que os usuários alternem a exibição do mapa, usamos um ProximityPrompt que anexamos a um modelo 3D. Esta é uma maneira fácil de permitir a interação do usuário com elementos do mundo.

Finalmente, usando um ModuleScript UITweenModule dentro do ReplicatedStorage, animamos o ocultamento e a exibição da UI com TweenService e um pouco de lógica para determinar o estado. Ao rastrear o que o usuário clicou, pudemos ocultar e mostrar elementos tweenando várias propriedades, como alfa, posição e tamanho.
UITweenModule ModuleScriptlocal TweenService = game:GetService("TweenService")local UITween = {}-- para desvanecer imagensfunction UITween.fadePart(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TempoEnum.EasingStyle.Quad, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay --Tempo de atraso)local tween = TweenService:Create(object, tweenAlpha, {Transparency = amount})tween:Play()endfunction UITween.fade(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TempoEnum.EasingStyle.Quad, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay --Tempo de atraso)local tween = TweenService:Create(object, tweenAlpha, {ImageTransparency = amount})tween:Play()end-- para desvanecer imagensfunction UITween.fadeBackground(object, amount, time, delay)local tweenAlpha = TweenInfo.new(time, --TempoEnum.EasingStyle.Quad, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay --Tempo de atraso)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, --TempoEnum.EasingStyle.Quad, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay --Tempo de atraso)local tween1 = TweenService:Create(object, tweenAlpha, {TextTransparency = amount})tween1:Play()end-- para mover texto e imagensfunction UITween.move(object, position, time, delay)task.wait(delay)object:TweenPosition(position, Enum.EasingDirection.Out, Enum.EasingStyle.Quint, time)end-- para mudar o tamanhofunction UITween.size(object, size, time, delay, override, callback)local tweenSize = TweenInfo.new(time, --TempoEnum.EasingStyle.Quint, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay, --Tempo de atrasooverride,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, --TempoEnum.EasingStyle.Quint, --EasingStyleEnum.EasingDirection.Out, --EasingDirection0, --Contagem de repetiçãofalse, --Reverte se verdadeirodelay, --Tempo de atrasooverride,callback)local tween = TweenService:Create(object, tweenSize, {Rotation = rotation})tween:Play()end-- para desfocar a câmera do jogofunction 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 ativar o brilho da câmera do jogofunction 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")-- Adicionar Módulo UITweenlocal UITween = require(ReplicatedStorage.UITweenModule)-- Encontrar Guis e objetos UI do jogadorlocal playerGui = game:GetService('Players').LocalPlayer:WaitForChild('PlayerGui')local screenGuiMapUIFrame = playerGui:WaitForChild("ScreenGuiMapUIFrame").SurfaceGuilocal mapUIFrameStroke = screenGuiMapUIFrame.FrameStrokelocal mapUIFrameFill = screenGuiMapUIFrame.FrameFill-- Tamanhos 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)-- Exemplo 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)
Aqui está o resultado final do mapa interativo: