/** Rotates and turns the wheels appropriately, and adjust for suspension * updates the speed-weighted objects' animations. * * \param dt time since last frame * \param distance How far the wheels have rotated since last time. * \param steer The actual steer settings. * \param suspension Suspension height for all four wheels. * \param speed The speed of the kart in meters/sec, used for the * speed-weighted objects' animations * \param current_lean_angle How much the kart is leaning (positive meaning * left side down) * \param gt_replay_index The index to get replay data, used by ghost kart */ void KartModel::update(float dt, float distance, float steer, float speed, float current_lean_angle, int gt_replay_index) { core::vector3df wheel_steer(0, steer*30.0f, 0); for(unsigned int i=0; i<4; i++) { if (!m_kart || !m_wheel_node[i]) continue; #ifdef DEBUG if (UserConfigParams::m_physics_debug && !m_kart->isGhostKart()) { const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i); // Make wheels that are not touching the ground invisible m_wheel_node[i]->setVisible(wi.m_raycastInfo.m_isInContact); } #endif core::vector3df pos = m_wheel_graphics_position[i].toIrrVector(); float suspension_length = 0.0f; GhostKart* gk = dynamic_cast<GhostKart*>(m_kart); // Prevent using m_default_physics_suspension uninitialized if (gk && gt_replay_index == -1) break; if (gk) { suspension_length = gk->getSuspensionLength(gt_replay_index, i); } else { suspension_length = m_kart->getVehicle()->getWheelInfo(i). m_raycastInfo.m_suspensionLength; } // Check documentation of Kart::updateGraphics for the following line pos.Y += m_default_physics_suspension[i] - suspension_length - m_kart_lowest_point; // Adjust the wheel position for lean: the lean can cause the 'leaned // to' side to be partly in the ground - which looks ok (like the tyres // being compressed), but the other side will be in the air. To avoid // this, increase the position of the wheels on the side that are // higher in the ground so that the wheel still touch the ground. if(current_lean_angle > 0 && (i&1) == 1) // i&1 == 0: left side { pos.Y -= 2*current_lean_angle; } else if (current_lean_angle < 0 && (i&1) == 0) // i&1 == 1: right side { pos.Y += 2*current_lean_angle; } m_wheel_node[i]->setPosition(pos); // Now calculate the new rotation: (old + change) mod 360 float new_rotation = m_wheel_node[i]->getRotation().X + distance / m_wheel_graphics_radius[i] * RAD_TO_DEGREE; new_rotation = fmodf(new_rotation, 360); core::vector3df wheel_rotation(new_rotation, 0, 0); // Only apply steer to first 2 wheels. if (i < 2) wheel_rotation += wheel_steer; m_wheel_node[i]->setRotation(wheel_rotation); } // for (i < 4) // If animations are disabled, stop here if (m_animated_node == NULL) return; if (m_play_non_loop && m_animated_node->getLoopMode() == true) { m_play_non_loop = false; this->setAnimation(AF_DEFAULT); } // Update the speed-weighted objects' animations if (m_kart != NULL) { for (size_t i = 0; i < m_speed_weighted_objects.size(); i++) { SpeedWeightedObject& obj = m_speed_weighted_objects[i]; #define GET_VALUE(obj, value_name) \ obj.m_properties.value_name > SPEED_WEIGHTED_OBJECT_PROPERTY_UNDEFINED ? obj.m_properties.value_name : \ m_kart->getKartProperties()->getSpeedWeightedObjectProperties().value_name // Animation strength float strength = 1.0f; const float strength_factor = GET_VALUE(obj, m_strength_factor); if (strength_factor >= 0.0f) { strength = speed * strength_factor; btClamp<float>(strength, 0.0f, 1.0f); } // Animation speed const float speed_factor = GET_VALUE(obj, m_speed_factor); if (speed_factor >= 0.0f) { float anim_speed = speed * speed_factor; obj.m_node->setAnimationSpeed(anim_speed); } // Texture animation core::vector2df tex_speed; tex_speed.X = GET_VALUE(obj, m_texture_speed.X); tex_speed.Y = GET_VALUE(obj, m_texture_speed.Y); if (tex_speed != core::vector2df(0.0f, 0.0f)) { obj.m_texture_cur_offset += speed * tex_speed * dt; if (obj.m_texture_cur_offset.X > 1.0f) obj.m_texture_cur_offset.X = fmod(obj.m_texture_cur_offset.X, 1.0f); if (obj.m_texture_cur_offset.Y > 1.0f) obj.m_texture_cur_offset.Y = fmod(obj.m_texture_cur_offset.Y, 1.0f); for (unsigned int i = 0; i < obj.m_node->getMaterialCount(); i++) { video::SMaterial &irrMaterial = obj.m_node->getMaterial(i); for (unsigned int j = 0; j < video::MATERIAL_MAX_TEXTURES; j++) { video::ITexture* t = irrMaterial.getTexture(j); if (!t) continue; core::matrix4 *m = &irrMaterial.getTextureMatrix(j); m->setTextureTranslate(obj.m_texture_cur_offset.X, obj.m_texture_cur_offset.Y); } // for j<MATERIAL_MAX_TEXTURES } // for i<getMaterialCount } #undef GET_VALUE } } // Check if the end animation is being played, if so, don't // play steering animation. if(m_current_animation!=AF_DEFAULT) return; if(m_animation_frame[AF_LEFT]<0) return; // no animations defined // Update animation if necessary // ----------------------------- float frame; if(steer>0.0f) frame = m_animation_frame[AF_STRAIGHT] - ( ( m_animation_frame[AF_STRAIGHT] -m_animation_frame[AF_RIGHT] )*steer); else if(steer<0.0f) frame = m_animation_frame[AF_STRAIGHT] + ( (m_animation_frame[AF_STRAIGHT] -m_animation_frame[AF_LEFT] )*steer); else frame = (float)m_animation_frame[AF_STRAIGHT]; m_animated_node->setCurrentFrame(frame); } // update
/** Rotates and turns the wheels appropriately, and adjust for suspension + updates the speed-weighted objects' animations. * \param dt time since last frame * \param rotation_dt How far the wheels have rotated since last time. * \param steer The actual steer settings. * \param suspension Suspension height for all four wheels. * \param speed The speed of the kart in meters/sec, used for the * speed-weighted objects' animations */ void KartModel::update(float dt, float rotation_dt, float steer, float speed) { core::vector3df wheel_steer(0, steer*30.0f, 0); for(unsigned int i=0; i<4; i++) { if(!m_wheel_node[i]) continue; const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i); #ifdef DEBUG if(UserConfigParams::m_physics_debug && m_kart) { // Make wheels that are not touching the ground invisible m_wheel_node[i]->setVisible(wi.m_raycastInfo.m_isInContact); } #endif float rel_suspension = wi.m_raycastInfo.m_suspensionLength - m_default_physics_suspension[i]; // If the suspension is too compressed if(rel_suspension< m_min_suspension[i]) rel_suspension = m_min_suspension[i]; else if(rel_suspension > m_max_suspension[i]) rel_suspension = m_max_suspension[i]; core::vector3df pos = m_wheel_graphics_position[i].toIrrVector(); pos.Y -= rel_suspension; m_wheel_node[i]->setPosition(pos); // Now calculate the new rotation: (old + change) mod 360 float new_rotation = m_wheel_node[i]->getRotation().X + rotation_dt * RAD_TO_DEGREE; new_rotation = fmodf(new_rotation, 360); core::vector3df wheel_rotation(new_rotation, 0, 0); // Only apply steer to first 2 wheels. if (i < 2) wheel_rotation += wheel_steer; m_wheel_node[i]->setRotation(wheel_rotation); } // for (i < 4) // If animations are disabled, stop here if (m_animated_node == NULL) return; // Update the speed-weighted objects' animations for(size_t i=0 ; i < m_speed_weighted_objects.size() ; i++) { SpeedWeightedObject& obj = m_speed_weighted_objects[i]; #define GET_VALUE(obj, value_name) \ obj.m_properties.value_name > SPEED_WEIGHTED_OBJECT_PROPERTY_UNDEFINED ? obj.m_properties.value_name : \ m_kart->getKartProperties()->getSpeedWeightedObjectProperties().value_name // Animation strength float strength = 1.0f; const float strength_factor = GET_VALUE(obj, m_strength_factor); if(strength_factor >= 0.0f) { strength = speed * strength_factor; btClamp<float>(strength, 0.0f, 1.0f); } // Animation speed const float speed_factor = GET_VALUE(obj, m_speed_factor); if(speed_factor >= 0.0f) { float anim_speed = speed * speed_factor; obj.m_node->setAnimationSpeed(anim_speed); } // Texture animation core::vector2df tex_speed; tex_speed.X = GET_VALUE(obj, m_texture_speed.X); tex_speed.Y = GET_VALUE(obj, m_texture_speed.Y); if(tex_speed != core::vector2df(0.0f, 0.0f)) { obj.m_texture_cur_offset += speed * tex_speed * dt; if(obj.m_texture_cur_offset.X > 1.0f) obj.m_texture_cur_offset.X = fmod(obj.m_texture_cur_offset.X, 1.0f); if(obj.m_texture_cur_offset.Y > 1.0f) obj.m_texture_cur_offset.Y = fmod(obj.m_texture_cur_offset.Y, 1.0f); for(unsigned int i=0; i<obj.m_node->getMaterialCount(); i++) { video::SMaterial &irrMaterial=obj.m_node->getMaterial(i); for(unsigned int j=0; j<video::MATERIAL_MAX_TEXTURES; j++) { video::ITexture* t=irrMaterial.getTexture(j); if(!t) continue; core::matrix4 *m = &irrMaterial.getTextureMatrix(j); m->setTextureTranslate(obj.m_texture_cur_offset.X, obj.m_texture_cur_offset.Y); } // for j<MATERIAL_MAX_TEXTURES } // for i<getMaterialCount } #undef GET_VALUE } // Check if the end animation is being played, if so, don't // play steering animation. if(m_current_animation!=AF_DEFAULT) return; if(m_animation_frame[AF_LEFT]<0) return; // no animations defined // Update animation if necessary // ----------------------------- float frame; if(steer>0.0f) frame = m_animation_frame[AF_STRAIGHT] - ( ( m_animation_frame[AF_STRAIGHT] -m_animation_frame[AF_RIGHT] )*steer); else if(steer<0.0f) frame = m_animation_frame[AF_STRAIGHT] + ( (m_animation_frame[AF_STRAIGHT] -m_animation_frame[AF_LEFT] )*steer); else frame = (float)m_animation_frame[AF_STRAIGHT]; m_animated_node->setCurrentFrame(frame); } // update