// Compute initial brake value. float Driver::getBrake() { // Car drives backward? if (car->_speed_x < -MAX_UNSTUCK_SPEED) { // Yes, brake. return 1.0; } else { // We drive forward, normal braking. tTrackSeg *segptr = car->_trkPos.seg; float mu = segptr->surface->kFriction; float maxlookaheaddist = currentspeedsqr/(2.0f*mu*G); float lookaheaddist = getDistToSegEnd(); float allowedspeed = getAllowedSpeed(segptr); if (allowedspeed < car->_speed_x) { return MIN(1.0f, (car->_speed_x-allowedspeed)/(FULL_ACCEL_MARGIN)); } segptr = segptr->next; while (lookaheaddist < maxlookaheaddist) { allowedspeed = getAllowedSpeed(segptr); if (allowedspeed < car->_speed_x) { if (brakedist(allowedspeed, mu) > lookaheaddist) { return 1.0f; } } lookaheaddist += segptr->length; segptr = segptr->next; } return 0.0f; } }
float Driver::getBrake() { tTrackSeg *segptr = car->_trkPos.seg; float mu = segptr->surface->kFriction;//*TIREMU*MU_FACTOR; float maxlookaheaddist = currentspeedsqr/(2.0*mu*G); float lookaheaddist = getDistToSegEnd(); float allowedspeed = getAllowedSpeed(segptr); if (allowedspeed < car->_speed_x) { return MIN(1.0, (car->_speed_x-allowedspeed)/(FULL_ACCEL_MARGIN)); } segptr = segptr->next; while (lookaheaddist < maxlookaheaddist) { allowedspeed = getAllowedSpeed(segptr); if (allowedspeed < car->_speed_x) { if (brakedist(allowedspeed, mu) > lookaheaddist) { return 1.0; } } lookaheaddist += segptr->length; segptr = segptr->next; } return 0.0; }
/* compute target point for steering */ v2d Driver::getTargetPoint() { tTrackSeg *seg = car->_trkPos.seg; float lookahead = LOOKAHEAD_CONST + car->_speed_x*LOOKAHEAD_FACTOR; float length = getDistToSegEnd(); float offset = getOvertakeOffset(); if (pit->getInPit()) { if (currentspeedsqr > pit->getSpeedlimitSqr()) { lookahead = PIT_LOOKAHEAD + car->_speed_x*LOOKAHEAD_FACTOR; } else { lookahead = PIT_LOOKAHEAD; } } while (length < lookahead) { seg = seg->next; length += seg->length; } length = lookahead - length + seg->length; float fromstart = seg->lgfromstart; fromstart += length; offset = pit->getPitOffset(offset, fromstart); v2d s; s.x = (seg->vertex[TR_SL].x + seg->vertex[TR_SR].x)/2.0; s.y = (seg->vertex[TR_SL].y + seg->vertex[TR_SR].y)/2.0; if ( seg->type == TR_STR) { v2d d, n; n.x = (seg->vertex[TR_EL].x - seg->vertex[TR_ER].x)/seg->length; n.y = (seg->vertex[TR_EL].y - seg->vertex[TR_ER].y)/seg->length; n.normalize(); d.x = (seg->vertex[TR_EL].x - seg->vertex[TR_SL].x)/seg->length; d.y = (seg->vertex[TR_EL].y - seg->vertex[TR_SL].y)/seg->length; return s + d*length + offset*n; } else { v2d c, n; c.x = seg->center.x; c.y = seg->center.y; float arc = length/seg->radius; float arcsign = (seg->type == TR_RGT) ? -1.0 : 1.0; arc = arc*arcsign; s = s.rotate(c, arc); n = c - s; n.normalize(); return s + arcsign*offset*n; } }
// Compute offset to normal target point for overtaking or let pass an opponent. float Driver::getOffset() { int i; float catchdist, mincatchdist = FLT_MAX, mindist = -1000.0f; Opponent *o = NULL; // Increment speed dependent. float incfactor = MAX_INC_FACTOR - MIN(fabs(car->_speed_x)/MAX_INC_FACTOR, (MAX_INC_FACTOR - 1.0f)); // Let overlap or let less damaged team mate pass. for (i = 0; i < opponents->getNOpponents(); i++) { // Let the teammate with less damage overtake to use slipstreaming. // The position change happens when the damage difference is greater than // TEAM_DAMAGE_CHANGE_LEAD. if (((opponent[i].getState() & OPP_LETPASS) && !opponent[i].isTeamMate()) || (opponent[i].isTeamMate() && (car->_dammage - opponent[i].getDamage() > TEAM_DAMAGE_CHANGE_LEAD) && (opponent[i].getDistance() > -TEAM_REAR_DIST) && (opponent[i].getDistance() < -car->_dimension_x) && car->race.laps == opponent[i].getCarPtr()->race.laps)) { // Behind, larger distances are smaller ("more negative"). if (opponent[i].getDistance() > mindist) { mindist = opponent[i].getDistance(); o = &opponent[i]; } } } if (o != NULL) { tCarElt *ocar = o->getCarPtr(); float side = car->_trkPos.toMiddle - ocar->_trkPos.toMiddle; float w = car->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN; if (side > 0.0f) { if (myoffset < w) { myoffset += OVERTAKE_OFFSET_INC*incfactor; } } else { if (myoffset > -w) { myoffset -= OVERTAKE_OFFSET_INC*incfactor; } } return myoffset; } // Overtake. for (i = 0; i < opponents->getNOpponents(); i++) { if ((opponent[i].getState() & OPP_FRONT) && !(opponent[i].isTeamMate() && car->race.laps <= opponent[i].getCarPtr()->race.laps)) { catchdist = MIN(opponent[i].getCatchDist(), opponent[i].getDistance()*CATCH_FACTOR); if (catchdist < mincatchdist) { mincatchdist = catchdist; o = &opponent[i]; } } } if (o != NULL) { // Compute the width around the middle which we can use for overtaking. float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN; // Compute the opponents distance to the middle. float otm = o->getCarPtr()->_trkPos.toMiddle; // Define the with of the middle range. float wm = o->getCarPtr()->_trkPos.seg->width*CENTERDIV; if (otm > wm && myoffset > -w) { myoffset -= OVERTAKE_OFFSET_INC*incfactor; } else if (otm < -wm && myoffset < w) { myoffset += OVERTAKE_OFFSET_INC*incfactor; } else { // If the opponent is near the middle we try to move the offset toward // the inside of the expected turn. // Try to find out the characteristic of the track up to catchdist. tTrackSeg *seg = car->_trkPos.seg; float length = getDistToSegEnd(); float oldlen, seglen = length; float lenright = 0.0f, lenleft = 0.0f; mincatchdist = MIN(mincatchdist, DISTCUTOFF); do { switch (seg->type) { case TR_LFT: lenleft += seglen; break; case TR_RGT: lenright += seglen; break; default: // Do nothing. break; } seg = seg->next; seglen = seg->length; oldlen = length; length += seglen; } while (oldlen < mincatchdist); // If we are on a straight look for the next turn. if (lenleft == 0.0f && lenright == 0.0f) { while (seg->type == TR_STR) { seg = seg->next; } // Assume: left or right if not straight. if (seg->type == TR_LFT) { lenleft = 1.0f; } else { lenright = 1.0f; } } // Because we are inside we can go to the border. float maxoff = (o->getCarPtr()->_trkPos.seg->width - car->_dimension_y)/2.0-BORDER_OVERTAKE_MARGIN; if (lenleft > lenright) { if (myoffset < maxoff) { myoffset += OVERTAKE_OFFSET_INC*incfactor; } } else { if (myoffset > -maxoff) { myoffset -= OVERTAKE_OFFSET_INC*incfactor; } } } } else { // There is no opponent to overtake, so the offset goes slowly back to zero. if (myoffset > OVERTAKE_OFFSET_INC) { myoffset -= OVERTAKE_OFFSET_INC; } else if (myoffset < -OVERTAKE_OFFSET_INC) { myoffset += OVERTAKE_OFFSET_INC; } else { myoffset = 0.0f; } } return myoffset; }
// Compute target point for steering. vec2f Driver::getTargetPoint() { tTrackSeg *seg = car->_trkPos.seg; float lookahead; float length = getDistToSegEnd(); float offset = getOffset(); if (pit->getInPit()) { // To stop in the pit we need special lookahead values. if (currentspeedsqr > pit->getSpeedlimitSqr()) { lookahead = PIT_LOOKAHEAD + car->_speed_x*LOOKAHEAD_FACTOR; } else { lookahead = PIT_LOOKAHEAD; } } else { // Usual lookahead. lookahead = LOOKAHEAD_CONST + car->_speed_x*LOOKAHEAD_FACTOR; // Prevent "snap back" of lookahead on harsh braking. float cmplookahead = oldlookahead - car->_speed_x*RCM_MAX_DT_ROBOTS; if (lookahead < cmplookahead) { lookahead = cmplookahead; } } oldlookahead = lookahead; // Search for the segment containing the target point. while (length < lookahead) { seg = seg->next; length += seg->length; } length = lookahead - length + seg->length; float fromstart = seg->lgfromstart; fromstart += length; // Compute the target point. offset = myoffset = pit->getPitOffset(offset, fromstart); vec2f s; s.x = (seg->vertex[TR_SL].x + seg->vertex[TR_SR].x)/2.0f; s.y = (seg->vertex[TR_SL].y + seg->vertex[TR_SR].y)/2.0f; if ( seg->type == TR_STR) { vec2f d, n; n.x = (seg->vertex[TR_EL].x - seg->vertex[TR_ER].x)/seg->length; n.y = (seg->vertex[TR_EL].y - seg->vertex[TR_ER].y)/seg->length; n.normalize(); d.x = (seg->vertex[TR_EL].x - seg->vertex[TR_SL].x)/seg->length; d.y = (seg->vertex[TR_EL].y - seg->vertex[TR_SL].y)/seg->length; return s + d*length + offset*n; } else { vec2f c, n; c.x = seg->center.x; c.y = seg->center.y; float arc = length/seg->radius; float arcsign = (seg->type == TR_RGT) ? -1.0f : 1.0f; arc = arc*arcsign; s = s.rotate(c, arc); n = c - s; n.normalize(); return s + arcsign*offset*n; } }