Physical Blood

Before I start, I just want to say that I have little coding experience, and this request is something way out of my knowledge. I was just wondering how difficult it would be for someone to do this and how much time it would take. I don’t want to bother anyone with this request if it’s too much of an effort.

Basically, I want to try and have a physical blood system in the likes of Half Life 2 SMOD. For those that are not familiar with it, let me try and explain the best I can. I drew a shitty comic:

The first panel illustrates an “invisible” entity that seems to appear when you shoot an NPC. This entity has gravity, and it seems that little blood droplet particles appear out of it as it falls.

In the second panel, the entity hits the world and paints a blood decal while also emitting another misty particle. When it hits the world, it also plays a sound. The entity could also hit other npcs or ragdolls and paint them with the blood decal.

Would this be difficult to accomplish? As someone with very little coding knowledge, I know it’s already way out of my hands, but would someone be able to do this for me or lead me in the right direction? I’m already making the particles. I would really appreciate it.

Straight-forward. Use ParticleEmitter to emit effects. Basically when it is hit you start it and SetGravity on the blood droplets, and make a ploof of blood appear. Enable collision on the blood droplets so that when they hit the ground, you can util.AddDecal on the ground or player.

Using PlayerTraceAttack, the trace for the attack is provided so you can use trace.HitPos to get where the blood will start. Like Acecool said, use a ParticleEmitter. For each particle, you will need to define the callback when it collides to create a decal.

I think this might help. I appreciate your guys’ posts, but I don’t know where to go from there. I already have something really rough implemented, but it’s not exactly what I want.

local function CollideCallback(particle, hitpos, hitnormal)
	if not particle.HitAlready then
		particle.HitAlready = true

		local pos = hitpos + hitnormal
		util.Decal("Blood", pos, hitpos - hitnormal)


function EFFECT:Init(data)
	local Pos = data:GetOrigin() + Vector(0,0,10)

	local emitter = ParticleEmitter(Pos)
	for i=1, data:GetMagnitude() do
		local particle = emitter:Add("archysaw/sprite_bloodspray"..math.random(1,8), Pos + VectorRand() * 8)
		particle:SetDieTime(math.Rand(3, 6))
		particle:SetStartSize(math.Rand(10, 14))
		particle:SetRoll(math.Rand(0, 360))
		particle:SetRollDelta(math.Rand(-20, 20))
		particle:SetGravity(Vector(0, 0, -600))
		particle:SetColor(255, 0, 0)

function EFFECT:Think()
	return false

function EFFECT:Render()

This seems to simply create a decal with physical properties, but I’d like for it to be an actual particle effect (like the droplets). It creates a splatter on the world (but not on ragdolls…), but it does not emit a mist when it hits the ground nor does it create a sound…which I guess is obvious since there’s nothing about sound in this snippet.

On collision for it to create a mist, you simply do the same thing as with the normal particles. On callback emit another particle before or after the decal.

I’ll show you an example of something I do which is not quite what you’re doing, but similar. Exhaust effects on a car; when the exhaust hits a wall it creates a stationary puff at the collision point. I did this so it doesn’t look like exhaust going through the wall. You want essentially the same thing.

Take a look at the flamelet where it spawns; that is on collide.

// Exhaust Effects - Josh ‘Acecool’ Moser

// Helper function
local function ExhaustEffect( ent, _e, _pos, _mat, _tab )
local p = _e:Add( _mat, _pos )
p:SetDieTime( 0.5 );
p:SetStartSize( 10 );
p:SetEndSize( 25 );
p:SetStartSize( _tab.startsize );
p:SetStartAlpha( _tab.alpha );
p:SetEndAlpha( 0 );
p:SetStartLength( 35 );
p:SetEndLength( 10 );
p:SetVelocity( ent:GetAngles( ):Right( ) * 55 );
– p:SetVelocityScale( -100 );
p:SetGravity( Vector( 0, 0, 100 ) );

p:SetRoll( 15 )
p:SetRollDelta( 1 )
p:SetBounce( 1 )
p:SetAirResistance( 0 )

p:SetCollide( true );
p:SetCollideCallback( function( part, hitpos, hitnormal )
	local _e = LocalPlayer( ):GetEmitter( hitpos );
	local p = _e:Add(_mat, hitpos)
	p:SetDieTime(math.Rand(0.25, 0.50))
	-- //p:SetColor( COLOR_BLUE )
	p:SetVelocity(Vector(0,0,10) + (VectorRand() * 5))

	part:SetDieTime( 0.5 )
	_e:Finish( );
end );


And I call them using that helper-function like this:
[lua] local _pos = _v:LocalToWorld( v.pos );
local _e = LocalPlayer( ):GetEmitter( _pos );

		local _ang = v.ang or ANGLE_REAR;

		ExhaustEffect( _v, _e, _pos, "particles/smokey.vmt", { ang = _ang, startsize = math.random( 1, 10 ), alpha = math.random( 15, 25 ) } );
		ExhaustEffect( _v, _e, _pos, "particle/particle_smokegrenade", { ang = _ang, startsize = math.random( 1, 10 ), alpha = math.random( 15, 25 ) } );
		ExhaustEffect( _v, _e, _pos, "sprites/heatwave", { ang = _ang, startsize = 25, alpha = math.random( 50, 255 ) } );

		if ( math.random( 1, 20 ) == 1 ) then
			ExhaustEffect( _v, _e, _pos, "particles/flamelet" .. math.random( 1,5 ) .. ".vmt", { ang = _ang, startsize = 10, alpha = 15 } );

		_e:Finish( );[/lua]

I use a particle-emitter manager I wrote to fix the new particle crash I was experiencing. It looks like this:

Use your on-collide, it is very useful for creating additional effects.