Disabling physics on out of scope bots/mobs
by Peter Simard · 10/18/2007 (2:07 pm) · 9 comments
Installation
Place inside the Player public block in player.h:
Modify Player::ProcessTick() in player.cc:
Add these functions to the end of player.cc:
Note: You can use isSleeping() from script inside your AI calls to to further optimize performance.
Place inside the Player public block in player.h:
void setSleeping(bool flag); bool isSleeping(); void updateSleepState(); bool mIsSleeping;
Modify Player::ProcessTick() in player.cc:
[b]From:[/b]
if (!isGhost())
updateAnimation(TickSec);
PROFILE_START(Player_PhysicsSection);
if(isServerObject() || (didRenderLastRender() || getControllingClient()))
[b]To:[/b]
if (!isGhost())
{
updateAnimation(TickSec);
updateSleepState();
}
PROFILE_START(Player_PhysicsSection);
if ((isServerObject() || (didRenderLastRender() || getControllingClient())) && !isSleeping())Add these functions to the end of player.cc:
void Player::updateSleepState()
{
if(getControllingClient())
{
setSleeping(false);
return;
}
Point3F localPosition = getPosition();
SimGroup* pClientGroup = Sim::getClientGroup();
F32 wakeRange = 1000;
Sky * sky = gServerSceneGraph->getCurrentSky();
if(sky)
wakeRange = sky->getVisibleDistance() * 2;
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
{
GameConnection* nc = static_cast<GameConnection*>(*itr);
Player* plr = dynamic_cast<Player*>(nc->getControlObject());
if (plr)
{
// This is a player that a client controls.
// If it is within Scope * 2, the mob will not sleep
if ((localPosition - plr->getPosition()).len() < wakeRange)
{
// It is within the wake range, so don't sleep
setSleeping(false);
return;
}
}
}
setSleeping(true);
}
void Player::setSleeping(bool flag)
{
// Ignore it if its the same
if(flag == mIsSleeping)
return;
mIsSleeping = flag;
if(mIsSleeping)
{
Con::executef(this, 1, "onSleep");
}
else
{
Con::executef(this, 1, "onWake");
}
}
bool Player::isSleeping()
{
return mIsSleeping;
}
ConsoleMethod( Player, isSleeping, bool, 2, 2, "()")
{
return object->isSleeping();
}Note: You can use isSleeping() from script inside your AI calls to to further optimize performance.
#2
I'll try to play with it soon.. But then I'll need to re-design AI logic in our project.. Huh...
10/18/2007 (2:43 pm)
Very interesting.I'll try to play with it soon.. But then I'll need to re-design AI logic in our project.. Huh...
#3
10/18/2007 (3:46 pm)
@Brian - If the object is being controlled by a client, it will early out of updateSleepState:if(getControllingClient()) return;
#4
10/19/2007 (4:51 am)
Nice job Peter, handy for certain things definitely!!
#5
Btw, only one suggestion, change
10/19/2007 (11:23 am)
hey, this is great resource! Now I can run more zone servers on single computer, nice!Btw, only one suggestion, change
if(getControllingClient())
{
setSleeping(false);
return;
}This is needed in case the player object created without being controlled by client, and later the client attached to it. Or if you use camera and "drop player to camera". Perfect!
#6
10/19/2007 (2:59 pm)
Thanks for the fix bank. I have updated the resource.
#7
12/27/2007 (10:34 pm)
im not sure where the Player public block is in player.h, im not that experienced in the c++ aspect of torque thanks
#8
replace "updateSleepState()" with this:
It's now easier to configure when AI will sleep.
My code checks if the control object is one of: Player, Vehicle, Camera.
Before, it was only allowing Player's as control object, so if you "dead", control object switches to the Camera and AI stopped "thinking". So now you can easily configure it to your needs.
Second change - we now comparing lenSquared() to save processor ticks on calculating real distance.
09/07/2009 (1:18 pm)
Minor update.replace "updateSleepState()" with this:
void Player::updateSleepState()
{
if(getControllingClient())
{
setSleeping(false);
return;
}
Point3F localPosition = getPosition();
SimGroup* pClientGroup = Sim::getClientGroup();
F32 wakeRange = 1000;
Sky * sky = gServerSceneGraph->getCurrentSky();
if(sky)
wakeRange = sky->getVisibleDistance() * 2;
const F32 wakeRangeSq = wakeRange * wakeRange;
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
{
GameConnection* nc = static_cast<GameConnection*>(*itr);
GameBase* ctrlobj = dynamic_cast<GameBase*>(nc->getControlObject());
if (ctrlobj && ctrlobj->getTypeMask() & (PlayerObjectType | VehicleObjectType | CameraObjectType))
{
// This is a control object that a client controls.
// If it is within Scope * 2, the mob will not sleep
if ((localPosition - ctrlobj->getPosition()).lenSquared() < wakeRangeSq)
{
// It is within the wake range, so don't sleep
setSleeping(false);
return;
}
}
}
setSleeping(true);
}What's new:It's now easier to configure when AI will sleep.
My code checks if the control object is one of: Player, Vehicle, Camera.
Before, it was only allowing Player's as control object, so if you "dead", control object switches to the Camera and AI stopped "thinking". So now you can easily configure it to your needs.
Second change - we now comparing lenSquared() to save processor ticks on calculating real distance.
#9
I should probably look into this again since I obviously didnt know how to make it work before.
09/23/2009 (9:21 am)
LOL, judging by my previous statement and the date it was made, I had no idea what I was doing back then... LMAO, good stuff.I should probably look into this again since I obviously didnt know how to make it work before.

Torque Owner Michael Bacon
Default Studio Name
I would however optimize updateSleepState() by checking to see if this player is a control object itself. If it is you don't have to run the loop that checks every client. Right now on real player objects (as this works on both real players and ai players) it would get to the current player and eventually run the check on itself which of course would be 0 distance. Unless there was another player nearby that could trigger it before it got to itself.