Don't click here unless you want to be banned.

LSL Wiki : TutorialRobotics

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl338.us.archive.org

Robotics


This page is currently under construction (But don't let that stop you contributing)- Tip

The objective of this page is to provide information, techniques and tips on the scripting of autonomous objects (And to give me some practice in formating a wiki page Tip). That is, objects that move on their own.

This tutorial is intended for those with a good general knowledge of LSL and programming.

The term 'robot' will be used on this page to describe such an autonomous object.






Basics


Functions and events you need to know and understand


FunctionsEventsNotes
llSetPos, llSetPrimitiveParams For non physical movement
llTarget, llTargetRemove at_target, not_at_targetIn order to know whether or not the robot has reached a specific location
llRotTarget, llRotTargetRemoveat_rot_target, not_at_rot_targetIn order to know whether or not the robot is facing in a specific direction
 collision, collision_start, collision_endIn order to know when the robot has hit something
llLookAt, llRotLookAt , llSetRot To make a robot face a specific direction. Not recomended for vehicle based robots.
llSetForce, llSetForceAndTorque, llApplyImpulse, llMoveToTarget, llStopMoveToTarget  For non-vehicle, physics based movement
llSetBuoyancy In order to make small physics based robots hover. Not recomended for vehicle based robots.
llSensor, llSensorRepeatsensor, no_sensorIn order to detect what is around the the robot







Movement


You have a choice of three different principles for movement each with their own advantages and restrictions:

Non-physics based


A non-physical robot can be moved using llSetPos, or llSetPrimitiveParams. Rotation can be achieved using llSetRot, llLookat or llRotLookAt depending on the application. The comments for llSetPos have further information on how to get round some of the limitations for long distance movement.

llSetPos has a 10-meter range limit. There are a few ways to get around this, but the fastest is to use this bit of code:

vector target;
while(llVecDist(llGetPos(), target) > 0.01) llSetPos(target);
or so that you dont use energy
warpPos( vector destpos ) 
{   //R&D by Keknehv Psaltery, 05/25/2006
    //with a little pokeing by Strife, and a bit more
    //some more munging by Talarus Luan
    //Final cleanup by Keknehv Psaltery
    // Compute the number of jumps necessary
    integer jumps = (integer)(llVecDist(destpos, llGetPos()) / 10.0) + 1;
    // Try and avoid stack/heap collisions
    if (jumps > 100 )
        jumps = 100;    //  1km should be plenty
    list rules = [ PRIM_POSITION, destpos ];  //The start for the rules list
    integer count = 1;
    while ( ( count = count << 1 ) < jumps)
        rules = (rules=[]) + rules + rules;   //should tighten memory use.
    llSetPrimitiveParams( rules + llList2List( rules, (count - jumps) << 1, count) );
}

Here is an example of a non physical robot by AnorcaCalamari
//Written by Anorca Calamari on the TG
//This robot moves non-physically. 
//It only turns phantom so that you can walk through it. It does not need to be phantom to go through walls.
//It randomly chooses targets within 50 meters excluding the owner. 
//If noone is within 50 meters or only the owner is within 50 meters it increases the range. It continues
//increasing till it finds a target and moves there,at which point it resets to 50.

integer range=50;

default
{
    touch_start(integer total_number)
    {
        if(llDetectedKey(0) == llGetOwner())
        {
            llSetStatus(STATUS_PHANTOM,TRUE);
            llOwnerSay("ROBOT ON");
            state on;
        }
    }
    
}

state on
{
    state_entry()
    {
        llSensorRepeat("","",AGENT,range,PI,2.5);
    }
    
    sensor(integer num_detected)
    {
        integer target = (integer)llFrand((float)num_detected);
        
        if(llDetectedKey(target) == llGetOwner())
        {
            integer target = (integer)llFrand((float)num_detected);
        }
        
        if(num_detected == 0 | num_detected == 1 && llDetectedKey(0) == llGetOwner())
        {
            integer range=range+10;
        }
        
       
        while(llGetPos() != llDetectedPos(target) + <0,0,2> && llDetectedKey(target) != llGetOwner())
        {
            llSetPos(llDetectedPos(target) + <0,0,2>);
        }
        
        if(llGetPos() == llDetectedPos(target) + <0,0,2>)
        {
            range=50;
        }
        
        
    }
    
    touch_start(integer total_number)
    {
        if(llDetectedKey(0) == llGetOwner())
        {
            llOwnerSay("ROBOT OFF");
            llResetScript();
        }
    }
}

Anorca Calamari's example didn't appear to work for me (OpenSim, 0.6.4). Here is an example of a non-physical robot which did work. It makes use of RandomVector, from the ScriptLibrary. It is slightly bugged -- robot movement is not terribly smooth, and it tends to stop after an arbitrary amount of time. If anyone could tell me why it stops, I'd be obliged. ~ StormSaber

// This is an example, from StormSaber, of a robot which moves non-physically. It uses a llSetPos to fake smooth movement.

float DELAY = 0.0; 
// The script sleeps this amount of time before moving to the next spot in between its current position and its target.
// In practice, theres no need to set this to anything other than 0 as LSL forces the script to sleep 0.2 seconds anyway.

float INCREMENT = 0.1; 
// This defines the amount by which the robot should move, in each iteration of the script. Higher is faster.

float TOLERANCE = 0.1; 
// When the robot is a certain distance from its target, it will give up and find another one. 
// (A metaphor would be that you tend not to measure the distance to your house in centremetres -- after a certain distance, it becomes moot.)
// You can play about for interesting results by finding the relationship between TOLERANCE and INCREMENT. 
// In practice, TOLERANCE probably shouldn't be less than INCREMENT.

vector target;
// Contains the current target we are moving towards

integer moving = FALSE;
// Are we moving? When the robot spawns, it should await commands from a user so the answer is 'no'.

// This function does the main work:
object_move_to(vector targetPos) {
  if (moving) { // Check if we're actually supposed to be moving...

      // We need to find out if we're close enough to the target that we should actually move closer to it.
      if (llVecDist(llGetPos(), targetPos) > TOLERANCE) {

            //If we still need to get closer, start by getting our current position.
            vector position = llGetPos();
            
            // We find where we need to go next by setting our axes one dimension at a time.
            // First we find out if our x position is larger than the targets x position.
            if (targetPos.x > position.x) {
                position.x = position.x + INCREMENT; // If it is, increment (make larger) our x position.
            } else if (targetPos.x < position.x) {
                    position.x = position.x - INCREMENT; // Otherwise, our x position is smaller than the targets. Decrement our x position.
            }
            
           // Now do the same for y.
            if (targetPos.y > position.y) {
                position.y = position.y + INCREMENT;
            } else if (targetPos.y < position.y) {
                    position.y = position.y - INCREMENT;
            }
            
            // Finally for z.
            if (targetPos.z > position.z) {
                position.z = position.z + INCREMENT;
            } else if (targetPos.z < position.z) {
                    position.z = position.z - INCREMENT;
            }
            
            // Teleport to our new position, which we've calculated to be only slightly closer to the target
            // In this context, slightly closer means closer by INCREMENT in all three axes.
            llSetPos(position);
            
            // Sleep for the recommended amount of time, to prevent ourselves going too fast.
            llSleep(DELAY);
            
            // Recursively call this function. We'll look, ending when we're close enough.
            object_move_to(targetPos);    
        } else {
            //Oop,  we've arrived. Time to choose another target...
            llWhisper(0, "... eep..");
            chooseTarget();
      }
    }
}

// FROM RandomVector on the lslwiki.net ScriptLibrary page
// Chooses a random number between min and max.
float randBetween(float min, float max) {
    return llFrand(max - min) + min;
}

// FROM RandomVector on the lslwiki.net ScriptLibrary page
vector randVector() {                         //HERE we use the randBetween we have up on top to 
                           //make a random number from 100 to 500 - on the Z axis. Fun for a trampoline :) 
    return <randBetween(10, 20),randBetween(10, 20),randBetween(20, 30)>;    
}

// Chooses a random position, informs everyone we're moving to it, then moves to it.
chooseTarget() {
    target = randVector();
    llShout(0, "Moving to " + (string) target);
    object_move_to(target);
}

// The script starts here. It informs the user the robot is online, then enters the 'not_moving' state.
default {
    state_entry() {
        llOwnerSay("Robot Online");
         state not_moving;
    }
}

// In the moving state, we choose a target then move to it.
state moving {
    state_entry() {
        moving = TRUE;
        chooseTarget();
    }

   // When touched in the moving state, make a chirp and then enter the 'not moving' state.
    touch_start(integer _i) {
        llOwnerSay("Eep!");
        state not_moving;
    }
}

// In the not moving state, we wait to be touched by a user.
state not_moving {
    state_entry() {
        moving = FALSE;
    }

    // When touched, we should chirp, then enter the moving state.
    touch_start(integer _i) {
        llOwnerSay("Eeeep!");
         state moving;
     }
}

I have never used non-physics based movement, so I shall leave it to others to add additional information to this section - Tip

Physics, Non-Vehicle Based


Example
This example shows a simple ground based, hopping motion. It was created for a small, mass < 5, robot. The robot moves towards its target, the nearest avatar, by turning towards its target and then jumping forward. If it is too near its target, it jumps back. After a few seconds near an Avatar, it leaves that one and moves towards another. Note: You can also use llMoveToTarget for physics based vehicles.
integer current_food_level = 0;
integer maximum_food_level = 2;
key current_target;
float max_food_range = 4;
float min_food_range = 2;
vector kick_up = <0,0,1.5>;
float forward_kick = 3;

default
{
    state_entry()
    {
        llOwnerSay("Script reset:moving to searching state");
        llSetStatus(STATUS_PHYSICS,TRUE);
        llSetStatus(STATUS_ROTATE_X, FALSE);
        llSetStatus(STATUS_ROTATE_Y, FALSE);
        state searching;
    }
}

state searching
{
    state_entry()
    {
        llSensorRepeat("","",AGENT,50, 2 * PI, 3);
    }
    sensor(integer total)
    {
       if(total == 0)
       {    
            current_target = llDetectedKey(0);
        }
        else
        {
            current_target = llDetectedKey(1);
        }
        state moving;
    }
    state_exit()
    {
        llSensorRemove();
    }
}
state moving
{
    //This state moves the robot towards or away from the selected Agent.
    state_entry()
    {
        llSensorRepeat("",current_target,AGENT,50, 2 * PI, 3);
        llSetTimerEvent(30);
    }
    no_sensor()
    {
        state searching;
    }
    state_exit()
    {
        llSensorRemove();
        llSetStatus(STATUS_PHANTOM,FALSE);
    }
    timer()
    {
        //If the target hant been reached after 30 seconds, the robot may be stuck behind something
        //So go phantom to get throught it.
        llSetStatus(STATUS_PHANTOM,TRUE);
    }
    sensor(integer total)
    {
      if(llVecDist(llGetPos(),llDetectedPos(0)) > max_food_range)
        {
           // llWhisper(0,"too far");
            llApplyImpulse((kick_up + <0,0,llFrand(1)>) * llGetMass(), FALSE);
            llApplyImpulse(-llVecNorm(llGetPos() - llDetectedPos(0)) * forward_kick * llGetMass(), FALSE);
        }
        else if(llVecDist(llGetPos(),llDetectedPos(0)) < min_food_range)
        {
            //move away from food
            llApplyImpulse((kick_up + <0,0,llFrand(1)>)  * llGetMass() , FALSE);
            llApplyImpulse(0.5 * llVecNorm(llGetPos() - llDetectedPos(0)) * forward_kick * llGetMass(), FALSE);
        }
        else 
        {
            //Just right, start feeding
            state feeding;
        }
    }
}
state feeding
{
    state_entry()
    {
        llSensorRepeat("",current_target,AGENT,20, 2 * PI, 3);
    }
    no_sensor()
    {
      //  llWhisper(0,"target lost, searching");
        state searching;
    }
    state_exit()
    {
        llSensorRemove();
    }
    sensor(integer total)
    {
  //  llWhisper(0,"pong");
      if(llVecDist(llGetPos(),llDetectedPos(0)) > max_food_range)
        {
      //      llWhisper(0,"too far");
            state moving;
        }
        else if(llVecDist(llGetPos(),llDetectedPos(0)) < min_food_range)
        {
            //move away from food
            state moving;
        }
        current_food_level = current_food_level + 1;
      //  llWhisper(0,"yum");
        if(current_food_level > maximum_food_level)
        {
            current_food_level = 0;
          //  llWhisper(0,"bored");
            state searching;
        }
    }
}


Flying
To make a non-vehicle, physics based robot float in the air or water or to fly, you need to set the bouyancy to 1.0 to cancel the effect of gravity. Because of the effect of energy loss, robot's using this technique cannot have a mass greater than 90 units. Use the llGetMass function to find the mass. If the model is just over 90 units in mass, try hollowing some of the prims.


Although the Create a flying pet example is unfinished, the movement routine is a good starter for any small flying robots. This swarm example (wiki version) on the forums is similar, but with a more complex AI.


Example
This example is taken from a small, mass < 10, flying robot. It is based on the Create a flying pet example. The code requires brain script to tell it, via link messages, a waypoint, a speed and a target distance (How near to get to the waypoint). This script then moves the robot using llSetForce and llApplyImpulse to the waypoint. It sends a link message when it has reached the waypoint.

The example has simple collision detection. If it collides with an object or the ground it moves back, to the left and up.

float heartbeat = 0.5;
float z_force = 0.4;
//Go back, left and up if it collides with the land or an object
vector collision_force = <-0.25,0.25,0.75>;
vector target_position;
integer target;

//Start of code from wiki
vector AXIS_UP = <0,0,1>; 
vector AXIS_LEFT = <0,1,0>; 
vector AXIS_FWD = <1,0,0>; 
// getRotToPointAxisAt() 
// Gets the rotation to point the specified axis at the specified position. 
// @param axis The axis to point. Easiest to just use an AXIS_* constant. 
// @param target The target, in region-local coordinates, to point the axis at. 
// @return The rotation necessary to point axis at target. 
// Created by Ope Rand, modifyed by Christopher Omega rotation 

rotation getRotToPointAxisAt(vector axis, vector target)  
{ 
    return  llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos());  
}
//End of code from wiki

all_stop()
{
    llSetForceAndTorque(<0.0,0.0,0.0>, <0.0,0.0,0.0>, TRUE);
    llApplyImpulse(-llGetVel() * llGetMass(), FALSE);
    llApplyRotationalImpulse(-llGetTorque() * llGetMass(), FALSE);
}

default
{
    state_entry()
    {

        llSetBuoyancy(1);
        llSetStatus(STATUS_PHYSICS,TRUE); 
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
        llSetTimerEvent(heartbeat);
        //llVolumeDetect(TRUE);
        //llSetStatus(STATUS_PHANTOM,TRUE);
        all_stop();
    } 
    link_message(integer sender_num,integer num, string data,key id)
    {
        if(num == 150)
        {
             list data = llParseStringKeepNulls( data, ["-=-"], [] );
             string Cmd = llList2String( data, 0 );
             if( Cmd == "MOVE" )
            {
                  target_position = (vector)llList2String( data, 1 );        
                 float speed = (float)llList2String( data, 2 );
                 float range = (float)llList2String( data, 3 );
                llTargetRemove(target); 
                target = llTarget(target_position,range);
                llSetForce(<speed,0,0> * llGetMass(),TRUE);
            }
            if(Cmd == "STOP" )
            {
                //Received a stop message
                llTargetRemove(target); 
                all_stop();
            }    
        }
     }
    not_at_target()
    {

        llRotLookAt(getRotToPointAxisAt(AXIS_FWD , target_position), 1, 0.5);
        vector currentpos = llGetPos();
        if(currentpos.z > target_position.z + 0.5)
        {
                //little push downwards
             llApplyImpulse(<0,0,-z_force> * llGetMass(),FALSE);
        }
        else
        {
            if(currentpos.z < target_position.z - 0.5)
            {
                //little upwards
                llApplyImpulse(<0,0,z_force> * llGetMass(),FALSE);
            }
        }    
    }
    at_target(integer target_id,vector t_pos,vector o_pos)
    {   
        all_stop();
        llTargetRemove(target);
        llMessageLinked(LINK_SET,150,"ATPOS","");  
    }
    timer()
    {
        //Apply some friction
        llApplyImpulse(-llGetVel() * llGetMass() * 0.6,FALSE);   
    }//end timer
    collision_start(integer num_detected)
    {
        //Hit something?
        //go abit higher
        llApplyImpulse((collision_force) * llGetMass(),TRUE);  
    }
    land_collision_start(vector num_detected)
    {
        //Hit something?
        //go abit higher
        llApplyImpulse((collision_force) * llGetMass(),TRUE);  
    }
    on_rez(integer param)
    {
        llTargetRemove(target); 
        all_stop();
    }
}


state turn_to_target
{
    state_entry()
    {
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
        llRotLookAt(getRotToPointAxisAt(AXIS_FWD , target_position), 0.1, 0.5);
        llSetTimerEvent(1);
    }
    timer()
    {
        state default;
    }
    link_message(integer sender_num,integer num, string data,key id)
    {
        if(num == 150)
        {
             list data = llParseStringKeepNulls( data, ["-=-"], [] );
             string Cmd = llList2String( data, 0 );
             if( Cmd == "MOVE" )
            {
                  target_position = (vector)llList2String( data, 1 );        
                 float speed = (float)llList2String( data, 2 );
                 float range = (float)llList2String( data, 3 );
                llTargetRemove(target); 
                target = llTarget(target_position,range);
                llSetForce(<speed,0,0> * llGetMass(),TRUE);
            }
        }
    }
}


Vehicle Based



Example
This is an example of a simple vehicle based 'engine'. It does nothing except move and change direction as directed by the contents of the link messages it receives. Creating functional modules like this has a number of advantages, including being able to take an 'engine' such as this and drop it into a robot with different behaviours.

This example was originally in a Star Wars droid with a single behaviour of moving from waypoint to waypoint My first vehicle - Tip. It then spent some time in a small follower style pet. The last incarnation was in a large (20 m) ship capable of navigating across void sims.

float speed_multi = 3;
float turn_multi = 1;
set_motor(vector speed,vector turn)
{
      //      llOwnerSay("speed = " + (string)(speed * speed_multi * llGetMass()) + " turn = " +(string)turn);
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, speed * speed_multi);
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, turn* turn_multi);
    }
default
{
    state_entry()
    {

        integer chosen_type = VEHICLE_TYPE_CAR;

        llSetVehicleType(chosen_type);


        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 10.0);

        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0.1); 

        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 0.1); 

        llRemoveVehicleFlags(-1);

        llSetVehicleFlags(VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_LIMIT_MOTOR_UP);
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, ZERO_VECTOR);
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, ZERO_VECTOR);
    }
    on_rez(integer param)
    {
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, ZERO_VECTOR);
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, ZERO_VECTOR);        
    }
     link_message(integer sender,integer num,string data,key id)
    {
        list Arguments = llParseStringKeepNulls( data, ["-=-"], [] );
        string Command = llList2String( Arguments, 0 );
        if( Command == "FWD" )
        {
            llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <1,0,0>* speed_multi);
        }
        if( Command == "STRT" )
        {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,ZERO_VECTOR);
        }
        if( Command == "ROT_LFT" )
        {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0,0,PI>);
        }
        if( Command == "ROT_RGT" )
        {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0,0,PI>);
        }
        if( Command == "LFT" )
        {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0,0,PI_BY_TWO>);
        }
        if( Command == "RGT" )
        {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0,0,-PI_BY_TWO>);
        }
        if( Command == "STP" )
        {
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,ZERO_VECTOR);
        }

    }
}







Sensors


There are a couple of 'gotcha's' with sensors.

Location

Gimbal Mounts

Putting a sensor in its own prim has a number of advantages:
  • For ground based robots a problem can occur when a robot is travelling over uneven ground. If the sensor is in the root prim of the robot, it could end up pointing into the air or ground. With the sensor in a separate prim, its rotation can be altered to keep the sensor pointing in the correct direction. This is a common technique in RL robotics.
  • Mounting the sensor as far forward as possible has advatages for collision detection.
  • The sensor can be scripted to rotate slightly in the direction the robot is turning.

Sensor Arc

As noted, an arc of PI is required to detect object/avatars in a sphere around a robot, not TWO_PI. In practice, if a complete sphere is what is required, it doesnt matter whethere PI or TWO_PI are used. But it must be taken into account if less than a complete sphere is required.

If an animal is being simulated, then the animals field of view is, in part, determined by whether it is hunting or hunted. Hunters tend to have their eyes looking forward to give them good depth perception but with a narrower field of view. The hunted have their eyes either side of their head giving them a wide field of view, so they can see hunters behind them. Think of the difference between the eye position of a cat compared with a rabbit. Take this into account when deciding on the sensor arc.






Collision Avoidance


The objective of collision avoidance is to detect a potential obstacle and then take action to avoid a collision.






Sensor Range and Repeat Rate


It is worth doing a few rough calculations when deciding on the arc, rate and range parameters of your sensor sweep.

Example How far ahead does a robot moving at 10 meters a second have to look to have enough time to spot potential obstacles?
Assumptions, a one second sensor sweep, ignore the limitations of sensors with regards over 16 objects and only centres being detected.
  • In one second, the robot travels 10 meters, therefore in the next second it will collide with any object within the 10 meters ahead. A one second sensor with a 10 meter range will pick up any hazzards.







  • Thinking ahead

    Not all the moving objects detected in a sensor sweep are a hazard, it depends on the direction they are moving in. Whether or not an object is on a collision course can be determined as follows:




    And/Or


    Faking Collision Avoidance

    Collision avoidance is tricky. In a controlled environment (hint Void sims) good results can be achieved. In the real world (err... you know what I mean), it is not easy to detect all potential hazards or decide how to avoid them. A simple but effective alternative is to fake it with a invisible bumper.


    Getting Stuck

    It's a one in a million chance, but very very occasionally a robot may get stuck. Trapped between two prims or unable to navigate around an obsticle, the robot constantly collides with the blocking object.

    In many cases, dependant on relative speeds, the robot can inter-penetrate I know there is a better word, when I'm awake I'll remember - Tip the obstacle. In this case, physics wil be turned off.

    For the creator this is another interesting problem, but for everyone else this is a Bad Thing. Constant collisions between objects is irritating especially if the noise is not suppressed. It is also a major drain on simulator resources, and may result in the Lindens tapping on your door.

    First problem that has to be solved is, how does the robot know it is stuck, A number of techniques can be used in combination depending on the scenario:

    Like many aspects of behaviours, there is no one 'Flag' that can read to determine if a robot is stuck. Its case of experimenting, finding out what in practice causes your robot to become trapped and then figuring out how to detect it. Try having the 'is it stuck' functionality as a single script which sends out a link message when it thinks the robot is stuck.

    The action you take depends on whether you want the robot to continue onto its destination or not. If not, select a new destination, preferable in the opposite direction to the obsticle.

    If the robot still needs to get to its original destination, the action depends on how sophisticated your behaviours are. A simple trick is to turn the robot phantom for a while and let in move through the blocking object. Use the Collision event to determine when the robot has reached the other side.






    Behaviours







    External References


    CW Reynolds page on steering behaviours. Craig Reynolds created the flocking algorithm. This is a must read. The java applets are great, but there is more information in the actual paper itself.

    AI planning in the FEAR game. Top of the right hand column are some presentations describing some of the high level strategies used to develop an AI capable of planning ahead to achieve its goal.






    Functions | Physics | Vehicles
    There are 12 comments on this page. [Display comments/form]