Created
February 23, 2020 22:13
-
-
Save howmanysmall/d2ec7e781c9a02093d12374715f3b1ed to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[=[ | |
--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 Workspace = game:GetService("Workspace") | |
local Players = game:GetService("Players") | |
local RunService = game:GetService("RunService") | |
local TweenService = game:GetService("TweenService") | |
-- Constants | |
local Settings = { | |
-- Rate: How many droplets spawn per second | |
-- Rate = 64; | |
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 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} | |
---------------------------------------------------------------------------- | |
--- 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 | |
-- raycast | |
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 | |
--DEBUG | |
--local function UnderObject(pos, l) | |
-- l = l or 120 | |
-- -- raycast | |
-- local hit, position = Workspace:FindPartOnRayWithIgnoreList(Ray.new(pos, UpVec * l), ignoreList) | |
-- if hit then | |
-- return (hit.Transparency ~= 1 and not string.find(hit.Name, "Droplet") and not string.find(hit.Name, "Extrusion")) 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 --------------------------------------------------- | |
---------------------------------------------------------------------------- | |
math.randomseed(tick()) | |
while true do | |
wait(1 / Rate) | |
--Only render droplets if: | |
--Camera isn't looking down | |
--Render settings are high enough | |
--Camera isn't under an awning or roof or something | |
-- debug.profilebegin("NEW_IF_THEN") | |
if ScreenBlockCFrame.LookVector.Y > -0.4 and CanShow and not UnderObject(ScreenBlockCFrame.Position) then | |
-- debug.profilebegin("NEW_CREATE_DROPLET") | |
CreateDroplet() | |
-- debug.profileend() | |
end | |
-- debug.profileend() | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[=[ | |
--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 Settings = { | |
-- Rate: How many droplets spawn per second | |
Rate = 8; -- 64 | |
-- 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; | |
}; | |
---------------------------------------------------------------------------- | |
--- Variables ------------------------------------------------------------ | |
---------------------------------------------------------------------------- | |
--Services | |
local RunService = game:GetService("RunService") | |
local TweenService = game:GetService("TweenService") | |
--Player related | |
local Camera = workspace.CurrentCamera | |
local Player = game.Players.LocalPlayer | |
local Mouse = Player:GetMouse() | |
local GameSettings = UserSettings().GameSettings | |
--Raycasting | |
local ignoreList = {Player.Character or Player.CharacterAdded:Wait()} | |
--Localizing | |
local ipairs = ipairs | |
local instance = Instance.new | |
local rgbColor = Color3.fromRGB | |
local random = math.random | |
local v3, cf = Vector3.new, CFrame.new | |
local UpVec = v3(0,1,0) | |
--Settings localized | |
local Rate = Settings.Rate | |
local Size = Settings.Size | |
local Tint = Settings.Tint or rgbColor(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} | |
---------------------------------------------------------------------------- | |
--- Prefab Basic Objects ------------------------------------------------- | |
---------------------------------------------------------------------------- | |
--Droplet holder | |
local ScreenBlock = instance("Part") | |
ScreenBlock.Size = v3(2,2,2) | |
ScreenBlock.Transparency = 1 | |
ScreenBlock.Anchored = true | |
ScreenBlock.CanCollide = false | |
ScreenBlock.Parent = Camera | |
RunService:BindToRenderStep("ScreenRainUpdate", Enum.RenderPriority.Camera.Value + 1, function() ScreenBlock.CFrame = Camera.CFrame end) | |
--Droplet object | |
local Dropet_Prefab = instance("Part") | |
Dropet_Prefab.Material = Enum.Material.Glass | |
Dropet_Prefab.CanCollide = false | |
Dropet_Prefab.Transparency = 0.5 | |
Dropet_Prefab.Name = "Droplet_Main" | |
Dropet_Prefab.Color = Tint | |
Dropet_Prefab.Size = v3(1,1,1) | |
local ObjectMesh = instance("SpecialMesh") | |
ObjectMesh.MeshType = Enum.MeshType.Sphere | |
ObjectMesh.Parent = Dropet_Prefab | |
---------------------------------------------------------------------------- | |
--- Functions ------------------------------------------------------------ | |
---------------------------------------------------------------------------- | |
--Welds together two objects | |
local function Weld(a, b) | |
local weld = Instance.new("Weld") | |
weld.C0 = a.CFrame:inverse() * b.CFrame | |
weld.Part0 = a | |
weld.Part1 = b | |
weld.Parent = a | |
return weld | |
end | |
local function DestroyDroplet(d) | |
wait(Fade) | |
d:Destroy() | |
end | |
--Returns whether the given position is under cover | |
local function UnderObject(pos,l) | |
local ray = Ray.new(pos, UpVec * (l or 120)) | |
-- raycast | |
local hit, position = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList) | |
if hit then | |
return hit.Transparency ~= 1 and true or UnderObject(position+UpVec, (l or 120) - (pos-position).Magnitude) | |
else | |
return false | |
end | |
end | |
--DEBUG | |
--local function UnderObject(pos,l) | |
-- local ray = Ray.new(pos, UpVec * (l or 120)) | |
-- -- raycast | |
-- local hit, position = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList) | |
-- if hit then | |
-- return (hit.Transparency ~= 1 and not string.find(hit.Name, "Droplet") and not string.find(hit.Name, "Extrusion")) and true or UnderObject(position+UpVec, (l or 120) - (pos-position).Magnitude) | |
-- else | |
-- return false | |
-- end | |
--end | |
--Creates a random droplet on screen | |
local function CreateDroplet() | |
--Setup | |
local stretch = 1+(random(1,15)/10) | |
local Tweens = {}; | |
--Main droplet object | |
local DropletMain = Dropet_Prefab:Clone() | |
local SizeOffset = random((Size/3)*-10,(Size/3)*10)/10 | |
DropletMain.Mesh.Scale = v3(Size+SizeOffset,Size+SizeOffset,Size+SizeOffset) | |
DropletMain.CFrame = cf() | |
--Create droplet extrusions | |
for i=1, random(1,4) do | |
local Extrusion = Dropet_Prefab:Clone() | |
Extrusion.Name = "Extrusion_"..i | |
local eSizeOffset = random((Size/3)*-100,(Size/3)*100)/100 | |
Extrusion.Mesh.Scale = v3((Size/1.5)+eSizeOffset, (Size/1.5)+eSizeOffset, (Size/1.5)+eSizeOffset) | |
Extrusion.CFrame = cf(v3(random(-(Size*40),(Size*40))/100,random(-(Size*40),(Size*40))/100,0)) | |
Extrusion.Parent = DropletMain | |
Weld(Extrusion, DropletMain) | |
ignoreList[#ignoreList+1] = Extrusion | |
Tweens[#Tweens+1] = TweenService:Create(Extrusion, fadeInfo, fadeGoal) | |
local s,o = Extrusion.Mesh.Scale, Extrusion.Mesh.Offset | |
Tweens[#Tweens+1] = TweenService:Create(Extrusion.Mesh, strechInfo, { | |
Scale = v3(s.X, s.Y*(stretch), s.Z); | |
Offset = v3(0,-(s.Y*stretch)/2.05,0); | |
}) | |
end | |
ignoreList[#ignoreList+1] = DropletMain | |
Tweens[#Tweens+1] = TweenService:Create(DropletMain, fadeInfo, fadeGoal) | |
local s,o = DropletMain.Mesh.Scale, DropletMain.Mesh.Offset | |
Tweens[#Tweens+1] = TweenService:Create(DropletMain.Mesh, strechInfo, { | |
Scale = v3(s.X, s.Y*(stretch), s.Z); | |
Offset = v3(0,-(s.Y*stretch)/2.05,0); | |
}) | |
DropletMain.CFrame = ScreenBlock.CFrame:toWorldSpace(cf(random(-100,100)/100, random(-100,100)/100, -1)) | |
Weld(DropletMain, ScreenBlock) | |
for _, t in ipairs(Tweens) do | |
t:Play() | |
end | |
local DestroyRoutine = coroutine.create(DestroyDroplet) | |
coroutine.resume(DestroyRoutine, DropletMain) | |
DropletMain.Parent = ScreenBlock | |
end | |
---------------------------------------------------------------------------- | |
--- Functionality Loop --------------------------------------------------- | |
---------------------------------------------------------------------------- | |
math.randomseed(tick()) | |
while wait(1/Rate) do | |
--Only render droplets if: | |
--Camera isn't looking down | |
--Render settings are high enough | |
--Camera isn't under an awning or roof or something | |
-- debug.profilebegin("OLD_IF_THEN") | |
if (Camera.CFrame.lookVector.Y>-0.4) and (GameSettings.SavedQualityLevel.Value >= 8) and (not UnderObject(Camera.CFrame.Position)) then | |
-- debug.profilebegin("OLD_CREATE_DROPLET") | |
CreateDroplet() | |
-- debug.profileend() | |
end | |
-- debug.profileend() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment