Hello! I made a script that generates low-poly clouds for my low-poly world.
The script is entirely client-sided; since it’s purely aesthetic, I saw no need to have it be on the server. This is what they look like:
As you can see, there are a LOT of clouds! At any given moment, the client is rendering between 900 to 1,100 clouds.
The way it works is I’ve got 20 unions. Half of them are small clouds separated into a file in ReplicatedStorage called A and the other half are big bunches of clouds in a folder called B. There is a higher chance of a cloud from A being created than B, about a 75 percent chance to B’s 25 percent. Additionally, in any given node in the sky where a cloud could appear, there’s only a 20 percent chance of a cloud appearing.
I use unions because I figure it’d be better than rendering a bunch of smaller blocks individually and welding them. Also, unions look better when transparent in my opinion. As the sun goes down, the color of all the clouds changes too in order to match the night sky.
When a player first joins my game, a script in ReplicatedFirst creates a big line of nodes in the distance, each responsible for sending a line of clouds every 10 seconds. When the clouds spawn, they can be off on the X or Z axis by between 0 or 500 studs to keep the clouds from looking like a grid and more natural. They can also be up 10 or down 10 studs. As clouds get farther away, they are automatically removed as new ones take their place so that the number of clouds is never continuously increasing, taking up the client’s memory.
I find that my game runs relatively fine when I play. My ping hovers between 60 to 110 when I test. I wanna see if I can make that a bit better.
Here is my main script. (Note: the script that causes the clouds to change color is part of a separate Time Cycle script, which I won’t show because I don’t think it’s part of the problem)
local OPAQUE = 0 --Cloud transparency
local SPEED = 10 --Studs clouds move per second
local DISTANCE = 25 --Distance between each point
local NUMBER = 300 --How many clouds to be generated ahead and to the sides of the starting part
local RANDOM = 500 --Max studs a cloud can be off a point by
local A = script.Parent.CloudStorage.A
local B = script.Parent.CloudStorage.B
local TS = game:GetService("TweenService")
local activity = workspace:WaitForChild("Activity")
local storage = activity.Clouds:WaitForChild("Storage")
local points = activity.Clouds:WaitForChild("Points")
local start = activity.Clouds:WaitForChild("Start")
local function generatePoints()
local pointsList = {}
local lastPoint = start
local side = 1
for pointNum = 1, NUMBER do
local newPoint = Instance.new("Part")
newPoint.Name = pointNum
newPoint.Transparency = 1
newPoint.Anchored = true
newPoint.CanCollide = false
newPoint.CFrame = lastPoint.CFrame * CFrame.new(DISTANCE * side * pointNum, 0, 0)
newPoint.Parent = points
lastPoint = newPoint
side = side * -1 --Alternate left and right
pointsList[tostring(pointNum)] = newPoint
wait()
end
pointsList["0"] = start
return pointsList
end
local function createCloud(point, headStart)
local willACloudAppear = math.random(1, 5) --20% chance of a cloud appearing
local appearInfo = TweenInfo.new(5, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
local moveInfo = TweenInfo.new(10, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
if willACloudAppear == 1 then
local pickCloud = math.random(1, 4) --One in four chance of a smaller cloud
if pickCloud ~= 1 then
pickCloud = B[math.random(1, 10)]
else
pickCloud = A[math.random(1, 10)]
end
local createCloud = pickCloud:Clone()
createCloud.Name = "1"
createCloud.Parent = storage
createCloud.Transparency = 1
if headStart == nil then
headStart = 0
end
createCloud.CFrame = point.CFrame * CFrame.new(math.random(-RANDOM, RANDOM), math.random(-10, 10), math.random(-RANDOM, RANDOM)) * CFrame.new(0, 0, -headStart * 750) --The RANDOM variable allows clouds to spawn with a bit of freedom in where they are in conjunction with their node
local cloudAppear = TS:Create(createCloud, appearInfo, {Transparency = OPAQUE})
cloudAppear:Play()
local moveNum = 0
spawn(function()
repeat
local cloudMove = TS:Create(createCloud, moveInfo, {CFrame = createCloud.CFrame * CFrame.new(0, 0, -SPEED * 10)})
cloudMove:Play()
wait(10)
moveNum = moveNum + 1
until moveNum >= (DISTANCE - headStart)
local cloudGone = TS:Create(createCloud, appearInfo, {Transparency = 1})
cloudGone:Play()
wait(1)
createCloud:Destroy()
end)
end
end
local createPoints = generatePoints()
spawn(function()
for start = 1, 11 do --This generates a bunch of clouds right when the player joins
spawn(function() --Without it, the sky would at first be blank as clouds approached from the distance
for i = 0, NUMBER do
createCloud(createPoints[tostring(i)], start)
wait()
end
end)
end
end)
while wait(10) do
spawn(function()
for i = 0, NUMBER do
createCloud(createPoints[tostring(i)])
wait()
end
end)
end
Any helpful tips on how I could improve is super appreciated! Thanks!