Help with script performance

  1. What do you want to achieve? Keep it simple and clear!
    I’ve made this script that makes a part or meshpart that is added to a folder, follow the player… and if the part is called “Skull” also faces the player as it follows him. The script achieves its goal but I want to it to be less cpu consuming.

  2. What is the issue? Include screenshots / videos if possible!
    The script is consuming too much CPU causing lag even if there is no part added or
    the part is allready destroyed. Also the Script Performance window shows peaks of the script rate from 76/s to 150/s

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    tried destroying the part after the function is done instead of just removing it but no changes

This is my code

local folder = script.Parent
local Players = game:GetService("Players")
local maxDistance = 50
TouchWait = false
local Remote = game.ReplicatedStorage.Events:WaitForChild("PopupEvent")

-- Follow Player --
function getClosestPlayer(v)
	v.CanCollide = false
	local closest_player, closest_distance = nil, 100
	for i, player in pairs(workspace:GetChildren()) do
		if player:FindFirstChild("Humanoid") and game.Players:GetPlayerFromCharacter(player) ~= nil then
			local distance = (v.Position - player.PrimaryPart.Position).Magnitude
			if distance < closest_distance then
				closest_player = player
				closest_distance = distance
			end
		end
	end
	return closest_player, closest_distance
end

function Loop(v,Movement)
	local damping
	if v.Name == "Skull" then
		damping = 800
	else
		damping = 1000
	end
	
	while true do
		local player, distance = getClosestPlayer(v)
		if player and distance > 1 then
			Movement.Position = player.PrimaryPart.Position
			Movement.D = damping
			Movement.MaxForce = Vector3.new(4000,10000,4000)
		end
		if v.Name == "Skull" then
			local nearestPlayer, nearestDistance
			for _, player in pairs(Players:GetPlayers()) do
				local character = player.Character
				local distance = player:DistanceFromCharacter(v.Position)
				if not character or 
					distance > maxDistance or
					(nearestDistance and distance >= nearestDistance)
				then
					continue
				end
				nearestDistance = distance
				nearestPlayer = player
			end

			--look to player's character by IA--
			if nearestPlayer then
				local char = nearestPlayer.Character
				local humanoidRootPart = char:FindFirstChild("HumanoidRootPart")
				if humanoidRootPart then
					v.CFrame = CFrame.lookAt(v.Position, humanoidRootPart.Position)
				end
			end
		end
		task.wait(1)
	end
end

function Refresh()
	for i, v in pairs(folder:GetChildren()) do
		if v:IsA("MeshPart") or v:IsA("Part") then
			-- PopUp Event --
			v.Touched:connect(function(hit)
				if hit.Parent then
					if hit.Parent:FindFirstChild("Humanoid")then
						local player = game.Players:GetPlayerFromCharacter(hit.Parent)
						if player then

						if hit.Parent.Humanoid.Health > 0 and v.CanTouch == true then
						v.CanTouch = false	
						v.CanCollide = false
							v.Transparency = 1
							if v.Name == "Coin" or v.Name == "Coin2" then
							v:FindFirstChild("Trail").Enabled = false
							local random = math.random(1,900)
							local xnew = random/1000
							local new = game.ReplicatedStorage.ShowAdd:Clone()
							new.Parent = player.PlayerGui.Main
							new.Position = UDim2.new(xnew,0,1,0)
							if v.Name == "Coin" then
								new.Text = "+1💴"
								player.playerstats.Coins.Value = player.playerstats.Coins.Value + 1
							end
							if v.Name == "Coin2" then
								v.NumberValue.Value = math.random(5,10)
								new.Text = "+" .. (v.NumberValue.Value) .. "💴"
								player.playerstats.Coins.Value = player.playerstats.Coins.Value + v.NumberValue.Value
							end
							local sound = Instance.new("Sound")
							sound.SoundId = "rbxassetid://330274138"
							sound.Parent = hit
							sound:Play()
							game.Debris:AddItem(sound,5)
							wait(1)

							end
							if v.Name == "Orb1" or v.Name == "Orb2" or v.Name == "Orb3" or v.Name == "OrbS" then
									if player:FindFirstChild("leaderstats3") then
									
								v.emitter:Emit(1)
								v:FindFirstChild("ParticleEmitter").Enabled = false
								local OrbSound = script:WaitForChild("Sound"):Clone()
								OrbSound.Parent = hit.Parent
								OrbSound:Play()
								game.Debris:AddItem(OrbSound, 4)
								if v.Name == "Orb1" then
											player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(10, 20)	
								end
								if v.Name == "Orb2" then
											player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(15, 35)	
								end
								if v.Name == "Orb3" then
											player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(20, 50)	
								end
								if v.Name == "OrbS" then
											player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(1, 5)	
								end
								end
							end
								if v.Name == "Skull" then
									local damage = math.random(1,5)

										hit.Parent:FindFirstChild("Humanoid"):TakeDamage(damage)
									
									local emitter = script.Part:Clone()
									emitter.Parent = hit.Parent:FindFirstChild("HumanoidRootPart")
									emitter.CFrame = v.CFrame
									game.Debris:AddItem(emitter, 3)
									
										local sound1 = Instance.new("Sound")
										sound1.SoundId = "rbxassetid://3059775781"
										sound1.Parent = hit.Parent
										sound1:Play()
										game.Debris:AddItem(sound1,5)

										local sound2 = Instance.new("Sound")
										sound2.SoundId = "rbxassetid://7837490457"
										sound2.Parent = hit.Parent
										sound2:Play()
										game.Debris:AddItem(sound2,5)
										
										local sound3 = Instance.new("Sound")
										sound3.SoundId = "rbxasset://sounds/uuhhh.wav"
										sound3.Parent = hit.Parent
										sound3:Play()
										game.Debris:AddItem(sound3,5)

								end
								if v:FindFirstChild("Material") then
								v:FindFirstChild("Trail").Enabled = false
								player.Materials:FindFirstChild(v.NameValue.Value).Value = player.Materials:FindFirstChild(v.NameValue.Value).Value + 1				
									Remote:FireClient(player,v.NameValue.Value,v.AssetID.Value)
									wait(1)
									end
							v:Destroy()
							end
						end
					end
					
					if hit.Parent:IsA('Tool') then	
						local tool = hit.Parent

						if tool.Slicing.Value == true  and v.Name == "Skull" then
							
							local emitter = script.Part:Clone()
							emitter.Parent = workspace
							emitter.CFrame = v.CFrame
							game.Debris:AddItem(emitter, 2)
							
							local sound2 = Instance.new("Sound")
							sound2.SoundId = "rbxassetid://7837490457"
							sound2.Parent = hit.Parent
							sound2:Play()
							game.Debris:AddItem(sound2,5)
							
							v:Destroy()
						end
					end
			end
			end)
			if not v:FindFirstChildOfClass("BodyPosition") then
				local Movement = Instance.new("BodyPosition",v)
				Loop(v,Movement)
			end
		end
	end
end

folder.ChildAdded:connect(Refresh)

Nueva imagen de mapa de bits.bmp (341.9 KB)

3 Likes

In function getClosestPlayer just iterate on the game.Players:GetPlayers()

What I’m talking about:

function getClosestPlayerHrp(radius) -- this function is from a public model
	local closestHrp, dist
	
	for _, player in ipairs(game.Players:GetPlayers()) do
		local plrChar = player.Character; if not plrChar then return end;
		local playerHumanoid = plrChar:FindFirstChild("Humanoid")
		if not playerHumanoid then
			continue
		end
--sorry if i didn't complete the code
4 Likes

You were so right… I wasn’t thinking the code correctly. By iterating through the whole workspace I was demanding too much memory. I just needed to iterate through the players… Thx!!!

2 Likes

Elseif method is better than 2 if methods.

if v.Name == "Orb1" then
	player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(10, 20)	
end
if v.Name == "Orb2" then
	player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(15, 35)	
end

To:

if v.Name == "Orb1" then
	player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(10, 20)	
elseif v.Name == "Orb2" then
	player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(15, 35)	
end

And I see many other functions that can be optimized. I will edit this post many times, I think.

  1. You’re checking the max distance many times, when you can just put it in getClosestPlayer() function
  2. Change BodyPosition to AlignPosition. Attachments are faster and not deprecated.
if v.Name == "Orb1" or v.Name == "Orb2" or v.Name == "Orb3" or v.Name == "OrbS" then

it’s better to check if its name is Skull than all of that

if v.Name == "Skull" then
  1. Learn if else end method. That’s the main issue
  2. Learn to use functions. It makes code tidier. For example: instead of
local sound1 = Instance.new("Sound")
sound1.SoundId = "rbxassetid://3059775781"
sound1.Parent = hit.Parent
sound1:Play()
game.Debris:AddItem(sound1,5)

local sound2 = Instance.new("Sound")
sound2.SoundId = "rbxassetid://7837490457"
sound2.Parent = hit.Parent
sound2:Play()
game.Debris:AddItem(sound2,5)
	
local sound3 = Instance.new("Sound")
sound3.SoundId = "rbxasset://sounds/uuhhh.wav"
sound3.Parent = hit.Parent
sound3:Play()
game.Debris:AddItem(sound3,5)

use this:

local function SoundPlay(id, parent) --function
    local sound = Instance.new("Sound")
    sound.SoundId = id
    sound.Parent = parent
    sound:Play()
    game.Debris:AddItem(sound, 5)
end

SoundPlay("rbxassetid://3059775781", hit.Parent)
SoundPlay("rbxassetid://7837490457", hit.Parent)
SoundPlay("rbxasset://sounds/uuhhh.wav", hit.Parent)
  1. Not clear structure there:
player.Materials:FindFirstChild(v.NameValue.Value).Value = player.Materials:FindFirstChild(v.NameValue.Value).Value + 1

Just use:

player.Materials:FindFirstChild(v.NameValue.Value).Value += 1
  1. This is too:
player.leaderstats3["Total XP"].Value = player.leaderstats3["Total XP"].Value + math.random(10, 20)	

Use:

player.leaderstats3["Total XP"].Value += math.random(10, 20)
  1. If you change if else structure with tables it will be 3 times faster.
  2. If you do it local but change leaderstats values on server through remote events it will be 5 times faster
  3. What is OrbS? OrbSpecial? if it gives that little much of XP then why isn’t it just Orb.
    It would be: Orb < Orb1 < Orb2 < Orb3 < Orb4 < Orb5
    Also, every of them except Orb(OrbS) have equal difference between them.
    Like you could use that formula: math.random(5 + 5 * OrbNumber, 5 + 15 * OrbNumber)
  4. hit.Parent:FindFirstChild("Humanoid") takes more time than hit.Parent.Humanoid so if we use both of them without a check(if there’s humanoid) and both of them gives same error then why would we choose slower version
  5. While true function will work even if you kill(destroy) skull, it’s very consuming loop
  6. There:
function Refresh()
	for i, v in pairs(folder:GetChildren()) do
		if v:IsA("MeshPart") or v:IsA("Part") then

Collection Service will be better but if u use only

function Refresh()
	for i, v in pairs(folder:GetChildren()) do

then it will be faster. Why you check for it to be Part or MeshPart? Create another folder with only Parts and MeshPart.

  1. Don’t use Touched event for something like this. It is very expensive for server.
    Use hitbox system for sword that kills them, and when they die script on server works

It’s all what I can say so far. You made whole working script with that little of knowledge, imagine what you can do if you learn other things. I recommend you to learn:

  • Remote Events
  • functions(module script if you want advanced)
  • Tables (they are faster than if else statements, basics are enough, I don’t know metatables yet but basics already made my code better)
  • Learn to write your architecture it helps to understand how to write your code
2 Likes

Thanks for your help!!! As you said I’m still learning and have long way to go… I will follow your advices to get a better performance game… Thx a lot for taking the time to write such a complete answer!

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.