-
Notifications
You must be signed in to change notification settings - Fork 4
Entity Intermediate
This article covers some intermediate aspects of the entity system.
There are 4 fundamental functions used to drive the behaviour of any entity:
Think
Use
Touch
Blocked
Each of these is responsible for an important part of an entity's behaviour.
Think functions are used to make entities act on their own. An entity "thinks" every so often and performs tasks while doing so.
For example, a train will think every frame to determine if it's reached the current node along its path. if so, it will calculate the velocity needed to move to the next node, or stop, if it has reached the final node.
Entities can think every frame or once every so often. This allows you to set timeouts for when an action should take place, or update something every 5 seconds, for example.
To set an entity as always thinking, you have to enable the FL_ALWAYSTHINK
flag:
pev.flags |= FL_ALWAYSTHINK;
Note: This can be expensive, especially if costly calculations are performed in the think function. This is typically reserved for entities that move themselves between move than 2 positions. Trains and vehicles are prime candidates for it.
To set the next think time, you will have to set entvars_t::nextthink
:
pev.nextthink = g_Engine.time + 5; // 5 seconds from now
For brush entities, instead of g_Engine.time
, you will have to use pev.ltime
:
pev.nextthink = pev.ltime + 5;
This is because the engine treats brush entities differently, and does not work properly when using g_Engine.time
.
Think functions are defined as follows:
void MyThink()
{
// Code here
}
It is currently impossible to set think functions through Angelscript for built-in entities, but for custom entities, it is possible by using the SetThink function:
pCustomEnt.SetThink( ThinkFunction( pCustomEnt.MyThink ) );
Where MyThink
is a think function defined in the custom entity's class. ThinkFunction
is a funcdef
. Its use is required here to convert the function to a type that the SetThink
function can use.
It is also possible to define a Think
function by overriding the default function. If this is done, you will not be able to set Think functions using SetThink
. Overriding the default is done like this:
void Think()
{
// Code here
}
Use functions are used to trigger entities. When an entity is "used", it responds by performing an action. For example, a button will react by optionally moving, and when it finishes moving, triggers its target. A door will open or close, while a changelevel changes the map.
There are a few ObjectCaps
flags that affect how player use behaves with specific entities:
Flag | Behavior | Parameters |
---|---|---|
FCAP_IMPULSE_USE | The entity is triggered when the player presses the use button. Holding down the button or releasing it does not trigger it again. | USE_SET with value 1 |
FCAP_CONTINUOUS_USE | Every frame that the use button is pressed, the entity is triggered. | USE_SET with value 1 |
FCAP_ONOFF_USE | Similar to impulse use, but if the player releases the use button and this entity is the target, it is triggered with USE_SET and a value of 0. | USE_SET with value 1, USE_SET with value 0 when use is released |
FCAP_DIRECTIONAL_USE | Used by trains. Does not affect player use. Instead, the entity will receive a trigger when the player presses the forward or back button while in control of this entity. Sent only in the frame that the button press is received, not continuous. | USE_SET with value 1 when forward is pressed, USE_SET with value -1 when back is pressed. |
The USE_TYPE
enum contains constants used to indicate what kind of use action is being performed on an entity.
Constant | Value | Description |
---|---|---|
USE_OFF | 0 | Explicit off (only close/deactivate/lock/disable etc). |
USE_ON | 1 | Explicit on (only open/activate/unlock/enable etc). |
USE_SET | 2 | Entity was +use'd by a player, or some other form of player input. |
USE_TOGGLE | 3 | Toggle on/off (if entity on do off, if entity off do on). |
USE_KILL | 4 | Explicitly destroy entity. Items remove themselves when they receive this. Most other entity types don't handle it. |
Use functions are defined as follows:
void MyUse( CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue )
{
// Code here
}
It is currently impossible to set use functions through Angelscript for built-in entities, but for custom entities, it is possible by using the SetUse
function:
pCustomEnt.SetUse( UseFunction( pCustomEnt.MyUse ) );
Where MyUse
is a use function defined in the custom entity's class. UseFunction
is a funcdef
. Its use is required here to convert the function to a type that the SetUse
function can use.
It is also possible to define a Use
function by overriding the default function. If this is done, you will not be able to set Use functions using SetUse. Overriding the default is done like this:
void Use( CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue )
{
// Code here
}
Touch functions are used to detect and respond to entities touching each-other.
Entities touch each-other when their collision hulls intersect. Depending on the type of entity, this may be a point, a bounding box, or a brush model.
When entities touch, the Touch functions for both entities are called, first the entity being moved, then the entity being touched.
Touch functions are defined as follows:
void MyTouch( CBaseEntity@ pOther )
{
// Code here
}
It is currently impossible to set touch functions through Angelscript for built-in entities, but for custom entities, it is possible by using the SetTouch
function:
pCustomEnt.SetTouch( TouchFunction( pCustomEnt.MyTouch ) );
Where MyTouch
is a touch function defined in the custom entity's class. TouchFunction
is a funcdef
. Its use is required here to convert the function to a type that the SetTouch
function can use.
It is also possible to define a Touch
function by overriding the default function. If this is done, you will not be able to set Touch functions using SetTouch
. Overriding the default is done like this:
void Touch( CBaseEntity@ pOther )
{
// Code here
}
Blocked functions are used to detect and respond to entities blocking each-other.
An entity blocks another entity when the entity moving towards the entity cannot move any further due to the blocking entity being in the way.
When an entity is blocked, its Blocked
function is called. The blocking entity's Blocked
function is not called.
Blocked functions are defined as follows:
void MyBlocked( CBaseEntity@ pOther )
{
// Code here
}
It is currently impossible to set blocked functions through Angelscript for built-in entities, but for custom entities, it is possible by using the SetBlocked
function:
pCustomEnt.SetBlocked( BlockedFunction( pCustomEnt.MyBlocked ) );
Where MyBlocked
is a blocked function defined in the custom entity's class. BlockedFunction
is a funcdef
. Its use is required here to convert the function to a type that the SetBlocked
function can use.
It is also possible to define a Blocked
function by overriding the default function. If this is done, you will not be able to set Blocked functions using SetBlocked
. Overriding the default is done like this:
void Blocked( CBaseEntity@ pOther )
{
// Code here
}