Looks like this is the part here @howmanysmaII comes in
God tier optimization, as usual. Thanks Lily!
I’ll be pushing your changes to master shortly.
Your changes are live! Thanks for the helping hand! <3
I like this! This would be prefect for a horror a game who thinks that would be awesome?!
Hello. I found a glitch. If the player is using the automatic graphics mode, the rain will not show up at all. I know it is above 8 graphics because the terrain water is still clear.
Not a bug, but rather an annoying feature of the way Automatic works. It doesn’t tell you what it’s being set to, so you have to just assume the worst or you’ll run into problems if it assumes high settings and is really low.
This is very annoying API behavior and developers have been asking for it to change for nearly half a decade at this point. Support a feature request!
I took the script and made it into a module so that you can Enable / Disable the Rain effect during the game, You can also change the settings of the rain during the game.
Module:Enable(Optional Settings) will enable the rain and if the Settings are given it will update the settings of the rain, If settings are not given it will continue to use the previously given settings or the default if non were given.
Module:Disable() Disables the rain
Module:SetSetting(Setting) will change the rain settings to the given settings, Not all settings have to be given.
Code :
--[=[
--Copyright boatbomber 2019--
--Given under a BSD 3-Clause License--
Explanation of license: https://tldrlegal.com/license/bsd-3-clause-license-(revised)
--FEATURES--
Creates droplets of "water" on the screen, with a distortion effect, giving great immersion
for games that have rainy environments.
Droplets will not spawn if the player is indoors or under cover of some sort.
Droplets will not spawn if the camera is pointed down, as that is avoiding "getting rain in the eyes".
--WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING--
THIS PRODUCT RELIES ON GLASS MATERIAL, THUS SHARING ALL THE LIMITATIONS OF GLASS.
Non-opaque objects are currently not visible through glass.
This includes, but is not limited to, transparent parts, decals on transparent
parts, particles, and world-space gui objects.
Additionally, it only looks right for users with graphic settings of at least 8.
Hence, I've set it to only spawn droplets if the user has the graphics set high enough.
--WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING-- --WARNING--
--]=]
local Module = {}
-- Constants
local Settings = {
-- Rate: How many droplets spawn per second
Rate = 8;
-- Size: How large the droplets roughly are (in studs)
Size = 0.1;
-- Tint: What color the droplets are tinted (leave as nil for a default realistic light blue)
Tint = Color3.fromRGB(226, 244, 255);
-- Fade: How long it takes for a droplet to fade
Fade = 1.5;
}
local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local UpVec = Vector3.new(0, 1, 0)
local DROPLET_SIZE = Vector3.new(1, 1, 1)
local EMPTY_CFRAME = CFrame.new()
----------------------------------------------------------------------------
--- Variables ------------------------------------------------------------
----------------------------------------------------------------------------
--Player related
local Camera = Workspace.CurrentCamera
local Player = Players.LocalPlayer
local GameSettings = UserSettings().GameSettings
local CanShow = GameSettings.SavedQualityLevel.Value >= 8
--Raycasting
local ignoreList = {Player.Character or Player.CharacterAdded:Wait()}
local IgnoreLength = 1
--Localizing
local ipairs = ipairs
--Settings localized
local Rate = Settings.Rate
local Size = Settings.Size
local Tint = Settings.Tint or Color3.fromRGB(226, 244, 255)
local Fade = Settings.Fade
--Fade tween
local fadeInfo = TweenInfo.new(Fade, Enum.EasingStyle.Sine, Enum.EasingDirection.In)
local strechInfo = TweenInfo.new(Fade / 1.05, Enum.EasingStyle.Quint, Enum.EasingDirection.In)
local fadeGoal = {Transparency = 1}
local accumulatedChance = 0
----------------------------------------------------------------------------
--- Prefab Basic Objects -------------------------------------------------
----------------------------------------------------------------------------
--Droplet holder
local ScreenBlock = Instance.new("Part")
ScreenBlock.Size = Vector3.new(2, 2, 2)
ScreenBlock.Transparency = 1
ScreenBlock.Anchored = true
ScreenBlock.CanCollide = false
ScreenBlock.Parent = Camera
local ScreenBlockCFrame = EMPTY_CFRAME
RunService:BindToRenderStep("ScreenRainUpdate", Enum.RenderPriority.Camera.Value + 1, function()
ScreenBlockCFrame = Camera.CFrame
ScreenBlock.CFrame = ScreenBlockCFrame
end)
----------------------------------------------------------------------------
--- Functions ------------------------------------------------------------
----------------------------------------------------------------------------
local function DestroyDroplet(d)
wait(Fade)
-- Proper GC
for _, Child in ipairs(d:GetChildren()) do
local Index = table.find(ignoreList, Child)
if Index then
ignoreList[Index] = ignoreList[IgnoreLength]
ignoreList[IgnoreLength] = nil
IgnoreLength = IgnoreLength - 1
end
end
local Index = table.find(ignoreList, d)
if Index then
ignoreList[Index] = ignoreList[IgnoreLength]
ignoreList[IgnoreLength] = nil
IgnoreLength = IgnoreLength - 1
end
d:Destroy()
end
--Returns whether the given position is under cover
local function UnderObject(pos, l)
l = l or 120
local hit, position = Workspace:FindPartOnRayWithIgnoreList(Ray.new(pos, UpVec * l), ignoreList)
if hit then
return hit.Transparency ~= 1 and true or UnderObject(position + UpVec, l - (pos - position).Magnitude)
else
return false
end
end
--Creates a random droplet on screen
local function CreateDroplet()
--Setup
local stretch = 1 + math.random(15) / 10
local RunAmount = math.random(4)
local Tweens = table.create(RunAmount * 2 + 2)
local TweensLength = 0
local SizeOffset = math.random((Size / 3) * -10, (Size / 3) * 10) / 10
local Scale = Size + SizeOffset
local MeshScale = Vector3.new(Scale, Scale, Scale)
--Main droplet object
local DropletMain = Instance.new("Part")
DropletMain.Material = Enum.Material.Glass
DropletMain.CFrame = EMPTY_CFRAME
DropletMain.CanCollide = false
DropletMain.Transparency = 0.5
DropletMain.Name = "Droplet_Main"
DropletMain.Color = Tint
DropletMain.Size = DROPLET_SIZE
local Mesh = Instance.new("SpecialMesh")
Mesh.MeshType = Enum.MeshType.Sphere
Mesh.Scale = MeshScale
Mesh.Parent = DropletMain
--Create droplet extrusions
for i = 1, RunAmount do
local eSizeOffset = math.random(
(Size / 3) * -100,
(Size / 3) * 100
) / 100
local ExtrusionCFrame = CFrame.new(Vector3.new(
math.random(-(Size * 40), Size * 40) / 100,
math.random(-(Size * 40), Size * 40) / 100,
0
))
local ExtrusionScale = Size / 1.5 + eSizeOffset
local ExtrusionMeshScale = Vector3.new(ExtrusionScale, ExtrusionScale, ExtrusionScale)
local Extrusion = Instance.new("Part")
Extrusion.Material = Enum.Material.Glass
Extrusion.CFrame = ExtrusionCFrame
Extrusion.CanCollide = false
Extrusion.Transparency = 0.5
Extrusion.Name = "Extrusion_" .. i
Extrusion.Color = Tint
Extrusion.Size = DROPLET_SIZE
local ExtrusionMesh = Instance.new("SpecialMesh")
ExtrusionMesh.MeshType = Enum.MeshType.Sphere
ExtrusionMesh.Scale = ExtrusionMeshScale
ExtrusionMesh.Parent = Extrusion
Extrusion.Parent = DropletMain
local weld = Instance.new("Weld")
weld.C0 = ExtrusionCFrame:Inverse() * EMPTY_CFRAME
weld.Part0 = Extrusion
weld.Part1 = DropletMain
weld.Parent = Extrusion
IgnoreLength = IgnoreLength + 1
TweensLength = TweensLength + 1
ignoreList[IgnoreLength] = Extrusion
Tweens[TweensLength] = TweenService:Create(Extrusion, fadeInfo, fadeGoal)
TweensLength = TweensLength + 1
Tweens[TweensLength] = TweenService:Create(ExtrusionMesh, strechInfo, {
Scale = Vector3.new(ExtrusionScale, ExtrusionScale * stretch, ExtrusionScale);
Offset = Vector3.new(0, -(ExtrusionScale * stretch) / 2.05, 0);
})
end
IgnoreLength = IgnoreLength + 1
TweensLength = TweensLength + 1
ignoreList[IgnoreLength] = DropletMain
Tweens[TweensLength] = TweenService:Create(DropletMain, fadeInfo, fadeGoal)
TweensLength = TweensLength + 1
Tweens[TweensLength] = TweenService:Create(Mesh, strechInfo, {
Scale = Vector3.new(Scale, Scale * stretch, Scale);
Offset = Vector3.new(0, -(Scale * stretch) / 2.05, 0);
})
local NewCFrame = ScreenBlockCFrame:ToWorldSpace(CFrame.new(
math.random(-100, 100) / 100,
math.random(-100, 100) / 100,
-1
))
DropletMain.CFrame = NewCFrame
local weld = Instance.new("Weld")
weld.C0 = NewCFrame:Inverse() * ScreenBlockCFrame
weld.Part0 = DropletMain
weld.Part1 = ScreenBlock
weld.Parent = DropletMain
for _, t in ipairs(Tweens) do
t:Play()
end
local DestroyRoutine = coroutine.create(DestroyDroplet)
coroutine.resume(DestroyRoutine, DropletMain)
DropletMain.Parent = ScreenBlock
end
local function OnGraphicsChanged()
CanShow = GameSettings.SavedQualityLevel.Value >= 8
end
GameSettings:GetPropertyChangedSignal("SavedQualityLevel"):Connect(OnGraphicsChanged)
----------------------------------------------------------------------------
--- Functionality Loop ---------------------------------------------------
----------------------------------------------------------------------------
local Connection
local Enabled = false
function Module:SetSetting(Setting)
if typeof(Setting) then
if typeof(Setting.Rate) == "number" then
Settings.Rate = Setting.Rate
end
if typeof(Setting.Size) == "number" then
Settings.Size = Setting.Size
end
if typeof(Setting.Tint) == "Color3" then
Settings.Tint = Setting.Tint
end
if typeof(Setting.Fade) == "number" then
Settings.Fade = Setting.Fade
end
Rate = Settings.Rate
Size = Settings.Size
Tint = Settings.Tint
Fade = Settings.Fade
end
end
function Module:Enable(Setting)
if Enabled == false then
Enabled = true
Connection = RunService.Heartbeat:Connect(function(deltaTime)
accumulatedChance += deltaTime * Settings.Rate
if CanShow and ScreenBlockCFrame.LookVector.Y > -0.4 and not UnderObject(ScreenBlockCFrame.Position) then
for i = 1, math.floor(accumulatedChance) do
CreateDroplet()
end
accumulatedChance %= 1
else
accumulatedChance %= 1
end
end)
if Setting then
Module:SetSetting(Setting)
end
end
end
function Module:Disable()
if Enabled == true then
Enabled = false
Connection:Disconnect()
end
end
return Module
Update!
- Uses object pooling to avoid creating and destroying so many parts constantly
- No longer uses Welds, uses WordRoot:BulkMoveTo instead
- No more TweenService usage
- Adjustable update frequency
- Better performance (getting 300FPS in the demo place on my laptop!)
- Neater code
Also put together a proper Rojo compliant repository instead of that one random .lua file.
Update!
- Now a module instead of LocalScript
- Added
ScreenRain:Enable(settings?)
- Added
ScreenRain:Disable()
- Added
ScreenRain:Configure(settings)
- Tweaked the transparency values for nicer effect
This update makes it easy to have weather systems and zone areas since you can now easily turn rain on and off and configure the settings on the fly!
If you want the behavior from before this update, your LocalScript should just look like this:
local ScreenRain = require(script:WaitForChild("ScreenRain"))
ScreenRain:Enable()
What do i put in the ScreenRain:Enable(setting) what do I put in the setting place?
You can put in a dictionary containing any of the settings that you wish to change from the defaults, although it is not necessary if you don’t wish to change them. Note that you do not need to include all the settings, only ones that you wish to change. Below is an example (using the default settings) of an input.
local Settings: {[string]: number | Color3} = {
Rate = 5, -- Spawn rate (droplets/second)
Size = 0.08, -- Average droplet size
Tint = Color3.fromRGB(226, 244, 255), -- Droplet colour
Fade = 1.5, -- Time to fade out
UpdateFreq = 1 / 45, -- Update frequency
}
ScreenRain:Enable(Settings)
oh okay now i understand thank you!
i won’t stop having this error for some reason:
Here the script:
local RainModule = require(game.ReplicatedStorage:WaitForChild('ScreenRain'))
local Settings: {[string]: number | Color3} = {
Rate = 5, -- Spawn rate (droplets/second)
Size = 0.08, -- Average droplet size
Tint = Color3.fromRGB(226, 244, 255), -- Droplet colour
Fade = 1.5, -- Time to fade out
UpdateFreq = 1 / 45, -- Update frequency
}
game.ReplicatedStorage.Water.OnClientEvent:Connect(function()
local Enabled = true
print('firedlolxd')
RainModule.Enable(Settings)
end)
in a local script
You must use :Enable()
not .Enable()
.
yeah sorry i forgot to say that i fixed the bug sorry! i confused javascript with lua
wow!!! i love this might use it in a game
How do I activate the rain and screen distortion? Sorry if this is obvious, I am new to this.
Anyone have an asset link as physical demonstration?
I see no video, that don’t exist or private
DevForum lost all the videos! No idea what happened there