function BloodEngine.new(Limit: number, RandomOffset: boolean, Speed: number, DripDelay: number, DripVisible: boolean, FilterInstances: {})
local self = setmetatable({}, BloodEngine)
-- Creates a folder for drips if necessary
local DripsFolder = Terrain:FindFirstChild("DripsFolder") or Instance.new("Folder", Terrain)
DripsFolder.Name = DripsFolder.Name == "DripsFolder" and DripsFolder.Name or "DripsFolder"
-- Create and initialize the RaycastParams object outside of the function
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
--This is line 110
raycastParams.FilterDescendantsInstances = {DripsFolder, Unpack(FilterInstances)}
raycastParams.IgnoreWater = true
-- Assign class variables
self.Settings = {
DripLimit = Limit or Constants.Limit,
Speed = Speed or Constants.Speed,
DripDelay = DripDelay or Constants.DripDelay,
RandomOffset = RandomOffset or Constants.RandomOffset,
DripVisible = DripVisible or Constants.DripVisible
}
self.Drips = {}
self.DripsFolder = DripsFolder
self.RaycastParams = raycastParams
-- Assign other variables
local Distance = Constants.Distance
self._Random = Random.new()
-- Connect a single function to the Heartbeat event of the RunService
RunService.Heartbeat:Connect(function()
-- If no drips exist, stop managing. Saves Performance.
if (#self.Drips <= 0) then
return
end
-- Iterate over all drips in the drips table
for Index, DripArray in self.Drips do
-- Retreive information
local -- Unpack information
DripInstance: MeshPart,
EndSound: Sound,
BasePart: BasePart,
IsPool: boolean = Unpack(DripArray)
-- Perform a raycast from the position of the part in the direction of its velocity and find the closest part to the drip
local result = workspace:Raycast(DripInstance.Position, Vector3.new(0, -Distance, 0), self.RaycastParams)
-- Check if the result is not nil and if the hit object is not the basePart
if DripInstance and result and result.Instance ~= BasePart and not IsPool then
-- Move the part to the hit position
DripArray.IsPool = true
DripInstance.Anchored = true
DripInstance.CanCollide = false
DripInstance.Transparency = DripPart.Transparency
DripInstance.CFrame = CFrame.new(result.Position) * CFrame.Angles(0, 0, 0)
-- Grow the size of the part over time to create a blood pool
local Info = TweenInfo.new(0.5, Enum.EasingStyle.Cubic)
local RandomTweenIncrement = self._Random:NextNumber(3, 5) / 5
local CurrentSize = DripInstance.Size
local SizeGoal = Vector3.new(RandomTweenIncrement, self._Random:NextNumber(1, 10) / 100, RandomTweenIncrement)
local Tween = TweenService:Create(DripInstance, Info, {Size = SizeGoal})
-- Play size tween and start the ending sound
EndSound:Play()
Tween:Play()
-- Decrease the size and transparency of the part after a few seconds have passed
-- Then destroy and delete it from the blood parts dataset
local DefaultTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Quad)
local DefaultTween = TweenService:Create(DripInstance, DefaultTweenInfo, {Transparency = 1, Size = Vector3.new(0.01, 0.01, 0.01)})
task.delay(self._Random:NextNumber(10, 15), function()
DefaultTween:Play()
DefaultTween.Completed:Connect(function()
-- Remove the drip instance from existance and from the Drips dataset
table.remove(self.Drips, Index)
DripInstance:Destroy()
end)
end)
end
end
-- Check if the number of blood parts exceeds the bloodLimit
if #self.Drips > self.Settings.DripLimit then
-- Decrease the size and transparency of the part after a few seconds have passed
-- Then destroy and delete it from the blood parts dataset
local OldestDrip: MeshPart? = table.remove(self.Drips, #self.Drips)
local DefaultTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Quad)
local DefaultTween = TweenService:Create(OldestDrip, DefaultTweenInfo, {Transparency = 1, Size = Vector3.new(0.01, 0.01, 0.01)})
DefaultTween:Play()
DefaultTween.Completed:Connect(function()
OldestDrip:Destroy()
end)
end
end)
return self
end