My projectile script lags so much

looks like other game’s projectile is not laggy but mine is making a lot of lag.
It wasn’t laggy before map update(yes it was baseplate before update) and it lags a lot now.
Where is problem and how to fix? please let me know how to make efficient raycast projectile.

local pierceImmune = {}
									local projectileRay = RaycastParams.new()
									projectileRay.FilterType = Enum.RaycastFilterType.Whitelist

									local bullet = param.hitPart:Clone()
									bullet.CFrame = CFrame.new(param.fireCF.Position, param.fireCF.Position + param.fireDirection * 1)
									bullet.Parent = workspace.projectile
									--game:GetService("RunService").Heartbeat:wait()
									
									local rayFilter = {}
									if not param.rayFilter then
										for _, filterTarget in pairs(workspace.entity:GetChildren()) do
											if not table.find(immune, filterTarget) then
												for _, filterPart in pairs(filterTarget:GetChildren()) do
													if filterPart:IsA("BasePart") then
														if not table.find(pierceImmune, filterPart) and not table.find(rayFilter, filterPart) then
															table.insert(rayFilter, filterPart)
														end
													end
												end
											end
										end
										for _, filterTarget in pairs(workspace.map:GetDescendants()) do
											if filterTarget:IsA("BasePart") then
												if filterTarget.Anchored == true and filterTarget.CanCollide == true and not table.find(rayFilter, filterTarget) then
													table.insert(rayFilter, filterTarget)
												end
											end
										end
									end
									local function bulletCast(bulletDistance)
										local funcStart = tick()
										projectileRay.FilterDescendantsInstances = rayFilter
										local rayResult = workspace:Raycast(bullet.Position, param.fireDirection * bulletDistance, projectileRay)
										if rayResult then
											if rayResult.Instance.Parent:FindFirstChild("Humanoid") then
												if not table.find(targets, rayResult.Instance) then
													table.insert(targets, rayResult.Instance)
													for _, filterPart in pairs(rayResult.Instance.Parent:GetChildren()) do
														if filterPart:IsA("BasePart") and not table.find(rayFilter, filterPart) then
															table.insert(pierceImmune, filterPart)
														end
													end 
													if param.pierce == true then
														table.insert(pierceImmune, rayResult.Instance)
														bullet.Position += bullet.CFrame.LookVector * bulletDistance
													else
														bullet.Position = rayResult.Position
														bullet.Anchored = false
														local newWeld = Instance.new("WeldConstraint")
														newWeld.Part0 = bullet
														newWeld.Part1 = rayResult.Instance
														newWeld.Parent = bullet
														coroutine.wrap(function()
															wait(3)
															bullet:Destroy()
														end)()
														print(tick() - funcStart)
														return "break"
													end
												end
											else
												if param.pierce == true then
													table.insert(pierceImmune, rayResult.Instance)
													bullet.Position += bullet.CFrame.LookVector * bulletDistance
												else
													bullet.Position = rayResult.Position
													coroutine.wrap(function()
														wait(3)
														bullet:Destroy()
													end)()
													print(tick() - funcStart)
													return "break"
												end
											end
										else
											bullet.Position += bullet.CFrame.LookVector * bulletDistance
										end
									end
									
									local moveCount = math.floor(param.maxRange / param.bulletSpeed)
									coroutine.wrap(function()
										for count = 1, moveCount do
											while game:GetService("ReplicatedStorage").status.timestop.Value == true do
												game:GetService("RunService").Heartbeat:wait()
											end
											game:GetService("RunService").Heartbeat:wait()
											local result = bulletCast(param.bulletSpeed)
											if param.pierce == false then
												if result == "break" then
													hitTarget()
												end
											else
												hitTarget()
											end
											if result == "break" then
												break
											end
										end
										while game:GetService("ReplicatedStorage").status.timestop.Value == true do
											game:GetService("RunService").Heartbeat:wait()
										end
										game:GetService("RunService").Heartbeat:wait()
										if param.maxRange - moveCount * param.bulletSpeed > 0 then
											local result = bulletCast(param.maxRange - moveCount * param.bulletSpeed)
											if result == nil then
												bullet:Destroy()
											end
										end
										coroutine.wrap(function()
											pcall(function()
												wait(3)
												bullet:Destroy()
											end)
										end)()
									end)()

If I am not mistaken, projectile animation is typically handled on the client. If a bullet is animated on the server side, any lag between the server and client will become extremely noticeable,

I suggest you handle bullet animation on the client and use a RemoteEvent to send a signal to the server which send a signal back to the other existing clients that tell them to animate a local projectile on their side.

1 Like