Gibs

From Valve Developer Community
Jump to navigation Jump to search
English (en)Deutsch (de)Translate (Translate)

Today, we are going to learn how to implement general gibbing using the CGibs class. This can work on NPCs/Players. Gibs are essentially the "advanced behavior of the remains of an entity" - e. g. when a zombie or a player gets killed, you don't want the model to just disappear or fall on the ground. You want the cadaveric model to behave accordingly to what happened, respectively, according to what caused its death - a grenade explosion, fire, etc. - that's where gibs come in.

Editing Event_Killed

So first, open up the Zombine code (npc_zombine.cpp) and search for the void "Event_Killed" Delete everything in there except for BaseClass::Event_Killed( info ). This calls up the Regular Event_Killed so that we can still have a ragdoll and the zombine dies correctly.

To get models for the giblets, you can download a pack from Garrysmod.org if youre into Garry's Mod Classic, You can also model your own that act like physics props and have a surface property of flesh.

Put those in your mod folder, and in the Event_Killed section, add this:

if( info.GetDamageType() & ( DMG_BUCKSHOT | DMG_BLAST ) )
{
	SetModel( "models/zombie/classic_legs.mdl" );

	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/pgib_p1.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/pgib_p2.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/pgib_p3.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/pgib_p4.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/pgib_p5.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/hgibs_jaw.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/hgibs_scapula.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/hgibs_scapula.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p1.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p2.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p3.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p4.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p5.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/rgib_p6.mdl", 5 );
	CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/gibs/gibhead.mdl", 5 );
}

This will make it so that when you shoot the zombie with any gun that uses the Buckshot ammo (Shotgun), or when receiving explosive damage he will blow into many pieces, and will lose his torso. There are different DMGs in shareddefs.h, such as DMG_BURN, DMG_BULLET, etc., and replace (DMG_BUCKSHOT | DMG_BLAST) with whatever you want.

You can 'add' more types by combining different flags together.

Before you compile, make sure that you Precache the models you're using, or you will get a lot of errors.

If you want the enemy to gib only when a significant amount of damage is done, add this 'if' conditional statement around the first one in the earlier example.

if( info.GetDamage() >= ( m_iMaxHealth * 0.75f ) )
{
	//Earlier Gib Function
}

In this case, if an enemy has 100 health, you'll have to take at least ~75% of their health within the killing blow for them to gib.

Fading/Removing Gibs

If you're working with the Multiplayer SDK, you may want to have your gibs fade after a period of time rather than stay on the world. The issue is that the SpawnSpecificGibs function doesn't use the argument for lifespan (5 seconds as noted in the previous example).

To fix this issue, load up the gibs source file (gib.cpp), find the function "CGib::SpawnSpecificGibs", and paste this in place of the original function.

void CGib::SpawnSpecificGibs(	CBaseEntity*	pVictim, 
								int				nNumGibs, 
								float			vMinVelocity, 
								float			vMaxVelocity, 
								const char*		cModelName,
								float			flLifetime)
{
	for ( int i = 0; i < nNumGibs; i++ )
	{
		CGib *pGib = CREATE_ENTITY( CGib, "gib" );
		pGib->Spawn( cModelName, flLifetime );
		pGib->m_nBody = i;
		pGib->InitGib( pVictim, vMinVelocity, vMaxVelocity );
		pGib->m_lifeTime = flLifetime;

		if ( pVictim != NULL )
		{
			pGib->SetOwnerEntity( pVictim );
		}
	}
}

The change between the two functions is that now the Spawn function uses the lifetime argument to know when to fade away.

Burning Gibs When Gibbing an Ignited Player

Let's say you hit an ignited player with a well aimed rocket, so you want him to chunk up into a bunch of flaming gibs. If so, just add this if statement that asks the game whether the victim is on fire, and if so, ignite his gibs as well.

void CGib::SpawnSpecificGibs(	CBaseEntity*	pVictim, 
								int				nNumGibs, 
								float			vMinVelocity, 
								float			vMaxVelocity, 
								const char*		cModelName,
								float			flLifetime)
{
	for ( int i = 0; i < nNumGibs; i++ )
	{
		CGib *pGib = CREATE_ENTITY( CGib, "gib" );
		pGib->Spawn( cModelName, flLifetime );
		pGib->m_nBody = i;
		pGib->InitGib( pVictim, vMinVelocity, vMaxVelocity );
		pGib->m_lifeTime = flLifetime;

		if ( pVictim != NULL )
		{
			pGib->SetOwnerEntity( pVictim );
		}

		//If pVictim is on fire, ignite pVictim's gibs as well.
		if ( pVictim->GetFlags() & FL_ONFIRE )
		{
			pGib->Ignite( ( flLifetime - 1 ), false );
		}
	}
}

Adding Ragdoll Gibs

Slam12f 06:59, 20 May 2013 (PDT) - Sorry for my English :)

So, it's very interesting lesson, but something does not suffice... To be exact lack the Ragdoll Gibs how said Pfannkuchen. For example, the explosion can tear only the legs and torso will be saved. But!

If you add Torse how gibs, this not work correct. For this we must use enty CBaseEntity *CreateRagGib.

Incidentally it's implemented when you chop off legsnpc_zombie using GravityGun and a blade of saw.

So, after:

void CNPC_Zombine::Event_Killed( const CTakeDamageInfo &info )
{

add this Vectors, he give position of our model, and time of fade:

	// Вектора для модели торса
	Vector vecLegsForce; // Даём понять что vecLegsForce это вектор
	vecLegsForce.x = random->RandomFloat( -400, 400 ); // Рандомное значение по оси X от -400 до 400
	vecLegsForce.y = random->RandomFloat( -400, 400 ); // Рандомное значение по оси Y от -400 до 400
	vecLegsForce.z = random->RandomFloat( 0, 250 ); // Рандомное значение по оси Z от -400 до 400
	float flFadeTime = 0.0; // Время исчезновения.

After or defore any CGib::SpawnSpecificGibs add this code:

		// Ragdoll Gibs торса через ентю
		CBaseEntity *pLegsGib = CreateRagGib( "models/zombie/classic_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() );
			if ( pLegsGib )	{ CopyRenderColorTo( pLegsGib ); }

I think you can understand all parameters of CreateRagGib.

If you use your model don't forget in void CNPC_Zombine::Precache( void ) after BaseClass::Precache(); add your model, for example:

PrecacheModel( "models/zombie/zombie_soldier_left_legs.mdl" ); // Кэширование левой ноги
PrecacheModel( "models/zombie/zombie_soldier_left_legs_up.mdl" ); // Кэширование левой ноги верхняя часть
PrecacheModel( "models/zombie/zombie_soldier_left_legs_down.mdl" ); // Кэширование левой ноги нижняя часть

But that's not all!!! I show how you can do Random gibs, and how add effect of blood.

Effect of Blood(BloodSpray)

That's effect I done with help UTIL_BloodSpray.

Note.pngNote: Please read all information about blood: UTIL_BloodDecalTrace UTIL_BloodDrips UTIL_BloodImpact UTIL_BloodSpray UTIL_BloodStream UTIL_ShouldShowBlood

I think you read about these effects, and now let's implement one of them. More concrete UTIL_BloodSpray.

The first, after our new vector add this:

	// Вектор для спрайта
	Vector vecDamageDir = info.GetDamageForce();

Our effect appears in the area damage. The next step, before CGib::SpawnSpecificGibs or CBaseEntity *pLegsGib = CreateRagGib add this code:

		// Реализация крови
		UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL );

UTIL_BloodSpray have position, color of bool, amount of blood, and effects.

BLOOD_COLOR_RED - color of blood. All define:

  • BLOOD_COLOR_RED
  • BLOOD_COLOR_YELLOW
  • BLOOD_COLOR_GREEN
  • BLOOD_COLOR_MECH

FX_BLOODSPRAY_ALL - concrete effect of blood

  • FX_BLOODSPRAY_DROPS // Капли
  • FX_BLOODSPRAY_GORE // Запёкшаяся кровь
  • FX_BLOODSPRAY_CLOUD // Облака (Этот эффект используется в ep2 когда сбиваешь зомбайна)
  • FX_BLOODSPRAY_ALL // Всё и сразу

Random gibs

Random effect it's really good things! Because At explosion can tear off any part of the body, this time torn off the arm, the next legs. and etc. So, add this after our Vectors:

	m_RandomGib = random->RandomInt( 1, 2 );

1 min value, 2 max value.

We have 2 variants. The first for example: Legs, Torso, HeadCrab and the skull. The Second: Body, headcrab and skull.

if( info.GetDamageType() & ( DMG_BLAST ) ) // this just that you don't get lost.
 { // это только чтобы вы не потерялись в вашем коде.
   if ( m_RandomGib == 1 )
   {
		UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 17, FX_BLOODSPRAY_ALL );
		SetModel( "models/zombie/classic_torso.mdl" ); 
		// Gibs
		CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/Gibs/HGIBS.mdl", 5 );

		CBaseEntity *pLegsGib = CreateRagGib( "models/zombie/classic_legs.mdl", GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() );
			if ( pLegsGib )	{ CopyRenderColorTo( pLegsGib ); }		
   }
   if ( m_RandomGib == 2 ) // or you can write "else". ( m_RandomGib == 2 ) - this if you have 3 random value for example.
   {			 // или можете написать "else". ( m_RandomGib == 2 )- это если у вас допустим 3 рандомных значения.
		// Реализация крови
		UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL );
		// Главная модель
		SetModel( "models/zombie/zombie_soldier_torso.mdl" ); 
		// Gibs
		CGib::SpawnSpecificGibs( this, 1, 750, 1500, "models/Gibs/HGIBS.mdl", 5 );	
   }

Example Video

I recorded a video that demonstrates this effect.

Look at the result of our work: http://youtu.be/V36JwLtfJbY