Particles In Code: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(direct dispatching)
m (Setting bug notice hidetested=1 param on page where the bug might not need tested in param specified)
 
(11 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{toc-right}}
{{toc-right}}
This page details the management of [[:Category:Particle System|"Orange Box" particles]] in C++ code. It does not cover the old, hard-coded particle tech.


== Precaching ==
== Precaching ==


Particle effects must be [[precache]]d before they can be used. This is done by listing them in <code>[[particles_manifest.txt]]</code>, then making this call:
Particle systems must be [[Precaching Assets|precached]] before they can be used. This can be achieved by listing the PCF file containing them in <code>[[particles_manifest.txt]]</code> and utilizing the [[function]] [[PrecacheParticleSystem|PrecacheParticleSystem()]] in code. As an alternative all particle effects within a PCF can be precached by adding a '!' character as a prefix to the path used in <code>particles_manifest.txt</code>.


Precache via code:
<source lang=cpp>PrecacheParticleSystem( "your_particle_effect_name" );</source>
<source lang=cpp>PrecacheParticleSystem( "your_particle_effect_name" );</source>


== Dispatching ==


Particles systems are "dispatched" on the client.
Precache via script:
<source lang=cpp>particles_manifest
{
"file" "!particles/blood_impact.pcf" // all effects will be precached on map spawn
"file" "particles/fire_01.pcf" // effects contained in this file will have to be precached manually
 
[...]
}</source>
 
== Shared ==


{{tip|You can stop all systems tied to a given entity with <code>StopParticleEffects( CBaseEntity* pEntity )</code>. But you cannot otherwise control the lifespan of a system from code. It will self-terminate on its own internal schedule.}}
=== Dispatching ===


=== Simple ===
When dispatched from the server, the particle systems will be networked as [[Temporary Entity|temporary entities]].


<source lang=cpp>
<source lang=cpp>
#include "particle_parse.h"
#include "particle_parse.h"


void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity *pEntity )
// Create at world co-ords
void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity,
DispatchParticleEffect( "my_particle", vecOrigin, angAngles, pOwnerEntity )
int iAttachmentPoint, bool bResetAllParticlesOnEntity  )</source>


The first function creates the system at some arbitrary world co-ordinates. The second spawns it at an [[attachment]].
// Create at model attachment
DispatchParticleEffect( "my_particle", ParticleAttachment_t, pOwner, iAttachment, bResetAllParticlesOnEntity )</source>


{{bug|Valve's code for dispatching a particle attached to a model is broken. [[SDK Known Issues List Fixed#Server Dispatching an Attached Particle Effect|Get the fix here.]]}}
* See also <code>[[#ParticleAttachment_t|ParticleAttachment_t]]</code>, below.
* <code>vecStart</code>, taken by some overloads of <code>DispatchParticleEffect()</code>, defines the location of [[Control Point (particles)|control point]] 1. If you don't specify <code>vecStart</code>, the value of <code>vecOrigin</code> is used instead.


=== Complex ===
{{bug|hidetested=1|Valve's code for dispatching a particle on a model [[attachment]] is broken. [[SDK Known Issues List Fixed#Server Dispatching an Attached Particle Effect|Get the fix here.]]}}


If you need to control the system after it spawns, the helper functions above won't do. Instead:
=== Destroying ===
 
; <code>StopParticleEffects( CBaseEntity* )</code>
: Stops all effects on the given entity.
 
== Client ==
 
=== Creating ===
 
For more control over the effect, a particle system can be created by a new <code>[[CNewParticleEffect]]</code> object and managed through the owning entity's <code>[[ParticleProp()]]</code> accessor:


<source lang=cpp>
<source lang=cpp>
#include "particles_new.h"
#include "particles_new.h"


CNewParticleEffect* pEffect = ParticleProp()->Create( "rail_shot", PATTACH_ABSORIGIN );
C_MyEntity::MessWithParticles()
{
// Create a new system
CNewParticleEffect* pEffect = ParticleProp()->Create( "my_particles", PATTACH_ABSORIGIN );
// System already exists
CNewParticleEffect* pEffect = ParticleProp()->FindEffect( "my_particles" );
}
</source>


pEffect->SetControlPoint( 1, vecSomeVector );
'''Particles_new.h''' must also be #included here.
</source>
 
Alternatively, you can hook into particle creation events:
 
<source lang=cpp>void C_MyEntity::OnNewParticleEffect( const char* pszParticleName, CNewParticleEffect* pNewParticleEffect )
{
if ( V_strcmp(pszParticleName, "target_effect_name") == 0 )
{
// Do something
}
}</source>
 
{{warning|A [[#Dispatching|dispatch]] message from the server configures both [[Control Point (particles)|control point]] 0 '''AND''' 1. The values are applied after <code>OnNewParticleEffect()</code> is called, so don't bother trying to assign either of those CPs from it!}}
 
=== Control points ===
 
When dispatching an effect from the server you can define the location of [[Control Point (particles)|control points]] 0 (with <code>vecOrigin</code>) and 1 (with <code>vecStart</code>).
 
On the client, you can configure the location, rotation and parent entity of any CP with these <code>CNewParticleEffect</code> functions:
 
; <code>SetControlPoint( [[Vector]] )</code>
: Arbitrary set the CP's value.
; <code>SetControlPointEntity( CBaseEntity* )</code>
: Follow the given entity's [[origin]]. {{confirm|Set to NULL to disable following.}}
; <code>SetControlPointOrientation( [[QAngle]] )</code>
; <code>SetControlPointRightVector()</code>
; <code>SetControlPointForwardVector()</code>
; <code>SetControlPointUpVector()</code>
: Set orientation with a [[QAngle]] or a series of Vectors.
 
=== Destroying ===
 
; <code>StopParticleEffects( CBaseEntity* )</code>
: Stops all effects on the given entity.
; <code>ParticleProp()->StopParticlesInvolving( CBaseEntity* )</code>
: Stops all effects with a control point attached to the given entity. {{todo|Global or only on current entity?}}
; <code>ParticleProp()->StopParticlesNamed( const char* )</code>
: Stops all effects with the given system name. {{todo|Global or only on current entity?}}
; <code>CNewParticleEffect<nowiki>::</nowiki>StopEmission( bool bInfiniteOnly, bool bRemoveAllParticles, bool bWakeOnStop)</code>
: Stops the current particle system, without removing it. {{todo|Meaning of first and third arguments.}}
 
== ParticleAttachment_t ==
 
One of these values is passed when dispatching or creating an effect:


See also <code>[[CNewParticleEffect]]</code>.
; <code>PATTACH_ABSORIGIN</code>
; <code>PATTACH_ABSORIGIN_FOLLOW</code>
: Spawn at (and optionally follow) the entity's [[origin]].
; <code>PATTACH_POINT</code>
; <code>PATTACH_POINT_FOLLOW</code>
: Spawn at (and optionally follow) an [[attachment]] point on the entity's model.
; <code>PATTACH_CUSTOMORIGIN</code>
: Spawn at a given origin.
; <code>PATTACH_WORLDORIGIN</code>
: Don't associate with an entity at all. ''Use with caution - could easily cause memory leaks.''


[[Category: Particle System]]
[[Category:Particle System]]
[[Category:Programming]]

Latest revision as of 07:14, 20 May 2025

This page details the management of "Orange Box" particles in C++ code. It does not cover the old, hard-coded particle tech.

Precaching

Particle systems must be precached before they can be used. This can be achieved by listing the PCF file containing them in particles_manifest.txt and utilizing the function PrecacheParticleSystem() in code. As an alternative all particle effects within a PCF can be precached by adding a '!' character as a prefix to the path used in particles_manifest.txt.


Precache via code:

PrecacheParticleSystem( "your_particle_effect_name" );


Precache via script:

particles_manifest
{
	"file"		"!particles/blood_impact.pcf"	// all effects will be precached on map spawn
	"file"		"particles/fire_01.pcf"		// effects contained in this file will have to be precached manually

	[...]
}

Shared

Dispatching

When dispatched from the server, the particle systems will be networked as temporary entities.

#include "particle_parse.h"

// Create at world co-ords
DispatchParticleEffect( "my_particle", vecOrigin, angAngles, pOwnerEntity )

// Create at model attachment
DispatchParticleEffect( "my_particle", ParticleAttachment_t, pOwner, iAttachment, bResetAllParticlesOnEntity )
  • See also ParticleAttachment_t, below.
  • vecStart, taken by some overloads of DispatchParticleEffect(), defines the location of control point 1. If you don't specify vecStart, the value of vecOrigin is used instead.
Icon-Bug.pngBug:Valve's code for dispatching a particle on a model attachment is broken. Get the fix here.

Destroying

StopParticleEffects( CBaseEntity* )
Stops all effects on the given entity.

Client

Creating

For more control over the effect, a particle system can be created by a new CNewParticleEffect object and managed through the owning entity's ParticleProp() accessor:

#include "particles_new.h"

C_MyEntity::MessWithParticles()
{
	// Create a new system
	CNewParticleEffect* pEffect = ParticleProp()->Create( "my_particles", PATTACH_ABSORIGIN );
	
	// System already exists
	CNewParticleEffect* pEffect = ParticleProp()->FindEffect( "my_particles" );
}

Particles_new.h must also be #included here.

Alternatively, you can hook into particle creation events:

void C_MyEntity::OnNewParticleEffect( const char* pszParticleName, CNewParticleEffect* pNewParticleEffect )
{
	if ( V_strcmp(pszParticleName, "target_effect_name") == 0 )
	{
		// Do something
	}
}
Warning.pngWarning:A dispatch message from the server configures both control point 0 AND 1. The values are applied after OnNewParticleEffect() is called, so don't bother trying to assign either of those CPs from it!

Control points

When dispatching an effect from the server you can define the location of control points 0 (with vecOrigin) and 1 (with vecStart).

On the client, you can configure the location, rotation and parent entity of any CP with these CNewParticleEffect functions:

SetControlPoint( Vector )
Arbitrary set the CP's value.
SetControlPointEntity( CBaseEntity* )
Follow the given entity's origin.
Confirm:Set to NULL to disable following.
SetControlPointOrientation( QAngle )
SetControlPointRightVector()
SetControlPointForwardVector()
SetControlPointUpVector()
Set orientation with a QAngle or a series of Vectors.

Destroying

StopParticleEffects( CBaseEntity* )
Stops all effects on the given entity.
ParticleProp()->StopParticlesInvolving( CBaseEntity* )
Stops all effects with a control point attached to the given entity.
Todo: Global or only on current entity?
ParticleProp()->StopParticlesNamed( const char* )
Stops all effects with the given system name.
Todo: Global or only on current entity?
CNewParticleEffect::StopEmission( bool bInfiniteOnly, bool bRemoveAllParticles, bool bWakeOnStop)
Stops the current particle system, without removing it.
Todo: Meaning of first and third arguments.

ParticleAttachment_t

One of these values is passed when dispatching or creating an effect:

PATTACH_ABSORIGIN
PATTACH_ABSORIGIN_FOLLOW
Spawn at (and optionally follow) the entity's origin.
PATTACH_POINT
PATTACH_POINT_FOLLOW
Spawn at (and optionally follow) an attachment point on the entity's model.
PATTACH_CUSTOMORIGIN
Spawn at a given origin.
PATTACH_WORLDORIGIN
Don't associate with an entity at all. Use with caution - could easily cause memory leaks.