Looking for feedback on this "local weather effects" script

I made a script to activate certain effects on the client for certain weather in my game. However, the script feels a little messy and rough, especially the repeat I have set up in the “rainy” startFunction(). I was just wondering if there are ways I can improve and optimize this system I have set up.

Code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Lighting = game:GetService("Lighting")
local RunService = game:GetService("RunService")
local Debris = game:GetService("Debris")
local player = game:GetService("Players").LocalPlayer
local lightingUnused = Lighting.unused
local serverData = ReplicatedStorage.serverData
local weather = serverData.weather
local cam = workspace.CurrentCamera

math.randomseed(tick())

local lastWeather
local weatherStepC
--local shelteredC
local weatherParticlesPart = workspace.WeatherParticles
local weatherParticles = weatherParticlesPart:GetChildren()
local allLighting = lightingUnused:GetChildren()
local weatherFunctions = {
	["sunny"] = { 
		startFunction = function()
			Lighting.Brightness = 1
			lightingUnused["Clear Sky"].Parent = Lighting
			lightingUnused.SunRays.Parent = Lighting
		end,
		endFunction = function()
			Lighting["Clear Sky"].Parent = lightingUnused
			Lighting.SunRays.Parent = lightingUnused
		end},
	["rainy"] = { 
		startFunction = function()
			lightingUnused["Rainy Sky"].Parent = Lighting
			lightingUnused["Cloudy Atmosphere"].Parent = Lighting
			Lighting.Brightness = 0.5
			script.RainAmbience:Play()
			for _,v in ipairs(weatherParticles) do
				if v.Name == "Rain" then
					v.Enabled = true
				end
			end
			weatherStepC = RunService.RenderStepped:Connect(function()
				weatherParticlesPart.Position = cam.CFrame.Position
			end)
			local direction = Vector3.new(0, -100, 0)
			local raycastParams = RaycastParams.new()
			repeat 
				task.wait()
				local origin = cam.CFrame.Position + Vector3.new(math.random(-25, 25), 50, math.random(-25, 25))
				local rainRay = workspace:Raycast(origin, direction, raycastParams)
				if rainRay then
					local part = workspace.RainHit:Clone()
					local particle = part.RainDrop
					part.Position = rainRay.Position
					part.Parent = workspace.roaming
					particle:Emit(1)
					Debris:AddItem(part, particle.Lifetime.Max)
				end
			until weather.Value ~= "rainy"
		end,
		endFunction = function()
			script.RainAmbience:Stop()
			for _,v in ipairs(weatherParticles) do
				if v.Name == "Rain" then
					v.Enabled = false
				end
			end
			weatherStepC:Disconnect()
			weatherStepC = nil
			Lighting["Rainy Sky"].Parent = lightingUnused
			Lighting["Cloudy Atmosphere"].Parent = lightingUnused
		end},
	["snowy"] = { 
		startFunction = function() 
			Lighting.Brightness = 0.5
			lightingUnused["Snowy Sky"].Parent = Lighting
			lightingUnused["Cloudy Atmosphere"].Parent = Lighting
			script.SnowAmbience:Play()
			for _,v in ipairs(weatherParticles) do
				if v.Name == "Snow" then
					v.Enabled = true
				else
					v.Enabled = false
				end
			end
			weatherStepC = RunService.RenderStepped:Connect(function()
				weatherParticlesPart.Position = cam.CFrame.Position
			end)
		end,
		endFunction = function()
			script.SnowAmbience:Stop()
			for _,v in ipairs(weatherParticles) do
				if v.Name == "Snow" then
					v.Enabled = false
				end
			end
			weatherStepC:Disconnect()
			weatherStepC = nil
			Lighting["Snowy Sky"].Parent = lightingUnused
			Lighting["Cloudy Atmosphere"].Parent = lightingUnused
		end}
}
local function weatherChange()
	if lastWeather and weatherFunctions[lastWeather].endFunction then
		weatherFunctions[lastWeather].endFunction()
	end
	lastWeather = weather.Value
	if weatherFunctions[weather.Value].startFunction then
		weatherFunctions[weather.Value].startFunction()
	end
end
weatherChange()
weather:GetPropertyChangedSignal("Value"):Connect(weatherChange)
1 Like

I don’t know if this part of what you consider messy, but personally, I don’t put functions in tables like that:

local t = {
  fun = function()
  end
}

I prefer to do

local t = {}
function t.fun()
end

like I would in a module script and if you want, you could split this up into a modulescript

local weather = {
  sunny = {},
 -- etc.
}
function weather.sunny.start()
end
-- and whatever other functions
return weather

And this could even by more object oriented if needed (but don’t over-complicate)

In terms of the repeat, unless you do a logic overhaul (this would require some other way to place RainHits), I can’t find any way but a loop. The only semi-improvement would be to use while instead of repeat, just because a repeat isnt strictly needed and while is more common, and I think while is more readable

2 Likes

Thanks for your feedback! I had no idea you could put functions in a table like that. I’m probably going to split the table into a ModuleScript as that would be more organized.

1 Like

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