Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

(Tycoon upgrades) Can someone help me with this Problem(adding another dropper)?{FIXED}

Ok, I put a different mess, before but I wanted to go into more detail.

I am making a free-build / Tycoon

I had the tycoon working with just one dropper, and one upgrader. (both would not show up until you hit the buy button)

When I added another dropper, and another wall upgrade. (both would show always and that snot right)

I want the new dropper to not show until you buy, same for the wall upgrade.

everything is the same as the first 2, all are in the right folders, and named the right name.

here is the script that controls them, can someone help please?

P.S. I am getting a message in my output that says 11:59:32.087 - Object is not a valid member of Model 11:59:32.087 - Script 'Workspace.Tycoon Kit.Tycoons.Bright blue.PurchaseHandler', Line 41 11:59:32.088 - Stack End

---handels all buttons

objects = {}  ---empty erray for script
teamcolor = BrickColor.new(script.Parent.Name)
config = script.Parent.Parent.Parent.Configuration
wait(1)

script.Parent.Essentials.Spawn.TeamColor = teamcolor
script.Parent.Essentials.Spawn.BrickColor = teamcolor

script.Parent.Essentials.Collector.Touched:connect(function(hit)
	if hit:FindFirstChild("Cash") then
		script.Parent.Cash.Value = script.Parent.Cash.Value + hit.Cash.Value  --checks if they ahve cash and takes the price from it
		Instance.new("Sparkles",hit).Color=Color3.new(math.random(1,255)/255,math.random(1,255)/255,math.random(1,255)/255)
		game.Debris:AddItem(hit,0.1)
	end
end)


script.Parent.Essentials.Giver.Touched:connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent) ---makes sure that is is a player
	if player ~= nil then
		if script.Parent.Owner.Value == player then  ---makes sure that it is the owner
			if hit.Parent:FindFirstChild("Humanoid") then   
				if hit.Parent.Humanoid.Health > 0 then     ---makes sure thta the player is alive when touched
					local cashmoney = game.ServerStorage.MoneyStorage:FindFirstChild(player.Name)---checks the storage for cash
					if cashmoney ~= nil then 
						cashmoney.Value = cashmoney.Value + script.Parent.Cash.Value
						script.Parent.Cash.Value = 0  ----makes sure that they have enough money to buy the item
					end
				end
			end
		end
	end
end)

script.Parent:WaitForChild("Buttons")   ---- waits for all the buttons to arrive
for i,v in pairs(script.Parent.Buttons:GetChildren()) do   
	if v:FindFirstChild("Head") then   ---makes sure it is a button
		
		local object = script.Parent.Purchases:FindFirstChild(v.Object.Value)---look for an object by the name of the button
		if object ~= nil then
			objects[object.Name] = object:Clone()  --- clones the object
			object:Destroy()  ----destroys the object
		else
			print("Button: "..v.Name.." is missing its object and has been removed.")
			v.Head.CanCollide = false
			v.Head.Transparency = 1   ---removes the button
		end
								
		if v:FindFirstChild("Dependency") then
			v.Head.CanCollide = false
			v.Head.Transparency = 1
			coroutine.resume(coroutine.create(function()
				if script.Parent.PurchasedObjects:WaitForChild(v.Dependency.Value) then
					if config.ButtonFadeInDependency.Value == true then
						for i=1,20 do
							wait(config.ButtonFadeInTime.Value/20)
							v.Head.Transparency = v.Head.Transparency - 0.05
						end
					end
					v.Head.CanCollide = true
					v.Head.Transparency = 0
				end
			end))
		end
		
		v.Head.Touched:connect(function(hit)
			local player = game.Players:GetPlayerFromCharacter(hit.Parent)
			if v.Head.CanCollide == true then
				if player ~= nil then
					if script.Parent.Owner.Value == player then
						if hit.Parent:FindFirstChild("Humanoid") then
							if hit.Parent.Humanoid.Health > 0 then
								local cashmoney = game.ServerStorage.MoneyStorage:FindFirstChild(player.Name)
								if cashmoney ~= nil then
									if cashmoney.Value >= v.Price.Value then
										cashmoney.Value = cashmoney.Value - v.Price.Value  ---makes sure you have enough money
										objects[v.Object.Value].Parent = script.Parent.PurchasedObjects ---makes the object go away until bought
										if config.ButtonExplodeOnBuy.Value == true then
											local explosion = Instance.new("Explosion",workspace)
											explosion.Position = v.Head.Position
											explosion.DestroyJointRadiusPercent = 0
											explosion.BlastPressure = 0
										end
										if config.ButtonFadeOutOnBuy.Value == true then
											v.Head.CanCollide = false
											coroutine.resume(coroutine.create(function()
												for i=1,20 do
													wait(config.ButtonFadeOutTime.Value/20)
													v.Head.Transparency = v.Head.Transparency + 0.05
												end
											end))
										else
											v.Head.CanCollide = false
											v.Head.Transparency = 1
										end
									end
								end
							end
						end
					end
				end
			end
		end)
		
	end
end

1 answer

✓ Accepted answer

As the error says, there isn't something called "Object" inside a model. The model in question is v on line 41, which is a child of script.Parent.Buttons. That means one of the models there must not have an object called Object.


This code is really complicated looking. There's no reason to write code that is indented 11 levels deep. Simplify.

Here's a whole host of improvements to your code:

  • Use math.random() instead of math.random(1, 255) / 255.
  • Don't need to say ~= nil in a condition. It's easier to read just if player then, etc.
  • Similarly, no need to say == true.
  • Don't use coroutine.resume(coroutine.create(. Just use spawn(.
  • Use good variable names. v is a button. You don't use i so you should call it _.
  • Don't define an anonymous function that's 9 levels of indentation deep inside of 2 levels of indentation. Make a named function for it.
  • :WaitForChild can't return nil, so it doesn't make sense to use it an if.
  • Try writing a function for the fading, rather that duplicating that code twice.
  • Try using and instead of just embedding ifs in each other.
  • You try to get a player from a part touching fairly often. Why not right a function?
  • Consider using an early return in case of failure (not player or not button.Head.CanCollide) to reduce indentation levels

In the end, I've gotten something like this, which is at least a little cleaner:

---handles all buttons

objects = {}  ---empty erray for script
teamcolor = BrickColor.new(script.Parent.Name)
config = script.Parent.Parent.Parent.Configuration
wait(1)

script.Parent.Essentials.Spawn.TeamColor = teamcolor
script.Parent.Essentials.Spawn.BrickColor = teamcolor

function syncFade(part, time)
	for i = 1, 20 do
		part.Transparency = part.Transparency + 0.05
		wait(time / 20)
	end
end

script.Parent.Essentials.Collector.Touched:connect(function(hit)
	if hit:FindFirstChild("Cash") then
		script.Parent.Cash.Value = script.Parent.Cash.Value + hit.Cash.Value  --checks if they ahve cash and takes the price from it
		Instance.new("Sparkles",hit).Color = Color3.new( math.random(), math.random() , math.random() )
		game.Debris:AddItem(hit,0.1)
	end
end)

function getPlayer(part)
	local character = part.Parent
	if character then
		local player = game.Players:GetPlayerFromCharacter(character)
		local humanoid = character:FindFirstChild("Humanoid")
		if humanoid and humanoid.Health > 0 then
			return player
		end
	end
end

script.Parent.Essentials.Giver.Touched:connect(function(hit)
	local player = getPlayer(hit)
	if player then
		if script.Parent.Owner.Value == player then  ---makes sure that it is the owner
			---makes sure thta the player is alive when touched
			local cashmoney = game.ServerStorage.MoneyStorage:FindFirstChild(player.Name)---checks the storage for cash
			if cashmoney then 
				cashmoney.Value = cashmoney.Value + script.Parent.Cash.Value
				script.Parent.Cash.Value = 0  ----makes sure that they have enough money to buy the item
			end
		end
	end
end)

function buttonTouched(button, hit)
	local player = getPlayer(hit)
	if not button.Head.CanCollide or not player then
		return
	end
	if script.Parent.Owner.Value == player then
		local cashmoney = game.ServerStorage.MoneyStorage:FindFirstChild(player.Name)
		if cashmoney then
			if cashmoney.Value >= button.Price.Value then
				cashmoney.Value = cashmoney.Value - button.Price.Value  ---makes sure you have enough money
				objects[button.Object.Value].Parent = script.Parent.PurchasedObjects ---makes the object go away until bought
				if config.ButtonExplodeOnBuy.Value then
					local explosion = Instance.new("Explosion",workspace)
					explosion.Position = button.Head.Position
					explosion.DestroyJointRadiusPercent = 0
					explosion.BlastPressure = 0
				end
				if config.ButtonFadeOutOnBuy.Value then
					button.Head.CanCollide = false
					spawn(function()
						syncFade(button.Head, config.ButtonFadeOutTime.Value)
					end)
				else
					button.Head.CanCollide = false
					button.Head.Transparency = 1
				end
			end
		end
	end
end

script.Parent:WaitForChild("Buttons")   ---- waits for all the buttons to arrive
for _, button in pairs(script.Parent.Buttons:GetChildren()) do   
	if button:FindFirstChild("Head") then   ---makes sure it is a button
		local object = script.Parent.Purchases:FindFirstChild(button.Object.Value)---look for an object by the name of the button
		if object then
			objects[object.Name] = object:Clone()  --- clones the object
			object:Destroy()  ----destroys the object
		else
			print("Button: " .. button.Name .. " is missing its object and has been removed.")
			button.Head.CanCollide = false
			button.Head.Transparency = 1   ---removes the button
		end
		if button:FindFirstChild("Dependency") then
			button.Head.CanCollide = false
			button.Head.Transparency = 1
			spawn(function()
				script.Parent.PurchasedObjects:WaitForChild(button.Dependency.Value)
				if config.ButtonFadeInDependency.Value then
					syncFade( button.Head, config.ButtonFadeInTime.Value)
				end
				button.Head.CanCollide = true
				button.Head.Transparency = 0
			end)
		end
		button.Head.Touched:connect(function(hit)
			buttonTouched(button, hit)
		end)
	end
end

Though I think you could probably simplify even more.

This discussion is preserved as it was. New answers, comments, and votes are closed.