Improving lightning strike code

I took some model and code from a YouTube video for a tool and modified it to be used on its own to randomly make a lightning strike happen in an area of a part that will kill or damage players near it.

I’m just not too sure how I went about it. It works, that’s for sure but I don’t know how efficient the code is.

Here is the ServerScript:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")

local cameraEvent = ReplicatedStorage.events.cameraEvent 

local lightningEmitter = Workspace.lightningPart

local attachmentsList = {}
local lightningDebounce = true

while true do
	local randomX = lightningEmitter.Position.X + math.random(-lightningEmitter.Size.X / 2, lightningEmitter.Size.X / 2)
	local randomZ = lightningEmitter.Position.Z + math.random(-lightningEmitter.Size.Z / 2, lightningEmitter.Size.Z / 2)

	local hitPosition = Vector3.new(randomX, lightningEmitter.Position.Y, randomZ)
	local cloudCframe = CFrame.new(hitPosition) + Vector3.new(0, 35, 0)

	local cloud = ReplicatedStorage.Lightning.Cloud:Clone()
	cloud.CFrame = cloudCframe
	cloud.Parent = workspace

	task.wait(math.random(5, 15))

	local glow = ReplicatedStorage.Lightning.CloudGlow:Clone()
	glow.CFrame = cloudCframe
	glow.Parent = workspace

	task.wait(3)

	local attachmentsAmount = math.random(7, 11)

	local increment = (hitPosition - cloudCframe.Position).Magnitude / attachmentsAmount

	local lastWidth = Random.new():NextNumber(0.5, 1.3)

	task.spawn(function()
		for i = 1, attachmentsAmount do
			local attachment = Instance.new("Attachment")

			task.delay(1, function()
				attachment:Destroy()
			end)

			table.insert(attachmentsList, attachment)

			local basePosition = Vector3.new(0, -(i - 1) * increment, 0)
			
			local rx = Random.new():NextNumber(-4, 4)
			local ry = Random.new():NextNumber(-3, 3)
			local rz = Random.new():NextNumber(-4, 4)

			basePosition += Vector3.new(rx, ry, rz)

			if lightningDebounce then
				lightningDebounce = false

				task.delay(0.35, function()
					local hitVFX = ReplicatedStorage.Lightning.HitParticles:Clone()
					hitVFX.Position = hitPosition
					hitVFX.Parent = workspace

					local sound = ReplicatedStorage.Lightning.LightningSound:Clone()
					sound.Parent = hitVFX
					sound:Play()

					task.delay(0.3, function()
						for i, descendant in pairs(hitVFX:GetDescendants()) do
							if descendant:IsA("ParticleEmitter") or descendant:IsA("PointLight") then
								descendant.Enabled = false
							end
						end

						task.wait(3)
						hitVFX:Destroy()
						lightningDebounce = true
					end)
				end)
			end

			if i == 1 then
				basePosition = Vector3.new(0, 0, 0)
			elseif i == attachmentsAmount then
				basePosition =  hitPosition - cloudCframe.Position

				local min = hitPosition - Vector3.new(ReplicatedStorage.Lightning.StrikeArea.Size.X / 2, 0, ReplicatedStorage.Lightning.StrikeArea.Size.Z / 2)
				local max = hitPosition + Vector3.new(ReplicatedStorage.Lightning.StrikeArea.Size.X / 2, 10, ReplicatedStorage.Lightning.StrikeArea.Size.Z / 2)
				local region = Region3.new(min, max)

				local partsInRadius = workspace:FindPartsInRegion3(region, nil, 1000)

				for i, part in pairs(partsInRadius) do
					if part.Name == "HumanoidRootPart" then
						local player = Players:GetPlayerFromCharacter(part.Parent)
						local distance = (hitPosition - Vector3.new(hitPosition.X, hitPosition.Y, part.Position.Z)).Magnitude

						if player then
							cameraEvent:FireClient(player, "cameraShake", hitPosition)

							if distance <= 4 then
								part.Parent.Humanoid:TakeDamage(math.huge)
							elseif distance > 4 and distance < 8 then
								part.Parent.Humanoid:TakeDamage(50)
							elseif distance > 8 and distance < 12 then
								part.Parent.Humanoid:TakeDamage(25)
							end
						end
					end
				end
			end

			attachment.Position = basePosition
			attachment.Parent = cloud

			local beam = Instance.new("Beam")
			beam.Attachment0 = attachmentsList[i - 1]
			beam.Attachment1 = attachment
			beam.Color = ColorSequence.new{ColorSequenceKeypoint.new(0, Color3.fromRGB(135, 143, 255)), ColorSequenceKeypoint.new(1, Color3.fromRGB(135, 143, 255))}
			beam.Transparency = NumberSequence.new{NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 0)}
			beam.LightInfluence = 0
			beam.Brightness = 5
			beam.LightEmission = 5
			beam.FaceCamera = true
			beam.Width0 = lastWidth
			beam.Width1 = math.clamp(lastWidth + Random.new():NextNumber(-0.4, 0.2), 0.1, 1)
			beam.Parent = cloud

			lastWidth = beam.Width1

			task.delay(1, function()
				beam:Destroy()
			end)

			task.wait(Random.new():NextNumber(0.03, 0.05))
		end

		cloud.CloudParticles.Enabled = false
	end)

	task.wait(0.2)
	glow.Attachment.GlowParticles.Enabled = false

	for i, descendant in pairs(cloud:GetDescendants()) do
		if descendant:IsA("ParticleEmitter") or descendant:IsA("PointLight") then
			descendant.Enabled = false
		end
	end

	task.wait(1)
	glow:Destroy()

	task.wait(2)
	cloud:Destroy()
	table.clear(attachmentsList)
end

Here is the project file:
lightning.rbxl (62.9 KB)

There is also the strange issue with the cloud particles kinda just flickering on and off on occasion when it respawns. Not sure what that is about.

use runservice instead of a while true do loop

  • turn Random.new() into a local variable at the top
  • use RunService instead of a loop
  • turn Vector3.new(0, 0, 0)s into Vector3.zero
  • replace Humanoid:TakeDamage with Humanoid.Health -= x or Humanoid.Health = 0
  • turn the beam.Color = ColorSequence.new into a local variable for reuse