LocalScripts stop working after SurfaceGui assigned to same adornee twice #RobloxDev

So here’s the problem I found (solution below, too 🙂 )

I have trees in Battle Farm that are managed through a series of SurfaceGuis (with buttons to plant, cut down, etc). The Guis are in the player.PlayerGui (since the buttons use LocalScripts) and assigned an Adornee called “Readout”, which is an invisible brick wrapped around the tree trunk:

When there is no tree planted in the spot, that SAME Readout brick has a SurfaceGui that says “Click to Plant”:

And when I first load each tree, they work fine.

HOWEVER – if you

  1. Click to plant a tree (GUI 1)
  2. THEN click the “water” button ON THAT SAME TREE (GUI 2)  after it’s planted,
  3. Nothing happens. In a gui that if loaded first (loading a planted tree) works fine.

I tried a lot of things:

  1. Deleting any SurfaceGuis from player.PlayerGui with the Readout assigned as Adornee using Destroy()
  2. Trying the same but using game.Debris:AddItem(gui,0)
  3. Testing for script Disabled, Zindex, etc etc

Ultimately, here’s what worked:

Before swapping out the GUI, I first cloned the readout part, destroyed the old readout part and assigned the GUI to the new (identical) readout part. Lots of extra overhead but it was the only way I could find to fix it.

function tycooncontrol.applyDecalToTreeReadout(player, orig_readout_part, planted_or_unplanted)
	-- first we're going to try deleting and redoing the readout part
	for _, gui in pairs(player.PlayerGui:GetChildren()) do
		if gui.ClassName == "SurfaceGui" and gui.Adornee == orig_readout_part then
			gui:Destroy() -- destoying any guis attached to the current readout part
		end
	end
	orig_readout_part.CanCollide = false
	local readout_part = orig_readout_part:Clone()
	readout_part.Parent = orig_readout_part.Parent
	orig_readout_part:Destroy()

FilteringEnabled and StarterGui #RobloxDev

One of the many “opportunities for improvement” about FilteringEnabled is that some things will appear to work in Studio but not on the client, which means you can’t trust what you see when you press play in Studio.

A big one is that anything you place in StarterGui replicates to the PlayerGui just fine in studio run mode, but not once you publish it and play it on the client.

So, I always have a script on my PlayerAdded that loops through the guis in StarterGui and replicates them to the player gui, if they’re not there already.

-- put this inside your PlayerAdded function
repeat wait() until player:FindFirstChild("PlayerGui")
for _, gui in pairs(game.StarterGui:GetChildren()) do
     if not player.PlayerGui:FindFirstChild(gui.Name) then
          local g = gui:Clone()
          g.Parent = player.PlayerGui
     end
end

To be honest I’ve pretty much stopped using StarterGui with my games at all (which are all FE). I usually put the guis into a folder in the workspace and then replicate them into the PlayerGui when needed.

One last thing on GUIs: in 99% of use cases I’ve come across you want to have StarterGui > ResetPlayerGuiOnSpawn unchecked. It’s checked by default, but  I usually want my guis to come back when a player respawns.

 

Advertising on Roblox

Getting the word out about a game on Roblox is still something I’m working with. I’m not convinced their advertising mechanisms actually drive users to the games, but I need more data before I decide if/how to best get my games out there.

The algorithm for ad acceptance/rejection is pretty interesting (SLASH maddening). I just got this ad rejected immediately:

As in, no one even looked at it. The response page came back with “Ad Rejected”. I tweaked the image a bit, I renamed the file… reject reject reject.

One of the big problems with these rejections is that you don’t get any feedback. If the algorithm is deciding there’s, say, too much of one color, it could tell you that in its response (but it doesn’t). Or if there’s a font or word it doesn’t like. Again, you get nothing but the rejection, which means you get to waste a lot of time guessing.

So for fun I uploaded this one:

It was immediately approved. You can’t tell me that Roblox would rather that I run THIS ad than another one. Or maybe they would. Earlier today I saw an ad that was all green. That’s it. So maybe they’re assuming their user base will click on anything. I am kind of tempted to run the above ad and see if it gets any clicks. (ETA: I didn’t)

I renamed my first file WITHOUT the word “robot” in the filename (it had been ad_robotvs.png etc). I named it skyscraper_rb.png. It got through.

 

When your SurfaceGui isn’t showing up on its adornee #RobloxDev

So this might be a problem only I have because I am a weirdo but … just in case.
I was running a script where I:

  1. Cloned a model
  2. Passed the cloned model through to a function to do some stuff to it, including:
  3. Cloned a SurfaceGui
  4. Assigned the SurfaceGui parent to the PlayerGui
  5. Set the SurfaceGui Adornee to one of the pieces in my cloned model
  6. Parented the model in the workspace

The problem was, my GUI was not showing on the model. The cloned gui was in my player.PlayerGui, and the Adornee was assigned, but it was invisible.
I checked if it was enabled, I checked if all the elements were visible .. nothing.
And then I realized that the model’s parent was set AFTER the adornee was being assigned to the part in the model.
When I gave the model a parent in the workspace and THEN assigned the Adornee, all was well. I am left to assume I shouldn’t be assigning adornees in models outside the workspace.

So: if you’re assigning a SurfaceGui adornee to a model without a parent, try parenting the model first.

Sounds and FilteringEnabled #RobloxDev

Haven’t gotten to test this all that much but have found that the sound:Stop() does not do anything in client mode if FilteringEnabled is on and the sound is parented in the PlayerGui.

This is one of MANY MANY things I’ve found about FilteringEnabled that isn’t exactly mentioned in the documentation, and I don’t know if that’s because it’s really a problem or if there’s a solution I just haven’t been able to find through searching.

At any rate, I have two functions to handle sounds. One that creates the sound if it doesn’t exist (usually in player.PlayerGui) and then plays it. The other destroys it (sound:Destroy()). This is the only way so far I’ve been able to get sounds to stop in play mode.

I’ve also found that to get a sound to play more than once in the client (let’s say you want a cash register sound every time a player buys something) you first have to do

sound:Stop()
sound:Play()

.. instead of just sound:Play()

… though again – hopefully I’m just missing something and will find a better way someday.

 

Oh the humanity! I need #robloxdev help with a leaderstats problem.

I have a problem. Maybe you can help me solve it. If you can’t reply here, you can find me on twitter @derangedokapi.

So here it is: my previously working leaderboards now look like this:

Notice the column headers on the leaderboard are shifted. The first should be coins, the second should be Tokens, and the third should be Level. The values underneath are correct.

Here’s the code:

configs.leaderstat_values = {
	current_currency = {label = configs.currency_plural, stat = "current_currency", vartype = "StringValue", prepend = configs.currency_prefix},
	current_premium = {label = configs.premium_plural, stat = "current_premium", vartype = "StringValue", prepend = configs.premium_prefix},
	level = {label = "Level", stat = "level", vartype = "NumberValue", prepend = nil},
}

That sets up what values I want (it’s just a housekeeping thing). Here’s where I set up and/or update the leaderboard:

	
if not player:FindFirstChild("leaderstats") then
	local ls = Instance.new("Model")
	ls.Name = "leaderstats"
	ls.Parent = player
	for nm, arr in pairs(configs.leaderstat_values) do
		local v = Instance.new(arr.vartype)
		v.Name = arr.label
		local val = datafetch.getStat(player, arr.stat)
		if arr.vartype == "StringValue" then
			v.Value = arr.prepend .. utils.abbreviateNumberDisplay(val)
		else
			v.Value = val
		end
		v.Parent = ls
	end
end

So basically I’m setting it up and populating it. I’ve tried it the MUCH more explicit way of setting each variable individually (the original battle farm and bubble chase do this). I haven’t touched their code and they are also showing this issue. So I am going to have to assume it was a client or studio change of some kind.

Any help appreciated!

Scaling R15 Models with NumberValue objects – script vs. manual

So I’m pretty good at scripting and pretty lousy at working with models. I tried to get around dealing with sizing my monster characters by doing it through script instead of manipulating the models. Spoiler alert: BIG MISTAKE.

Basically I did this with script:

  1. Created a bunch of monster spawner locations
  2. Picked an enemy from an enemy type list I’d set up
  3. Cloned the chosen enemy model into the workspace
  4. Moved it to the position of the spawner

This was fine for my standard sized zombie model.

It was NOT fine for my giant zombie model.  I first tried to scale it using code by

  1. Cloning the regular sized Zombie model via script
  2. Using script to create scale NumberValue Objects in the monster’s Humanoid (see wiki) and setting them:
    1. BodyDepthScale = 5
    2. BodyHeightScale = 5
    3. BodyWidthScale = 5
    4. HeadScale = 5
  3. Then cloned them off.

Here’s what happened:

Head in torso!

Legs merged!

The Solution (so far)

Well.. I haven’t found a way to do this through script. However, I did have success doing it manually:

  1. In Studio (not script), I copied the Zombie model
  2. I created the four variables above in the Giant Zombie humanoid:
  3. When I did that, the pieces of the zombie got all out of alignment, which gives some clues as to why when you do it with script you get a jumbled mess. So, I manually put the Zombie back together again, lining up the head, torso, arms etc.

Better!

I’d love to be able to do this with scripting, and can probably write something to place the parts back where they belong, but for now this will allow me to have giants roaming around without me going absolutely bonkers.

 

When a part keeps falling off a model you’re trying to animate

So I’ve been working with NPCs to try and introduce some enemies to the new Battle Farm. I started with some existing models since I am brand new to moving NPCs around and wanted to see some scripting examples. I downloaded this one which does almost exactly what I wanted it to do (I will modify but it’s a great start for what I need).

The only problem was: when I started the game the Zombie’s head would fall off! I knew I couldn’t anchor it or the Zombie would be stuck.

Turns out what I needed was MakeJoints(). In this case all I needed to do was add it to the zombie load script like so:

script.Parent:MakeJoints()

Done and done!

 

 

Debugging Roblox games in the client using the Developer Console

As the game creator, you can see your output window by using the Developer Console. Get there by pressing F9 while playing in the client. Choose the “Server output” window and you’ll be able to see anything you would see in the output window in Studio.

Some cool things you can do with this output window:

  • filter the output for certain words
  • run commands off the command line

Note that only the game creators can see server output and run commands. Players of your game will have a console that shows errors output to the client.

When I first started developing, I found debugging my game on the client incredibly frustrating, because I didn’t know about the output window for the client. I wrote a bunch of functions to debug information to chat, which was cumbersome and difficult to use.

You can find more information on the Developer Console on the wiki.