Script not being cloned into a part (HELP)

Hey, I was working on stun rocks that stun the player. I tested the stun script and it works and now I just have to clone the script into the rocks that are created. Problem is when I try to clone the script in to the rocks it doesn’t work, but when I clone a sound to an part, it works.

Here’s the function I call


function StraightStunRocks(root,player)
	local parms = RaycastParams.new()
	parms.FilterDescendantsInstances = {workspace.Ability.Debris,characters}
	parms.FilterType = Enum.RaycastFilterType.Blacklist
	local angle = 0
	local extraheight = 0
	local cf = player.Character.HumanoidRootPart.CFrame
	-- Creating Rocks
	for i = 1,4 do
		local size = math.random(4,7)
		local height = 5
		local part = Instance.new("Part")
		local sound = Instance.new("Sound")
		local stun = script.Stun:Clone()
		stun.Parent = part
		stun.Enabled = true
		sound.Parent = part
		sound.SoundId = "rbxassetid://9125869138"
		sound.RollOffMaxDistance = 200
		sound.RollOffMinDistance = 6
		sound.Volume = 1.2
		local lv = player.Character.HumanoidRootPart.CFrame.LookVector
		local direction = player.Character.HumanoidRootPart.Position + (lv * ((i+1) * (2.5 + i)))
		-- Properties
		part.Anchored = true
		part.Size = Vector3.new(1,1,1)
		part.CFrame = player.Character.HumanoidRootPart.CFrame
		game.Debris:AddItem(part,5)
		game.Debris:AddItem(stun,4)
		local raycast = workspace:Raycast(part.CFrame.p,part.CFrame.UpVector * -15, parms)
		if raycast then
			part.CanCollide = false
			part.Material = Enum.Material.Rock
			part.BrickColor = BrickColor.new("Brown")
			part.Position = direction + Vector3.new(0,-5,0)
			part.Size = Vector3.new(8,height + extraheight,8)
			part.Orientation = Vector3.new(part.Orientation.X,math.random(-180,180),part.Orientation.Z)
			part.Parent = workspace.Ability.Debris
			sound:Play()
			local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(.25,Enum.EasingStyle.Bounce,Enum.EasingDirection.Out),{Position = part.Position + Vector3.new(0,5,0)}):Play()
			delay(4,function()
				local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(1),{Transparency = 1}):Play()		
			end)
		end
		print(extraheight)
		extraheight += 4
		wait(0.2)
	end
end

Stun Script

repeat wait(0.2) until script.Parent:IsA("Part")
local part = script.Parent
local gui = script.StunGUI
local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://11273357512"
anim.Parent = script
local function Stun(player)
	local hum = player.Character:FindFirstChild("Humanoid")
	if anim then
		StunAnim = hum:LoadAnimation(anim)
	end
	gui.ImageLabel.ImageTransparency = 1
	local guiClone = gui:Clone()
	guiClone.Parent = hum.Parent:FindFirstChild("HumanoidRootPart")
	local guiTween = game.TweenService:Create(guiClone.ImageLabel,TweenInfo.new(0.5,Enum.EasingStyle.Sine,Enum.EasingDirection.Out),{ImageTransparency = 0})
	local guiFade = game.TweenService:Create(guiClone.ImageLabel,TweenInfo.new(0.5,Enum.EasingStyle.Sine,Enum.EasingDirection.Out),{ImageTransparency = 1})
	local Stun = Instance.new("BoolValue")
	Stun.Name = "Stun"
	Stun.Parent = player
	guiTween:Play()
	StunAnim:Play()
	hum.WalkSpeed = 0
	hum.JumpPower = 0
	game.Debris:AddItem(Stun,4)
	wait(4)
	guiFade:Play()
	StunAnim:Stop()
	hum.WalkSpeed = 16
	hum.JumpPower = 50
end

local deb = false
part.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid",true) then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		print("found")
		if not player:FindFirstChild("Stun") and not deb then
			deb = true
			print("stunning...")
			Stun(player)
			deb = false
		end
	end
end)

Explorer:
Screen Shot 2022-10-14 at 6.08.20 PM
Thanks for reading (Please help, I tried everything!)

Hello!

I believe from my past experience, you can’t clone things from ServerScriptService, since Roblox automatically makes scripts not shown in ServerScriptService after running your game. If anything, you could already have the script that’s needed inside of the StunRock already, and have a script handle the cloning.

1 Like

Makes sense, I tried to put it in replicated storage and it didn’t work still, maybe it has to do something with the script being in serverscriptservice

I believe your issue is that you’re enabling the script (although by the looks of it, it’s already enabled, which would be a problem) before parenting it to the player.

1 Like

I tried to take ur advice by making a remote and making a local script handle the rocks and scripting

Local Script

game:GetService("ReplicatedStorage").Remotes.Rocks.OnClientEvent:Connect(function(player,extraheight)
	local size = math.random(4,7)
	local height = 5
	local part = Instance.new("Part")
	local sound = Instance.new("Sound")
	local stun = game.ReplicatedStorage.Scripts.Stun:Clone()

	sound.Parent = part
	sound.SoundId = "rbxassetid://9125869138"
	sound.RollOffMaxDistance = 200
	sound.RollOffMinDistance = 6
	sound.Volume = 1.2
	local lv = player.Character.HumanoidRootPart.CFrame.LookVector
	local direction = player.Character.HumanoidRootPart.Position + (lv * ((i+1) * (2.5 + i)))
	-- Properties
	part.Anchored = true
	part.Size = Vector3.new(1,1,1)
	part.CFrame = player.Character.HumanoidRootPart.CFrame
	stun.Parent = part
	game.Debris:AddItem(part,5)
	game.Debris:AddItem(stun,4)
	local raycast = workspace:Raycast(part.CFrame.p,part.CFrame.UpVector * -15, parms)
	if raycast then
		part.CanCollide = false
		part.Material = Enum.Material.Rock
		part.BrickColor = BrickColor.new("Brown")
		part.Position = direction + Vector3.new(0,-5,0)
		part.Size = Vector3.new(8,height + extraheight,8)
		part.Orientation = Vector3.new(part.Orientation.X,math.random(-180,180),part.Orientation.Z)
		part.Parent = workspace.Ability.Debris
		sound:Play()
		local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(.25,Enum.EasingStyle.Bounce,Enum.EasingDirection.Out),{Position = part.Position + Vector3.new(0,5,0)}):Play()
		delay(4,function()
			local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(1),{Transparency = 1}):Play()		
		end)
	end
	print(extraheight)
	extraheight += 4
	wait(0.2)		local size = math.random(4,7)
	local height = 5
	local part = Instance.new("Part")
	local sound = Instance.new("Sound")
	local stun = script.Stun:Clone()

	sound.Parent = part
	sound.SoundId = "rbxassetid://9125869138"
	sound.RollOffMaxDistance = 200
	sound.RollOffMinDistance = 6
	sound.Volume = 1.2
	local lv = player.Character.HumanoidRootPart.CFrame.LookVector
	local direction = player.Character.HumanoidRootPart.Position + (lv * ((i+1) * (2.5 + i)))
	-- Properties
	part.Anchored = true
	part.Size = Vector3.new(1,1,1)
	part.CFrame = player.Character.HumanoidRootPart.CFrame
	stun.Parent = part
	game.Debris:AddItem(part,5)
	game.Debris:AddItem(stun,4)
	local raycast = workspace:Raycast(part.CFrame.p,part.CFrame.UpVector * -15, parms)
	if raycast then
		part.CanCollide = false
		part.Material = Enum.Material.Rock
		part.BrickColor = BrickColor.new("Brown")
		part.Position = direction + Vector3.new(0,-5,0)
		part.Size = Vector3.new(8,height + extraheight,8)
		part.Orientation = Vector3.new(part.Orientation.X,math.random(-180,180),part.Orientation.Z)
		part.Parent = workspace.Ability.Debris
		sound:Play()
		local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(.25,Enum.EasingStyle.Bounce,Enum.EasingDirection.Out),{Position = part.Position + Vector3.new(0,5,0)}):Play()
		delay(4,function()
			local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(1),{Transparency = 1}):Play()		
		end)
	end
	print(extraheight)
	extraheight += 4
	wait(0.2)
end)

Script

function StraightStunRocks(root,player)
	local parms = RaycastParams.new()
	parms.FilterDescendantsInstances = {workspace.Ability.Debris,characters}
	parms.FilterType = Enum.RaycastFilterType.Blacklist
	local cf = player.Character.HumanoidRootPart.CFrame
	-- Creating Rocks
	for i = 1,4 do
		game.ReplicatedStorage.Remotes.Rocks:FireClient(player,4)
	end
end

It worked but it still didn’t clone the scripts

Nice catch, it still didn’t work though, that was when I tried to clone it when the script was disabled and I forgot to remove that

Is the actual script in the workspace disabled to begin with?

No, I enabled it first, and it’s inside the main script
Screen Shot 2022-10-14 at 6.08.20 PM

The script repeats wait(0.2) until the parent is a part, so I don’t have to worry about disabling it
(the 0.2 was for optimization even though my method is not very good for the game)

I mean, disable the script outside of the game, and when the script clones it, then enable it. It should always be disabled to begin with

Not really. You can clone from ServerScriptService, for as long as a server script was the one who did the cloning. Now, as for the person’s problem, although I am not completely certain what the issue is, I do want to point out a few problems with the overall structure.

First and foremost, the script is enabled by default. That is a bad habit. If you are going to clone scripts into parts, have them disabled by default, parent them, and then enable them. That will solve MANY problems caused by the initial parent.

Secondly (and most importantly), you should avoid doing something like this. I highly recommend using CollectionService as it is far more efficient and it won’t cause unnecessary copies of code. If you do not know how to use it, I recommend watching the following video:

2 Likes

Thanks, it was originally disabled, then enabled once cloned, I’ll check it out and tell you the results

So something like this? It didn’t work though, it was not printing the for loop but it printed the if statement when i joined the game

local CollectionService = game:GetService("CollectionService")

function StraightStunRocks(root,player)
	local parms = RaycastParams.new()
	parms.FilterDescendantsInstances = {workspace.Ability.Debris,characters}
	parms.FilterType = Enum.RaycastFilterType.Blacklist
	local angle = 0
	local extraheight = 0
	local cf = player.Character.HumanoidRootPart.CFrame
	-- Creating Rocks
	for i = 1,4 do
		local size = math.random(4,7)
		local height = 5
		local part = Instance.new("Part")
		local sound = Instance.new("Sound")
		CollectionService:AddTag(part,"Stun")
		sound.Parent = part
		sound.SoundId = "rbxassetid://9125869138"
		sound.RollOffMaxDistance = 200
		sound.RollOffMinDistance = 6
		sound.Volume = 1.2
		local lv = player.Character.HumanoidRootPart.CFrame.LookVector
		local direction = player.Character.HumanoidRootPart.Position + (lv * ((i+1) * (2.5 + i)))
		-- Properties
		part.Anchored = true
		part.Size = Vector3.new(1,1,1)
		part.CFrame = player.Character.HumanoidRootPart.CFrame
		game.Debris:AddItem(part,5)
		local raycast = workspace:Raycast(part.CFrame.p,part.CFrame.UpVector * -15, parms)
		if raycast then
			part.CanCollide = false
			part.Material = Enum.Material.Rock
			part.BrickColor = BrickColor.new("Brown")
			part.Position = direction + Vector3.new(0,-5,0)
			part.Size = Vector3.new(8,height + extraheight,8)
			part.Orientation = Vector3.new(part.Orientation.X,math.random(-180,180),part.Orientation.Z)
			part.Parent = workspace.Ability.Debris
			sound:Play()
			local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(.25,Enum.EasingStyle.Bounce,Enum.EasingDirection.Out),{Position = part.Position + Vector3.new(0,5,0)}):Play()
			delay(4,function()
				local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(1),{Transparency = 1}):Play()		
			end)
		end
		print(extraheight)
		extraheight += 4
		wait(0.2)
	end
end

CollectionService.TagAdded:Connect(function(tag)
	local taggedParts = CollectionService:GetTagged("Stun")
	if taggedParts then
		print("reached if statement")
		for _,rock in pairs(taggedParts) do
			print("reached forr statement")
			local stun = script.Stun:Clone()
			stun.Enabled = true
			stun.Parent = rock
			--game.Debris:AddItem(stun,5) removed this just incase this was the problem
		end
	end
end)

First run a loop through CollectionService:GetTagged("Stun") and run that code in there (also, put stun.Parent = rock before stun.Enabled = true), and then have the CollectionService.TagAdded event checker. Also, when I mentioned CollectionService, I did not have that in mind. I’ll make a quick demo in about an hour to explain what I meant by using CollectionService.

1 Like

Do I run the loop inside the other loop? for i = 1,4 is the other loop im talking about

As promised, I will give examples of what I am talking about.

Example

Say we want to make a script were whenever a player touches a brick, it will take 20 HP away. Of course, we want this to happen to every “kill brick” in our game.

Initial Topic (Solution) Approach

In the initial topic, your approach would be to make a script that clones the kill script and put it in every part. Let us consider this as our explorer:

image

Here is the code for the “KillPartGiver” script:

-- Variables --

local KillParts = workspace:WaitForChild("Kill Parts")
local KillScript = script:WaitForChild("KillScript")

-- Scripting --

for _, Part in ipairs(KillParts:GetChildren()) do
	local NewScript = KillScript:Clone()
	NewScript.Parent = Part
	NewScript.Enabled = true
end

And here is the code for the “KillScript” script:

-- Variables --

local Part: Part = script.Parent

-- Scripting --

Part.Touched:Connect(function(Hit)
	if Hit.Parent:FindFirstChild("Humanoid") then
		Hit.Parent.Humanoid.Health -= 20
	end
end)

This will work, but it is a bad habit to duplicate scripts into other parts when they will all have the same exact function. This is where CollectionService comes into play.

CollectionService (Working) Attempt

Now, CollectionService allows to basically “tag” objects in order to access them more easily. Lets correct the reply you sent me so I can show you what you basically did.

Let us assume we are using the same explorer but have tagged all parts under the “Kill Parts” folder with the tag “KillPart”:

image

Here is the code for the “KillPartGiver” script:

-- Services --

local CollectionService = game:GetService("CollectionService")

-- Variables --

local KillScript = script:WaitForChild("KillScript")

-- Scripting --

for _, Part in ipairs(CollectionService:GetTagged("KillPart")) do
	local NewScript = KillScript:Clone()
	NewScript.Parent = Part
	NewScript.Enabled = true
end

CollectionService:GetInstanceAddedSignal("KillPart"):Connect(function(Part)
	local NewScript = KillScript:Clone()
	NewScript.Parent = Part
	NewScript.Enabled = true
end)

And here is the code for the “KillScript” script:

-- Variables --

local Part: Part = script.Parent

-- Scripting --

Part.Touched:Connect(function(Hit)
	if Hit.Parent:FindFirstChild("Humanoid") then
		Hit.Parent.Humanoid.Health -= 20
	end
end)

Yes, this does work as well, but you are still duplicating a script and creating unnecessary script instances.

Proper CollectionService Approach

So, if that isn’t the way to do it, what is? Well, the best thing is to use a single script for everything. Let me explain.

Let us assume that this is our explorer:

image

And this is the code for the “KillPartMainHandler” script:

-- Services --

local CollectionService = game:GetService("CollectionService")

-- Functions --

local function CreateKillScriptListener(Part)
	Part.Touched:Connect(function(Hit)
		if Hit.Parent:FindFirstChild("Humanoid") then
			Hit.Parent.Humanoid.Health -= 20
		end
	end)
end

-- Scripting --

for _, Part in ipairs(CollectionService:GetTagged("KillPart")) do
	CreateKillScriptListener(Part)
end

CollectionService:GetInstanceAddedSignal("KillPart"):Connect(CreateKillScriptListener)

Do you notice something? If you haven’t noticed it already, I condensed all of our “KillScript” into a single function called CreateKillScriptListener() and run that function for every tagged instance and whenever a new tagged instance is added. This is the proper way to use CollectionService.

CollectionService was made for multiple reasons, but it has primarily been used to avoid creating unnecessary scripts. If you look in-game while the game is running, you will see that none of the parts actually have a script in them. This is ideal since you are avoiding duplicate scripts and also have the ability to add new parts during run-time without having to worry about cloning yet another script. This is also better for organization and performance (as far as I’m aware).

The Best Practice

Expanding on the code above, it is also good to remove any connections made whenever the part is destroyed or has their tag removed. Why do that? The reason is performance. Although I think there is a garbage collector nonetheless, it is good to manually disconnect any connections so you avoid having unnecessary listeners in the background. The code below does this exact thing:

-- Services --

local CollectionService = game:GetService("CollectionService")

-- Tables --

local KillPartConnections = {}

-- Functions --

local function CreateKillScriptListener(Part)
	if KillPartConnections[Part] then return end
	
	KillPartConnections[Part] = Part.Touched:Connect(function(Hit)
		if Hit.Parent:FindFirstChild("Humanoid") then
			Hit.Parent.Humanoid.Health -= 20
		end
	end)
end

-- Scripting --

for _, Part in ipairs(CollectionService:GetTagged("KillPart")) do
	CreateKillScriptListener(Part)
end

CollectionService:GetInstanceAddedSignal("KillPart"):Connect(CreateKillScriptListener)

CollectionService:GetInstanceRemovedSignal("KillPart"):Connect(function(Part)
	if KillPartConnections[Part] then
		KillPartConnections[Part]:Disconnect()
		KillPartConnections[Part] = nil
	end
end)

Of course, this isn’t necessary to get this working, but it is a good practice.

Conclusion

This is the proper usage of CollectionService. Hopefully you understand the concept of it and adapt your code accordingly. Once you learn to use CollectionService correctly, you will understand how much of a powerful tool it is. Hopefully this helped you understand better. If you have any questions, do let me know.

1 Like

This looks like it would work but all I see is a optimized version of what I was first doing.

Here’s my first attempt:

local CollectionService = game:GetService("CollectionService")

function StraightStunRocks(root,player)
	local parms = RaycastParams.new()
	parms.FilterDescendantsInstances = {workspace.Ability.Debris,characters}
	parms.FilterType = Enum.RaycastFilterType.Blacklist
	local angle = 0
	local extraheight = 0
	local cf = player.Character.HumanoidRootPart.CFrame
	-- Creating Rocks
	for i = 1,4 do
		local size = math.random(4,7)
		local height = 5
		local part = Instance.new("Part")
		local sound = Instance.new("Sound")
		sound.Parent = part
		sound.SoundId = "rbxassetid://9125869138"
		sound.RollOffMaxDistance = 200
		sound.RollOffMinDistance = 6
		sound.Volume = 1.2
		local lv = player.Character.HumanoidRootPart.CFrame.LookVector
		local direction = player.Character.HumanoidRootPart.Position + (lv * ((i+1) * (2.5 + i)))
		-- Properties
		part.Anchored = true
		part.Size = Vector3.new(1,1,1)
		part.CFrame = player.Character.HumanoidRootPart.CFrame
		game.Debris:AddItem(part,5)
		local raycast = workspace:Raycast(part.CFrame.p,part.CFrame.UpVector * -15, parms)
		if raycast then
			part.CanCollide = false
			part.Material = Enum.Material.Rock
			part.BrickColor = BrickColor.new("Brown")
			part.Position = direction + Vector3.new(0,-5,0)
			part.Size = Vector3.new(8,height + extraheight,8)
			part.Orientation = Vector3.new(part.Orientation.X,math.random(-180,180),part.Orientation.Z)
			part.Parent = workspace.Ability.Debris
			-- adding tag once inside folder
			CollectionService:AddTag(part,"Stun")
			sound:Play()
			local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(.25,Enum.EasingStyle.Bounce,Enum.EasingDirection.Out),{Position = part.Position + Vector3.new(0,5,0)}):Play()
			delay(4,function()
				local Tween = game:GetService("TweenService"):Create(part,TweenInfo.new(1),{Transparency = 1}):Play()		
			end)
		end
		print(extraheight)
		extraheight += 4
		wait(0.2)
	end

	for _, Part in ipairs(CollectionService:GetTagged("Stun")) do
		local NewScript = script.Stun:Clone()
		NewScript.Parent = Part
		NewScript.Enabled = true
	end
	CollectionService:GetInstanceAddedSignal("Stun"):Connect(function(Part)
		local NewScript = script.Stun:Clone()
		NewScript.Parent = Part
		NewScript.Enabled = true
	end)
end

I’ve also haven’t used CollectionService as it’s my first time.

I also tried printing (NewScript.Parent) and it doesn’t print anything

trying to revive this topic i havent found any good solutions or solutions in general :sad:

My only recommendation from this point onward is to debug to see what is working and what isn’t. Firstly, check if the scripts are actually being parented to the parts. From there, check if the Touched event fires (add something like print("TOUCHED") right under the part.Touched:Connect(function(hit) line). Simply go through lines of code and see what runs and doesn’t. That is what I do. If the Touched event runs (you see “TOUCHED” in the output) but “found” never gets printed, it means that something between those lines of code doesn’t execute. Use this process and let us know up to what point the code runs.

Also, make sure that the CollectionService functions (the loop and the GetInstanceAddedSignal event) are outside of the function so they “run” all time and also avoid running them multiple times.