Thinking: Difference between revisions
m (Robot: fixing template case.) |
No edit summary |
||
Line 11: | Line 11: | ||
* New values override old. | * New values override old. | ||
void CMyEntity::Think() | <span style="color:blue;">void</span> CMyEntity::Think() | ||
{ | { | ||
Msg( "I think, therefore I am.\n" ); | Msg( <span style="color:brown;">"I think, therefore I am.\n"</span> ); | ||
SetNextThink( gpGlobals->curtime + 1 ); // Think again in 1 second | SetNextThink( gpGlobals->curtime + 1 ); <span style="color:green;">// Think again in 1 second</span> | ||
} | } | ||
Line 27: | Line 27: | ||
* New values override old. | * New values override old. | ||
void CMyEntity::Think() | <span style="color:blue;">void</span> CMyEntity::Think() | ||
{ | { | ||
Msg( "I think, therefore I am.\n" ); | Msg( <span style="color:brown;">"I think, therefore I am.\n"</span> ); | ||
SetThink( &CMyEntity::Think2 ); // Think with this function next | SetThink( &CMyEntity::Think2 ); <span style="color:green;">// Think with this function next</span> | ||
SetNextThink( gpGlobals->curtime + 1 ); | SetNextThink( gpGlobals->curtime + 1 ); | ||
} | } | ||
void CMyEntity::Think2() | <span style="color:blue;">void</span> CMyEntity::Think2() | ||
{ | { | ||
Msg( "Variety is the spice of life.\n" ); | Msg( <span style="color:brown;">"Variety is the spice of life.\n"</span> ); | ||
SetThink( &CMyEntity::Think ); // Think with this function next | SetThink( &CMyEntity::Think ); <span style="color:green;">// Think with this function next</span> | ||
SetNextThink( gpGlobals->curtime + 1 ); | SetNextThink( gpGlobals->curtime + 1 ); | ||
} | } | ||
Line 51: | Line 51: | ||
<code>[[CAI_ActBusyQueueGoal]]</code> provides good examples, such as: | <code>[[CAI_ActBusyQueueGoal]]</code> provides good examples, such as: | ||
void CAI_ActBusyQueueGoal::MoveQueueUp() | <span style="color:blue;">void</span> CAI_ActBusyQueueGoal::MoveQueueUp() | ||
{ | { | ||
// Find the node the NPC has arrived at, and tell the guy behind him to move forward | <span style="color:green;">// Find the node the NPC has arrived at, and tell the guy behind him to move forward</span> | ||
if ( GetNextThink( QUEUE_MOVEUP_THINK_CONTEXT ) < gpGlobals->curtime ) | <span style="color:blue;">if</span> ( GetNextThink( QUEUE_MOVEUP_THINK_CONTEXT ) < gpGlobals->curtime ) | ||
{ | { | ||
float flTime = gpGlobals->curtime + RandomFloat( 0.3, 0.5 ); | <span style="color:blue;">float</span> flTime = gpGlobals->curtime + RandomFloat( 0.3, 0.5 ); | ||
SetContextThink( &CAI_ActBusyQueueGoal::MoveQueueUpThink, flTime, QUEUE_MOVEUP_THINK_CONTEXT ); | SetContextThink( &CAI_ActBusyQueueGoal::MoveQueueUpThink, flTime, QUEUE_MOVEUP_THINK_CONTEXT ); | ||
} | } | ||
Line 65: | Line 65: | ||
A utility function that returns the time of the entity’s last think as a float. | A utility function that returns the time of the entity’s last think as a float. | ||
float dt = gpGlobals->curtime - GetLastThink(); | <span style="color:blue;">float</span> dt = gpGlobals->curtime - GetLastThink(); | ||
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Change tongue altitude | SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); <span style="color:green;">// Change tongue altitude</span> | ||
[[Image:Barnacle.jpg|right|50px|npc_barnacle]] | [[Image:Barnacle.jpg|right|50px|npc_barnacle]] | ||
Line 76: | Line 76: | ||
There are also: | There are also: | ||
*<code>float GetNextThink()</code> | *<code><span style="color:blue;">float</span> GetNextThink()</code> | ||
*<code>int GetNextThinkTick()</code> | *<code><span style="color:blue;">int</span> GetNextThinkTick()</code> | ||
*<code>int GetLastThinkTick()</code> | *<code><span style="color:blue;">int</span> GetLastThinkTick()</code> | ||
=== ClientThink() === | === ClientThink() === | ||
Line 84: | Line 84: | ||
Thinking can also occur on the client, but its effects are limited. Additionally, only one think function is supported for each entity. | Thinking can also occur on the client, but its effects are limited. Additionally, only one think function is supported for each entity. | ||
void C_MyEntity::ClientThink() | <span style="color:blue;">void</span> C_MyEntity::ClientThink() | ||
{ | { | ||
Msg( "Don't put anything [[expensive]] in this function!\n" ); | Msg( <span style="color:brown;">"Don't put anything [[expensive]] in this function!\n"</span> ); | ||
SetNextClientThink( CLIENT_THINK_ALWAYS ); // Think every frame | SetNextClientThink( CLIENT_THINK_ALWAYS ); <span style="color:green;">// Think every frame</span> | ||
} | } | ||
Revision as of 17:15, 20 January 2009
An entity’s Think() function is the root gateway for executing its code without the need of external inputs. It is called once on spawn, with any subsequent calls decided by the programmer. This page describes the functions needed to set up an automated "think loop".

void
, and must be added to the entity's DATADESC with DEFINE_THINKFUNC
.
SetNextThink()
- Defines when the entity next automatically thinks.
- Accepts a floating point value.
- New values override old.
void CMyEntity::Think() { Msg( "I think, therefore I am.\n" ); SetNextThink( gpGlobals->curtime + 1 ); // Think again in 1 second }
This code causes the entity to print a message to the console once per second. Note the use of gpGlobals->curtime
, which returns the time of execution.

SetNextThink( 0 )
or SetNextThink( null )
will pause automatic thinking.SetThink()
- Changes the active automatic think function
- Accepts a function pointer: add ‘&’ before the name and omit its closing parentheses.
- New values override old.
void CMyEntity::Think() { Msg( "I think, therefore I am.\n" ); SetThink( &CMyEntity::Think2 ); // Think with this function next SetNextThink( gpGlobals->curtime + 1 ); } void CMyEntity::Think2() { Msg( "Variety is the spice of life.\n" ); SetThink( &CMyEntity::Think ); // Think with this function next SetNextThink( gpGlobals->curtime + 1 ); }
This code switches thinking between two functions. A real-world application is to change an entity between various life stages: consider a buildable gun turret. One think function would run while it waits to be unpackaged, another while it is being built, another while it is active, and a fourth when it dies. Creating think functions for each discrete stage increases code stability and aids debugging.
SetContextThink()
Fires a think function once, at a defined time. The third parameter is a "context", a string value that seems to be used to group multiple thinkfuncs under a given heading.
CAI_ActBusyQueueGoal
provides good examples, such as:
void CAI_ActBusyQueueGoal::MoveQueueUp() { // Find the node the NPC has arrived at, and tell the guy behind him to move forward if ( GetNextThink( QUEUE_MOVEUP_THINK_CONTEXT ) < gpGlobals->curtime ) { float flTime = gpGlobals->curtime + RandomFloat( 0.3, 0.5 ); SetContextThink( &CAI_ActBusyQueueGoal::MoveQueueUpThink, flTime, QUEUE_MOVEUP_THINK_CONTEXT ); } }
GetLastThink()
A utility function that returns the time of the entity’s last think as a float.
float dt = gpGlobals->curtime - GetLastThink(); SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Change tongue altitude
This real-world think code for npc_barnacle modulates the speed of tongue movement, even if the frequency of thinking changes. dt
is short for “delta time”.

There are also:
float GetNextThink()
int GetNextThinkTick()
int GetLastThinkTick()
ClientThink()
Thinking can also occur on the client, but its effects are limited. Additionally, only one think function is supported for each entity.
void C_MyEntity::ClientThink() { Msg( "Don't put anything expensive in this function!\n" ); SetNextClientThink( CLIENT_THINK_ALWAYS ); // Think every frame }
Some examples of client-side thinking are:
- Visual effects / particles
- VGUI screen interaction
- Modifying player speed (calculated on the client as well as server to avoid lag)
- Striders’ legs snapping ropes (disabled by default)
SetNextClientThink()
Used to re-fire ClientThink()
. In addition to normal float values, it accepts:
- CLIENT_THINK_ALWAYS
- Think on the client once every frame. Use with caution!
- Replaces Simulate().
- CLIENT_THINK_NEVER
- Pause all automated client thinking.