Rotating Pickups
Jump to navigation
Jump to search
This article is an orphan, meaning that few or no articles link to it.
You can help by adding links to this article from other relevant articles.
January 2024
You can help by adding links to this article from other relevant articles.
January 2024
In this tutorial we'll create a rotating health pickup entity, like the ones in TF2. When a player walks over it they will gain some health and the item will disappear until a respawn timer completes.
Get the code here. You should be familiar with creating entities, so only the interesting parts will be picked out.
Functionality
- Server
- Initialise the entity as a trigger
- Ensure that the item floats above any walkable surfaces
- Create a decal to mark the item's position when it is invisible
- Handle touches from players (give health, play a respawn sound)
- Client
- Rotate the model
- Handle model visibility
Server
Spawn()
- Note how some of
CItem
's changes have to be undone (it's not designed with impossible floating objects in mind). Source is a big and mature engine, and it's always worth checking what your base classes are doing. - We are setting
MdlTop
before fiddling about with the bounding box. This will be used when repositioning the entity; if we just used the origin, then if/when a larger model is used it might reach so high that it obscures the player's view.
Activate()
- Here we trace down to our desired height, adding to the entity's Z position if we come up short. This is done in
Activate()
instead ofSpawn()
in case we spawned before the entity beneath us. - This is also where we fire a decal onto the ground. This might look bad in some cases, so a flag to bypass the call is provided.
Precache()
- We need to get the return value from
UTIL_PrecacheDecal()
, butPrecace()
is called statically (i.e. directly, not through any instance of the class). Storing the value in a global variable is the only sensible solution.
Client
ClientThink()
C_RotatingPickup::ClientRotAng
is used to rotate the model, notCBaseEntity
's built-in variable. This is because even though the latter has been excluded from this entity's datatable, it is still zeroed when the entity materialises (I suspect thatCItem
is resetting the entity's location through some sort of back door). Not callingGetAbsAngles()
also provides a small performance boost.
PostDataUpdate()
- If you have looked into receive proxies, you may be wondering why we are testing against a cached value when we could simply hook into the receipt of an updated one. Two reasons:
- You can't have proxies on
RecvPropBool()
. - Proxies are static and should never, ever be used to run entity logic. Receive proxies are called not only when receiving entity updates, but also when validating predicted values. It's quite possible for a proxy to be re-used by another entity too.
- You can't have proxies on