Hey all. So I have this neat little raycast rain system that is already pretty optimized, but there are still some minor framerate drop issues. And a good solution I can think of here is using BulkMoveTo which is perfect for my situation as I am moving hundreds of parts for every hearbeat.
But there’s one issue, I have no idea on how to create an array for the list of CFrames needed to move each and every single part effectively.
How should I do this?
local RainRadiusX = 80 -- Left, Right
local RainRadiusZ = 70 -- Forward, Back
local MaxRainDistance = 800
local RainSpeed = 300
local Rate = 15
local RainParts = 500
local RainOffsetZ = 30
local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Whitelist
local Gamesettings = UserSettings().GameSettings
local RS = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Terrain = workspace.Terrain
local PartCache = require(ReplicatedStorage:WaitForChild("PartCache")) -- All this does is move parts to it's desired location when it needs to be used, or moves it very far away so that it doesn't get rendered.
local RainPartsFolder = Instance.new("Folder")
RainPartsFolder.Name = "RainContent"
RainPartsFolder.Parent = workspace
local RainPartTemplate = Instance.new("Part")
RainPartTemplate.Material = Enum.Material.SmoothPlastic
RainPartTemplate.Color = Color3.fromRGB(255, 255, 255)
RainPartTemplate.Size = Vector3.new(0.1, 5, 0.1)
RainPartTemplate.Transparency = 0.9
RainPartTemplate.CanCollide = false
RainPartTemplate.CanTouch = false
RainPartTemplate.CastShadow = false
RainPartTemplate.Anchored = true
RainPartTemplate.Name = "RainPart"
local SplashPart = Instance.new("Part")
SplashPart.Size = Vector3.new(0.1, 0.1, 0.1)
SplashPart.Transparency = 1
SplashPart.CanCollide = false
RainPartTemplate.CastShadow = false
SplashPart.Anchored = true
SplashPart.CanTouch = false
SplashPart.Name = "RainSplashPart"
SplashPart.Parent = RainPartsFolder
local SplashParticle = script.SplashEffect:Clone()
SplashParticle.Parent = SplashPart
local AbsorbantMaterials = { -- Materials that don't create the rain splash effect
Enum.Material.Grass,
Enum.Material.Fabric,
Enum.Material.Sand,
}
local DeltaTime = 0
local RainDeltaIncrement = RainSpeed
local WhiteListIndex = 0
local Whitelist = {}
local Cache = PartCache.new(RainPartTemplate, RainParts, RainPartsFolder) -- All this module does is move parts either really far away out of render distance, or brings the part used it can be used as a rain drop instead of destroying and creating new parts
local function SetupWhitelist(InstanceToSearch)
for i, child in ipairs(InstanceToSearch:GetDescendants()) do
if child:IsA("BasePart") and child.CanCollide and child.Transparency < 1 then
WhiteListIndex = WhiteListIndex + 1
table.insert(Whitelist, WhiteListIndex, child) -- Add the part to the whitelist
end
end
end
function CastRain()
Params.FilterDescendantsInstances = Whitelist
local RainOrigin = (game.Workspace.CurrentCamera.CFrame * CFrame.new(0, 0, -RainOffsetZ)).Position + Vector3.new(0, math.random(100, 120), 0)
local RandomPosition = RainOrigin + Vector3.new(math.random(-RainRadiusX/2, RainRadiusX/2), 0, math.random(-RainRadiusZ/2, RainRadiusZ/2))
local Direction = Vector3.new(0, -MaxRainDistance, 0)
local RainRay = workspace:Raycast(RandomPosition, Direction, Params)
if RainRay then
local HitPos = RainRay.Position
local Dist = (RainOrigin - HitPos).Magnitude
-- Create the rain drop
local RainPart = Cache:GetPart()
RainPart.Position = RandomPosition
local RainFallCFrame = CFrame.new(0, -RainDeltaIncrement, 0)
-- Move the rain drop until it hits the surface
repeat
RS.RenderStepped:Wait()
RainPart.CFrame *= RainFallCFrame
until RainPart.CFrame.Y <= HitPos.Y
-- Create the splash effect
if not table.find(AbsorbantMaterials, RainRay.Instance.Material) and RainRay.Instance.CanCollide then
SplashPart.Position = HitPos
SplashParticle:Emit(1)
end
Cache:ReturnPart(RainPart)
end
end
local function CheckQuality()
local Quality = Gamesettings.SavedQualityLevel.Value
if Quality == 10 then
Rate = 15
elseif Quality >= 8 then
Rate = 10
elseif Quality >= 5 then
Rate = 6
else
Rate = 3
end
end
Gamesettings.Changed:Connect(CheckQuality)
RS.Heartbeat:Connect(function(step)
for i = 1, Rate do
CastRain()
RainDeltaIncrement = RainSpeed * step
DeltaTime = step
end
end)
SetupWhitelist(workspace)
CheckQuality()