void PxVehicleDriveSmoothAnalogRawInputsAndSetAnalogInputs (const PxVehiclePadSmoothingData& padSmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable, const PxVehicleDrive4WRawInputData& rawInputData, const PxF32 timestep, const bool isVehicleInAir, const PxVehicleWheels& vehicle, PxVehicleDriveDynData& driveDynData) { //gearup/geardown const bool gearup=rawInputData.getGearUp(); const bool geardown=rawInputData.getGearDown(); driveDynData.setGearUp(gearup); driveDynData.setGearDown(geardown); //Update analog inputs for focus vehicle. //Process the accel. { const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL]; const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL]; const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL); const PxF32 targetVal=rawInputData.getAnalogAccel(); const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL, accel); } //Process the brake { const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE]; const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE]; const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE); const PxF32 targetVal=rawInputData.getAnalogBrake(); const PxF32 brake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE, brake); } //Process the handbrake. { const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE]; const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE]; const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE); const PxF32 targetVal=rawInputData.getAnalogHandbrake(); const PxF32 handbrake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE, handbrake); } //Process the steer { const PxF32 vz=vehicle.computeForwardSpeed(); const PxF32 vzAbs=PxAbs(vz); const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT]; const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT]; const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT)-driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT); const PxF32 targetVal=rawInputData.getAnalogSteer()*(isVehicleInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs)); const PxF32 steer=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT, 0.0f); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT, steer); } }
void FPhysXVehicleManager::RemoveVehicle( TWeakObjectPtr<UWheeledVehicleMovementComponent> Vehicle ) { check(Vehicle != NULL); check(Vehicle->PVehicle); PxVehicleWheels* PVehicle = Vehicle->PVehicle; int32 RemovedIndex = Vehicles.Find(Vehicle); Vehicles.Remove( Vehicle ); PVehicles.Remove( PVehicle ); delete[] PVehiclesWheelsStates[RemovedIndex].wheelQueryResults; PVehiclesWheelsStates.RemoveAt(RemovedIndex); // LOC_MOD double check this //PVehiclesWheelsStates.Remove(PVehiclesWheelsStates[RemovedIndex]); if ( PVehicle == TelemetryVehicle ) { TelemetryVehicle = NULL; } switch( PVehicle->getVehicleType() ) { case PxVehicleTypes::eDRIVE4W: ((PxVehicleDrive4W*)PVehicle)->free(); break; case PxVehicleTypes::eDRIVETANK: ((PxVehicleDriveTank*)PVehicle)->free(); break; case PxVehicleTypes::eNODRIVE: ((PxVehicleNoDrive*)PVehicle)->free(); break; default: checkf( 0, TEXT("Unsupported vehicle type")); break; } }
void PxVehicleDriveSmoothDigitalRawInputsAndSetAnalogInputs (const PxVehicleKeySmoothingData& keySmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable, const PxVehicleDrive4WRawInputData& rawInputData, const PxF32 timestep, const bool isVehicleInAir, const PxVehicleWheels& vehicle, PxVehicleDriveDynData& driveDynData) { const bool gearup=rawInputData.getGearUp(); const bool geardown=rawInputData.getGearDown(); driveDynData.setGearDown(geardown); driveDynData.setGearUp(gearup); const PxF32 accel=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL,keySmoothing,rawInputData.getDigitalAccel(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL)); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL,accel); const PxF32 brake=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE,keySmoothing,rawInputData.getDigitalBrake(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE)); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE,brake); const PxF32 handbrake=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE,keySmoothing,rawInputData.getDigitalHandbrake(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE)); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE,handbrake); PxF32 steerLeft=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT,keySmoothing,rawInputData.getDigitalSteerLeft(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT)); PxF32 steerRight=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT,keySmoothing,rawInputData.getDigitalSteerRight(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT)); const PxF32 vz=vehicle.computeForwardSpeed(); const PxF32 vzAbs=PxAbs(vz); const PxF32 maxSteer=(isVehicleInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs)); const PxF32 steer=PxAbs(steerRight-steerLeft); if(steer>maxSteer) { const PxF32 k=maxSteer/steer; steerLeft*=k; steerRight*=k; } driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT, steerLeft); driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT, steerRight); }
void SampleVehicle_CameraController::update(const PxReal dtime, const PxVehicleWheels& focusVehicle, PxScene& scene) { const PxRigidDynamic* actor=focusVehicle.getRigidDynamicActor(); update(dtime,actor,scene); }
void SampleVehicle_VehicleController::update(const PxF32 timestep, PxVehicleWheels& focusVehicle) { PX_ASSERT(eVEHICLE_TYPE_DRIVE4W==focusVehicle.getVehicleType()); PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle; PxVehicleDriveDynData& driveDynData=vehDrive4W.mDriveDynData; //Toggle autogear flag if(mToggleAutoGears) { driveDynData.toggleAutoGears(); mToggleAutoGears = false; } //Store raw inputs in replay stream if in recording mode. //Set raw inputs from replay stream if in replay mode. //Store raw inputs from active stream in handy arrays so we don't need to worry //about which stream (live input or replay) is active. //Work out if we are using keys or gamepad controls depending on which is being used //(gamepad selected if both are being used). PxVehicleDrive4WRawInputData carRawInputs; processRawInputs(timestep,driveDynData.getUseAutoGears(),carRawInputs); //Work out if the car is to flip from reverse to forward gear or from forward gear to reverse. //Store if the car is moving slowly to help decide if the car is to toggle from reverse to forward in the next update. bool toggleAutoReverse = false; bool newIsMovingForwardSlowly = false; processAutoReverse(focusVehicle, driveDynData, carRawInputs, toggleAutoReverse, newIsMovingForwardSlowly); mIsMovingForwardSlowly = newIsMovingForwardSlowly; //If the car is to flip gear direction then switch gear as appropriate. if(toggleAutoReverse) { mInReverseMode = !mInReverseMode; if(mInReverseMode) { driveDynData.forceGearChange(PxVehicleGearsData::eREVERSE); } else { driveDynData.forceGearChange(PxVehicleGearsData::eFIRST); } } //If in reverse mode then swap the accel and brake. if(mInReverseMode) { if(mUseKeyInputs) { const bool accel=carRawInputs.getDigitalAccel(); const bool brake=carRawInputs.getDigitalBrake(); carRawInputs.setDigitalAccel(brake); carRawInputs.setDigitalBrake(accel); } else { const PxF32 accel=carRawInputs.getAnalogAccel(); const PxF32 brake=carRawInputs.getAnalogBrake(); carRawInputs.setAnalogAccel(brake); carRawInputs.setAnalogBrake(accel); } } // Now filter the raw input values and apply them to focus vehicle // as floats for brake,accel,handbrake,steer and bools for gearup,geardown. if(mUseKeyInputs) { PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(gKeySmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,(PxVehicleDrive4W&)focusVehicle); } else { PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(gCarPadSmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,(PxVehicleDrive4W&)focusVehicle); } }
void SampleVehicle_VehicleController::processAutoReverse (const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleDrive4WRawInputData& carRawInputs, bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const { newIsMovingForwardSlowly = false; toggleAutoReverse = false; if(driveDynData.getUseAutoGears()) { //If the car is travelling very slowly in forward gear without player input and the player subsequently presses the brake then we want the car to go into reverse gear //If the car is travelling very slowly in reverse gear without player input and the player subsequently presses the accel then we want the car to go into forward gear //If the car is in forward gear and is travelling backwards then we want to automatically put the car into reverse gear. //If the car is in reverse gear and is travelling forwards then we want to automatically put the car into forward gear. //(If the player brings the car to rest with the brake the player needs to release the brake then reapply it //to indicate they want to toggle between forward and reverse.) const bool prevIsMovingForwardSlowly=mIsMovingForwardSlowly; bool isMovingForwardSlowly=false; bool isMovingBackwards=false; const bool isInAir = focusVehicle.isInAir(); if(!isInAir) { bool accelRaw,brakeRaw,handbrakeRaw; if(mUseKeyInputs) { accelRaw=carRawInputs.getDigitalAccel(); brakeRaw=carRawInputs.getDigitalBrake(); handbrakeRaw=carRawInputs.getDigitalHandbrake(); } else { accelRaw=carRawInputs.getAnalogAccel() > 0 ? true : false; brakeRaw=carRawInputs.getAnalogBrake() > 0 ? true : false; handbrakeRaw=carRawInputs.getAnalogHandbrake() > 0 ? true : false; } const PxF32 forwardSpeed = focusVehicle.computeForwardSpeed(); const PxF32 forwardSpeedAbs = PxAbs(forwardSpeed); const PxF32 sidewaysSpeedAbs = PxAbs(focusVehicle.computeSidewaysSpeed()); const PxU32 currentGear = driveDynData.getCurrentGear(); const PxU32 targetGear = driveDynData.getTargetGear(); //Check if the car is rolling against the gear (backwards in forward gear or forwards in reverse gear). if(PxVehicleGearsData::eFIRST == currentGear && forwardSpeed < -THRESHOLD_ROLLING_BACKWARDS_SPEED) { isMovingBackwards = true; } else if(PxVehicleGearsData::eREVERSE == currentGear && forwardSpeed > THRESHOLD_ROLLING_BACKWARDS_SPEED) { isMovingBackwards = true; } //Check if the car is moving slowly. if(forwardSpeedAbs < THRESHOLD_FORWARD_SPEED && sidewaysSpeedAbs < THRESHOLD_SIDEWAYS_SPEED) { isMovingForwardSlowly=true; } //Now work if we need to toggle from forwards gear to reverse gear or vice versa. if(isMovingBackwards) { if(!accelRaw && !brakeRaw && !handbrakeRaw && (currentGear == targetGear)) { //The car is rolling against the gear and the player is doing nothing to stop this. toggleAutoReverse = true; } } else if(prevIsMovingForwardSlowly && isMovingForwardSlowly) { if((currentGear > PxVehicleGearsData::eNEUTRAL) && brakeRaw && !accelRaw && (currentGear == targetGear)) { //The car was moving slowly in forward gear without player input and is now moving slowly with player input that indicates the //player wants to switch to reverse gear. toggleAutoReverse = true; } else if(currentGear == PxVehicleGearsData::eREVERSE && accelRaw && !brakeRaw && (currentGear == targetGear)) { //The car was moving slowly in reverse gear without player input and is now moving slowly with player input that indicates the //player wants to switch to forward gear. toggleAutoReverse = true; } } //If the car was brought to rest through braking then the player needs to release the brake then reapply //to indicate that the gears should toggle between reverse and forward. if(isMovingForwardSlowly && !brakeRaw && !accelRaw && !handbrakeRaw) { newIsMovingForwardSlowly = true; } } } }
void SampleVehicle_VehicleController::update(const PxF32 timestep, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, PxVehicleWheels& focusVehicle) { PxVehicleDriveDynData* driveDynData=NULL; bool isTank=false; PxVehicleDriveTankControlModel::Enum tankDriveModel=PxVehicleDriveTankControlModel::eSTANDARD; switch(focusVehicle.getVehicleType()) { case PxVehicleTypes::eDRIVE4W: { PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle; driveDynData=&vehDrive4W.mDriveDynData; isTank=false; } break; case PxVehicleTypes::eDRIVENW: { PxVehicleDriveNW& vehDriveNW=(PxVehicleDriveNW&)focusVehicle; driveDynData=&vehDriveNW.mDriveDynData; isTank=false; } break; case PxVehicleTypes::eDRIVETANK: { PxVehicleDriveTank& vehDriveTank=(PxVehicleDriveTank&)focusVehicle; driveDynData=&vehDriveTank.mDriveDynData; isTank=true; tankDriveModel=vehDriveTank.getDriveModel(); } break; default: PX_ASSERT(false); break; } //Toggle autogear flag if(mToggleAutoGears) { driveDynData->toggleAutoGears(); mToggleAutoGears = false; } //Store raw inputs in replay stream if in recording mode. //Set raw inputs from replay stream if in replay mode. //Store raw inputs from active stream in handy arrays so we don't need to worry //about which stream (live input or replay) is active. //Work out if we are using keys or gamepad controls depending on which is being used //(gamepad selected if both are being used). PxVehicleDrive4WRawInputData carRawInputs; PxVehicleDriveTankRawInputData tankRawInputs(tankDriveModel); if(!isTank) { processRawInputs(timestep,driveDynData->getUseAutoGears(),carRawInputs); } else { processRawInputs(timestep,driveDynData->getUseAutoGears(),tankRawInputs); } //Work out if the car is to flip from reverse to forward gear or from forward gear to reverse. bool toggleAutoReverse = false; bool newIsMovingForwardSlowly = false; if(!isTank) { processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, carRawInputs, toggleAutoReverse, newIsMovingForwardSlowly); } else { processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, tankRawInputs, toggleAutoReverse, newIsMovingForwardSlowly); } mIsMovingForwardSlowly = newIsMovingForwardSlowly; //If the car is to flip gear direction then switch gear as appropriate. if(toggleAutoReverse) { mInReverseMode = !mInReverseMode; if(mInReverseMode) { driveDynData->forceGearChange(PxVehicleGearsData::eREVERSE); } else { driveDynData->forceGearChange(PxVehicleGearsData::eFIRST); } } //If in reverse mode then swap the accel and brake. if(mInReverseMode) { if(mUseKeyInputs) { if(!isTank) { const bool accel=carRawInputs.getDigitalAccel(); const bool brake=carRawInputs.getDigitalBrake(); carRawInputs.setDigitalAccel(brake); carRawInputs.setDigitalBrake(accel); } else { //Keyboard controls for tank not implemented yet. const bool accelLeft=tankRawInputs.getDigitalLeftThrust(); const bool accelRight=tankRawInputs.getDigitalRightThrust(); const bool brakeLeft=tankRawInputs.getDigitalLeftBrake(); const bool brakeRight=tankRawInputs.getDigitalRightBrake(); tankRawInputs.setDigitalLeftThrust(brakeLeft); tankRawInputs.setDigitalRightThrust(brakeRight); tankRawInputs.setDigitalLeftBrake(accelLeft); tankRawInputs.setDigitalRightBrake(accelRight); } } else { if(!isTank) { const PxF32 accel=carRawInputs.getAnalogAccel(); const PxF32 brake=carRawInputs.getAnalogBrake(); carRawInputs.setAnalogAccel(brake); carRawInputs.setAnalogBrake(accel); } else if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel) { const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust(); const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust(); tankRawInputs.setAnalogLeftThrust(-thrustLeft); tankRawInputs.setAnalogRightThrust(-thrustRight); } else { const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust(); const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust(); const PxF32 brakeLeft=tankRawInputs.getAnalogLeftBrake(); const PxF32 brakeRight=tankRawInputs.getAnalogRightBrake(); tankRawInputs.setAnalogLeftThrust(brakeLeft); tankRawInputs.setAnalogLeftBrake(thrustLeft); tankRawInputs.setAnalogRightThrust(brakeRight); tankRawInputs.setAnalogRightBrake(thrustRight); } } } // Now filter the raw input values and apply them to focus vehicle // as floats for brake,accel,handbrake,steer and bools for gearup,geardown. if(mUseKeyInputs) { if(!isTank) { const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs (gKeySmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle); } else { PxVehicleDriveTankSmoothDigitalRawInputsAndSetAnalogInputs (gKeySmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle); } } else { if(!isTank) { const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults); PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs (gCarPadSmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle); } else { PxVehicleDriveTankSmoothAnalogRawInputsAndSetAnalogInputs (gTankPadSmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle); } } }
void PxVehicleCopyDynamicsData(const PxVehicleCopyDynamicsMap& wheelMap, const PxVehicleWheels& src, PxVehicleWheels* trg) { PX_CHECK_AND_RETURN(trg, "PxVehicleCopyDynamicsData requires that trg is a valid vehicle pointer"); PX_CHECK_AND_RETURN(src.getVehicleType() == trg->getVehicleType(), "PxVehicleCopyDynamicsData requires that both src and trg are the same type of vehicle"); #ifdef PX_CHECKED { const PxU32 numWheelsSrc = src.mWheelsSimData.getNbWheels(); const PxU32 numWheelsTrg = trg->mWheelsSimData.getNbWheels(); PxU8 copiedWheelsSrc[PX_MAX_NB_WHEELS]; PxMemZero(copiedWheelsSrc, sizeof(PxU8) * PX_MAX_NB_WHEELS); PxU8 setWheelsTrg[PX_MAX_NB_WHEELS]; PxMemZero(setWheelsTrg, sizeof(PxU8) * PX_MAX_NB_WHEELS); for(PxU32 i = 0; i < PxMin(numWheelsSrc, numWheelsTrg); i++) { const PxU32 srcWheelId = wheelMap.sourceWheelIds[i]; PX_CHECK_AND_RETURN(srcWheelId < numWheelsSrc, "PxVehicleCopyDynamicsData - wheelMap contains illegal source wheel id"); PX_CHECK_AND_RETURN(0 == copiedWheelsSrc[srcWheelId], "PxVehicleCopyDynamicsData - wheelMap contains illegal source wheel id"); copiedWheelsSrc[srcWheelId] = 1; const PxU32 trgWheelId = wheelMap.targetWheelIds[i]; PX_CHECK_AND_RETURN(trgWheelId < numWheelsTrg, "PxVehicleCopyDynamicsData - wheelMap contains illegal target wheel id"); PX_CHECK_AND_RETURN(0 == setWheelsTrg[trgWheelId], "PxVehicleCopyDynamicsData - wheelMap contains illegal target wheel id"); setWheelsTrg[trgWheelId]=1; } } #endif const PxU32 numWheelsSrc = src.mWheelsSimData.getNbWheels(); const PxU32 numWheelsTrg = trg->mWheelsSimData.getNbWheels(); //Set all dynamics data on the target to zero. //Be aware that setToRestState sets the rigid body to //rest so set the momentum back after calling setToRestState. PxRigidDynamic* actorTrg = trg->getRigidDynamicActor(); PxVec3 linVel = actorTrg->getLinearVelocity(); PxVec3 angVel = actorTrg->getAngularVelocity(); switch(src.getVehicleType()) { case PxVehicleTypes::eDRIVE4W: ((PxVehicleDrive4W*)trg)->setToRestState(); break; case PxVehicleTypes::eDRIVENW: ((PxVehicleDriveNW*)trg)->setToRestState(); break; case PxVehicleTypes::eDRIVETANK: ((PxVehicleDriveTank*)trg)->setToRestState(); break; case PxVehicleTypes::eNODRIVE: ((PxVehicleNoDrive*)trg)->setToRestState(); break; default: break; } actorTrg->setLinearVelocity(linVel); actorTrg->setAngularVelocity(angVel); //Keep a track of the wheels on trg that have their dynamics data set as a copy from src. PxU8 setWheelsTrg[PX_MAX_NB_WHEELS]; PxMemZero(setWheelsTrg, sizeof(PxU8) * PX_MAX_NB_WHEELS); //Keep a track of the average wheel rotation speed of all enabled wheels on src. PxU32 numEnabledWheelsSrc = 0; PxF32 accumulatedWheelRotationSpeedSrc = 0.0f; //Copy wheel dynamics data from src wheels to trg wheels. //Track the target wheels that have been given dynamics data from src wheels. //Compute the accumulated wheel rotation speed of all enabled src wheels. const PxU32 numMappedWheels = PxMin(numWheelsSrc, numWheelsTrg); for(PxU32 i = 0; i < numMappedWheels; i++) { const PxU32 srcWheelId = wheelMap.sourceWheelIds[i]; const PxU32 trgWheelId = wheelMap.targetWheelIds[i]; trg->mWheelsDynData.copy(src.mWheelsDynData, srcWheelId, trgWheelId); setWheelsTrg[trgWheelId] = 1; if(!src.mWheelsSimData.getIsWheelDisabled(srcWheelId)) { numEnabledWheelsSrc++; accumulatedWheelRotationSpeedSrc += src.mWheelsDynData.getWheelRotationSpeed(srcWheelId); } } //Compute the average wheel rotation speed of src. PxF32 averageWheelRotationSpeedSrc = 0; if(numEnabledWheelsSrc > 0) { averageWheelRotationSpeedSrc = (accumulatedWheelRotationSpeedSrc/ (1.0f * numEnabledWheelsSrc)); } //For wheels on trg that have not had their dynamics data copied from src just set //their wheel rotation speed to the average wheel rotation speed. for(PxU32 i = 0; i < numWheelsTrg; i++) { if(0 == setWheelsTrg[i] && !trg->mWheelsSimData.getIsWheelDisabled(i)) { trg->mWheelsDynData.setWheelRotationSpeed(i, averageWheelRotationSpeedSrc); } } //Copy the engine rotation speed/gear states/autobox states/etc. switch(src.getVehicleType()) { case PxVehicleTypes::eDRIVE4W: case PxVehicleTypes::eDRIVENW: case PxVehicleTypes::eDRIVETANK: { const PxVehicleDriveDynData& driveDynDataSrc = ((const PxVehicleDrive&)src).mDriveDynData; PxVehicleDriveDynData* driveDynDataTrg = &((PxVehicleDrive*)trg)->mDriveDynData; *driveDynDataTrg = driveDynDataSrc; } break; default: break; } }