Almost all entities in Half-Life have at least two of the three primary functions: Think, Touch, and Use. These functions are key to how an entity works.
The Use Function
The Use function is used whenever an entity can be triggered. Most of the effects entities, such as an env_sprite, have a use function. So, let's break down a Use function.
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
The first parameter is
. When the Use function is called, this parameter identifies the entity which activated this particular Use function. It does not have to be the entity which actually called this entity's Use function. For example, if a player walks into a trigger_once, it calls its target's Use function and passes the player pointer as the activator.
the entity which called the particular
function. From the
function, you can modify the variables and call more functions to perform actions on those entities as you see fit.
The third parameter is the use type. There are three major use types:
. You can check what
is and then perform different actions based on its value.
Parameter four is basically unused in most entities. It's just a simple value that you can assign when the entity is fired. It may be used for special cases or something.
Ok, now we will learn one of the key things about these three functions. If you are declaring a Use, Touch, or Think function and its name is not
, you must put
between the function type and function name.
void EXPORT UseFunction( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
If you forget the
, the function will not be remembered between level changes or level saves. It is vitally important that you check to make sure all your functions have this.
Now, the reason you would want to name it something other than
is if you have multiple Use functions. The particular Use function that will be called is determined by using the
SetUse( functionname );
SetUse( UseFunction );
If you only have one Use function, just keep it named
and it will automatically be set, no
needed. To fire an entity's Use function, use the
function in an entity; this will fire its
's Use function (assuming it has one).
So we can set up a use function right, but what if we want to remove one? Well, that's easy. In a case where you have a specific event happen and you don't want an entity to be usable any more, just throw in one simple line:
SetUse( NULL );
Bam! No more use function for it. And of course if you want it back, you can just call
with an actual function instead of
The Touch Function
The Touch function is used whenever an entity is touched. Its primary use is for triggers like a trigger_once or trigger_multiple, but it also has many others. The other major uses include tracking when an entity hits a wall, bounces, reflects, etc. When an entity touches another, the engine calls the
function which in return calls the touched entity's Touch function with the pointer of the toucher.
void Touch( CBaseEntity *pOther );
is the entity which touched the entity with the Touch function. Again, you can modify it however you like. The Touch function shares many of the same properties as the Use function. You MUST have
between the function type and name:
void TouchFunction( CBaseEntity *pOther );
If the name of the function is Touch
, you do not need to use the
function either. Otherwise, you must use the
command in the same manner as the
SetTouch( TouchFunction );
Again like use functions you can also remove a touch function from being set. One simple line:
SetTouch( NULL );
The Think Function
Of the three primary functions, the Think function is the most important. A Think function is called every x seconds and executes code that gives the impression of "thinking." Almost every entity has a Think function: monsters, players, weapons, effects entities, all of them. Some Think functions call other functions while they think, giving a branching effect. For example, the apache flies around and hunts players using the
function. But, within the
function is called the
function, which controls the dynamic physics to tilt the chopper in the appropriate direction as it flies. Here is what a basic Think function looks like:
void Think( void );
Pretty plain. Now let's look at a Think function's actual body:
void CYourClass::Think( void )
ALERT(at_console, "I am thinking!\n");
pev->nextthink = gpGlobals->time + 0.1;
Ok, time to detail. The first line with the
is just a simple alert to tell us that our Think function is being called. Now the second line is extremely important in any Think function.
is a variable that stores the time value for the engine to use. The engine uses this number to know when to trigger the think function again. In this case, we're taking the current global time (
) and adding 0.1 seconds to that. Right, so we'll get the message "I am thinking!" about 10 times a second. It's a simple Think function and serves no practical purpose, but it is indeed a Think function.
Again, Think functions work like the Use and Touch functions. Generally, you'll use a
call within an entity's Spawn function, such as:
SetThink( ThinkFunction );
pev->nextthink = gpGlobals->time + X.X;
Again, that tells the engine at what time to call our Think function. If it is just named Think, there is no need for a SetThink, but you still must set the
variable to a time value.
You can stop an entity from thinking in two manners. First, just like use and touch, you can do:
SetThink( NULL );
But, you can also set nextthink to something before
the current global time, for example:
pev->nextthink = 0;
If set before the global time, the engine will never call the function again because that time has already passed. This is useful if you want to keep the think function attached to the entity, but might not want to think in specific cases.
Put It to Use!
Time to put what we've learned to use in a small example. Attached to this tutorial is a small example utilizing all of these functions in the code for a projectile entity. Read the comments to understand how it all comes together. You'll want to create the projectile with
and set its angles to whatever. I hope you've learned just how important the Think, Touch, and Use functions are in creating everything and anything in Half-Life.