/* Initial configuration */ void SimConfig(tCarElt *carElt, tRmInfo* ReInfo) { tCar *car = &(SimCarTable[carElt->index]); memset(car, 0, sizeof(tCar)); car->carElt = carElt; car->DynGCg = car->DynGC = carElt->_DynGC; car->trkPos = carElt->_trkPos; car->ctrl = &carElt->ctrl; car->params = carElt->_carHandle; car->ReInfo = ReInfo; SimCarConfig(car); SimCarCollideConfig(car); sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); sgEulerToQuat (car->posQuat, -RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_pitch), RAD2DEG(carElt->_roll)); sgQuatToMatrix (car->posMat, car->posQuat); simu_total_time = 0.0f; simu_init_time = GfTimeClock(); //sgMakeRotMat4 (car->posMat, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); }
/* Initial configuration */ void SimConfig(tCarElt *carElt) { tCar *car = &(SimCarTable[carElt->index]); memset(car, 0, sizeof(tCar)); car->carElt = carElt; car->DynGCg = car->DynGC = carElt->_DynGC; car->trkPos = carElt->_trkPos; car->ctrl = &carElt->ctrl; car->params = carElt->_carHandle; SimCarConfig(car); SimCarCollideConfig(car, PTrack); sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); }
// Collision response for walls. // TODO: Separate common code with car-car collision response. static void SimCarWallCollideResponse(void *clientdata, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData) { tCar* car; // The car colliding with the wall. float nsign; // Normal direction correction for collision plane. sgVec2 p; // Cars collision point delivered by solid. // TODO: If other movable objects are added which could collide with the wall, it will be // necessary to validate if the object is actually a car. if (obj1 == clientdata) { car = (tCar*) obj2; nsign = -1.0f; p[0] = (float) collData->point2[0]; p[1] = (float) collData->point2[1]; } else { car = (tCar*) obj1; nsign = 1.0f; p[0] = (float) collData->point1[0]; p[1] = (float) collData->point1[1]; } sgVec2 n; // Collision normal delivered by solid, corrected such that it points away from the wall. n[0] = nsign * (float) collData->normal[0]; n[1] = nsign * (float) collData->normal[1]; float pdist = sgLengthVec2(n); // Distance of collision points. sgNormaliseVec2(n); sgVec2 r; sgSubVec2(r, p, (const float*)&(car->statGC)); tCarElt *carElt = car->carElt; sgVec2 vp; // Speed of car collision point in global frame of reference. sgVec2 rg; // raduis oriented in global coordinates, still relative to CG (rotated aroung CG). float sina = sin(carElt->_yaw); float cosa = cos(carElt->_yaw); rg[0] = r[0]*cosa - r[1]*sina; rg[1] = r[0]*sina + r[1]*cosa; vp[0] = car->DynGCg.vel.x - car->DynGCg.vel.az * rg[1]; vp[1] = car->DynGCg.vel.y + car->DynGCg.vel.az * rg[0]; sgVec2 tmpv; static const float CAR_MIN_MOVEMENT = 0.02f; static const float CAR_MAX_MOVEMENT = 0.05f; sgScaleVec2(tmpv, n, MIN(MAX(pdist, CAR_MIN_MOVEMENT), CAR_MAX_MOVEMENT)); if (car->blocked == 0) { sgAddVec2((float*)&(car->DynGCg.pos), tmpv); car->blocked = 1; } // Doing no dammage and correction if the cars are moving out of each other. if (sgScalarProductVec2(vp, n) > 0) { return; } float rp = sgScalarProductVec2(rg, n); // Pesudo cross product to find out if we are left or right. // TODO: SIGN, scrap value? float rpsign = n[0]*rg[1] - n[1]*rg[0]; const float e = 1.0f; // energy restitution float j = -(1.0f + e) * sgScalarProductVec2(vp, n) / (car->Minv + rp * rp * car->Iinv.z); const float ROT_K = 0.5f; // Damage. tdble damFactor, atmp; atmp = atan2(r[1], r[0]); if (fabs(atmp) < (PI / 3.0)) { // Front collision gives more damage. damFactor = 1.5f; } else { // Rear collision gives less damage. damFactor = 1.0f; } static const float DMGFACTOR = 0.00002f; if ((car->carElt->_state & RM_CAR_STATE_FINISH) == 0) { car->dammage += (int)(CAR_DAMMAGE * (DMGFACTOR*j*j) * damFactor * simDammageFactor[car->carElt->_skillLevel]); } sgScaleVec2(tmpv, n, j * car->Minv); sgVec2 v2a; if (car->collision & SEM_COLLISION_CAR) { sgAddVec2(v2a, (const float*)&(car->VelColl.x), tmpv); car->VelColl.az = car->VelColl.az + j * rp * rpsign * car->Iinv.z * ROT_K; } else { sgAddVec2(v2a, (const float*)&(car->DynGCg.vel), tmpv); car->VelColl.az = car->DynGCg.vel.az + j * rp * rpsign * car->Iinv.z * ROT_K; } static float VELMAX = 3.0f; if (fabs(car->VelColl.az) > VELMAX) { car->VelColl.az = SIGN(car->VelColl.az) * VELMAX; } sgCopyVec2((float*)&(car->VelColl.x), v2a); // Move the car for the collision lib. sgMakeCoordMat4(carElt->pub.posMat, car->DynGCg.pos.x, car->DynGCg.pos.y, car->DynGCg.pos.z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); dtSelectObject(car); dtLoadIdentity(); dtTranslate(-carElt->_statGC_x, -carElt->_statGC_y, 0.0f); dtMultMatrixf((const float *)(carElt->_posMat)); car->collision |= SEM_COLLISION_CAR; }
static void SimCarCollideResponse(void * /*dummy*/, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData) { sgVec2 n; // Collision normal delivered by solid: Global(point1) - Global(point2) tCar *car[2]; // The cars. sgVec2 p[2]; // Collision points delivered by solid, in body local coordinates. sgVec2 r[2]; // Collision point relative to center of gravity. sgVec2 vp[2]; // Speed of collision point in world coordinate system. sgVec3 pt[2]; // Collision points in global coordinates. int i; car[0] = (tCar*)obj1; car[1] = (tCar*)obj2; // Handle cars collisions during pit stops as well. static const int NO_SIMU_WITHOUT_PIT = RM_CAR_STATE_NO_SIMU & ~RM_CAR_STATE_PIT; if ((car[0]->carElt->_state & NO_SIMU_WITHOUT_PIT) || (car[1]->carElt->_state & NO_SIMU_WITHOUT_PIT)) { return; } if (car[0]->carElt->index < car[1]->carElt->index) { // vector conversion from double to float. p[0][0] = (float)collData->point1[0]; p[0][1] = (float)collData->point1[1]; p[1][0] = (float)collData->point2[0]; p[1][1] = (float)collData->point2[1]; n[0] = (float)collData->normal[0]; n[1] = (float)collData->normal[1]; } else { // swap the cars (not the same for the simu). car[0] = (tCar*)obj2; car[1] = (tCar*)obj1; p[0][0] = (float)collData->point2[0]; p[0][1] = (float)collData->point2[1]; p[1][0] = (float)collData->point1[0]; p[1][1] = (float)collData->point1[1]; n[0] = -(float)collData->normal[0]; n[1] = -(float)collData->normal[1]; } sgNormaliseVec2(n); sgVec2 rg[2]; // radius oriented in global coordinates, still relative to CG (rotated aroung CG). tCarElt *carElt; for (i = 0; i < 2; i++) { // vector GP (Center of gravity to collision point). p1 and p2 are delivered from solid as // points in the car coordinate system. sgSubVec2(r[i], p[i], (const float*)&(car[i]->statGC)); // Speed of collision points, linear motion of center of gravity (CG) plus rotational // motion around the CG. carElt = car[i]->carElt; float sina = sin(carElt->_yaw); float cosa = cos(carElt->_yaw); rg[i][0] = r[i][0]*cosa - r[i][1]*sina; rg[i][1] = r[i][0]*sina + r[i][1]*cosa; vp[i][0] = car[i]->DynGCg.vel.x - car[i]->DynGCg.vel.az * rg[i][1]; vp[i][1] = car[i]->DynGCg.vel.y + car[i]->DynGCg.vel.az * rg[i][0]; } // Relative speed of collision points. sgVec2 v1ab; sgSubVec2(v1ab, vp[0], vp[1]); // try to separate the cars. The computation is necessary because dtProceed is not called till // the collision is resolved. for (i = 0; i < 2; i++) { sgCopyVec2(pt[i], r[i]); pt[i][2] = 0.0f; // Transform points relative to cars local coordinate system into global coordinates. sgFullXformPnt3(pt[i], car[i]->carElt->_posMat); } // Compute distance of collision points. sgVec3 pab; sgSubVec2(pab, pt[1], pt[0]); float distpab = sgLengthVec2(pab); sgVec2 tmpv; sgScaleVec2(tmpv, n, MIN(distpab, 0.05)); // No "for" loop here because of subtle difference AddVec/SubVec. if (car[0]->blocked == 0 && !(car[0]->carElt->_state & RM_CAR_STATE_NO_SIMU)) { sgAddVec2((float*)&(car[0]->DynGCg.pos), tmpv); car[0]->blocked = 1; } if (car[1]->blocked == 0 && !(car[1]->carElt->_state & RM_CAR_STATE_NO_SIMU)) { sgSubVec2((float*)&(car[1]->DynGCg.pos), tmpv); car[1]->blocked = 1; } // Doing no dammage and correction if the cars are moving out of each other. if (sgScalarProductVec2(v1ab, n) > 0) { return; } // impulse. float rpn[2]; rpn[0] = sgScalarProductVec2(rg[0], n); rpn[1] = sgScalarProductVec2(rg[1], n); // Pseudo cross product to find out if we are left or right. // TODO: SIGN, scrap value? float rpsign[2]; rpsign[0] = n[0]*rg[0][1] - n[1]*rg[0][0]; rpsign[1] = -n[0]*rg[1][1] + n[1]*rg[1][0]; const float e = 1.0f; // energy restitution float j = -(1.0f + e) * sgScalarProductVec2(v1ab, n) / ((car[0]->Minv + car[1]->Minv) + rpn[0] * rpn[0] * car[0]->Iinv.z + rpn[1] * rpn[1] * car[1]->Iinv.z); for (i = 0; i < 2; i++) { if (car[i]->carElt->_state & RM_CAR_STATE_NO_SIMU) { continue; } // Damage. tdble damFactor, atmp; atmp = atan2(r[i][1], r[i][0]); if (fabs(atmp) < (PI / 3.0)) { // Front collision gives more damage. damFactor = 1.5f; } else { // Rear collision gives less damage. damFactor = 1.0f; } if ((car[i]->carElt->_state & RM_CAR_STATE_FINISH) == 0) { car[i]->dammage += (int)(CAR_DAMMAGE * fabs(j) * damFactor * simDammageFactor[car[i]->carElt->_skillLevel]); } // Compute collision velocity. const float ROT_K = 1.0f; float js = (i == 0) ? j : -j; sgScaleVec2(tmpv, n, js * car[i]->Minv); sgVec2 v2a; if (car[i]->collision & SEM_COLLISION_CAR) { sgAddVec2(v2a, (const float*)&(car[i]->VelColl.x), tmpv); car[i]->VelColl.az = car[i]->VelColl.az + js * rpsign[i] * rpn[i] * car[i]->Iinv.z * ROT_K; } else { sgAddVec2(v2a, (const float*)&(car[i]->DynGCg.vel), tmpv); car[i]->VelColl.az = car[i]->DynGCg.vel.az + js * rpsign[i] * rpn[i] * car[i]->Iinv.z * ROT_K; } static float VELMAX = 3.0f; if (fabs(car[i]->VelColl.az) > VELMAX) { car[i]->VelColl.az = SIGN(car[i]->VelColl.az) * VELMAX; } sgCopyVec2((float*)&(car[i]->VelColl.x), v2a); // Move the car for the collision lib. tCarElt *carElt = car[i]->carElt; sgMakeCoordMat4(carElt->pub.posMat, car[i]->DynGCg.pos.x, car[i]->DynGCg.pos.y, car[i]->DynGCg.pos.z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); dtSelectObject(car[i]); dtLoadIdentity(); dtTranslate(-carElt->_statGC_x, -carElt->_statGC_y, 0.0f); dtMultMatrixf((const float *)(carElt->_posMat)); car[i]->collision |= SEM_COLLISION_CAR; } }
void SimUpdate(tSituation *s, double deltaTime, int telemetry) { int i; int ncar; tCarElt *carElt; tCar *car; sgVec3 P; static const float UPSIDE_DOWN_TIMEOUT = 5.0f; double timestamp_start = GfTimeClock(); SimDeltaTime = deltaTime; SimTelemetry = 0;//telemetry; for (ncar = 0; ncar < s->_ncars; ncar++) { SimCarTable[ncar].collision = 0; SimCarTable[ncar].blocked = 0; } for (ncar = 0; ncar < s->_ncars; ncar++) { car = &(SimCarTable[ncar]); carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_NO_SIMU) { RemoveCar(car, s); continue; } else if (((s->_maxDammage) && (car->dammage > s->_maxDammage)) || (car->fuel == 0) || (car->upside_down_timer > UPSIDE_DOWN_TIMEOUT) || (car->carElt->_state & RM_CAR_STATE_ELIMINATED)) { RemoveCar(car, s); if (carElt->_state & RM_CAR_STATE_NO_SIMU) { continue; } } if (s->_raceState & RM_RACE_PRESTART) { car->ctrl->gear = 0; } CHECK(car); ctrlCheck(car); CHECK(car); SimSteerUpdate(car); CHECK(car); SimGearboxUpdate(car); CHECK(car); SimEngineUpdateTq(car); CHECK(car); if (!(s->_raceState & RM_RACE_PRESTART)) { SimCarUpdateWheelPos(car); CHECK(car); SimBrakeSystemUpdate(car); CHECK(car); SimAeroUpdate(car, s); CHECK(car); for (i = 0; i < 2; i++){ SimWingUpdate(car, i, s); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateRide(car, i); } CHECK(car); for (i = 0; i < 2; i++){ SimAxleUpdate(car, i); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateForce(car, i); } CHECK(car); } SimTransmissionUpdate(car); CHECK(car); if (!(s->_raceState & RM_RACE_PRESTART)) { SimWheelUpdateRotation(car); CHECK(car); SimCarUpdate(car, s); CHECK(car); } } SimCarCollideCars(s); /* printf ("%f - ", s->currentTime); */ for (ncar = 0; ncar < s->_ncars; ncar++) { car = &(SimCarTable[ncar]); CHECK(car); carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_NO_SIMU) { continue; } CHECK(car); SimCarUpdate2(car, s); /* copy back the data to carElt */ carElt->pub.DynGC = car->DynGC; carElt->pub.DynGCg = car->DynGCg; #if 0 sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); #else sgQuatToMatrix (carElt->pub.posMat, car->posQuat); carElt->pub.posMat[3][0] = car->DynGCg.pos.x; carElt->pub.posMat[3][1] = car->DynGCg.pos.y; carElt->pub.posMat[3][2] = car->DynGCg.pos.z - carElt->_statGC_z; carElt->pub.posMat[0][3] = SG_ZERO ; carElt->pub.posMat[1][3] = SG_ZERO ; carElt->pub.posMat[2][3] = SG_ZERO ; carElt->pub.posMat[3][3] = SG_ONE ; #endif carElt->_trkPos = car->trkPos; for (i = 0; i < 4; i++) { carElt->priv.wheel[i].relPos = car->wheel[i].relPos; carElt->_wheelSeg(i) = car->wheel[i].trkPos.seg; carElt->_brakeTemp(i) = car->wheel[i].brake.temp; carElt->pub.corner[i] = car->corner[i].pos; } carElt->_gear = car->transmission.gearbox.gear; carElt->_enginerpm = car->engine.rads; carElt->_fuel = car->fuel; carElt->priv.collision |= car->collision; carElt->_dammage = car->dammage; P[0] = -carElt->_statGC_x; P[1] = -carElt->_statGC_y; P[2] = -carElt->_statGC_z; sgXformPnt3(P, carElt->_posMat); carElt->_pos_X = P[0]; carElt->_pos_Y = P[1]; carElt->_pos_Z = P[2]; } simu_total_time += GfTimeClock() - timestamp_start; }
static void RemoveCar(tCar *car, tSituation *s) { int i; tCarElt *carElt; tTrkLocPos trkPos; int trkFlag; tdble travelTime; tdble dang; #define PULL_Z_OFFSET 3.0 #define PULL_SPD 0.5 carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_PULLUP) { carElt->_pos_Z += car->restPos.vel.z * SimDeltaTime; carElt->_yaw += car->restPos.vel.az * SimDeltaTime; carElt->_roll += car->restPos.vel.ax * SimDeltaTime; carElt->_pitch += car->restPos.vel.ay * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z > (car->restPos.pos.z + PULL_Z_OFFSET)) { carElt->_state &= ~RM_CAR_STATE_PULLUP; carElt->_state |= RM_CAR_STATE_PULLSIDE; travelTime = DIST(car->restPos.pos.x, car->restPos.pos.y, carElt->_pos_X, carElt->_pos_Y) / PULL_SPD; car->restPos.vel.x = (car->restPos.pos.x - carElt->_pos_X) / travelTime; car->restPos.vel.y = (car->restPos.pos.y - carElt->_pos_Y) / travelTime; } return; } if (carElt->_state & RM_CAR_STATE_PULLSIDE) { carElt->_pos_X += car->restPos.vel.x * SimDeltaTime; carElt->_pos_Y += car->restPos.vel.y * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if ((fabs(car->restPos.pos.x - carElt->_pos_X) < 0.5) && (fabs(car->restPos.pos.y - carElt->_pos_Y) < 0.5)) { carElt->_state &= ~RM_CAR_STATE_PULLSIDE; carElt->_state |= RM_CAR_STATE_PULLDN; } return; } if (carElt->_state & RM_CAR_STATE_PULLDN) { carElt->_pos_Z -= car->restPos.vel.z * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z < car->restPos.pos.z) { carElt->_state &= ~RM_CAR_STATE_PULLDN; carElt->_state |= RM_CAR_STATE_OUT; } return; } if (carElt->_state & RM_CAR_STATE_NO_SIMU) { return; } if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { carElt->_state |= RM_CAR_STATE_BROKEN; } else { carElt->_state |= RM_CAR_STATE_OUTOFGAS; } carElt->_gear = car->transmission.gearbox.gear = 0; carElt->_enginerpm = car->engine.rads = 0; if (!(carElt->_state & RM_CAR_STATE_DNF)) { if (fabs(carElt->_speed_x) > 1.0) { return; } } carElt->_state |= RM_CAR_STATE_PULLUP; carElt->priv.collision = car->collision = 0; for(i = 0; i < 4; i++) { carElt->_skid[i] = 0; carElt->_wheelSpinVel(i) = 0; carElt->_brakeTemp(i) = 0; } carElt->pub.DynGC = car->DynGC; carElt->_speed_x = 0; /* compute the target zone for the wrecked car */ trkPos = car->trkPos; if (trkPos.toRight > trkPos.seg->width / 2.0) { while (trkPos.seg->lside != 0) { trkPos.seg = trkPos.seg->lside; } trkPos.toLeft = -3.0; trkFlag = TR_TOLEFT; } else { while (trkPos.seg->rside != 0) { trkPos.seg = trkPos.seg->rside; } trkPos.toRight = -3.0; trkFlag = TR_TORIGHT; } trkPos.type = TR_LPOS_SEGMENT; RtTrackLocal2Global(&trkPos, &(car->restPos.pos.x), &(car->restPos.pos.y), trkFlag); car->restPos.pos.z = RtTrackHeightL(&trkPos) + carElt->_statGC_z; car->restPos.pos.az = RtTrackSideTgAngleL(&trkPos); car->restPos.pos.ax = 0; car->restPos.pos.ay = 0; car->restPos.vel.z = PULL_SPD; travelTime = (car->restPos.pos.z + PULL_Z_OFFSET - carElt->_pos_Z) / car->restPos.vel.z; dang = car->restPos.pos.az - carElt->_yaw; NORM_PI_PI(dang); car->restPos.vel.az = dang / travelTime; dang = car->restPos.pos.ax - carElt->_roll; NORM_PI_PI(dang); car->restPos.vel.ax = dang / travelTime; dang = car->restPos.pos.ay - carElt->_pitch; NORM_PI_PI(dang); car->restPos.vel.ay = dang / travelTime; }
void SimUpdateSingleCar(int index, double deltaTime,tSituation *s) { int i; //int ncar; tCarElt *carElt; tCar *car; SimDeltaTime = (tdble) deltaTime; SimCarTable[index].collision = 0; SimCarTable[index].blocked = 0; car = &(SimCarTable[index]); carElt = car->carElt; CHECK(car); ctrlCheck(car); CHECK(car); SimSteerUpdate(car); CHECK(car); SimGearboxUpdate(car); CHECK(car); SimEngineUpdateTq(car); CHECK(car); SimCarUpdateWheelPos(car); CHECK(car); SimBrakeSystemUpdate(car); CHECK(car); SimAeroUpdate(car, s); CHECK(car); for (i = 0; i < 2; i++){ SimWingUpdate(car, i, s); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateRide(car, i); } CHECK(car); for (i = 0; i < 2; i++){ SimAxleUpdate(car, i); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateForce(car, i); } CHECK(car); SimTransmissionUpdate(car); CHECK(car); SimWheelUpdateRotation(car); CHECK(car); SimCarUpdate(car, s); CHECK(car); /* copy back the data to carElt */ carElt->pub.DynGC = car->DynGC; carElt->pub.DynGCg = car->DynGCg; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); carElt->_trkPos = car->trkPos; for (i = 0; i < 4; i++) { carElt->priv.wheel[i].relPos = car->wheel[i].relPos; carElt->_wheelSeg(i) = car->wheel[i].trkPos.seg; carElt->_brakeTemp(i) = car->wheel[i].brake.temp; carElt->pub.corner[i] = car->corner[i].pos; } carElt->_gear = car->transmission.gearbox.gear; carElt->_enginerpm = car->engine.rads; carElt->_fuel = car->fuel; carElt->priv.collision |= car->collision; carElt->_dammage = car->dammage; }
void SimUpdate(tSituation *s, double deltaTime) { int i; int ncar; tCarElt *carElt; tCar *car; SimDeltaTime = (tdble) deltaTime; for (ncar = 0; ncar < s->_ncars; ncar++) { SimCarTable[ncar].collision = 0; SimCarTable[ncar].blocked = 0; } for (ncar = 0; ncar < s->_ncars; ncar++) { car = &(SimCarTable[ncar]); carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_NO_SIMU) { RemoveCar(car, s); continue; } else if (((s->_maxDammage) && (car->dammage > s->_maxDammage)) || (car->fuel == 0) || (car->carElt->_state & RM_CAR_STATE_ELIMINATED)) { RemoveCar(car, s); if (carElt->_state & RM_CAR_STATE_NO_SIMU) { continue; } } if (s->_raceState & RM_RACE_PRESTART && (car->carElt->_skillLevel < 3 || !(s->_features & RM_FEATURE_PENALTIES))) { car->ctrl->brakeCmd = 1.0; car->ctrl->clutchCmd = 1.0; } CHECK(car); ctrlCheck(car); CHECK(car); SimSteerUpdate(car); CHECK(car); SimGearboxUpdate(car); CHECK(car); SimEngineUpdateTq(car); CHECK(car); if (!(s->_raceState & RM_RACE_PRESTART) || car->carElt->_skillLevel == 3) { SimCarUpdateWheelPos(car); CHECK(car); SimBrakeSystemUpdate(car); CHECK(car); SimAeroUpdate(car, s); CHECK(car); for (i = 0; i < 2; i++){ SimWingUpdate(car, i, s); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateRide(car, i); } CHECK(car); for (i = 0; i < 2; i++){ SimAxleUpdate(car, i); } CHECK(car); for (i = 0; i < 4; i++){ SimWheelUpdateForce(car, i); } CHECK(car); SimTransmissionUpdate(car); CHECK(car); SimWheelUpdateRotation(car); CHECK(car); SimCarUpdate(car, s); CHECK(car); } else { SimTransmissionUpdate(car); SimEngineUpdateRpm(car, 0.0); } } SimCarCollideCars(s); /* printf ("%f - ", s->currentTime); */ for (ncar = 0; ncar < s->_ncars; ncar++) { car = &(SimCarTable[ncar]); CHECK(car); carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_NO_SIMU) { continue; } CHECK(car); SimCarUpdate2(car, s); /* telemetry */ /* copy back the data to carElt */ carElt->pub.DynGC = car->DynGC; carElt->pub.DynGCg = car->DynGCg; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); carElt->_trkPos = car->trkPos; for (i = 0; i < 4; i++) { carElt->priv.wheel[i].relPos = car->wheel[i].relPos; carElt->_wheelSeg(i) = car->wheel[i].trkPos.seg; carElt->_brakeTemp(i) = car->wheel[i].brake.temp; carElt->pub.corner[i] = car->corner[i].pos; } carElt->_gear = car->transmission.gearbox.gear; carElt->_enginerpm = car->engine.rads; carElt->_fuel = car->fuel; carElt->priv.collision |= car->collision; carElt->_dammage = car->dammage; } }
static void RemoveCar(tCar *car, tSituation *s) { int i; tCarElt *carElt; tTrkLocPos trkPos; int trkFlag; tdble travelTime; tdble dang; static tdble PULL_Z_OFFSET = 3.0; static tdble PULL_SPD = 0.5; carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_PULLUP) { carElt->_pos_Z += car->restPos.vel.z * SimDeltaTime; carElt->_yaw += car->restPos.vel.az * SimDeltaTime; carElt->_roll += car->restPos.vel.ax * SimDeltaTime; carElt->_pitch += car->restPos.vel.ay * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z > (car->restPos.pos.z + PULL_Z_OFFSET)) { carElt->_state &= ~RM_CAR_STATE_PULLUP; carElt->_state |= RM_CAR_STATE_PULLSIDE; // Moved pullside velocity computation down due to floating point error accumulation. } return; } if (carElt->_state & RM_CAR_STATE_PULLSIDE) { // Recompute speed to avoid missing the parking point due to error accumulation (the pos might be // in the 0-10000 range, depending on the track and vel*dt is around 0-0.001, so basically all // but the most significant digits are lost under bad conditions, happens e.g on e-track-4). // Should not lead to a division by zero because the pullside process stops if the car is within // [0.5, 0.5]. Do not move it back. travelTime = DIST(car->restPos.pos.x, car->restPos.pos.y, carElt->_pos_X, carElt->_pos_Y) / PULL_SPD; car->restPos.vel.x = (car->restPos.pos.x - carElt->_pos_X) / travelTime; car->restPos.vel.y = (car->restPos.pos.y - carElt->_pos_Y) / travelTime; carElt->_pos_X += car->restPos.vel.x * SimDeltaTime; carElt->_pos_Y += car->restPos.vel.y * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if ((fabs(car->restPos.pos.x - carElt->_pos_X) < 0.5) && (fabs(car->restPos.pos.y - carElt->_pos_Y) < 0.5)) { carElt->_state &= ~RM_CAR_STATE_PULLSIDE; carElt->_state |= RM_CAR_STATE_PULLDN; } return; } if (carElt->_state & RM_CAR_STATE_PULLDN) { carElt->_pos_Z -= car->restPos.vel.z * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z < car->restPos.pos.z) { carElt->_state &= ~RM_CAR_STATE_PULLDN; carElt->_state |= RM_CAR_STATE_OUT; } return; } if (carElt->_state & (RM_CAR_STATE_NO_SIMU & ~RM_CAR_STATE_PIT)) { return; } if (carElt->_state & RM_CAR_STATE_PIT) { if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { // Broken during pit stop. carElt->_state &= ~RM_CAR_STATE_PIT; carElt->_pit->pitCarIndex = TR_PIT_STATE_FREE; } else { return; } } if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { carElt->_state |= RM_CAR_STATE_BROKEN; } else { carElt->_state |= RM_CAR_STATE_OUTOFGAS; } carElt->_gear = car->transmission.gearbox.gear = 0; carElt->_enginerpm = car->engine.rads = 0; if (!(carElt->_state & RM_CAR_STATE_DNF)) { if (fabs(carElt->_speed_x) > 1.0) { return; } } carElt->_state |= RM_CAR_STATE_PULLUP; // RM_CAR_STATE_NO_SIMU evaluates to > 0 from here, so we remove the car from the // collision detection. SimCollideRemoveCar(car, s->_ncars); carElt->priv.collision = car->collision = 0; for(i = 0; i < 4; i++) { carElt->_skid[i] = 0; carElt->_wheelSpinVel(i) = 0; carElt->_brakeTemp(i) = 0; } carElt->pub.DynGC = car->DynGC; carElt->_speed_x = 0; // Compute the target zone for the wrecked car. trkPos = car->trkPos; if (trkPos.toRight > trkPos.seg->width / 2.0) { while (trkPos.seg->lside != 0) { trkPos.seg = trkPos.seg->lside; } trkPos.toLeft = -3.0; trkFlag = TR_TOLEFT; } else { while (trkPos.seg->rside != 0) { trkPos.seg = trkPos.seg->rside; } trkPos.toRight = -3.0; trkFlag = TR_TORIGHT; } trkPos.type = TR_LPOS_SEGMENT; RtTrackLocal2Global(&trkPos, &(car->restPos.pos.x), &(car->restPos.pos.y), trkFlag); car->restPos.pos.z = RtTrackHeightL(&trkPos) + carElt->_statGC_z; car->restPos.pos.az = RtTrackSideTgAngleL(&trkPos); car->restPos.pos.ax = 0; car->restPos.pos.ay = 0; car->restPos.vel.z = PULL_SPD; travelTime = (car->restPos.pos.z + PULL_Z_OFFSET - carElt->_pos_Z) / car->restPos.vel.z; dang = car->restPos.pos.az - carElt->_yaw; FLOAT_NORM_PI_PI(dang); car->restPos.vel.az = dang / travelTime; dang = car->restPos.pos.ax - carElt->_roll; FLOAT_NORM_PI_PI(dang); car->restPos.vel.ax = dang / travelTime; dang = car->restPos.pos.ay - carElt->_pitch; FLOAT_NORM_PI_PI(dang); car->restPos.vel.ay = dang / travelTime; }