Modular Pathfinding Kit

There is a lot of options for how to create pathfinding creatures. It’s best to start by having an idea of what you want to create, either a real world analogue like a horse or a dog, or something mythical such as a ghost or fairy.
 things that don’t work (at present):
 1. 3D spatial movement - for example underwater free movement or aerial free movement
 2. mixing physics and pathfinding (for instance using llApplyImpulse with a pathfinding character)
=Quick Guide=
> object + pathfinding character skeleton + behavioural tropes = autonomous pathfinding creature
This guide gives quick guidance of how to create specific behavioural tropes (commonly found autonomous characteristics) and doesn't go into detail about individual functions - see Pathfinding LSL Functions for more details.
=Components=
==pathfinding character skeleton==
doSomething()
{
// insert pathfinding functionality here
}
// called as necessary from events such as script reset or rezzing
startup()
{
// create the character
 llCreateCharacter([ CHARACTER_MAX_SPEED, 25,
 CHARACTER_DESIRED_SPEED, 15.0]);
 doSomething();
}
default
{
 on_rez(integer start_param)
 {
 llResetScript();
 }
 state_entry()
 {
 startup();
 }
}
==Behavioural Tropes==
===flying/hovering===
3D spatial free flight is at present unavailable. We can however fake it but one of the following methods:
# create a small object with a tall root prim - not recommended, causes excessive collisions
# create a small object and create a large character envelope - recommended
The example below creates a character with a 1.5m tall and 0.25m wide envelope. If the object itself if 0.25 it will appear to be "flying", or, more accurately, hovering.
 llCreateCharacter([ CHARACTER_MAX_SPEED, 25,
 CHARACTER_DESIRED_SPEED, 15.0,
 CHARACTER_RADIUS, 0.25,
 CHARACTER_LENGTH, 1.5]);
In order to further the illusion of flying we can do a number of things. If the creature is something that works at near ground height, such as a hummingbird or dragonfly just use one of the movement tropes, such as wandering.
If you want the creature to fly higher than the 10.0m maximum character height (which will give a centre of mass height of 5.0m), we can use a platform. If you want a parrot to fly between trees place a prim or series of prims that stretch between them and use something like llPatrolPoints or llWanderWithin. Even if you use a series of narrow pathways the pathfinding will find a way to valid targets.
We can make a really nice effect by using a mesh surface with an undulating form - the creature will follow the dips and rises giving the appearance of varying flight.
For ground hugging creatures we can something similar that looks natural for hovering creatures by dynamically changing the envelope size of the creature by calling llUpdateCharacter, as below. Call this function repeatedly with different values and the character will change the level it hovers at.
 llUpdateCharacter([CHARACTER_LENGTH, 6.5]);
===fleeing===
There are two distinct behaviours we can exploit. If we wanted a character to run from a specific point such as an explosion we can use llFleeFrom. If we want to run from a specific object or agent (avatar) use llEvade
===hiding===
Part of llEvade is hiding (blocked line of sight) from the agent/object the character is fleeing from. See llEvade for more details.
===move-wait-repeat===
By responding to path events we can create varying behaviour. All pathfinding functions are moving to specific targe coordinates, whether determined randomly by something like llWanderWithin, specific as in llPatrolPoints or even llPursue. 
Have a look at Path update for guidance, and see the example script in the multiple states discussion at the end of this article.
===chase===
Use llPursue and specify a target object or avatar.
===hunt===
Use a sensor of some description, such as llSensorRepeat or some sort of collision detection such llVolumeDetect
===wait===
To make a character pause you can use a state change with a new event trigger making the character active again, or simply use something like:
 llExecCharacterCmd(CHARACTER_CMD_STOP, []);
 llSleep(15.0);
 vector currentPosition = llGetPos();
// resume with any desired pathfinding function
 llWanderWithin(currentPosition, <10.0, 10.0, 5.0>, []);
===wandering===
Use llWanderWithin to specify an area to wander within.
===hopping/jumping===
Use llExecCharacterCmd(CHARACTER_CMD_JUMP, [height, 1.0]) to make the character hop 1m into the air. If done with a timer event while using another pathfinding command such as llWanderWithin the hop will have an arc rather than just vertical movement. 
==Optional Extras==
To add to immersion it's worth adding some extras. If desired add...
===animation===
see Animation Streamlined for tips
===sounds===
see Creature Sounds and Event Driven Sounds
===more than one state===
States are an excellent way of managing pathfinding creatures, but note however that pathfinding behaviour survives state changes - it's simple a simpler way of managing a status than using a variable. See the example below, which simulates a rabbit grazing.
animateGrassEating()
{
// insert a cunning grass eating animation here
}
 
animateTailWiggle()
{
// insert very cute tail wiggle animation here
}
 
startup()
{
 llCreateCharacter([ CHARACTER_MAX_SPEED, 2.0, CHARACTER_DESIRED_SPEED, 1.0, CHARACTER_DESIRED_TURN_SPEED, 2.0]);
 if (TRUE)
 {
 state wander;
 }
}
 
default
{
 on_rez(integer start_param)
 {
 llResetScript();
 }
 
 state_entry()
 {
 startup();
 }
}
 
state wander
{
 state_entry()
 {
 vector currentPosition = llGetPos();
 llWanderWithin(currentPosition, <10.0, 10.0, 5.0>, []);
 }
 
 path_update(integer type, list reserved)
 {
 if (type == PU_SLOWDOWN_DISTANCE_REACHED)
 {
 llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
 state graze;
 }
 }
}
 
state graze
{
 state_entry()
 {
 animateGrassEating();
 
 llSetTimerEvent(15.0);
 }
 
 timer()
 {
 llSetTimerEvent((float)FALSE);
 animateTailWiggle();
 state wander;
 }
}
===random timers===
In the example above the rabbit eat grass for 15 seconds then wanders again, for a random period defined by how long it takes to reach it's next random wander target. This 15 second wait will make it an easy target for hunting creatures or agents (hunting game? what if this was a zombie bunny with a taste for brains? hmm, brains).
To make things less predictable use:
// random period in between [0.0, 15.0)
// which means the random float returned could be 0.0 but not 15.0
 llSetTimerEvent( llFrand(15.0) );
// random period in between (0.0, (30.0-random number up to 15)]
// which means the resulting float could be 0 but not (30 - random number up to but not including 15)
 llSetTimerEvent( 30.0 - llFrand(15.0) );
===enabled check===
If you're giving other people your creations, you'd be wise to have your script check to see if pathfinding is enabled where they rez it. Pathfinding can be disabled on private regions.
// returns TRUE if patfinding is enabled, FALSE if not.
integer IsPFEnabled()
{
 if ( llGetEnv("dynamic_pathfinding") == "enabled" ) 
 return TRUE;
 return FALSE;
}
----
Return to Good_Building_Practices