Beispiel #1
0
void PhysicsVehicle::update(float elapsedTime, float steering, float braking, float driving)
{
    float v = getSpeedKph();
    //MathUtil::smooth(&_speedSmoothed, v, elapsedTime, 0, 1200);
	kmSmooth(&_speedSmoothed, v, elapsedTime, 0, 1200);
    if (elapsedTime > 0)
    {
        // Avoid accumulation of downforce while paused (zero elapsedTime)
        applyDownforce();
    }

    // Adjust control inputs based on vehicle speed.
    steering = getSteering(v, steering);
    driving = getDriving(v, driving, braking);
    braking = getBraking(v, braking);

    // Allow braking to take precedence over driving.
    if (driving > 0 && braking > 0)
    {
        driving = 0;
    }

    PhysicsVehicleWheel* wheel;
    for (int i = 0; i < _vehicle->getNumWheels(); i++)
    {
        wheel = getWheel(i);

        if (wheel->isSteerable())
        {
            _vehicle->setSteeringValue(steering * _steeringGain, i);
        }
        else
        {
            _vehicle->applyEngineForce(driving * _drivingForce, i);
            _vehicle->setBrake(braking * _brakingForce, i);
        }

        wheel->update(elapsedTime);
        wheel->transform(wheel->getNode());
    }
}
Beispiel #2
0
void VehicleObject::tickPhysics(float dt)
{
	RW_UNUSED(dt);

	if( physVehicle )
	{
		// todo: a real engine function
		float velFac = info->handling.maxVelocity;
		float engineForce = info->handling.acceleration * throttle * velFac;
		if (fabs(engineForce) >= 0.001f) {
			collision->getBulletBody()->activate(true);
		}

		float brakeF = getBraking();
		
		if( handbrake )
		{
			brakeF = 5.f;
		}

		for(int w = 0; w < physVehicle->getNumWheels(); ++w) {
			btWheelInfo& wi = physVehicle->getWheelInfo(w);
			if( info->handling.driveType == VehicleHandlingInfo::All ||
					(info->handling.driveType == VehicleHandlingInfo::Forward && wi.m_bIsFrontWheel) ||
					(info->handling.driveType == VehicleHandlingInfo::Rear && !wi.m_bIsFrontWheel))
			{
					physVehicle->applyEngineForce(engineForce, w);
			}

			float brakeReal = 5.f * info->handling.brakeDeceleration * (wi.m_bIsFrontWheel? info->handling.brakeBias : 1.f - info->handling.brakeBias);
			physVehicle->setBrake(brakeReal * brakeF, w);

			if(wi.m_bIsFrontWheel) {
				float sign = std::signbit(steerAngle) ? -1.f : 1.f;
				physVehicle->setSteeringValue(std::min(info->handling.steeringLock*(3.141f/180.f), std::abs(steerAngle)) * sign, w);
				//physVehicle->setSteeringValue(std::min(3.141f/2.f, std::abs(steerAngle)) * sign, w);
			}
		}

		// Update passenger positions
		for (auto& seat : seatOccupants)
		{
			auto character = static_cast<CharacterObject*>(seat.second);

			glm::vec3 passPosition;
			if (character->isEnteringOrExitingVehicle())
			{
				passPosition = getSeatEntryPositionWorld(seat.first);
			}
			else
			{
				passPosition = getPosition();
				if (seat.first < info->seats.size()) {
					passPosition += getRotation() * (info->seats[seat.first].offset);
				}
			}
			seat.second->updateTransform(passPosition, getRotation());
		}

		if( vehicle->type == VehicleData::BOAT ) {
			if( isInWater() ) {
				float sign = std::signbit(steerAngle) ? -1.f : 1.f;
				float steer = std::min(info->handling.steeringLock*(3.141f/180.f), std::abs(steerAngle)) * sign;
				auto orient = collision->getBulletBody()->getOrientation();

				// Find the local-space velocity
				auto velocity = collision->getBulletBody()->getLinearVelocity();
				velocity = velocity.rotate(-orient.getAxis(), orient.getAngle());

				// Rudder force is proportional to velocity.
				float rAngle = steer * (velFac * 0.5f + 0.5f);
				btVector3 rForce = btVector3(1000.f * velocity.y() * rAngle, 0.f, 0.f)
						.rotate(orient.getAxis(), orient.getAngle());
				btVector3 rudderPoint = btVector3(0.f, -info->handling.dimensions.y/2.f, 0.f)
						.rotate(orient.getAxis(), orient.getAngle());
				collision->getBulletBody()->applyForce(
							rForce,
							rudderPoint);

				btVector3 rudderVector = btVector3(0.f, 1.f, 0.f)
						.rotate(orient.getAxis(), orient.getAngle());
				collision->getBulletBody()->applyForce(
							rudderVector * engineForce * 100.f,
							rudderPoint);


				btVector3 dampforce( 10000.f * velocity.x(), velocity.y() * 100.f, 0.f );
				collision->getBulletBody()->applyCentralForce(-dampforce.rotate(orient.getAxis(), orient.getAngle()));
			}
		}

		const auto& ws = getPosition();
		auto wX = (int) ((ws.x + WATER_WORLD_SIZE/2.f) / (WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE));
		auto wY = (int) ((ws.y + WATER_WORLD_SIZE/2.f) / (WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE));
		btVector3 bbmin, bbmax;
		// This is in world space.
		collision->getBulletBody()->getAabb(bbmin, bbmax);
		float vH = bbmin.z();
		float wH = 0.f;


		if( wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 && wY < WATER_HQ_DATA_SIZE ) {
			int i = (wX*WATER_HQ_DATA_SIZE) + wY;
			int hI = engine->data->realWater[i];
			if( hI < NO_WATER_INDEX ) {
				wH = engine->data->waterHeights[hI];
				wH += engine->data->getWaveHeightAt(ws);
				// If the vehicle is currently underwater
				if( vH <= wH ) {
					// and was not underwater here in the last tick
					if( _lastHeight >= wH ) {
						// we are for real, underwater
						inWater = true;
					}
					else if( inWater == false ) {
						// It's just a tunnel or something, we good.
						inWater = false;
					}
				}
				else {
					// The water is beneath us
					inWater = false;
				}
			}
			else {
				inWater = false;
			}
		}

		if( inWater ) {
			// Ensure that vehicles don't fall asleep at the top of a wave.
			if(! collision->getBulletBody()->isActive() )
			{
				collision->getBulletBody()->activate(true);
			}
			
			float bbZ = info->handling.dimensions.z/2.f;

			float oZ = 0.f;
			oZ = -bbZ/2.f + (bbZ * (info->handling.percentSubmerged/120.f));

			if( vehicle->type != VehicleData::BOAT ) {
				// Damper motion
				collision->getBulletBody()->setDamping(0.95f, 0.9f);
			}

			if( vehicle->type == VehicleData::BOAT ) {
				oZ = 0.f;
			}

			// Boats, Buoyancy offset is affected by the orientation of the chassis.
			// Vehicles, it isn't.
			glm::vec3 vFwd = glm::vec3(0.f, info->handling.dimensions.y/2.f, oZ),
					vBack = glm::vec3(0.f, -info->handling.dimensions.y/2.f, oZ);
			glm::vec3 vRt = glm::vec3( info->handling.dimensions.x/2.f, 0.f, oZ),
					vLeft = glm::vec3(-info->handling.dimensions.x/2.f, 0.f, oZ);

			vFwd = getRotation() * vFwd;
			vBack = getRotation() * vBack;
			vRt = getRotation() * vRt;
			vLeft = getRotation() * vLeft;

			// This function will try to keep v* at the water level.
			applyWaterFloat( vFwd);
			applyWaterFloat( vBack);
			applyWaterFloat( vRt);
			applyWaterFloat( vLeft);
		}
		else {
			if( vehicle->type == VehicleData::BOAT ) {
				collision->getBulletBody()->setDamping(0.1f, 0.8f);
			}
			else {
				collision->getBulletBody()->setDamping(0.05f, 0.0f);
			}
		}

		_lastHeight = vH;

		// Update hinge object rotations
		for(auto& it : dynamicParts) {
			if(it.second.body == nullptr) continue;
			if( it.second.moveToAngle )
			{
				auto angledelta = it.second.targetAngle - it.second.constraint->getHingeAngle();
				if( glm::abs(angledelta) <= 0.01f )
				{
					it.second.constraint->enableAngularMotor(false, 1.f, 1.f);
					dynamicParts[it.first].moveToAngle = false;
				}
				else
				{
					it.second.constraint->enableAngularMotor(true, glm::sign(angledelta) * 5.f, 1.f);
				}
			}
			
			// If the part is moving quite fast and near the limit, lock it.
			/// @TODO not all parts rotate in the z axis.
			float zspeed = it.second.body->getAngularVelocity().getZ();
			if(it.second.openAngle < 0.f) zspeed = -zspeed;
			if(zspeed >= PART_CLOSE_VELOCITY)
			{
				auto d = it.second.constraint->getHingeAngle() - it.second.closedAngle;
				if( glm::abs(d) < 0.05f )
				{
					dynamicParts[it.first].moveToAngle = false;
					setPartLocked(&(it.second), true);
				}
			}
		}
	}
}