Gibs: Difference between revisions
Ninjaofsauce (talk | contribs) (Added category and see also) |
(???) |
||
| Line 1: | Line 1: | ||
{{LanguageBar | {{LanguageBar}} | ||
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. | 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. | ||
| Line 117: | Line 117: | ||
== Adding Ragdoll Gibs == | == Adding Ragdoll Gibs == | ||
So, it's very interesting lesson, but something does not suffice... To be exact lack the Ragdoll Gibs how said '''Pfannkuchen'''. | So, it's very interesting lesson, but something does not suffice... To be exact lack the Ragdoll Gibs how said '''Pfannkuchen'''. | ||
| Line 135: | Line 133: | ||
add this Vectors, he give position of our model, and time of fade: | add this Vectors, he give position of our model, and time of fade: | ||
<source lang=cpp> | <source lang=cpp> | ||
Vector vecLegsForce; | |||
Vector vecLegsForce; | vecLegsForce.x = random->RandomFloat( -400, 400 ); | ||
vecLegsForce.x = random->RandomFloat( -400, 400 ); | vecLegsForce.y = random->RandomFloat( -400, 400 ); | ||
vecLegsForce.y = random->RandomFloat( -400, 400 ); | vecLegsForce.z = random->RandomFloat( 0, 250 ); | ||
vecLegsForce.z = random->RandomFloat( 0, 250 ); | float flFadeTime = 0.0; | ||
float flFadeTime = 0.0; | |||
</source> | </source> | ||
| Line 147: | Line 144: | ||
<source lang=cpp> | <source lang=cpp> | ||
// Ragdoll Gibs | // Ragdoll Gibs | ||
CBaseEntity *pLegsGib = CreateRagGib( "models/zombie/classic_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() ); | CBaseEntity *pLegsGib = CreateRagGib( "models/zombie/classic_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() ); | ||
if ( pLegsGib ) { CopyRenderColorTo( pLegsGib ); } | if ( pLegsGib ) { CopyRenderColorTo( pLegsGib ); } | ||
| Line 157: | Line 154: | ||
If you use your model don't forget in '''void CNPC_Zombine::Precache( void )''' after '''BaseClass::Precache();''' add your model, for example: | If you use your model don't forget in '''void CNPC_Zombine::Precache( void )''' after '''BaseClass::Precache();''' add your model, for example: | ||
<source lang=cpp> | <source lang=cpp> | ||
PrecacheModel( "models/zombie/zombie_soldier_left_legs.mdl" ); | PrecacheModel( "models/zombie/zombie_soldier_left_legs.mdl" ); | ||
PrecacheModel( "models/zombie/zombie_soldier_left_legs_up.mdl" ); | PrecacheModel( "models/zombie/zombie_soldier_left_legs_up.mdl" ); | ||
PrecacheModel( "models/zombie/zombie_soldier_left_legs_down.mdl" ); | PrecacheModel( "models/zombie/zombie_soldier_left_legs_down.mdl" ); | ||
</source> | </source> | ||
| Line 174: | Line 171: | ||
The first, after our new vector add this: | The first, after our new vector add this: | ||
<source lang=cpp> | <source lang=cpp> | ||
Vector vecDamageDir = info.GetDamageForce(); | Vector vecDamageDir = info.GetDamageForce(); | ||
</source> | </source> | ||
| Line 181: | Line 177: | ||
<source lang=cpp> | <source lang=cpp> | ||
UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL ); | UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL ); | ||
</source> | </source> | ||
| Line 194: | Line 189: | ||
'''FX_BLOODSPRAY_ALL''' - concrete effect of blood | '''FX_BLOODSPRAY_ALL''' - concrete effect of blood | ||
* FX_BLOODSPRAY_DROPS | * FX_BLOODSPRAY_DROPS | ||
* FX_BLOODSPRAY_GORE | * FX_BLOODSPRAY_GORE | ||
* FX_BLOODSPRAY_CLOUD | * FX_BLOODSPRAY_CLOUD | ||
* FX_BLOODSPRAY_ALL | * FX_BLOODSPRAY_ALL | ||
== Random gibs == | == Random gibs == | ||
| Line 212: | Line 207: | ||
if( info.GetDamageType() & ( DMG_BLAST ) ) // this just that you don't get lost. | if( info.GetDamageType() & ( DMG_BLAST ) ) // this just that you don't get lost. | ||
{ | { | ||
if ( m_RandomGib == 1 ) | if ( m_RandomGib == 1 ) | ||
{ | { | ||
| Line 224: | Line 219: | ||
} | } | ||
if ( m_RandomGib == 2 ) // or you can write "else". ( m_RandomGib == 2 ) - this if you have 3 random value for example. | if ( m_RandomGib == 2 ) // or you can write "else". ( m_RandomGib == 2 ) - this if you have 3 random value for example. | ||
{ | { | ||
UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL ); | UTIL_BloodSpray( WorldSpaceCenter(), vecDamageDir, BLOOD_COLOR_RED, 13, FX_BLOODSPRAY_ALL ); | ||
SetModel( "models/zombie/zombie_soldier_torso.mdl" ); | SetModel( "models/zombie/zombie_soldier_torso.mdl" ); | ||
// Gibs | // Gibs | ||
| Line 245: | Line 238: | ||
[[Creating an NPC]] | [[Creating an NPC]] | ||
[[Category:Programming]][[Category:Tutorials]] | [[Category:Programming]] | ||
[[Category:Tutorials]] | |||
Latest revision as of 00:50, 29 October 2025
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
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.x = random->RandomFloat( -400, 400 );
vecLegsForce.y = random->RandomFloat( -400, 400 );
vecLegsForce.z = random->RandomFloat( 0, 250 );
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.
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
- 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.
{
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