/** Updates skidding status. * \param dt Time step size. * \param is_on_ground True if the kart is on ground. * \param steering Raw steering of the kart [-1,1], i.e. not adjusted by * the kart's max steering angle. * \param skidding True if the skid button is pressed. */ void Skidding::update(float dt, bool is_on_ground, float steering, KartControl::SkidControl skidding) { // If a kart animation is shown, stop all skidding bonuses. if(m_kart->getKartAnimation()) { reset(); return; } m_skid_bonus_ready = false; if (is_on_ground) { if((fabs(steering) > 0.001f) && m_kart->getSpeed()>m_min_skid_speed && (skidding==KartControl::SC_LEFT||skidding==KartControl::SC_RIGHT)) { m_skid_factor += m_skid_increase *dt/m_time_till_max_skid; } else if(m_skid_factor>1.0f) { m_skid_factor *= m_skid_decrease; } } else { m_skid_factor = 1.0f; // Lose any skid factor as soon as we fly } if(m_skid_factor>m_skid_max) m_skid_factor = m_skid_max; else if(m_skid_factor<1.0f) m_skid_factor = 1.0f; // FIXME hiker: remove once the new skidding code is finished. if(m_skid_state == SKID_OLD) { updateSteering(steering, dt); return; } // If skidding was started and a graphical jump should still // be displayed, update the data if(m_remaining_jump_time>0) { m_jump_speed -= World::getWorld()->getTrack()->getGravity()*dt; m_gfx_jump_offset += m_jump_speed * dt; m_remaining_jump_time -= dt; if(m_remaining_jump_time<0) { m_remaining_jump_time = 0.0f; m_gfx_jump_offset = 0.0f; } } // This is only reached if the new skidding is enabled // --------------------------------------------------- // There are four distinct states related to skidding, controlled // by m_skid_state: // SKID_NONE: no skidding is happening. From here SKID_ACCUMULATE // is reached when the skid key is pressed. // SKID_ACCUMULATE_{LEFT,RIGHT}: // The kart is still skidding. The skidding time will be // accumulated in m_skid_time, and once the minimum time for a // bonus is reached, the "bonus gfx now available" gfx is shown. // If the skid button is not pressed anymore, this will trigger // a potential bonus. Also the rotation of the physical body to // be in synch with the graphical kart is started (which is // independently handled in the kart physics). // SKID_SHOW_GFX_{LEFT<RIGHT} // Shows the skidding gfx while the bonus is available. // FIXME: what should we do if skid key is pressed while still in // SKID_SHOW_GFX??? Adjusting the body rotation is difficult. // For now skidding will only start again once SKID_SHOW_GFX // is changed to SKID_NONE. switch(m_skid_state) { case SKID_NONE: { if(skidding!=KartControl::SC_LEFT && skidding!=KartControl::SC_RIGHT) break; // Don't allow skidding while the kart is (apparently) // still in the air, or when the kart is too slow if(m_remaining_jump_time>0 || m_kart->getSpeed() <m_min_skid_speed) break; m_skid_state = skidding==KartControl::SC_RIGHT ? SKID_ACCUMULATE_RIGHT : SKID_ACCUMULATE_LEFT; // Add a little jump to the kart. Determine the vertical speed // necessary for the kart to go 0.5*jump_time up (then it needs // the same time to come down again), based on v = gravity * t. // Then use this speed to determine the impulse necessary to // reach this speed. float v = World::getWorld()->getTrack()->getGravity() * 0.5f*m_physical_jump_time; btVector3 imp(0, v / m_kart->getBody()->getInvMass(),0); m_kart->getVehicle()->getRigidBody()->applyCentralImpulse(imp); // Some karts might use a graphical-only jump. Set it up: m_jump_speed = World::getWorld()->getTrack()->getGravity() * 0.5f*m_graphical_jump_time; m_remaining_jump_time = m_graphical_jump_time; #ifdef SKID_DEBUG #define SPEED 20.0f updateSteering(steering, dt); m_actual_curve->clear(); m_actual_curve->setVisible(true); m_predicted_curve->clear(); m_predicted_curve->setVisible(true); m_predicted_curve->setPosition(m_kart->getXYZ()); m_predicted_curve->setHeading(m_kart->getHeading()); float angle = m_kart->getKartProperties() ->getMaxSteerAngle(m_kart->getSpeed()) * fabsf(getSteeringFraction()); angle = m_kart->getKartProperties() ->getMaxSteerAngle(SPEED) * fabsf(getSteeringFraction()); float r = m_kart->getKartProperties()->getWheelBase() / asin(angle)*1.0f; const int num_steps = 50; float dx = 2*r / num_steps; for(float x = 0; x <=2*r; x+=dx) { float real_x = m_skid_state==SKID_ACCUMULATE_LEFT ? -x : x; Vec3 xyz(real_x, 0.2f, sqrt(r*r-(r-x)*(r-x))*(1.0f+SPEED/150.0f) *(1+(angle/m_kart->getKartProperties()->getMaxSteerAngle(SPEED)-0.6f)*0.1f)); Vec3 xyz1=m_kart->getTrans()(xyz); printf("predict %f %f %f speed %f angle %f\n", xyz1.getX(), xyz1.getY(), xyz1.getZ(), m_kart->getSpeed(), angle); m_predicted_curve->addPoint(xyz); } #endif m_skid_time = 0; // fallthrough } case SKID_ACCUMULATE_LEFT: case SKID_ACCUMULATE_RIGHT: { #ifdef SKID_DEBUG Vec3 v=m_kart->getVelocity(); if(v.length()>5) { float r = SPEED/sqrt(v.getX()*v.getX() + v.getZ()*v.getZ()); v.setX(v.getX()*r); v.setZ(v.getZ()*r); m_kart->getBody()->setLinearVelocity(v); } m_actual_curve->addPoint(m_kart->getXYZ()); printf("actual %f %f %f turn %f speed %f angle %f\n", m_kart->getXYZ().getX(),m_kart->getXYZ().getY(),m_kart->getXYZ().getZ(), m_real_steering, m_kart->getSpeed(), m_kart->getKartProperties()->getMaxSteerAngle(m_kart->getSpeed())); #endif m_skid_time += dt; float bonus_time, bonus_speed, bonus_force; unsigned int level = getSkidBonus(&bonus_time, &bonus_speed, &bonus_force); // If at least level 1 bonus is reached, show appropriate gfx if(level>0) { m_skid_bonus_ready = true; m_kart->getKartGFX()->setSkidLevel(level); } // If player stops skidding, trigger bonus, and change state to // SKID_SHOW_GFX_* if(skidding == KartControl::SC_NONE) { m_skid_state = m_skid_state == SKID_ACCUMULATE_LEFT ? SKID_SHOW_GFX_LEFT : SKID_SHOW_GFX_RIGHT; float t = std::min(m_skid_time, m_skid_visual_time); t = std::min(t, m_skid_revert_visual_time); float vso = getVisualSkidRotation(); btVector3 rot(0, vso*m_post_skid_rotate_factor, 0); m_kart->getVehicle()->setTimedRotation(t, rot); // skid_time is used to count backwards for the GFX m_skid_time = t; if(bonus_time>0) { m_kart->getKartGFX() ->setCreationRateRelative(KartGFX::KGFX_SKID, 1.0f); m_kart->m_max_speed-> instantSpeedIncrease(MaxSpeed::MS_INCREASE_SKIDDING, bonus_speed, bonus_speed, bonus_force, bonus_time, /*fade-out-time*/ 1.0f); } else m_kart->getKartGFX() ->setCreationRateAbsolute(KartGFX::KGFX_SKID, 0); } break; } // case case SKID_SHOW_GFX_LEFT: case SKID_SHOW_GFX_RIGHT: m_skid_time -= dt; if(m_skid_time<=0) { m_skid_time = 0; m_kart->getKartGFX() ->setCreationRateAbsolute(KartGFX::KGFX_SKID, 0); m_skid_state = SKID_NONE; } } // switch updateSteering(steering, dt); } // update
void AckermannKalmanFilter::updateRearWheelDisplacementsSteering(double dLeftWheel, double dRightWheel, double steering, double timestamp) { updateFrontLeftWheelDisplacementSteering(dLeftWheel, steering, timestamp); updateFrontRightWheelDisplacementSteering(dRightWheel, steering, timestamp); updateSteering(steering, timestamp); }