Thinking: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Eu traduzi tudo, mas pode ter alguns erros... eu nao sou muito bom em ver ce tem)
mNo edit summary
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{lang|Thinking}}[[Category:AI]][[Category:Functions]][[Category:Programming]]
{{LanguageBar}}
[[File:Entity init.png|right|130px|The Source engine entity initialization process.]]
[[File:Entity init.png|right|130px|The Source engine entity initialization process.]]


'''Think functions''' permitem entidades preparar código para ser feito no futuro. Quando você reagendar os ''Thinks'', loops automáticos podem ser criados para fazer a entidade fazer as funções automaticamente
'''Think functions''' allow entities to schedule code to be run in the future. By constantly rescheduling thinks, automated loops can be created that make an entity autonomous.
{{clr}}
== Preparando ==
<code>SetNextThink()</code> é usado para poder configurar quando a entidade deve executar a próxima função ''think'' . O código aceita valores com virgula.


<source lang=cpp>
== Scheduling ==
<code>SetNextThink()</code> is used to configure when an entity should next think. It accepts a [[float]] value.
 
<source lang=cpp style="background:initial">
void CMyEntity::Spawn()
void CMyEntity::Spawn()
{
{
BaseClass::Spawn();
BaseClass::Spawn();
SetNextThink( gpGlobals->curtime ); // Faça o think agora
SetNextThink( gpGlobals->curtime ); // Think now
}
}


void CMyEntity::Think()
void CMyEntity::Think()
{
{
BaseClass::Think(); //Sempre faça isso se você substituir Think()!
BaseClass::Think(); // Always do this if you override Think()


Msg( "Penso ,logo existo.\n" );
Msg( "I think, therefore I am.\n" );
SetNextThink( gpGlobals->curtime + 1 ); // Execute o '' think'' depois de 1 segundo!
SetNextThink( gpGlobals->curtime + 1 ); // Think again in 1 second
}
}
</source>
</source>


Olhe o uso de <tt>gpGlobals->curtime</tt> para fazer com que o valor passado seja relativo ao tempo de execução.
Notice the use of <tt>gpGlobals->curtime</tt> to make the value passed relative to the time of execution.
{{tip|<code>SetNextThink(-1)</code> ira cancelar qualquer '' think ''futuro! . É melhor usar esse comparado ao<tt>SetNextThink(NULL)</tt>, pois o<tt>TICK_NEVER_THINK</tt> é -1.}}
{{tip|<code>SetNextThink(-1)</code> will cancel any future thinks. This is better than <tt>SetNextThink(NULL)</tt>, because <tt>TICK_NEVER_THINK</tt> is -1.}}


== Novas Think Functions ==
== New Think Functions ==
Uma entidade pode ter inúmeras ''think functions'' adicionas. Para fazer uma nova:
An entity can have any number of additional think functions. To register a new one:
# Tenha certeza que a função é do tipo<tt>void</tt>.
# Ensure the function is <tt>void</tt>.
# Adicione ela para a [[DATADESC]] da entidade, usando <tt>DEFINE_THINKFUNC()</tt>!.
# Add it to the entity's [[DATADESC]] with <tt>DEFINE_THINKFUNC()</tt>.
# Chame <code>SetThink()</code> e passe o pointer para a função! (olhe o exemplo abaixo).
# Call <code>SetThink()</code> and pass a pointer to the function (see example below).
# Tenha certeza que <code>DECLARE_DATADESC();</code> esta em sua classe!
# Ensure <code>DECLARE_DATADESC();</code> is in your class.


<source lang=cpp>
<source lang=cpp>
BEGIN_DATADESC( CMyEntity )
BEGIN_DATADESC( CMyEntity )
DEFINE_THINKFUNC( MyThink ), // Registre uma nova função
DEFINE_THINKFUNC( MyThink ), // Register new think function
END_DATADESC()
END_DATADESC()


Line 41: Line 41:
{
{
BaseClass::Spawn();
BaseClass::Spawn();
SetThink( &CMyEntity::MyThink ); // Passe o pointer da função
SetThink( &CMyEntity::MyThink ); // Pass a function pointer
SetNextThink(gpGlobals->curtime);
SetNextThink(gpGlobals->curtime);
}
}
Line 47: Line 47:
void CMyEntity::MyThink()
void CMyEntity::MyThink()
{
{
Msg( "Penso,logo existo.\n" );
Msg( "I think, therefore I am.\n" );
SetNextThink( gpGlobals->curtime + 1 );
SetNextThink( gpGlobals->curtime + 1 );
}
}
</source>
</source>


Devindo seu codigos entre outras funções que estão sendo usado para o ''think'' deixa mais fácil trocar entre modos de operação!
Splitting your think code into different functions makes it easy to switch an entity between modes of operation.
{{tip|<code>SetThink()</code> pode ser chamado dentro de uma função ''think'' também. A próxima chamado será na nova função.}}
{{tip|<code>SetThink()</code> can be called from within a think function, too. The next call will be to the new function.}}


== Usando contexto ==
== Using Contexts ==
É possível agendar qualquer número de funções de pensamento lado a lado com "contextos de thinks". Para criar um novo contexto:
It is possible to schedule any number of think functions side-by-side with "think contexts." To create a new context:
# Chame <code>RegisterThinkContext([[string]] NomeDoContexto)</code>
# Call <code>RegisterThinkContext([[string]] ContextName)</code>
# Use< code>SetContextThink([[void]]* Function, float NextThinkTime, string NomeDoContexto)</code>
# Call <code>SetContextThink([[void]]* Function, float NextThinkTime, string ContextName)</code>
# For subsequent thinks, call <code>SetNextThink(float NextThinkTime, string NomeDoContexto)</code>
# For subsequent thinks, call <code>SetNextThink(float NextThinkTime, string ContextName)</code>


<source lang=cpp>
<source lang=cpp>
Line 68: Line 68:
void CMyEntity::Spawn()
void CMyEntity::Spawn()
{
{
SetNextThink( gpGlobals->curtime ); //Loop de pensamento padrão - sem contexto
SetNextThink( gpGlobals->curtime ); // Default think loop - no context
RegisterThinkContext( "TestContext" );
RegisterThinkContext( "TestContext" );
SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "ContextoTest" );
SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "TestContext" );
}
}


Line 89: Line 89:
</source>
</source>


Isso cria dois loops de pensamento simultâneos, ambos gravando no console em taxas diferentes.
This creates two simultaneous think loops, both writing to the console at different rates.
{{tip|Criar um novo contexto é uma ótima maneira de atrasar chamadas de função para o futuro sem perturbar os ciclos de pensamento existentes.}}
{{tip|Creating a new context is a great way to delay function calls to the future without upsetting existing think loops.}}
 
== Utilidades ==


== Utilities ==
These should be self-explanatory:


<source lang=cpp>
<source lang=cpp>
float GetLastThink() // Pegamos o ultimo ''think'' que foi executado
float GetLastThink()
float GetNextThink() // Pegamos o proximo ''think''  a ser executado
float GetNextThink()
int GetLastThinkTick() //Pegamos o ultimo ''tick'' do ultimo ''think'' que foi executado
int GetLastThinkTick()
int GetNextThinkTick() // Pegamos o proximo ''tick'' do próximo ''think'' a ser executado
int GetNextThinkTick()
</source>
</source>


[[File:Barnacle.jpg|right|50px|link=npc_barnacle]]
[[File:Barnacle.jpg|right|50px|link=npc_barnacle]]


As funções <code>GetLast</code> são úteis para controlar a taxa com que algo ocorre.
The <code>GetLast</code> functions are useful for controlling the rate at which something occurs.  
Este código de pensamento de {{ent|npc_barnacle}} modula a velocidade do movimento da língua, mesmo que a frequência do pensamento mude:
This think code from {{ent|npc_barnacle}} modulates the speed of tongue movement, even if the frequency of thinking changes:
 
<source lang=cpp>
<source lang=cpp>
 
float dt = gpGlobals->curtime - GetLastThink(); // dt is "delta time"
float dt = gpGlobals->curtime - GetLastThink(); // dt é "delta time"
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Change tongue altitude
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Mudamos a altitude de sua língua!
</source>
</source>


Para que sua animação não [[esquelética]] seja suave, esse código precisaria ser executado a cada quadro. Isso é exatamente o que acontece, até que a craca não esteja mais no [[PVS]] do jogador e a taxa diminua - exigindo assim o código acima.
For its non-[[skeletal]] animation to be smooth, this code would need to be executed every frame. This is exactly what happens, until the barnacle is no longer in the player's [[PVS]] and the rate is slowed down—thus requiring the above code.


==<tt>ClientThink()</tt>==
==<tt>ClientThink()</tt>==
''Thinking'' também pode acontecer no cliente, mas os efeitos são limitados!. Apenas podemos usar 1 função para cada entidade.
Thinking can also occur on the client, but its effects are limited. Only one think function is supported for each entity.


  <span style="color:blue;">void</span> C_MyEntity::ClientThink()
  <span style="color:blue;">void</span> C_MyEntity::ClientThink()
  {
  {
  Msg( <span style="color:brown;">"NÃO COLOQUE NADA [[PESADO]] NESSAFUNÇÃO!\n"</span> );
  Msg( <span style="color:brown;">"Don't put anything [[expensive]] in this function!\n"</span> );
  SetNextClientThink( CLIENT_THINK_ALWAYS ); <span style="color:green;">/ ''Think'' é executado todo frame</span>
  SetNextClientThink( CLIENT_THINK_ALWAYS ); <span style="color:green;">// Think every frame</span>
  }
  }


Alguns exemplos de ''client-side'' thinking são:
Some examples of client-side thinking are:
 
* Visual effects / particles
* VGUI screen interaction
* Modifying player speed (done on the client as well as server to avoid [[prediction]] errors)
* Striders’ legs snapping ropes (disabled by default)


* Efeitos visuais/partículas
<code>SetNextClientThink()</code> is used to schedule <code>ClientThink()</code>. There are two special values it accepts:
* Interação com VGUI
* Modificação da velocidade do jogador (feita tanto no cliente quanto no servidor para evitar erros de [[predição]])
* Pernas dos Peregrinos quebrando cordas (desativado por padrão)


<code>SetNextClientThink()</code> é usado para agendar <code>ClientThink()</code>. Existem dois valores especiais que ele aceita:
; <tt>CLIENT_THINK_ALWAYS</tt>: Think on the client once every frame. Use with caution! {{tip|Use <code>gpGlobals->frametime</code> to regulate speed.}}
; <tt>CLIENT_THINK_NEVER</tt>: Pause all automated client thinking.


; <tt>CLIENT_THINK_ALWAYS</tt>: Pense no cliente uma vez a cada frame. Use com cuidado! {{tip|Use <code>gpGlobals->frametime</code> para regular a velocidade.}}
[[Category:AI]]
; <tt>CLIENT_THINK_NEVER</tt>: pause todo o pensamento automatizado do cliente.
[[Category:Functions]]
[[Category:Programming]]

Latest revision as of 00:54, 24 August 2024

English (en)Deutsch (de)Español (es)Português do Brasil (pt-br)Русский (ru)Translate (Translate)
The Source engine entity initialization process.

Think functions allow entities to schedule code to be run in the future. By constantly rescheduling thinks, automated loops can be created that make an entity autonomous.

Scheduling

SetNextThink() is used to configure when an entity should next think. It accepts a float value.

void CMyEntity::Spawn()
{
	BaseClass::Spawn();
	SetNextThink( gpGlobals->curtime ); // Think now
}

void CMyEntity::Think()
{
	BaseClass::Think(); // Always do this if you override Think()

	Msg( "I think, therefore I am.\n" );
	SetNextThink( gpGlobals->curtime + 1 ); // Think again in 1 second
}

Notice the use of gpGlobals->curtime to make the value passed relative to the time of execution.

Tip.pngTip:SetNextThink(-1) will cancel any future thinks. This is better than SetNextThink(NULL), because TICK_NEVER_THINK is -1.

New Think Functions

An entity can have any number of additional think functions. To register a new one:

  1. Ensure the function is void.
  2. Add it to the entity's DATADESC with DEFINE_THINKFUNC().
  3. Call SetThink() and pass a pointer to the function (see example below).
  4. Ensure DECLARE_DATADESC(); is in your class.
BEGIN_DATADESC( CMyEntity )
	DEFINE_THINKFUNC( MyThink ), // Register new think function
END_DATADESC()

void CMyEntity::Spawn()
{
	BaseClass::Spawn();
	SetThink( &CMyEntity::MyThink ); // Pass a function pointer
	SetNextThink(gpGlobals->curtime);
}

void CMyEntity::MyThink()
{
	Msg( "I think, therefore I am.\n" );
	SetNextThink( gpGlobals->curtime + 1 );
}

Splitting your think code into different functions makes it easy to switch an entity between modes of operation.

Tip.pngTip:SetThink() can be called from within a think function, too. The next call will be to the new function.

Using Contexts

It is possible to schedule any number of think functions side-by-side with "think contexts." To create a new context:

  1. Call RegisterThinkContext(string ContextName)
  2. Call SetContextThink(void* Function, float NextThinkTime, string ContextName)
  3. For subsequent thinks, call SetNextThink(float NextThinkTime, string ContextName)
BEGIN_DATADESC( CMyEntity )
	DEFINE_THINKFUNC( ContextThink ),
END_DATADESC()

void CMyEntity::Spawn()
{
	SetNextThink( gpGlobals->curtime ); // Default think loop - no context 
	
	RegisterThinkContext( "TestContext" );
	SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "TestContext" );
}

void CMyEntity::Think()
{
	BaseClass::Think();

	Msg( "Think\n" );
	SetNextThink( gpGlobals->curtime + .1 );
}

void CMyEntity::ContextThink()
{
	Msg( "Context think\n" );
	SetNextThink(gpGlobals->curtime + .2, "TestContext" );
}

This creates two simultaneous think loops, both writing to the console at different rates.

Tip.pngTip:Creating a new context is a great way to delay function calls to the future without upsetting existing think loops.

Utilities

These should be self-explanatory:

float	GetLastThink()
float	GetNextThink()
int	GetLastThinkTick()
int	GetNextThinkTick()
Barnacle.jpg

The GetLast functions are useful for controlling the rate at which something occurs. This think code from npc_barnacle modulates the speed of tongue movement, even if the frequency of thinking changes:

float dt = gpGlobals->curtime - GetLastThink(); // dt is "delta time"
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Change tongue altitude

For its non-skeletal animation to be smooth, this code would need to be executed every frame. This is exactly what happens, until the barnacle is no longer in the player's PVS and the rate is slowed down—thus requiring the above code.

ClientThink()

Thinking can also occur on the client, but its effects are limited. 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 (done on the client as well as server to avoid prediction errors)
  • Striders’ legs snapping ropes (disabled by default)

SetNextClientThink() is used to schedule ClientThink(). There are two special values it accepts:

CLIENT_THINK_ALWAYS
Think on the client once every frame. Use with caution!
Tip.pngTip:Use gpGlobals->frametime to regulate speed.
CLIENT_THINK_NEVER
Pause all automated client thinking.