void PathRecord::Initialise( MyTrack* pTrack, tCarElt* pCar ) { // GfOut( "pr::init\n" ); const int NSEG = pTrack->GetSize(); m_pTrack = pTrack; m_pCar = pCar; delete [] m_pData; m_pData = new Rec[NSEG]; for( int i = 0; i < NSEG; i++ ) { m_pData[i].pSeg = &pTrack->GetAt(i); m_pData[i].avgV = 20; m_pData[i].avgW = pCar->_trkPos.toMiddle; } double pos = RtGetDistFromStart(pCar); m_lastSeg = pTrack->IndexFromPos(pos); m_lastPt.x = pCar->pub.DynGCg.pos.x; m_lastPt.y = pCar->pub.DynGCg.pos.y; m_lastSpd = hypot(pCar->_speed_X, pCar->_speed_Y); // GfOut( "pr::init done\n" ); }
void PathRecord::Update() { const int NSEG = m_pTrack->GetSize(); // work out which slice the car is in. int last_s = m_lastSeg; double dist = RtGetDistFromStart(m_pCar); int cur_s = m_pTrack->IndexFromPos(dist); // work out current speed and position. double spd = hypot(m_pCar->_speed_X, m_pCar->_speed_Y); Vec2d pt(m_pCar->pub.DynGCg.pos.x, m_pCar->pub.DynGCg.pos.y); if( //!m_pCar->On_pit_lane && last_s >= 0 && last_s != cur_s ) { // we have crossed at least one line boundary, so we need to calculate // the crossing point(s), and the speed(s) at those points. int next_s = (last_s + 1) % NSEG; while( last_s != cur_s ) { const Seg& s0 = m_pTrack->GetAt(next_s); double t, w; if( Utils::LineCrossesLine(m_lastPt, pt - m_lastPt, s0.pt.GetXY(), s0.norm.GetXY(), t, w) && t >= 0.0 && t <= 1.0 ) { double v = m_lastSpd + (spd - m_lastSpd) * t; Rec& rec = m_pData[next_s]; const double gamma = 0.8; rec.avgW = rec.avgW * (1 - gamma) + w * gamma; rec.avgV = rec.avgV * (1 - gamma) + v * gamma; } last_s = next_s; next_s = (next_s + 1) % NSEG; } } m_lastSeg = cur_s; m_lastPt = pt; m_lastSpd = spd; }
double MyTrack::CalcPos( tCarElt* car, double offset ) const { double pos = RtGetDistFromStart(car) + offset; return NormalisePos(pos); }
void ReCarsManageCar(tCarElt *car, bool& bestLapChanged) { char msg[64]; int i; int xx; tTrackSeg *sseg; tdble wseg; static const float ctrlMsgColor[] = {0.0, 0.0, 1.0, 1.0}; tSituation *s = ReInfo->s; tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]); // Update top speeds. if (car->_speed_x > car->_topSpeed) car->_topSpeed = car->_speed_x; // (practice and qualification only). if (car->_speed_x > info->topSpd) info->topSpd = car->_speed_x; if (car->_speed_x < info->botSpd) info->botSpd = car->_speed_x; // Pitstop management. if (car->_pit) { // If the driver can ask for a pit, update control messages whether slot occupied or not. if (car->ctrl.raceCmd & RM_CMD_PIT_ASKED) { // Pit already occupied? if (car->_pit->pitCarIndex == TR_PIT_STATE_FREE) snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Can Pit"); else snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Pit Occupied"); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. memcpy(car->ctrl.msgColor, ctrlMsgColor, sizeof(car->ctrl.msgColor)); } // If pitting, check if pitting delay over, and end up with pitting process if so. if (car->_state & RM_CAR_STATE_PIT) { car->ctrl.raceCmd &= ~RM_CMD_PIT_ASKED; // clear the flag. // Note: Due to asynchronous behaviour of the main updater and the situation updater, // we have to wait for car->_scheduledEventTime being set to smthg > 0. if (car->_scheduledEventTime > 0.0) { if (car->_scheduledEventTime < s->currentTime) { car->_state &= ~RM_CAR_STATE_PIT; car->_pit->pitCarIndex = TR_PIT_STATE_FREE; snprintf(msg, sizeof(msg), "%s pit stop %.1f s", car->_name, info->totalPitTime); msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so. ReSituation::self().setRaceMessage(msg, 5); GfLogInfo("%s exiting pit (%.1f s elapsed).\n", car->_name, info->totalPitTime); } else { snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "In pits %.1f s", s->currentTime - info->startPitTime); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. } } // If the driver asks for a pit, check if the car is in the right conditions // (position, speed, ...) and start up pitting process if so. } else if ((car->ctrl.raceCmd & RM_CMD_PIT_ASKED) && car->_pit->pitCarIndex == TR_PIT_STATE_FREE && (s->_maxDammage == 0 || car->_dammage <= s->_maxDammage)) { snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Pit request"); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. tdble lgFromStart = car->_trkPos.seg->lgfromstart; switch (car->_trkPos.seg->type) { case TR_STR: lgFromStart += car->_trkPos.toStart; break; default: lgFromStart += car->_trkPos.toStart * car->_trkPos.seg->radius; break; } if ((lgFromStart > car->_pit->lmin) && (lgFromStart < car->_pit->lmax)) { int side; tdble toBorder; if (ReInfo->track->pits.side == TR_RGT) { side = TR_SIDE_RGT; toBorder = car->_trkPos.toRight; } else { side = TR_SIDE_LFT; toBorder = car->_trkPos.toLeft; } sseg = car->_trkPos.seg->side[side]; wseg = RtTrackGetWidth(sseg, car->_trkPos.toStart); if (sseg->side[side]) { sseg = sseg->side[side]; wseg += RtTrackGetWidth(sseg, car->_trkPos.toStart); } if (((toBorder + wseg) < (ReInfo->track->pits.width - car->_dimension_y / 2.0)) && (fabs(car->_speed_x) < 1.0) && (fabs(car->_speed_y) < 1.0)) { // All conditions fullfilled => enter pitting process car->_state |= RM_CAR_STATE_PIT; car->_scheduledEventTime = 0.0; // Pit will really start when set to smthg > 0. car->_nbPitStops++; for (i = 0; i < car->_pit->freeCarIndex; i++) { if (car->_pit->car[i] == car) { car->_pit->pitCarIndex = i; break; } } info->startPitTime = s->currentTime; snprintf(msg, sizeof(msg), "%s in pits", car->_name); msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so. ReSituation::self().setRaceMessage(msg, 5); GfLogInfo("%s entering in pit slot.\n", car->_name); if (car->robot->rbPitCmd(car->robot->index, car, s) == ROB_PIT_MENU) { // the pit cmd is modified by menu. reCarsSchedulePitMenu(car); } else { ReCarsUpdateCarPitTime(car); } } else { // The cars speed or offset is out of accepted range // Show the user/developer/robot the reason of the issue tTeamDriver* TeamDriver = RtTeamDriverByCar(car); if (TeamDriver) { TeamDriver->StillToGo = 0.0; TeamDriver->MoreOffset = 0.0; TeamDriver->TooFastBy = 0.0; } float Offset = (float) ((toBorder + wseg) - (ReInfo->track->pits.width - car->_dimension_y / 2.0)); if (Offset >= 0.0) { // The car's position across the track is out of accepted range snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Offset: %.02f",Offset); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. if (TeamDriver) TeamDriver->MoreOffset = Offset; } float TooFastBy = MAX(fabs(car->_speed_x),fabs(car->_speed_y)); if (TooFastBy >= 1.0) { // The car's speed is out of accepted range snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Speed: %.02f",TooFastBy); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. if (TeamDriver) TeamDriver->TooFastBy = TooFastBy; } } } else { // The car's position along the track is out of accepted range // Show the user/developer/robot the reason of the issue tTeamDriver* TeamDriver = RtTeamDriverByCar(car); if (TeamDriver) { TeamDriver->StillToGo = 0.0; TeamDriver->MoreOffset = 0.0; TeamDriver->TooFastBy = 0.0; } if (car->_pit->lmin > lgFromStart) { float StillToGo = car->_pit->lmin - lgFromStart; snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Still to go: %0.2f m" ,StillToGo); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. if (TeamDriver) TeamDriver->StillToGo = StillToGo; } else if (car->_pit->lmax < lgFromStart) { float StillToGo = lgFromStart - car->_pit->lmax; snprintf(car->ctrl.msg[2], RM_CMD_MAX_MSG_SIZE, "Overrun: %0.2f m" ,StillToGo); car->ctrl.msg[2][RM_CMD_MAX_MSG_SIZE-1] = 0; // Some snprintf implementations fail to do so. if (TeamDriver) TeamDriver->StillToGo = -StillToGo; } } } } /* Check if it is in a new sector */ while (true) { if (car->_currentSector < ReInfo->track->numberOfSectors - 1 && car->_laps > 0 && info->lapFlag == 0) { /* Must pass at least one sector before the finish */ if (RtGetDistFromStart(car) > ReInfo->track->sectors[car->_currentSector]) { /* It is in a new sector : update split time */ car->_curSplitTime[car->_currentSector] = car->_curLapTime; ++car->_currentSector; continue; } } break; } /* Start Line Crossing */ if (info->prevTrkPos.seg != car->_trkPos.seg) { if ((info->prevTrkPos.seg->raceInfo & TR_LAST) && (car->_trkPos.seg->raceInfo & TR_START)) { if (info->lapFlag == 0) { // If the car has not yet finished the race : if (!(car->_state & RM_CAR_STATE_FINISH)) { // 1 more lap completed // (Note: lap with index 0 finishes when the car crosses the start line the 1st time, // and is thus considered a real lap, whereas it is not). car->_laps++; /*if (NetGetNetwork()) NetGetNetwork()->SendLapStatusPacket(car);*/ car->_remainingLaps--; if (car->_pos == 1 && s->currentTime < s->_totTime && s->_raceType == RM_TYPE_RACE) { /* First car passed finish time before the time ends: increase the number of laps for everyone */ for (xx = 0; xx < s->_ncars; ++xx) ++ReInfo->s->cars[xx]->_remainingLaps; ++s->_totLaps; } car->_currentSector = 0; if (car->_laps > 1) { car->_lastLapTime = s->currentTime - info->sTime; if (car->_bestLapTime != 0) { car->_deltaBestLapTime = car->_lastLapTime - car->_bestLapTime; } if ((car->_lastLapTime < car->_bestLapTime) || (car->_bestLapTime == 0)) { car->_bestLapTime = car->_lastLapTime; memcpy(car->_bestSplitTime, car->_curSplitTime, sizeof(double)*(ReInfo->track->numberOfSectors - 1) ); if (s->_raceType != RM_TYPE_RACE && s->_ncars > 1) { /* Best lap time is made better : update times behind leader */ bestLapChanged = true; car->_timeBehindLeader = car->_bestLapTime - s->cars[0]->_bestLapTime; if (car->_pos > 1) { car->_timeBehindPrev = car->_bestLapTime - s->cars[car->_pos - 1]->_bestLapTime; } else { /* New best time for the leader : update the differences */ for (xx = 1; xx < s->_ncars; ++xx) { if (s->cars[xx]->_bestLapTime > 0.0f) s->cars[xx]->_timeBehindLeader = s->cars[xx]->_bestLapTime - car->_bestLapTime; } } if (car->_pos + 1 < s->_ncars && s->cars[car->_pos+1]->_bestLapTime > 0.0f) car->_timeBeforeNext = s->cars[car->_pos + 1]->_bestLapTime - car->_bestLapTime; else car->_timeBeforeNext = 0; } } } if (car->_laps > 0) { car->_curTime += s->currentTime - info->sTime; if (car->_pos != 1 && s->_raceType == RM_TYPE_RACE) { car->_timeBehindLeader = car->_curTime - s->cars[0]->_curTime; car->_lapsBehindLeader = s->cars[0]->_laps - car->_laps; car->_timeBehindPrev = car->_curTime - s->cars[car->_pos - 2]->_curTime; s->cars[car->_pos - 2]->_timeBeforeNext = car->_timeBehindPrev; } else if (s->_raceType == RM_TYPE_RACE) { car->_timeBehindLeader = 0; car->_lapsBehindLeader = 0; car->_timeBehindPrev = 0; } info->sTime = (tdble)s->currentTime; if (ReInfo->s->_raceType == RM_TYPE_PRACTICE && (car->_laps > 1 || s->_totLaps == 0)) ReSavePracticeLap(car); } if (ReInfo->_displayMode == RM_DISP_MODE_NONE) { switch(s->_raceType) { case RM_TYPE_PRACTICE: ReUpdatePracticeCurRes(car); break; case RM_TYPE_QUALIF: ReUpdateQualifCurRes(car); break; case RM_TYPE_RACE: ReUpdateRaceCurRes(); break; default: break; } } info->topSpd = car->_speed_x; info->botSpd = car->_speed_x; if ((car->_remainingLaps < 0 && s->currentTime > s->_totTime) || (s->_raceState == RM_RACE_FINISHING)) { car->_state |= RM_CAR_STATE_FINISH; s->_raceState = RM_RACE_FINISHING; if (ReInfo->s->_raceType == RM_TYPE_RACE) { if (car->_pos == 1) { snprintf(msg, sizeof(msg), "Winner %s", car->_name); msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so. ReSituation::self().setRaceMessage(msg, 10, /*big=*/true); if (NetGetServer()) { NetGetServer()->SetFinishTime(s->currentTime+FINISHDELAY); } } else { const char *numSuffix = "th"; if (abs(12 - car->_pos) > 1) { /* leave suffix as 'th' for 11 to 13 */ switch (car->_pos % 10) { case 1: numSuffix = "st"; break; case 2: numSuffix = "nd"; break; case 3: numSuffix = "rd"; break; default: break; } } snprintf(msg, sizeof(msg), "%s finished %d%s", car->_name, car->_pos, numSuffix); msg[sizeof(msg)-1] = 0; // Some snprintf implementations fail to do so. ReSituation::self().setRaceMessage(msg, 5); } } } // Notify the UI when a lap is completed (by the leader) // and race results have been updated. if (car->_pos == 1) ReUI().onLapCompleted(car->_laps - 1); } else { // Prevent infinite looping of cars around track, // allowing one lap after finish for the first car, but no more for (i = 0; i < s->_ncars; i++) { s->cars[i]->_state |= RM_CAR_STATE_FINISH; } return; } } else { info->lapFlag--; } } if ((info->prevTrkPos.seg->raceInfo & TR_START) && (car->_trkPos.seg->raceInfo & TR_LAST)) { /* going backward through the start line */ info->lapFlag++; } } // Start Line Crossing // Apply race rules (penalties if enabled). reCarsApplyRaceRules(car); // Update misc car info. info->prevTrkPos = car->_trkPos; car->_curLapTime = s->currentTime - info->sTime; car->_distFromStartLine = car->_trkPos.seg->lgfromstart + (car->_trkPos.seg->type == TR_STR ? car->_trkPos.toStart : car->_trkPos.toStart * car->_trkPos.seg->radius); car->_distRaced = (car->_laps - 1) * ReInfo->track->length + car->_distFromStartLine; }
void PathRecord::GetPrediction( double& w, double& v ) const { double pos = RtGetDistFromStart(m_pCar); GetPredictionForPos( pos, w, v ); }
//==========================================================================* // Calc cars position from offset //--------------------------------------------------------------------------* double TTrackDescription::CalcPos(tCarElt* Car, double Offset) const { double Pos = RtGetDistFromStart(Car) + Offset; return NormalizePos(Pos); // Normalize to >= 0.0 }
//==========================================================================* // State (Sequential logic system) //--------------------------------------------------------------------------* void TSimpleStrategy::CheckPitState(float PitScaleBrake) { if (oPit == NULL) // No Pit no service return; if (!oPit->HasPits()) return; double TrackPos = RtGetDistFromStart(oCar); // Distance to pit switch(oState) // Check state { case PIT_NONE: // We are somewhere on the track, nothing has happend yet if ((!oPit->oPitLane[0].InPitSection(TrackPos)) && oGoToPit) { // if we are not parallel to the pits and get the flag, // let's stop in the pits. oState = PIT_BEFORE; } break; case PIT_BEFORE: // We are somewhere on the track and got the flag to go to pit if (oFuelChecked && oGoToPit) { // If we reache pit entry and flag is still set // switch to the pitlane oState = PIT_PREPARE; } break; case PIT_PREPARE: // We are near the pit entry on the track and got the flag to go to pit if (oPit->oPitLane[0].InPitSection(TrackPos) && oGoToPit) { // If we reache pit entry and flag is still set // switch to the pitlane oState = PIT_ENTER; } break; case PIT_ENTER: // We are on the pitlane and drive to our pit if (!oPit->oPitLane[0].CanStop(TrackPos)) { // We have to wait, till we reached the point to stop if (oDriver->CurrSpeed() < 3) { CarAccelCmd = // a little throttle MAX(0.05f,CarAccelCmd); CarBrakeCmd = 0.0; // Start braking LogSimplix.debug("#PIT_ENTER: Wait %g (%g)\n",TrackPos,oDriver->CurrSpeed()); } else LogSimplix.debug("#PIT_ENTER: Wait %g\n",TrackPos); break; } // We reached the poit to stopp oState = PIT_ASKED; LogSimplix.debug("#PIT_ENTER: %g\n",TrackPos); // falls through... case PIT_ASKED: // We are still going to the pit if (oPit->oPitLane[0].CanStop(TrackPos)) { // If we can stop a this position we start pit procedure LogSimplix.debug("#PIT_ASKED: CanStop %g (%g)\n",TrackPos,oDriver->CurrSpeed()); oDriver->oStanding = true; // For motion survey! oPitTicker = 0; // Start service timer CarAccelCmd = 0; // release throttle CarBrakeCmd = 1.0; // Start braking CarRaceCmd = RM_CMD_PIT_ASKED; // Tell TORCS to service us! To test oPitTicker comment out oState = PIT_SERVICE; } else { // We can't stop here (to early or to late) if (oPit->oPitLane[0].Overrun(TrackPos)) { // if to late LogSimplix.debug("#Overrun 1: %g\n",TrackPos); PitRelease(); oState = PIT_EXIT_WAIT; // pit stop finished, need to exit pits now. } else { LogSimplix.debug("#ToShort 1: %g\n",TrackPos); if (oDriver->CurrSpeed() < 3) { CarAccelCmd = // a little throttle MAX(0.05f,CarAccelCmd); CarBrakeCmd = 0.0; // Start braking } } } break; case PIT_SERVICE: // Wait to reach standstill to get service from TORCS oDriver->oStanding = true; // Keep motion survey quiet oPitTicker++; // Check time to start service if (oPitTicker > 10) // Check Timer { // If we have to wait LogSimplix.debug("#oPitTicker: %d\n",oPitTicker); tTeamDriver* TeamDriver = RtTeamDriverByCar(oCar); short int Major = RtTeamManagerGetMajorVersion(); short int Minor = RtTeamManagerGetMinorVersion(); if ((TeamDriver) && ((Major > NEEDED_MAJOR_VERSION) || ((Major = NEEDED_MAJOR_VERSION) && (Minor >= NEEDED_MINOR_VERSION)))) { LogSimplix.debug("#Pitting issues %s\n",oDriver->GetBotName()); LogSimplix.debug("#StillToGo : %.2f m\n",TeamDriver->StillToGo); LogSimplix.debug("#MoreOffset: %.2f m\n",TeamDriver->MoreOffset); LogSimplix.debug("#TooFastBy : %.2f m/s\n",TeamDriver->TooFastBy); // Learn from the response if (fabs(TeamDriver->StillToGo) > 0.0) { //CarSteerCmd = 0.0; // Straight on if (fabs(CarSpeedLong) < 1.0) { CarAccelCmd = // a little throttle MAX(0.005f,CarAccelCmd); CarBrakeCmd = 0.0; // No braking LogSimplix.debug("#Accel : %.2f\n",CarAccelCmd); } else { CarBrakeCmd = 0.1f; // Braking LogSimplix.debug("#Brake : %.2f\n",CarBrakeCmd); } CarClutchCmd = 0.5; // Press clutch if (TeamDriver->StillToGo > 0) CarGearCmd = 1; // First gear else CarGearCmd = -1; // reverse gear } else { // LogSimplix.debug("#Stopped\n"); CarAccelCmd = 0.0; // Stop throttle CarBrakeCmd = 1.0; // Lock brake CarClutchCmd = 0.0; // Release clutch CarGearCmd = 1; // First gear } } if (oPitTicker > 300) // Check Timer { // If we have to wait too long PitRelease(); // Something went wrong, we have oState = PIT_EXIT_WAIT; // to leave and release pit for teammate } } else if (oPit->oPitLane[0].Overrun(TrackPos)) { // If we couldn't stop in place LogSimplix.debug("#Overrun 2: %g\n",TrackPos); PitRelease(); // We have to release the pit oState = PIT_EXIT_WAIT; // for teammate } else { // There is nothing that hampers TORCS to service us LogSimplix.debug("#PIT_SERVICE: %g (%g)\n",TrackPos,oDriver->CurrSpeed()); CarLightCmd = 0; // No lights on CarAccelCmd = 0; // No throttle CarBrakeCmd = 1.0; // Still braking CarRaceCmd = RM_CMD_PIT_ASKED; // Tell TORCS to service us! To test oPitTicker comment out // oState is set to next state in PitRepair()! // If TORCS doesn't service us, no call to PitRepair() is done! // We run into timeout! (oPitTicker) oPitStartTicker = 600; } break; case PIT_EXIT_WAIT: // We are still in the box oDriver->oStanding = true; // Keep motion survey quiet if ((oMinTimeSlot < 7) // If start slot to short || ((oMinDistBack > -7) // or cars aside && (oMinDistBack < 5))) // we have to wait { oPitStartTicker--; if (oPitStartTicker < 0) { LogSimplix.debug("#PIT_EXIT: mts%g (mdb%gm)\n",oMinTimeSlot,oMinDistBack); oState = PIT_EXIT; } CarLightCmd = RM_LIGHT_HEAD2; // Only small lights on CarAccelCmd = 0.0; CarBrakeCmd = 1.0; } else { CarLightCmd = RM_LIGHT_HEAD1; // Only big lights on oState = PIT_EXIT; } break; case PIT_EXIT: // We are still in the box oDriver->oStanding = true; // Keep motion survey quiet oGoToPit = false; // Service is finished, lets go CarAccelCmd = 0.5; // Press throttle CarBrakeCmd = 0; // Release brake PitRelease(); // Release pit for teammate if (oDriver->CurrSpeed() > 5) oState = PIT_GONE; break; case PIT_GONE: // We are on our path back to the track if (!oPit->oPitLane[0].InPitSection(TrackPos)) { // If we reached the end of the pitlane CarLightCmd = RM_LIGHT_HEAD1 | // All lights on RM_LIGHT_HEAD2; oState = PIT_NONE; // Switch to default mode } break; } }
static void common_drive(int index, tCarElt* car, tSituation *s) { tdble slip; tdble ax0; tdble brake; tdble clutch; tdble throttle; tdble leftSteer; tdble rightSteer; int scrw, scrh, dummy; int idx = index - 1; tControlCmd *cmd = HCtx[idx]->CmdControl; const int BUFSIZE = 1024; char sstring[BUFSIZE]; static int firstTime = 1; if (firstTime) { if (HCtx[idx]->MouseControlUsed) { GfuiMouseShow(); GfctrlMouseInitCenter(); } GfuiKeyEventRegisterCurrent(onKeyAction); GfuiSKeyEventRegisterCurrent(onSKeyAction); firstTime = 0; } HCtx[idx]->distToStart = RtGetDistFromStart(car); HCtx[idx]->Gear = (tdble)car->_gear; /* telemetry */ GfScrGetSize(&scrw, &scrh, &dummy, &dummy); memset(&(car->ctrl), 0, sizeof(tCarCtrl)); car->_lightCmd = HCtx[idx]->lightCmd; if (car->_laps != HCtx[idx]->LastPitStopLap) { car->_raceCmd = RM_CMD_PIT_ASKED; } if (lastKeyUpdate != s->currentTime) { /* Update the controls only once for all the players */ updateKeys(); if (joyPresent) { GfctrlJoyGetCurrent(joyInfo); } GfctrlMouseGetCurrent(mouseInfo); lastKeyUpdate = s->currentTime; } if (((cmd[CMD_ABS].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ABS].val]) || ((cmd[CMD_ABS].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ABS].val].edgeUp) || ((cmd[CMD_ABS].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ABS].val].edgeUp)) { HCtx[idx]->ParamAbs = 1 - HCtx[idx]->ParamAbs; snprintf(sstring, BUFSIZE, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index); GfParmSetStr(PrefHdle, sstring, HM_ATT_ABS, Yn[1 - HCtx[idx]->ParamAbs]); GfParmWriteFile(NULL, PrefHdle, "Human"); } if (((cmd[CMD_ASR].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ASR].val]) || ((cmd[CMD_ASR].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ASR].val].edgeUp) || ((cmd[CMD_ASR].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ASR].val].edgeUp)) { HCtx[idx]->ParamAsr = 1 - HCtx[idx]->ParamAsr; snprintf(sstring, BUFSIZE, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index); GfParmSetStr(PrefHdle, sstring, HM_ATT_ASR, Yn[1 - HCtx[idx]->ParamAsr]); GfParmWriteFile(NULL, PrefHdle, "Human"); } const int bufsize = sizeof(car->_msgCmd[0]); snprintf(car->_msgCmd[0], bufsize, "%s %s", (HCtx[idx]->ParamAbs ? "ABS" : ""), (HCtx[idx]->ParamAsr ? "ASR" : "")); memcpy(car->_msgColorCmd, color, sizeof(car->_msgColorCmd)); if (((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_JOY_BUT) && (joyInfo->levelup[cmd[CMD_SPDLIM].val] == 1)) || ((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_KEYBOARD) && (keyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN)) || ((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_SKEYBOARD) && (skeyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN))) { speedLimiter = 1; snprintf(car->_msgCmd[1], bufsize, "Speed Limiter On"); } else { speedLimiter = 0; snprintf(car->_msgCmd[1], bufsize, "Speed Limiter Off"); } if (((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_LIGHT1].val]) || ((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_LIGHT1].val].edgeUp) || ((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_LIGHT1].val].edgeUp)) { if (HCtx[idx]->lightCmd & RM_LIGHT_HEAD1) { HCtx[idx]->lightCmd &= ~(RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2); } else { HCtx[idx]->lightCmd |= RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2; } } switch (cmd[CMD_LEFTSTEER].type) { case GFCTRL_TYPE_JOY_AXIS: ax0 = joyInfo->ax[cmd[CMD_LEFTSTEER].val] + cmd[CMD_LEFTSTEER].deadZone; if (ax0 > cmd[CMD_LEFTSTEER].max) { ax0 = cmd[CMD_LEFTSTEER].max; } else if (ax0 < cmd[CMD_LEFTSTEER].min) { ax0 = cmd[CMD_LEFTSTEER].min; } // normalize ax0 to -1..0 ax0 = (ax0 - cmd[CMD_LEFTSTEER].max) / (cmd[CMD_LEFTSTEER].max - cmd[CMD_LEFTSTEER].min); leftSteer = -SIGN(ax0) * cmd[CMD_LEFTSTEER].pow * pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_LEFTSTEER].val] - cmd[CMD_LEFTSTEER].deadZone; //FIXME: correct? if (ax0 > cmd[CMD_LEFTSTEER].max) { ax0 = cmd[CMD_LEFTSTEER].max; } else if (ax0 < cmd[CMD_LEFTSTEER].min) { ax0 = cmd[CMD_LEFTSTEER].min; } ax0 = ax0 * cmd[CMD_LEFTSTEER].pow; leftSteer = pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed / 10.0); break; case GFCTRL_TYPE_KEYBOARD: case GFCTRL_TYPE_SKEYBOARD: case GFCTRL_TYPE_JOY_BUT: if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_KEYBOARD) { ax0 = keyInfo[cmd[CMD_LEFTSTEER].val].state; } else if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_SKEYBOARD) { ax0 = skeyInfo[cmd[CMD_LEFTSTEER].val].state; } else { ax0 = joyInfo->levelup[cmd[CMD_LEFTSTEER].val]; } if (ax0 == 0) { HCtx[idx]->prevLeftSteer = leftSteer = 0; } else { ax0 = 2 * ax0 - 1; leftSteer = HCtx[idx]->prevLeftSteer + ax0 * cmd[CMD_LEFTSTEER].sens * s->deltaTime / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->pub.speed / 10.0); if (leftSteer > 1.0) leftSteer = 1.0; if (leftSteer < 0.0) leftSteer = 0.0; HCtx[idx]->prevLeftSteer = leftSteer; } break; default: leftSteer = 0; break; } switch (cmd[CMD_RIGHTSTEER].type) { case GFCTRL_TYPE_JOY_AXIS: ax0 = joyInfo->ax[cmd[CMD_RIGHTSTEER].val] - cmd[CMD_RIGHTSTEER].deadZone; if (ax0 > cmd[CMD_RIGHTSTEER].max) { ax0 = cmd[CMD_RIGHTSTEER].max; } else if (ax0 < cmd[CMD_RIGHTSTEER].min) { ax0 = cmd[CMD_RIGHTSTEER].min; } // normalize ax to 0..1 ax0 = (ax0 - cmd[CMD_RIGHTSTEER].min) / (cmd[CMD_RIGHTSTEER].max - cmd[CMD_RIGHTSTEER].min); rightSteer = -SIGN(ax0) * cmd[CMD_RIGHTSTEER].pow * pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_RIGHTSTEER].val] - cmd[CMD_RIGHTSTEER].deadZone; if (ax0 > cmd[CMD_RIGHTSTEER].max) { ax0 = cmd[CMD_RIGHTSTEER].max; } else if (ax0 < cmd[CMD_RIGHTSTEER].min) { ax0 = cmd[CMD_RIGHTSTEER].min; } ax0 = ax0 * cmd[CMD_RIGHTSTEER].pow; rightSteer = - pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed / 10.0); break; case GFCTRL_TYPE_KEYBOARD: case GFCTRL_TYPE_SKEYBOARD: case GFCTRL_TYPE_JOY_BUT: if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_KEYBOARD) { ax0 = keyInfo[cmd[CMD_RIGHTSTEER].val].state; } else if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_SKEYBOARD) { ax0 = skeyInfo[cmd[CMD_RIGHTSTEER].val].state; } else { ax0 = joyInfo->levelup[cmd[CMD_RIGHTSTEER].val]; } if (ax0 == 0) { HCtx[idx]->prevRightSteer = rightSteer = 0; } else { ax0 = 2 * ax0 - 1; rightSteer = HCtx[idx]->prevRightSteer - ax0 * cmd[CMD_RIGHTSTEER].sens * s->deltaTime/ (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->pub.speed / 10.0); if (rightSteer > 0.0) rightSteer = 0.0; if (rightSteer < -1.0) rightSteer = -1.0; HCtx[idx]->prevRightSteer = rightSteer; } break; default: rightSteer = 0; break; } car->_steerCmd = leftSteer + rightSteer; switch (cmd[CMD_BRAKE].type) { case GFCTRL_TYPE_JOY_AXIS: brake = joyInfo->ax[cmd[CMD_BRAKE].val]; if (brake > cmd[CMD_BRAKE].max) { brake = cmd[CMD_BRAKE].max; } else if (brake < cmd[CMD_BRAKE].min) { brake = cmd[CMD_BRAKE].min; } car->_brakeCmd = fabs(cmd[CMD_BRAKE].pow * pow(fabs((brake - cmd[CMD_BRAKE].minVal) / (cmd[CMD_BRAKE].max - cmd[CMD_BRAKE].min)), cmd[CMD_BRAKE].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_BRAKE].val] - cmd[CMD_BRAKE].deadZone; if (ax0 > cmd[CMD_BRAKE].max) { ax0 = cmd[CMD_BRAKE].max; } else if (ax0 < cmd[CMD_BRAKE].min) { ax0 = cmd[CMD_BRAKE].min; } ax0 = ax0 * cmd[CMD_BRAKE].pow; car->_brakeCmd = pow(fabs(ax0), cmd[CMD_BRAKE].sens) / (1.0 + cmd[CMD_BRAKE].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_JOY_BUT: car->_brakeCmd = joyInfo->levelup[cmd[CMD_BRAKE].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_brakeCmd = mouseInfo->button[cmd[CMD_BRAKE].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_brakeCmd = keyInfo[cmd[CMD_BRAKE].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_brakeCmd = skeyInfo[cmd[CMD_BRAKE].val].state; break; default: car->_brakeCmd = 0; break; } switch (cmd[CMD_CLUTCH].type) { case GFCTRL_TYPE_JOY_AXIS: clutch = joyInfo->ax[cmd[CMD_CLUTCH].val]; if (clutch > cmd[CMD_CLUTCH].max) { clutch = cmd[CMD_CLUTCH].max; } else if (clutch < cmd[CMD_CLUTCH].min) { clutch = cmd[CMD_CLUTCH].min; } car->_clutchCmd = fabs(cmd[CMD_CLUTCH].pow * pow(fabs((clutch - cmd[CMD_CLUTCH].minVal) / (cmd[CMD_CLUTCH].max - cmd[CMD_CLUTCH].min)), cmd[CMD_CLUTCH].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_CLUTCH].val] - cmd[CMD_CLUTCH].deadZone; if (ax0 > cmd[CMD_CLUTCH].max) { ax0 = cmd[CMD_CLUTCH].max; } else if (ax0 < cmd[CMD_CLUTCH].min) { ax0 = cmd[CMD_CLUTCH].min; } ax0 = ax0 * cmd[CMD_CLUTCH].pow; car->_clutchCmd = pow(fabs(ax0), cmd[CMD_CLUTCH].sens) / (1.0 + cmd[CMD_CLUTCH].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_JOY_BUT: car->_clutchCmd = joyInfo->levelup[cmd[CMD_CLUTCH].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_clutchCmd = mouseInfo->button[cmd[CMD_CLUTCH].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_clutchCmd = keyInfo[cmd[CMD_CLUTCH].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_clutchCmd = skeyInfo[cmd[CMD_CLUTCH].val].state; break; default: car->_clutchCmd = 0; break; } // if player's used the clutch manually then we dispense with autoClutch if (car->_clutchCmd != 0.0f) HCtx[idx]->autoClutch = 0; switch (cmd[CMD_THROTTLE].type) { case GFCTRL_TYPE_JOY_AXIS: throttle = joyInfo->ax[cmd[CMD_THROTTLE].val]; if (throttle > cmd[CMD_THROTTLE].max) { throttle = cmd[CMD_THROTTLE].max; } else if (throttle < cmd[CMD_THROTTLE].min) { throttle = cmd[CMD_THROTTLE].min; } car->_accelCmd = fabs(cmd[CMD_THROTTLE].pow * pow(fabs((throttle - cmd[CMD_THROTTLE].minVal) / (cmd[CMD_THROTTLE].max - cmd[CMD_THROTTLE].min)), cmd[CMD_THROTTLE].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_THROTTLE].val] - cmd[CMD_THROTTLE].deadZone; if (ax0 > cmd[CMD_THROTTLE].max) { ax0 = cmd[CMD_THROTTLE].max; } else if (ax0 < cmd[CMD_THROTTLE].min) { ax0 = cmd[CMD_THROTTLE].min; } ax0 = ax0 * cmd[CMD_THROTTLE].pow; car->_accelCmd = pow(fabs(ax0), cmd[CMD_THROTTLE].sens) / (1.0 + cmd[CMD_THROTTLE].spdSens * car->_speed_x / 10.0); if (isnan (car->_accelCmd)) { car->_accelCmd = 0; } /* printf(" axO:%f accelCmd:%f\n", ax0, car->_accelCmd); */ break; case GFCTRL_TYPE_JOY_BUT: car->_accelCmd = joyInfo->levelup[cmd[CMD_THROTTLE].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_accelCmd = mouseInfo->button[cmd[CMD_THROTTLE].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_accelCmd = keyInfo[cmd[CMD_THROTTLE].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_accelCmd = skeyInfo[cmd[CMD_THROTTLE].val].state; break; default: car->_accelCmd = 0; break; } if (s->currentTime > 1.0) { // thanks Christos for the following: gradual accel/brake changes for on/off controls. const tdble inc_rate = 0.2f; if (cmd[CMD_BRAKE].type == GFCTRL_TYPE_JOY_BUT || cmd[CMD_BRAKE].type == GFCTRL_TYPE_MOUSE_BUT || cmd[CMD_BRAKE].type == GFCTRL_TYPE_KEYBOARD || cmd[CMD_BRAKE].type == GFCTRL_TYPE_SKEYBOARD) { tdble d_brake = car->_brakeCmd - HCtx[idx]->pbrake; if (fabs(d_brake) > inc_rate && car->_brakeCmd > HCtx[idx]->pbrake) { car->_brakeCmd = MIN(car->_brakeCmd, HCtx[idx]->pbrake + inc_rate*d_brake/fabs(d_brake)); } HCtx[idx]->pbrake = car->_brakeCmd; } if (cmd[CMD_THROTTLE].type == GFCTRL_TYPE_JOY_BUT || cmd[CMD_THROTTLE].type == GFCTRL_TYPE_MOUSE_BUT || cmd[CMD_THROTTLE].type == GFCTRL_TYPE_KEYBOARD || cmd[CMD_THROTTLE].type == GFCTRL_TYPE_SKEYBOARD) { tdble d_accel = car->_accelCmd - HCtx[idx]->paccel; if (fabs(d_accel) > inc_rate && car->_accelCmd > HCtx[idx]->paccel) { car->_accelCmd = MIN(car->_accelCmd, HCtx[idx]->paccel + inc_rate*d_accel/fabs(d_accel)); } HCtx[idx]->paccel = car->_accelCmd; } } if (HCtx[idx]->AutoReverseEngaged) { /* swap brake and throttle */ brake = car->_brakeCmd; car->_brakeCmd = car->_accelCmd; car->_accelCmd = brake; } if (HCtx[idx]->ParamAbs) { if (fabs(car->_speed_x) > 10.0) { int i; tdble skidAng = atan2(car->_speed_Y, car->_speed_X) - car->_yaw; NORM_PI_PI(skidAng); if (car->_speed_x > 5 && fabs(skidAng) > 0.2) car->_brakeCmd = MIN(car->_brakeCmd, 0.10 + 0.70 * cos(skidAng)); if (fabs(car->_steerCmd) > 0.1) { tdble decel = ((fabs(car->_steerCmd)-0.1) * (1.0 + fabs(car->_steerCmd)) * 0.6); car->_brakeCmd = MIN(car->_brakeCmd, MAX(0.35, 1.0 - decel)); } const tdble abs_slip = 2.5; const tdble abs_range = 5.0; slip = 0; for (i = 0; i < 4; i++) { slip += car->_wheelSpinVel(i) * car->_wheelRadius(i); } slip = car->_speed_x - slip/4.0f; if (slip > abs_slip) car->_brakeCmd = car->_brakeCmd - MIN(car->_brakeCmd*0.8, (slip - abs_slip) / abs_range); } } if (HCtx[idx]->ParamAsr) { tdble trackangle = RtTrackSideTgAngleL(&(car->_trkPos)); tdble angle = trackangle - car->_yaw; NORM_PI_PI(angle); tdble maxaccel = 0.0; if (car->_trkPos.seg->type == TR_STR) maxaccel = MIN(car->_accelCmd, 0.2); else if (car->_trkPos.seg->type == TR_LFT && angle < 0.0) maxaccel = MIN(car->_accelCmd, MIN(0.6, -angle)); else if (car->_trkPos.seg->type == TR_RGT && angle > 0.0) maxaccel = MIN(car->_accelCmd, MIN(0.6, angle)); tdble origaccel = car->_accelCmd; tdble skidAng = atan2(car->_speed_Y, car->_speed_X) - car->_yaw; NORM_PI_PI(skidAng); if (car->_speed_x > 5 && fabs(skidAng) > 0.2) { car->_accelCmd = MIN(car->_accelCmd, 0.15 + 0.70 * cos(skidAng)); car->_accelCmd = MAX(car->_accelCmd, maxaccel); } if (fabs(car->_steerCmd) > 0.1) { tdble decel = ((fabs(car->_steerCmd)-0.1) * (1.0 + fabs(car->_steerCmd)) * 0.8); car->_accelCmd = MIN(car->_accelCmd, MAX(0.35, 1.0 - decel)); } tdble drivespeed = 0.0; switch (HCtx[idx]->drivetrain) { case D4WD: drivespeed = ((car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) * car->_wheelRadius(FRNT_LFT) + (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) * car->_wheelRadius(REAR_LFT)) / 4.0; break; case DFWD: drivespeed = (car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) * car->_wheelRadius(FRNT_LFT) / 2.0; break; default: drivespeed = (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) * car->_wheelRadius(REAR_LFT) / 2.0; break; } tdble slip = drivespeed - fabs(car->_speed_x); if (slip > 2.0) car->_accelCmd = MIN(car->_accelCmd, origaccel - MIN(origaccel-0.1, ((slip - 2.0)/10.0))); } if (speedLimiter) { tdble Dv; if (Vtarget != 0) { Dv = Vtarget - car->_speed_x; if (Dv > 0.0) { car->_accelCmd = MIN(car->_accelCmd, fabs(Dv/6.0)); } else { car->_brakeCmd = MAX(car->_brakeCmd, fabs(Dv/5.0)); car->_accelCmd = 0; } } } #ifndef WIN32 #ifdef TELEMETRY if ((car->_laps > 1) && (car->_laps < 5)) { if (HCtx[idx]->lap == 1) { RtTelemStartMonitoring("Player"); } RtTelemUpdate(car->_curLapTime); } if (car->_laps == 5) { if (HCtx[idx]->lap == 4) { RtTelemShutdown(); } } #endif #endif HCtx[idx]->lap = car->_laps; }
//==========================================================================* // Update // // ATTENTION oCar ist opponents car, so we can use our shortcuts!!! //--------------------------------------------------------------------------* void TOpponent::Update( const PCarElt MyCar, double MyDirX, double MyDirY, float &MinDistBack, double &MinTimeSlot) { if((CarState & RM_CAR_STATE_NO_SIMU) && // omit cars out of race (CarState & RM_CAR_STATE_PIT) == 0 ) // if not in pit return; oInfo.State.Speed = myhypot(CarSpeedX,CarSpeedY);// Speed of car // Track relative speed of opponents car TVec2d ToRight = oTrack->Normale(DistanceFromStartLine); oInfo.State.TrackVelLong = ToRight.x * CarSpeedY - ToRight.y * CarSpeedX; oInfo.State.TrackVelLat = ToRight.x * CarSpeedX + ToRight.y * CarSpeedY; // Track relative yaw of other car. oInfo.State.TrackYaw = CarYaw - TUtils::VecAngle(ToRight) - PI / 2; DOUBLE_NORM_PI_PI(oInfo.State.TrackYaw); // Average velocity of other car. oInfo.State.AvgVelLong = oInfo.State.AvgVelLong * AVG_KEEP + CarPubGlobVelX * AVG_CHANGE; oInfo.State.AvgVelLat = oInfo.State.AvgVelLat * AVG_KEEP + CarPubGlobVelY * AVG_CHANGE; oInfo.State.CarAvgVelLong = MyDirX * oInfo.State.AvgVelLong + MyDirY * oInfo.State.AvgVelLat; //oInfo.State.CarAvgVelLat = MyDirY * oInfo.State.AvgVelLong - MyDirX * oInfo.State.AvgVelLat; // Average acceleration of other car. oInfo.State.AvgAccLong = oInfo.State.AvgAccLong * AVG_KEEP + CarPubGlobAccX * AVG_CHANGE; oInfo.State.AvgAccLat = oInfo.State.AvgAccLat * AVG_KEEP + CarPubGlobAccY * AVG_CHANGE; oInfo.State.CarAvgAccLong = MyDirX * oInfo.State.AvgAccLong + MyDirY * oInfo.State.AvgAccLat; oInfo.State.CarAvgAccLat = MyDirY * oInfo.State.AvgAccLong - MyDirX * oInfo.State.AvgAccLat; // Offset from track center line. oInfo.State.Offset = -CarToMiddle; if(oCar == MyCar) return; // Car-Car relative calculations ... // calc other cars position, velocity relative to my car (global coords). double DistX = CarPubGlobPosX - MyCar->pub.DynGCg.pos.x; double DistY = CarPubGlobPosY - MyCar->pub.DynGCg.pos.y; double DiffVelX = CarSpeedX - MyCar->_speed_X; double DiffVelY = CarSpeedY - MyCar->_speed_Y; // work out relative position, velocity in local coords (coords of my car). oInfo.State.CarDistLong = MyDirX * DistX + MyDirY * DistY; oInfo.State.CarDistLat = MyDirY * DistX - MyDirX * DistY; oInfo.State.CarDiffVelLong = MyDirX * DiffVelX + MyDirY * DiffVelY; oInfo.State.CarDiffVelLat = MyDirY * DiffVelX - MyDirX * DiffVelY; oInfo.State.MinDistLong = (MyCar->_dimension_x + CarLength) / 2; oInfo.State.MinDistLat = (MyCar->_dimension_y + CarWidth) / 2; double MyVelAng = atan2(MyCar->_speed_Y, MyCar->_speed_X); double MyYaw = MyCar->_yaw - MyVelAng; DOUBLE_NORM_PI_PI(MyYaw); double OppYaw = CarYaw - MyVelAng; DOUBLE_NORM_PI_PI(OppYaw); // Additional distance needed while yawing of both cars double ExtSide = (oInfo.State.MinDistLong - oInfo.State.MinDistLat) * (fabs(sin(MyYaw)) + fabs(sin(OppYaw))); oInfo.State.MinDistLat += ExtSide + SIDE_MARGIN; oInfo.State.MinDistLong += TDriver::LengthMargin; // Distance of car from start of track. double MyPos = RtGetDistFromStart((tCarElt*)MyCar); double HisPos = RtGetDistFromStart((tCarElt*)oCar); double RelPos = HisPos - MyPos; double TrackLen = oTrack->Length(); if (RelPos > TrackLen / 2) RelPos -= TrackLen; else if (RelPos < -TrackLen / 2) RelPos += TrackLen; oInfo.State.RelPos = RelPos; if (fabs(CarToMiddle) - oTrack->Width() > 1.0) // If opponent is outside of track { // we assume it is in the pitlane if ((RelPos > MinDistBack) // Opponent is near && (RelPos < 5)) // and not in front { MinDistBack = (tdble) RelPos; } double T = -RelPos/oInfo.State.TrackVelLong; // Time to start out of pit if ((T > 0) // Opponent is back or aside && (T < 200)) // and arrives within 20 sec { if (MinTimeSlot > T) MinTimeSlot = T; } } }
void Opponent::UpdateSit(const CarElt* myCar, const TeamInfo* pTeamInfo, double myDirX, double myDirY) { CarElt* oCar = m_path.GetCar(); if( (oCar->_state & RM_CAR_STATE_NO_SIMU) ) return; // word out speed of car. m_info.sit.spd = hypot(oCar->_speed_X, oCar->_speed_Y); // work out track relative speed of other car. Vec2d norm = m_path.GetTrack()->CalcNormal(oCar->_distFromStartLine); m_info.sit.tVX = norm.x * oCar->_speed_Y - norm.y * oCar->_speed_X; m_info.sit.tVY = norm.x * oCar->_speed_X + norm.y * oCar->_speed_Y; // work out track relative yaw of other car. m_info.sit.tYaw = oCar->_yaw - Utils::VecAngle(norm) - PI * 0.5; NORM_PI_PI(m_info.sit.tYaw); // work out avg velocity of other car. m_info.sit.agVX = m_info.sit.agVX * 0.75 + oCar->pub.DynGCg.vel.x * 0.25; m_info.sit.agVY = m_info.sit.agVY * 0.75 + oCar->pub.DynGCg.vel.y * 0.25; m_info.sit.ragVX = myDirX * m_info.sit.agVX + myDirY * m_info.sit.agVY; m_info.sit.ragVY = myDirY * m_info.sit.agVX - myDirX * m_info.sit.agVY; // work out avg acceleration of other car. m_info.sit.agAX = m_info.sit.agAX * 0.75 + oCar->pub.DynGCg.acc.x * 0.25; m_info.sit.agAY = m_info.sit.agAY * 0.75 + oCar->pub.DynGCg.acc.y * 0.25; m_info.sit.ragAX = myDirX * m_info.sit.agAX + myDirY * m_info.sit.agAY; m_info.sit.ragAY = myDirY * m_info.sit.agAX - myDirX * m_info.sit.agAY; // work out lateral accelerations. double rAX = myDirX * oCar->pub.DynGCg.acc.x + myDirY * oCar->pub.DynGCg.acc.y; double rAY = myDirY * oCar->pub.DynGCg.acc.x - myDirX * oCar->pub.DynGCg.acc.y; m_info.sit.arAX = m_info.sit.arAX * 0.75 + rAX * 0.25; m_info.sit.arAY = m_info.sit.arAY * 0.75 + rAY * 0.25; // offset from track centre line. m_info.sit.offs = -oCar->_trkPos.toMiddle; // the rest of the calcs are car-car relative, and make no sense if both // cars are the same. if( oCar == myCar ) return; // calc other cars position, velocity relative to my car (global coords). double dPX = oCar->pub.DynGCg.pos.x - myCar->pub.DynGCg.pos.x; double dPY = oCar->pub.DynGCg.pos.y - myCar->pub.DynGCg.pos.y; double dVX = oCar->_speed_X - myCar->_speed_X; double dVY = oCar->_speed_Y - myCar->_speed_Y; // work out relative position, velocity in local coords (coords of my car). double rdPX = myDirX * dPX + myDirY * dPY; double rdPY = myDirY * dPX - myDirX * dPY; double rdVX = myDirX * dVX + myDirY * dVY; double rdVY = myDirY * dVX - myDirX * dVY; m_info.sit.rdPX = rdPX; m_info.sit.rdPY = rdPY; m_info.sit.rdVX = rdVX; m_info.sit.rdVY = rdVY; m_info.sit.minDX = (myCar->_dimension_x + oCar->_dimension_x) / 2; m_info.sit.minDY = (myCar->_dimension_y + oCar->_dimension_y) / 2; double myVelAng = atan2(myCar->_speed_Y, myCar->_speed_X); double myYaw = myCar->_yaw - myVelAng; NORM_PI_PI(myYaw); double oYaw = oCar->_yaw - myVelAng; NORM_PI_PI(oYaw); double extSide = (m_info.sit.minDX - m_info.sit.minDY) * (fabs(sin(myYaw)) + fabs(sin(oYaw))); // m_info.sit.minDY += MX(0, MN((rdPX - m_info.sit.minDY) * 0.1, 4)); m_info.sit.minDY += extSide + 1;//0.5; m_info.sit.minDX += 1.0;//pTeamInfo->IsTeamMate(myCar, oCar) ? 0.5 : 1.0; // if( fabs(extSide) > 0.2 ) // GfOut( "****** angDiff %.3f extSide %.2f ******\n", angDiff, extSide ); // work out positions of car from start of track. double myPos = RtGetDistFromStart((tCarElt*)myCar); double hisPos = RtGetDistFromStart((tCarElt*)oCar); double relPos = hisPos - myPos; double trackLen = m_path.GetTrack()->GetLength(); if( relPos > trackLen / 2 ) relPos -= trackLen; else if( relPos < -trackLen / 2 ) relPos += trackLen; m_info.sit.relPos = relPos; }