Blood Engine - A droplet emitter system

New Project(2)

v1.1.3
GithubModel

What is Blood Engine?


Blood Engine is a versatile resource that can be utilized for various applications, including creating effects like paint, water, blood, and more. It offers numerous methods tailored to meet your specific needs.

One of its key features is the ability to emit “droplets” - these are meshes that can take on the appearance of “Decals” [ image ] or “Spheres” [ image ]. These droplets can be emitted from any given origin point with a given velocity. Upon landing on a surface, such as a wall or floor, they transform into a pool.

This entire process is highly customizable, with 24 options at your disposal to tweak and adjust according to your requirements. This ensures that Blood Engine can adapt to a wide range of scenarios and use-cases, providing you with the flexibility to create the exact effect you’re aiming for.

(a small note here; the overall quality of the videos is poor due to my laptop’s specs)

Usage


Initialization

Firstly, you’ll need to initialize BloodEngine with your preferred settings. This can be done in either a client or server script. However, it’s generally more advisable to do this on the client side, so we’ll proceed with that approach.

The settings provide you with control over various aspects of droplets and pools. These include the maximum number of droplets that can be created, the type of droplets to use, the velocity of droplets upon emission, and much more.

-- Import the BloodEngine module
local BloodEngine = require(PathToModule)

-- Initialize BloodEngine with desired settings
local Engine = BloodEngine.new({
    Limit = 100, -- Sets the maximum number of droplets that can be created.
    Type = "Default", -- Defines the droplet type. It can be either "Default" (Sphere) or "Decal",
    RandomOffset = false, -- Determines whether a droplet should spawn at a random offset from a given position.
    OffsetRange = {-20, 10}, -- Specifies the offset range for the position vectors.
    DropletVelocity = {1, 2}, -- Controls the velocity of the emitted droplet.
    DropletDelay = {0.05, 0.1}, -- Sets the delay between emitting droplets in a loop (for the EmitAmount method).
    StartingSize = Vector3.new(0.01, 0.7, 0.01), -- Sets the initial size of the droplets upon landing.
    Expansion = true, -- Determines whether a pool can expand when a droplet lands on it.
    MaximumSize = 1, -- Sets the maximum size a pool can reach.
})

Emitting Droplets

After initializing the module, you’re all set to emit droplets. There are two key methods available for droplet emission: EmitAmount and Emit.

-- Emit a specific amount of droplets from a given origin in specific or nil direction
-- (Setting the Direction to nil will make droplets go in random directions)
Engine:EmitAmount(Origin, Direction, Amount)

-- Emit a single droplet from a given origin in a specific or nil direction
Engine:Emit(Origin, Direction)

In this instance, we’ll be utilizing the EmitAmount method. Typically, you’d use the Emit method when you want to create your own loop instead of relying on the built-in loop of EmitAmount . This gives you more control over the emission process.

Example

Now that we’ve covered all the necessary steps, it’s time to see the results in action. The following video provides a showcase of what we have done.


And that’s all there is to it! It’s really that simple to use this module. Feel free to explore all the different settings to customize it to your needs.

Changelog


Version 0.X.X
# 0.0.1

↳ General Changes

  • Official Release
# 0.0.2

↳ General Changes

  • Bouncing is now removed due to its instability.
  • You can now make drips go in random directions more efficiently.
  • Added the ability to make blood drips ignore certain descendants of parts efficiently.
# 0.0.3

↳ General Changes

  • Revamped how settings work/get applied.
  • Added an option to make pools expandable if collided by droplets.
  • Added the option to change the default size of a pool.
# 0.0.4

↳ General Changes

  • Improved drip raycast accuracy.
  • Added DecayDelay, manages the decay time for each pool.
  • Pools can now get on walls and attach/get welded to parts.
  • Support for decals/images for pools. Includes PBR Materials.
# 0.0.5

↳ General Changes

  • A showcase has been included on the GitHub Repository.
  • An efficient method, UpdateSettings, has been added for changing settings.
  • Resolved an issue that prevented the proper removal of excess droplets.
# 0.0.6


↳ General Changes

Accurate Raycasting: Implemented accurate raycasting using FastCast for improved precision.

Splash Effects: Introduced splash/impact effects to enhance visuals, includes the SplashAmount option, which manages how many particles to emit.

Ignore Players: Added the ability for the droplets to ignore players with the IgnorePlayers option, prevents any interaction between them.

Removal of Features: Temporarily removed the PoolExpansion feature. It is planned to be reintroduced in a future update following a rewrite to clean things up.

↳ Other Notes

The system’s feature set has grown unexpectedly, leading to cluttered and sorta hard-to-read code. A module rewrite is planned, including a complete rewrite of this post.

Version 1.X.X
# 1.0.0

↳ General Changes

Comprehensive Rewrite: The module has undergone a complete rewrite, enhancing its readability and ease of modification. This overhaul also improves the organization of the code, making it easier to locate specific elements.

Pool Expansion: Reintroducing the Pool Expansion feature, now enhanced with effects and new options such as:

  • Expansion: A toggle switch for this feature.
  • Distance: Defines the distance (in studs) within which a droplet should check for nearby pools.
  • ExpanseDivider: Controls the rate of pool size increase. Higher values result in a slower increase.
  • MaximumSize: Sets the maximum size a pool can reach.

Ignore Players: The IgnorePlayers option has been permanently removed. However, a guide on how to make droplets ignore players will be released in the future.

Splashing: Expanded the options for the splashing feature, providing more customization possibilities:

  • SplashName: The name of the attachment that releases particles on surface contact.
  • SplashByVelocity: If true, sets the number of particles based on the velocity of the droplet.
  • VelocityDivider: Controls the extent to which velocity can influence the splash amount. Higher values will lessen the effect.

Additional Options: Added and revamped several options to provide you with more control over the appearance of the droplets, pools and effects, as well as the functionality of the module:

  • FolderName: Specifies the name of the folder containing the droplets.
  • Type: Defines the droplet type. It can be either “Default” (Sphere) or “Decal”.
  • DefaultTransparency: Specifies the default transparency range of a pool.
  • Trail: Controls the visibility of the trail during droplet emission.
  • StartingSize: Sets the initial size of the droplets upon landing.
  • ScaleDown: Determines whether the pool should scale down when decaying.
  • Tweens: Contains all the tweens used by the module: Decay, Land and Expand

↳ Other Notes

With this major release, both the Github Repository’s page and this post have been thoroughly revised and rewritten.

# 1.0.1

↳ General Changes

Bugfixes: The Pool Expansion feature had this bug where it would unexpectedly expand beyond its limit. This occurred due to a droplet interacting with a pool mid-expansion, which expands it twice as much.

# 1.0.2

↳ General Changes

Different Settings Upon Emission: You can now apply different settings to the droplets using EmitAmount or Emit instead of manually changing it.

# 1.0.3

↳ General Changes

Small Fixes: There weren’t really any changes to the code, this update is more focused on assets. A certain decal was removed due it bugging out, and I made some changes to the properties of the droplets for a certain upcoming bugfix.

# 1.1.0

↳ General Changes

Improvements to Emission: You can now emit mixed droplets (decal & default) without making a new emitter instance!
Droplet Color: There’s a new DropletColor setting to change the color of your droplets/pools.

↳ Other Notes

While this was a minor update, what you can do with it is anything but.
Here’s a showcase to show what you can do with this new release:


You can now do a mix of Droplets and Decals. And without creating multiple emitter instances that might eat out your performance.

Here’s the code behind it:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local BloodEngine = require(ReplicatedStorage.BloodEngine)
local Engine = BloodEngine.new({
	Limit = 500,
})

local EMIT_AMOUNT = 50
local EMIT_DELAY = 5

local function Emit()
	-- A random chance of the droplet being a decal
	local IsDecal = math.random(0, 1) == 1
	
	-- Emits a droplet in a random direction relative to a part, and there's a chance that it could be a decal.
	Engine:Emit(script.Parent, nil, {
		Type = IsDecal and "Decal" or "Default",
		DefaultSize = IsDecal and { 1, 1.4 } or { 0.4, 0.7 }
	})
end

-- A custom iteration of the EmitAmount method
while true do
	for Index = 1, EMIT_AMOUNT, 1 do
		local DropletDelay = math.random(0.05, 0.1)

		Emit()
		task.wait(DropletDelay)
	end
	task.wait(EMIT_DELAY)
end
# 1.1.1

↳ General Changes

Fixes: Fixed an issue where if no Data/Settings table was provided, the module would error. This is in reference to this issue: Blood Engine - A droplet emitter system - #224 by Necro_las

# 1.1.2

↳ General Changes

A new Destroy method: Added a Destroy method, that I admit should have been there in the beginning. This is for developers who especially use StarterCharacterScripts. (Reference to issue: Blood Engine - A droplet emitter system - #233 by Lukeskyroblox1)

# 1.1.3

↳ General Changes

A new size setting: Added a new setting: YSize, which controls the range of the y size of the pool, giving you the ability to make it flat or thick. (Reference to suggestion: Blood Engine - A droplet emitter system - #239 by RIP_Bombs)

Misc


If you have any feedback or encounter any issues, please feel free to leave a reply below this post. In-depth guides for specific scenarios will be available soon on the Github Repository’s wiki. Stay tuned.

278 Likes

alr ima go sleep m job is done

45 Likes

Looks really cool! I wish Roblox allowed a bit more gore because I’m sure 13 and older aren’t sensitive to a bit of blood (or at least I’ve seen them get angry). Super realistic gore would be put in 17+ or something, but that’s how I view it.

(… I mean, doesn’t God’s Will have huge blood splatters? I don’t know if I remember that well because I turned it off due to lag.)

27 Likes

I mean this is the soft kind of gore if that’s what your asking for. I also wish Roblox allowed gore models to be viewed on 13+ games without it being disabled by default as I hate my games getting content deleted. Games are just games, they don’t make people do these actions at all.

32 Likes

Two questions:

  1. Why are the links from discord? They’ll definitely be scrapped.

  2. Is there a function to have constant spilling? I’m thinking to use this for leaky pipes and such, just wondering about this use case before I make my own system (if I feel like it).

16 Likes

To answer your questions

  1. I have uploaded the files on Github and Roblox now.

  2. What do you mean by constant spilling? This module can be used for other things such as water or other. But can you go further in depth about “constant spilling”

17 Likes

this is so combat warriors :cold_face: :hot_face: :hot_face:

22 Likes

wow combat warriors is the only game that has a blood dripping system no way :speaking_head::speaking_head::speaking_head:

31 Likes

i wasnt blaming that you copied i was praising that you made greatly like cw

10 Likes

ye i know im just stating the fact that other games (like criminality) have a blood dripping system
sorry if that was harsh as da context was hard to understand wid all these emojis

13 Likes

That’s good to hear it’s uploaded to a better source.

Constant spilling would be something like water running from a hose, constant water particles.

11 Likes

i’ll implement a method for it. thanks for the suggestion.

11 Likes

sadly i won’t be able to implement it as at the moment, i’m quite busy with game development on my game.

11 Likes

i merged the pull request, sorry for not adding the module’s source code as i was in a bit of a rush

8 Likes

this is amazing! well done, im just gonna take 10 years of my life to figure out how to hook it to emit when damage is taken :joy:

7 Likes

check if the player has lost damage on the client then emit blood, its not that hard (if that’s what your asking for though)

9 Likes

pretty much lol, im just not the best scripter. imma try a few things

7 Likes

bro idk why ur module doesn’t work it says that the module doesn’t work then it outputs an error about an random offset or whatever

5 Likes

i can’t fix something if you don’t show me the error

5 Likes

Great module! :tada:

I’d like to add something for those who have lesser scripting skills. If you would like to ignore player parts do:

local Instances = BloodInstance.RaycastParams.FilterDescendantsInstances
BloodInstance.RaycastParams.FilterDescendantsInstances = {Instances and unpack(Instances), character}

Here’s my full script

-- You can leave any of these values as nil, it'll use the default values
local DripSettings = {
	500, -- Limit: The maximum number of blood drips that can be active at once
	true, -- RandomOffset: Whether to use random positions for the blood drips
	0.5, -- Speed: The speed or velocity at which the blood drips fall
	0.01, -- DripDelay: The delay between emitting blood drips,
	false, -- DripVisibile: Determines if the blood drip is visibile when emitted
	{} -- Filter: An array used to make the drips ignore certain parts (go through them, not interact with them)
}

-- MODULES
local BloodEngine = require(game.ReplicatedStorage.BloodEngine)
local BloodInstance = BloodEngine.new(table.unpack(DripSettings)) -- customize to whatever you want

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)

		local Instances = BloodInstance.RaycastParams.FilterDescendantsInstances
		BloodInstance.RaycastParams.FilterDescendantsInstances = {Instances and unpack(Instances), character}

		local humanoid = character:WaitForChild("Humanoid") :: Humanoid?

		local root = character:WaitForChild("HumanoidRootPart")

		humanoid.Died:Once(function()
			BloodInstance:Emit(root, root.CFrame.LookVector, 100) -- also customize to whatever you want
		end)

	end)
end)
12 Likes