Projectiles: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Created page with ''''Projectiles''' are entities which emerge from weapons, and which usually explode either on contact or on a timer. Most inherit from either <code>CBaseGrenade</code> (for […')
 
(Precaching)
Line 48: Line 48:


Another possible solution is creating a single manager entity that spawns along with the world. This would take a lot of implementation, but could also be used to reduce network overhead by reducing the frequency at which updates for simple "straight line" projectiles are broadcast.
Another possible solution is creating a single manager entity that spawns along with the world. This would take a lot of implementation, but could also be used to reduce network overhead by reducing the frequency at which updates for simple "straight line" projectiles are broadcast.
== Precaching ==
Because projectiles generally don't exist until after a map spawns, they aren't automatically [[precache]]d. To overcome this use the precache functions of weapons that fire them to call <code>UTIL_PrecacheOther([[string]] classname)</code>.


== See also ==
== See also ==

Revision as of 09:56, 17 September 2009

Projectiles are entities which emerge from weapons, and which usually explode either on contact or on a timer. Most inherit from either CBaseGrenade (for VPhysics) or CBaseAnimating (for QPhysics).

Although perfectly ordinary entities in a technical sense, projectiles do require some special design considerations. This article will cover them.

Collisions and ownership

One annoyance with projectiles is their tendency to immediately bump into and potentially explode on the player who fired them. This happens either because the projectile spawned inside the player (in which case it will become stuck there), or because the player is moving fast enough to collide with it from behind very quickly.

Ownership is used to record which player fired a projectile, and in theory can be used to filter out owner collisions. But alas, for an object never collides with its owner. That's bad too, since if a player is teleported or respawns into the path of an owned projectile it ought to hit him like it would anyone else.

There are two approaches to solving this problem (aside from the inelegant and somewhat unreliable answer of trying to ensure that the projectile always spawns out in front of the player). Which you use depends on how you want your projectile's velocity to behave:

The SolidFlag approach

  1. Add support for the third-party SolidFlag FSOLID_COLLIDE_WITH_OWNER. Then:
    1. Add the flag and run UTIL_TraceEntity(). If the trace hits the owner, remove the flag again; otherwise leave it set.
    2. Add the flag when the projectile's owner shows up in EndTouch() as pOther.
  2. Add the player's velocity to the projectile's when it spawns. Otherwise players moving forward may clip into the projectile again immediately.
  3. Optionally, decay the projectile's velocity back to the natural value over time.

The 'grace period' approach

  1. Store ownership in a new variable. (Don't try to store ownership recursively via the weapon, because weapons can be removed. Only players persist through respawns.)
  2. Call AddSolidFlags(FSOLID_NOT_SOLID|FSOLID_TRIGGER).
  3. Add a bool that defines whether the entity is in its "grace period". Enable it on spawn.
  4. Schedule a think .2 seconds or so into the future, depending on the speed of the projectile and players, that disables the grace period bool.
  5. Run a test at the start of Touch() that returns early if the grace period is active and pOther is the owner.

This latter option is roughly how Valve prevent player collision with the Half-Life 2 RPG.

Tip.pngTip:You may or may not want to call SetCollisionGroup(COLLISION_GROUP_PROJECTILE), which stops the entity from colliding with debris, weapons, or other projectiles.

Persistence

Todo: How to best attribute kills, detect team ownership, etc. if the owner has disconnected.

Prediction

Prediction and lag compensation can be passed off for hitscan weapons because they are instant and invisible. This is not so with projectiles. To predict a rocket would mean the server spawning it a long way away from a lagged firer, potentially right in a surprised target's face: a very visible inconsistency that would also hurt gameplay, since players expect to be able to see projectiles coming.

The weapon itself is good for prediction, as is the depletion of the player's ammo stock, but not the projectiles.

Interpolation

A projectile will hang in the air for a moment before moving, and will disappear a moment before it explodes. Both of these things happen because an entity's position in the world is subject to interpolation, but its creation and destruction are not.

In Team Fortress 2, Valve worked around this limitation by turning interpolation off for certain projectiles (grenades and arrows), then spawning them on the client behind the player who fired, at a distance determined by the current interp period ("lerp"). Projectiles treated like this pass through the barrel of the weapon at the right moment without any pause, but spawn in an incorrect location. If an observer's lerp is much higher than the default 100ms, things start to look really bizarre!

Another possible solution is creating a single manager entity that spawns along with the world. This would take a lot of implementation, but could also be used to reduce network overhead by reducing the frequency at which updates for simple "straight line" projectiles are broadcast.

Precaching

Because projectiles generally don't exist until after a map spawns, they aren't automatically precached. To overcome this use the precache functions of weapons that fire them to call UTIL_PrecacheOther(string classname).

See also