示例#1
0
/** 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);
 }