PathEngine home previous: Line collision and collision infonext: SlideAgainst()
Contents, Programmers Guide, Example Projects, Tutorials, Tutorial 2, Translating the agent

Translating the agent

We use the keys 'W','S','A' and 'D' to control translation.
These move the agent forward, back, left and right respectively, relative to the current agent heading.

So the first half of the MoveAgentUnderKeyControl() function simply builds a vector from the combination of keys currently pressed, the current speed, and the current agent heading.

void MoveAgentUnderKeyControl(iTestBed *testbed, iPathEngine *pathengine,
                              iAgent *agent, float agent_heading,
                              iCollisionContext *context,
                              float speed)
{
    float sinof = sin(double(agent_heading));
    float cosof = cos(double(agent_heading));
    int32_t dx = 0,dy = 0;
// setup the desired movement vector in <dx,dy> from agent heading and a combination of keys pressed
    if(testbed->getKeyState("W"))
    {
    // forward
        dx+=sinof*speed;
        dy+=cosof*speed;
    }
    if(testbed->getKeyState("S"))
    {
    // backward (half speed)
        dx-=sinof*speed/2;
        dy-=cosof*speed/2;
    }
    if(testbed->getKeyState("A"))
    {
    // left (half speed)
        dx-=cosof*speed/2;
        dy+=sinof*speed/2;
    }
    if(testbed->getKeyState("D"))
    {
    // right (half speed)
        dx+=cosof*speed/2;
        dy-=sinof*speed/2;
    }

    if(dx==0 && dy==0)
    // no movement was requested
        return;

    //... implement the requested movement
}

To implement this movement we go through iAgent::firstCollisionTo().
If this returns zero then we know we can move without collision.
Otherwise it returns an iCollsionInfo object from which we will obtain information about the obstruction we want to slide against.

Passing a collision context into firstCollisionTo() means that the collision will take account of any obstacles that have been placed (and added to the context).

cPosition current=agent->getPosition();
cPosition target;

// check collision
// modify movement vector for each collision to slide against the first obstruction
target.x=current.x+dx;
target.y=current.y+dy;
iCollisionInfo *collisioninfo=agent->firstCollisionTo(context,target.x,target.y,target.cell);
int trys=0;
while(collisioninfo && trys<2)
{
    int32_t coords[4];
    collisioninfo->getCollidingLine(coords[0], coords[1], coords[2], coords[3]);
    delete collisioninfo;

    SlideAgainst(coords, current.x, current.y, dx, dy);
    target.x = current.x + dx;
    target.y = current.y + dy;
    collisioninfo = agent->firstCollisionTo(context, target.x, target.y, target.cell);
    trys++;
}
if(collisioninfo)
// failed to find a non-colliding movement vector
    delete collisioninfo;
else
// succeeded
    agent->moveTo(target);

The obstruction edge is obtained from the iCollisionInfo object as an array of four longs.
This corresponds to <startx,starty,endx,endy> for a 2d obstructing line.
This obstructing line comes from the expanded geometry, and so is relative to the agent centre.

SlideAgainst() is defined in 'sliding.cpp'.
This function modifies a movement vector to slide against an obstruction edge.

Note that for simplicity we don't make any attempt to move the agent right up to the point of contact.

Sometimes it is necessary to slide against two edges in order to get the correct behaviour at convex corners.
Two tries seems to be sufficient for most cases.


Documentation for PathEngine release 6.00 - Copyright © 2002-2016 PathEnginenext: SlideAgainst()