Exemplo n.º 1
0
/** Used to get the normal vector of the road (pointing upward).
    Local coordinates are used to locate the point where to
    get the road normal vector.
    The vector is normalized.
    @ingroup	tracktools
    @param	p	Local position
    @param	norm	Returned normalized road normal vector
 */
void
RtTrackSurfaceNormalL(tTrkLocPos *p, t3Dd *norm)
{
    tTrkLocPos	p1;
    t3Dd	px1, px2, py1, py2;
    t3Dd	v1, v2;
    tdble	lg;

    p1.seg = p->seg;

    p1.toStart = 0;
    p1.toRight = p->toRight;
    RtTrackLocal2Global(&p1, &px1.x, &px1.y, TR_TORIGHT);
    px1.z = RtTrackHeightL(&p1);

    if (p1.seg->type == TR_STR) {
	p1.toStart = p1.seg->length;
    } else {
	p1.toStart = p1.seg->arc;
    }
    RtTrackLocal2Global(&p1, &px2.x, &px2.y, TR_TORIGHT);
    px2.z = RtTrackHeightL(&p1);

    p1.toRight = 0;
    p1.toStart = p->toStart;
    RtTrackLocal2Global(&p1, &py1.x, &py1.y, TR_TORIGHT);
    py1.z = RtTrackHeightL(&p1);

    p1.toRight = p1.seg->width;
    RtTrackLocal2Global(&p1, &py2.x, &py2.y, TR_TORIGHT);
    py2.z = RtTrackHeightL(&p1);


    v1.x = px2.x - px1.x;
    v1.y = px2.y - px1.y;
    v1.z = px2.z - px1.z;
    v2.x = py2.x - py1.x;
    v2.y = py2.y - py1.y;
    v2.z = py2.z - py1.z;

    norm->x = v1.y * v2.z - v2.y * v1.z;
    norm->y = v2.x * v1.z - v1.x * v2.z;
    norm->z = v1.x * v2.y - v2.x * v1.y;
    lg = sqrt(norm->x * norm->x + norm->y * norm->y + norm->z * norm->z);
    if (lg == 0.0) {
	lg = 1.0f;
    } else {
	lg = 1.0f / lg;
    }
    norm->x *= lg;
    norm->y *= lg;
    norm->z *= lg;
}
Exemplo n.º 2
0
	void PTrackManager::CorrectCars()
	{
		for (int i = 0; i < nCars; i++)
		{
			tCarElt* curCar = &carList[i];

			// If current car on first segment, prevent from leaving segment
			if (curCar->pub.trkPos.seg->id == 0)
			{
				if (curCar->pub.trkPos.toStart < 10)
				{
					curCar->pub.trkPos.toStart = 10;
					RtTrackLocal2Global(&(curCar->_trkPos), &(curCar->_pos_X), &(curCar->_pos_Y), TR_TORIGHT);
					raceManager->_reSimItf.config(curCar, raceManager);
				}
			}
		}
	}
Exemplo n.º 3
0
	void PTrackManager::InitCars()
	{
		// Get pointer to car list
		carList = raceManager->carList;

		// Retrieve number of cars in race
		nCars = raceManager->s->raceInfo.ncars;

		// Start segment
		tTrackSeg* startSeg = track->GetStart();

		// Array of positions
		tTrkLocPos* positions = new tTrkLocPos[nCars];
		for (int i = 0; i < nCars; i++)
			positions[i] = tTrkLocPos();

		// Spacing between cars
		tdble carXSpacing = (startSeg->width / 2) - 3; // Assuming 3 is around average car width
		tdble carYSpacing = 20;

		/* Starting grid positons are calculated regardless of pole position as follows:
		    Y
			|---------|
			| P1  P2  |
			| P3  P4  |
			| P5  P6  |
			| P7  P8  |
			| P9  P10 | 
			|---------| - X
		*/

		// Calculate position grid here
		if (nCars > 1)
		{
			int row = 1;
			for (int i = 0; i < nCars; i++) // Grid Y
			{
				tTrkLocPos* curPos = &positions[i];

				curPos->seg = startSeg;
				curPos->toStart = startSeg->length - (carYSpacing * row);

				if (i % 2 > 0) // RIGHT POS
					curPos->toMiddle = carXSpacing;
				else if (i % 2 == 0) // LEFT POS
				{
					curPos->toMiddle = -carXSpacing;
					row++;
				}
			}
		}
		else
		{
			positions[0].seg = startSeg;
			positions[0].toStart = startSeg->length - carYSpacing;
			positions[0].toMiddle = carXSpacing;
		}

		// Assign car positions
		for (int i = 0; i < nCars; i++)
		{
			// Get the car
			tCarElt* curCar = &carList[i];

			// Assign the car the correct position
			curCar->pub.trkPos = positions[i];

			// Convert the local position to a global one, and assign to car's actual global position
			RtTrackLocal2Global(&(curCar->_trkPos), &(curCar->_pos_X), &(curCar->_pos_Y), TR_TOMIDDLE);
		}

		// Set up cars in physics sim
		for (int i = 0; i < nCars; i++)
		{
			tCarElt* curCar = &carList[i];
			raceManager->_reSimItf.config(curCar, raceManager);
		}

		delete[] positions;
	}
Exemplo n.º 4
0
/*
 * Function
 *  initStartingGrid
 *
 * Description
 *  Place the cars on the starting grid
 *
 * Parameters
 *  Race Information structure initialized
 *
 * Return
 *  none
 */
static void
initStartingGrid(void)
{
  char path[64];
  int i;
  tTrackSeg *curseg;
  int rows;
  tdble a, b;
  //tdble wi2; // Never used.
  tdble d1, d2,d3;
  tdble startpos, tr, ts;
  tdble speedInit;
  tdble heightInit;
  tCarElt *car;
  const char *pole;
  void *trHdle = ReInfo->track->params;
  void *params = ReInfo->params;

  snprintf(path, sizeof(path), "%s/%s", ReInfo->_reRaceName, RM_SECT_STARTINGGRID);

  /* Search for the first turn for find the pole side */
  curseg = ReInfo->track->seg->next;
  while (curseg->type == TR_STR) {
    /* skip the straight segments */
    curseg = curseg->next;
  }
  /* Set the pole for the inside of the first turn */
  if (curseg->type == TR_LFT) {
    pole = GfParmGetStr(params, path, RM_ATTR_POLE, "left");
  } else {
    pole = GfParmGetStr(params, path, RM_ATTR_POLE, "right");
  }
  /* Tracks definitions can force the pole side */
  pole = GfParmGetStr(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_POLE, pole);

  if (strcmp(pole, "left") == 0) {
    a = ReInfo->track->width;
    b = -a;
  } else {
    a = 0;
    b = ReInfo->track->width;
  }
  //wi2 = ReInfo->track->width * 0.5f; // Never used.

  rows = (int)GfParmGetNum(params, path, RM_ATTR_ROWS, (char*)NULL, 2);
  rows = (int)GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_ROWS, (char*)NULL, (tdble)rows);
  d1 = GfParmGetNum(params, path, RM_ATTR_TOSTART, (char*)NULL, 10);
  d1 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_TOSTART, (char*)NULL, d1);
  d2 = GfParmGetNum(params, path, RM_ATTR_COLDIST, (char*)NULL, 10);
  d2 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_COLDIST, (char*)NULL, d2);
  d3 = GfParmGetNum(params, path, RM_ATTR_COLOFFSET, (char*)NULL, 5);
  d3 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_COLOFFSET, (char*)NULL, d3);
  speedInit = GfParmGetNum(params, path, RM_ATTR_INITSPEED, (char*)NULL, 0.0);
  heightInit = GfParmGetNum(params, path, RM_ATTR_INITHEIGHT, (char*)NULL, 0.3f);
  heightInit = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_INITHEIGHT, (char*)NULL, heightInit);

  if (rows < 1) {
    rows = 1;
  }
  for (i = 0; i < ReInfo->s->_ncars; i++) {
    car = &(ReInfo->carList[i]);
    car->_speed_x = speedInit;
    startpos = ReInfo->track->length - (d1 + (i / rows) * d2 + (i % rows) * d3);
    tr = a + b * ((i % rows) + 1) / (rows + 1);
    curseg = ReInfo->track->seg;  /* last segment */
    while (startpos < curseg->lgfromstart) {
      curseg = curseg->prev;
    }
    ts = startpos - curseg->lgfromstart;
    car->_trkPos.seg = curseg;
    car->_trkPos.toRight = tr;
    switch (curseg->type) {
      case TR_STR:
        car->_trkPos.toStart = ts;
        RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT);
        car->_yaw = curseg->angle[TR_ZS];
        break;
      case TR_RGT:
        car->_trkPos.toStart = ts / curseg->radius;
        RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT);
        car->_yaw = curseg->angle[TR_ZS] - car->_trkPos.toStart;
        break;
      case TR_LFT:
        car->_trkPos.toStart = ts / curseg->radius;
        RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT);
        car->_yaw = curseg->angle[TR_ZS] + car->_trkPos.toStart;
        break;
    }
    car->_pos_Z = RtTrackHeightL(&(car->_trkPos)) + heightInit;

    FLOAT_NORM0_2PI(car->_yaw);

	RePhysicsEngine().configureCar(car);
  }
}
Exemplo n.º 5
0
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;

}
Exemplo n.º 6
0
void
grCustomizePits(void)
{
	tTrackPitInfo *pits;
	int i;
	tdble x, y;
	tdble x2, y2, z2;
	
	ThePits = new ssgBranch();
	PitsAnchor->addKid(ThePits);
	
	pits = &(grTrack->pits);
	/* draw the pit identification */
	
	switch (pits->type) {
	case TR_PIT_ON_TRACK_SIDE:
		for (i = 0; i < pits->nMaxPits; i++) {
			char buf[256];
			t3Dd normalvector;
			sgVec3 vtx;
			sgVec4 clr = {0,0,0,1};
			sgVec3 nrm;
			sgVec2 tex;
			ssgState *st;
			ssgVertexArray *pit_vtx = new ssgVertexArray(4);
			ssgTexCoordArray *pit_tex = new ssgTexCoordArray(4);
			ssgColourArray *pit_clr = new ssgColourArray(1);
			ssgNormalArray *pit_nrm = new ssgNormalArray(1);
			
			pit_clr->add(clr);
		
			if (pits->driversPits[i].car[0]) {
				// If we have more than one car in the pit use the team pit logo of driver 0. 
				if (pits->driversPits[i].freeCarIndex == 1) { 
					// One car assigned to the pit.
					sprintf(buf, "drivers/%s/%d;drivers/%s;data/textures;data/img;.",
						pits->driversPits[i].car[0]->_modName, pits->driversPits[i].car[0]->_driverIndex,
						pits->driversPits[i].car[0]->_modName);
				} else {
					// Multiple cars assigned to the pit.
					sprintf(buf, "drivers/%s;data/textures;data/img;.", pits->driversPits[i].car[0]->_modName);
				}
			} else {
				sprintf(buf, "data/textures;data/img;.");
			}
			
			
			st = grSsgLoadTexStateEx("logo.rgb", buf, FALSE, FALSE);
			((ssgSimpleState*)st)->setShininess(50);
			
			RtTrackLocal2Global(&(pits->driversPits[i].pos), &x, &y, pits->driversPits[i].pos.type);
			RtTrackSideNormalG(pits->driversPits[i].pos.seg, x, y, pits->side, &normalvector);
			x2 = x - pits->width/2.0 * normalvector.x + pits->len/2.0 * normalvector.y;
			y2 = y - pits->width/2.0 * normalvector.y - pits->len/2.0 * normalvector.x;
			z2 = RtTrackHeightG(pits->driversPits[i].pos.seg, x2, y2);
		
			nrm[0] = normalvector.x;
			nrm[1] = normalvector.y;
			nrm[2] = 0;
			pit_nrm->add(nrm);
		
			tex[0] = -0.7;
			tex[1] = 0.33;
			vtx[0] = x2;
			vtx[1] = y2;
			vtx[2] = z2;
			pit_tex->add(tex);
			pit_vtx->add(vtx);
			
			tex[0] = -0.7;
			tex[1] = 1.1;
			vtx[0] = x2;
			vtx[1] = y2;
			vtx[2] = z2 + 4.8;
			pit_tex->add(tex);
			pit_vtx->add(vtx);
			
			x2 = x - pits->width/2.0 * normalvector.x - pits->len/2.0 * normalvector.y;
			y2 = y - pits->width/2.0 * normalvector.y + pits->len/2.0 * normalvector.x;
			z2 = RtTrackHeightG(pits->driversPits[i].pos.seg, x2, y2);
		
			tex[0] = 1.3;
			tex[1] = 0.33;
			vtx[0] = x2;
			vtx[1] = y2;
			vtx[2] = z2;
			pit_tex->add(tex);
			pit_vtx->add(vtx);
			
			tex[0] = 1.3;
			tex[1] = 1.1;
			vtx[0] = x2;
			vtx[1] = y2;
			vtx[2] = z2 + 4.8;
			pit_tex->add(tex);
			pit_vtx->add(vtx);
		
			ssgVtxTable *pit = new ssgVtxTable(GL_TRIANGLE_STRIP, pit_vtx, pit_nrm, pit_tex, pit_clr);
			pit->setState(st);
			pit->setCullFace(0);
			ThePits->addKid(pit);
		}
	break;
	case TR_PIT_ON_SEPARATE_PATH:
	break;
	case TR_PIT_NONE:
	break;	
	}
}
Exemplo n.º 7
0
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;
}