Button on SurfaceGui only active sometimes after switching off and on AlwaysOnTop

The title is self-explanatory

I’m trying to make a game with no UI, so everything has to be either SurfaceGuis or other in-game things.

The SurfaceGui is:

  • Changed at the start of the game (to the viewmodel)
  • On a mid-small part
  • The button has the highest Zindex of every Gui object
  • Nothing else in the way is set to active or interactable

First loading into the game, it does this:

Then, to make the button work, I have to disable and enable AlwaysOnTop on the SurfaceGui. Sometimes it still doesn’t work and it has to wait or something:

I’ve looked into a couple of posts but none seemed to have the same issue I had.

3 Likes

You’ll need to wait for the GUI to redraw.

local button = gui:WaitForChild("Button")
button.Active = false
task.wait(0.1)
button.Active = true

Or

local gui = script.Parent
gui.AlwaysOnTop = false
task.wait(0.1)
gui.AlwaysOnTop = true

Even a Heartbeat for the wait.

local RunService = game:GetService("RunService")
local button = gui:WaitForChild("Button")
button.Active = false
RunService.Heartbeat:Wait()
button.Active = true
1 Like

thanks for the response

it doesn’t work

although it seems that after around 30 seconds (whether or not using your code) it seems to work like intended.

it works normally on bigger surfaces:

1 Like

Sweet. Probably needed to load up where it was. I really didn’t think my script as is would work..
Test speculating.. always have to test that stuff till you got it.. should have been close.

well, it still doesn’t work as intended since it needs to wait for some time each time the game loads. Do you have any other solutions for that? Like maybe forcibly load the Gui using a script

Also what do you mean “should have been close”

You can use the ReplicatedFirst container if you want things to be prioritised when loading

but what if the guis are already in the starterGui? should I put them in replicatedFirst or StarterGui?

Add a localscript to ReplicatedFirst, then place the GUI as a child of that script, instead of anywhere in StarterGUI. Then write

local Players = game:GetService("Players")
local player = Players.LocalPlayer
local PlayerGui = player:WaitForChild("PlayerGui")

local ClonedGUI = script:WaitForChild("whatever your GUI is called"):Clone()
ClonedGUI.Parent = PlayerGui

in the localscript

it doesn’t work, it does literally the same thing as before

Sorry to hear that, I guess it’s not a loading time issue. Have you connected any functions to the button? If not try to connect it to a simple print to figure out if this bug is purely visual or the actual click isn’t working. This of course won’t solve anything but will at least guide us in the right direction.

I have a function connected to the button that prints a message when the mouse enters, and it only works when the button is darkened when hovering (or when it’s loaded)

So its not just visual

This is a very strange problem…

Pretty stumped tbh, but I’ve read around and found a few cases of Zindex being set to -1 by default causing AlwaysOnTop to not work. Make sure that by changing any properties of the GUI you aren’t somehow resetting the Zindex to -1. Simplest way to check this is to find your button in your PlayerGUI in explorer while testing and replicate the bug while keeping track of the AlwaysOnTop and Zindex values.

There is no problem with the Z-Index, it was never -1 from my experience (I triple checked everything)

It is important to note that NOTHING works with input things, like scrolling frames.

I really need this thing solved for my game because there is pretty much 0 other alternative if I want to do the thing I want to do.

Yea this is very strange. Could you try to recreate this bug in as simple a roblox studio file as possible? I could try to mess around with it tomorrow and find a solution.

In the meantime you could try manually setting the Z-index in the script just before/after turning on alwaysontop, as well as triple checking that no other surfaceguis could be overlapping your given one (if you have not already done these).

I tried somethings, here’s what I’ve done:

The screen, when the game starts, is on a part, and with a local script I change it to be on the viewmodel’s screen

I tried to change the size and the CFrame of the part with the initial screen every render step to the viewmodel’s screen using a localscript, and I was able to interact with the stuff in the SurfaceGui.
Although, using this method of changing the screen’s CFrame, the screen has a delay when moving in the 3D space.

I then used this quick local script to weld them together

WorkspaceScreen.Size = ViewmodelScreen.Size + Vector3.new(1,0,0)
WorkspaceScreen.CFrame = ViewmodelScreen.CFrame

local ScreenWeld = Instance.new("WeldConstraint")
ScreenWeld.Parent = WorkspaceScreen
ScreenWeld.Part0 = ViewmodelScreen
ScreenWeld.Part1 = WorkspaceScreen

WorkspaceScreen.Anchored = false

Now, the workspace (initial) screen is glued to the viewmodel screen, but now the screen isn’t interactable. So what gives?

I hope this helps the case.

Maybe keep the WorkspaceScreen anchored and positioned via CFrame updates, not welded into the assembly. SurfaceGuis get input properly if the host part is anchored in world space.

Again test scripting.

local ws = workspace
local vm = ws:WaitForChild("ViewmodelScreen")
local scr = ws:WaitForChild("WorkspaceScreen")
local rs = game:GetService("RunService")

scr.Anchored = true

rs.RenderStepped:Connect(function()
	scr.CFrame = vm.CFrame
	scr.Size = vm.Size
end)

I said it before, but I didn’t give a clip to show, so here it is:

It is interactable but using this method makes it so that the screen has lag when changing the CFrame

Strangely, it doesn’t have the same CFrame latency when using animations from the viewmodel (the animation of the arm showing the agent)

Oh.. so close. Maybe lock them from moving.

edit:
I went and looked a few games that did this and sure enough the player can’t move.
I think you may have found out why..

My gut instinct is you have the SurfaceGui parented to the part that its displaying on, instead of being parented to your PlayerGui and changing the SurfaceGui.Adornee property. Would cause exactly these issues with this pattern of everything or nothing working.

I think I’ll do that, it’s sad that I need to do a band-aid solution like this but I see no other alternatives. Thanks for the help, I’ll mark you as the solution.