Thinking
You can help by finishing the translation.
Also, please make sure the article tries to comply with the alternate languages guide.Think-Funktionen erlauben Entities, Code geplant später ausführen zu lassen. Durch das konstante neuplanen eines Thinks, kann eine automatisierte Schleife erzeugt werden, die die Entity autonom macht.
Planung („Scheduling“)
SetNextThink()
wird verwendet, um einzustellen, wann der nächste Think einer Entity ausgeführt werden soll. Es nimmt float -Werte an.
void CMyEntity::Spawn()
{
BaseClass::Spawn();
SetNextThink( gpGlobals->curtime ); // Think jetzt
}
void CMyEntity::Think()
{
BaseClass::Think(); // Das muss immer gemacht werden, wenn Think() überschrieben wird
Msg( "Ich denke, also bin ich.\n" );
SetNextThink( gpGlobals->curtime + 1 ); // Think in 1 Sekunde nochmal
}
Beachte die Verwendung von gpGlobals->curtime
, um den übergebenen Wert relativ zum ausführungszeitpunkt zu machen.
SetNextThink(0)
oder SetNextThink(null)
werden jeden zukünftigen Think abbrechen.Neue Think-Funktionen
eine Entity kann eine beliebige Anzahl zusätzlicher Think-Funktionen haben. Um eine neue zu registrieren:
- Man muss sichergehen, dass die Funktion
void
ist. - Hinzufügen zur DATADESC der Entity mit DEFINE_THINKFUNC().
SetThink()
aufrufen und den Pointer zur Funktion übergeben (siehe Beispiel unten).- Man muss sichergehen, dass
DECLARE_DATADESC();
in der eigenen Klasse ist.
BEGIN_DATADESC( CMyEntity )
DEFINE_THINKFUNC( MyThink ), // Die neue Think-Funktion registrieren
END_DATADESC()
void CMyEntity::Spawn()
{
BaseClass::Spawn();
SetThink( &CMyEntity::MyThink ); // Einen Funktionszeiger übergeben
SetNextThink(gpGlobals->curtime);
}
void CMyEntity::MyThink()
{
Msg( "Ich denke, also bin ich.\n" );
SetNextThink( gpGlobals->curtime + 1 );
}
Der Think-Code einer Entity kann in verschiedene Funktionen aufgeteilt werden, um es wechseln zwischen dem Operationsmodi zu vereinfachen.
SetThink()
kann auch aus einer Think-Funktion heraus aufgerufen werden. Der nächste Aufruf wird dann an die neue Funktion gehen.Kontexte verwenden
Es ist möglich, eine beliebige Anzahl an Think-Funktionen mit einem „Think-Kontext“ Seite an Seite zu planen. Um einen neuen Kontext zu erzeugen:
RegisterThinkContext(string ContextName)
aufrufenSetContextThink(void * Function, float NextThinkTime, string ContextName)
aufrufenSetNextThink(float NextThinkTime, string ContextName)
für nachfolgende Thinks aufrufen
BEGIN_DATADESC( CMyEntity )
DEFINE_THINKFUNC( ContextThink ),
END_DATADESC()
void CMyEntity::Spawn()
{
SetNextThink( gpGlobals->curtime ); // Standard Think-Schleife - kein Kontext
RegisterThinkContext( "TestContext" );
SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "TestContext" );
}
void CMyEntity::Think()
{
BaseClass::Think();
Msg( "Think\n" );
SetNextThink( gpGlobals->curtime + .1 );
}
void CMyEntity::ContextThink()
{
Msg( "Kontext-Think\n" );
SetNextThink(gpGlobals->curtime + .2, "TestContext" );
}
Dies erzeugt 2 gleichzeitige Think-Schleifen, die beide mit unterschiedlicher Rate Konsolenausgaben machen.
Utilities
Diese sollten selbsterklärend sein:
float GetLastThink()
float GetNextThink()
int GetLastThinkTick()
int GetNextThinkTick()
Die GetLast
-Funktionen sind nützlich für die Kontrolle der Rate, in der etwas auftritt.
Dieser Think-Code des npc_barnacle moduliert die Deschwindigkeit der Zungenbewegung, auch wenn die Think-Häufigkeit sich ändert:
float dt = gpGlobals->curtime - GetLastThink(); // dt ist "delta time" ("Zeitunterschied")
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Ändern der Zungenhöhe
Damit diese nicht-Skelett -Animation weich ist, muss der Code jeden Frame ausgeführt werden. Genau das Passiert, bis das Barnacle nicht mehr in der PVS des Spieler ist, wonach die Rate verringert wird – wofür der obige Code nötig ist.
ClientThink()
Think kann ebenfalls auf der Clientseite auftreten, aber dessen Auswirkungen sind limitiert. Nur eine Think-Funktion wird für jede Entity unterstützt.
void C_MyEntity::ClientThink() { Msg( "Packe nichts teures in diese Funktion!\n" ); SetNextClientThink( CLIENT_THINK_ALWAYS ); // Think in jedem Frame }
Ein paar Beispiele für Clientseitige Thinks sind:
- visuelle Effekte / Partikel
- VGUI-Interaktionen
- Anpassung der Spielergeschwindigkeit (auf dem Client und auf dem Server, um Vorhersage probleme zu vermeiden)
- Fangseile der Strider (standardmäßig deaktiviert)
SetNextClientThink()
wird zum Planen von ClientThink()
verwendet. Es gibt 2 spezielle, akzeptierte Werte:
- CLIENT_THINK_ALWAYS
- Think auf Clientseite bei jedem Frame. Mit Vorsicht verwenden! Tipp:Man kann
gpGlobals->frametime
zur Regulierung der Geschwindigkeit verwenden. - CLIENT_THINK_NEVER
- Pausiert automatisch alle Client-Thinks.