diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ad4d1815..1f5bc7900 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -470,6 +470,7 @@ set( SRCS ${SRCS} src/main.cpp src/physics/physical_object.hpp src/physics/physics.cpp src/physics/physics.hpp + src/physics/stk_dynamics_world.hpp src/physics/triangle_mesh.cpp src/physics/triangle_mesh.hpp src/physics/user_pointer.hpp diff --git a/data/stk_config.xml b/data/stk_config.xml index 98307d1cd..00b6067e3 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -49,15 +49,15 @@ - + + time for skidmarks to fade out. --> + disabled when the kart is more than this value from the track. --> @@ -231,9 +231,12 @@ - + rest: Length of suspension when at rest. + travel-cm: maximum movement of suspension - in cm!! + exp-string-response: dampen the suspension spring reaction + exponentially --> + + impact of roll. + downward-impulse-factor: A speed proportional impulse applied each + frame that pushes the vehicle onto the ground. + track-connection-accel: An artificial force that pulls a wheel to + the ground if its off ground. Reduces the affect if a kart loses + contact with the ground (i.e. it then can't steer or accelerate + anymore). --> + chassis-angular-damping="0" + downward-impulse-factor="0" + track-connection-accel="0"/> - - - - - - + after being hit by an explosion. + radius: Kart closer to this value will be affected by + an explosion as well. --> diff --git a/src/Makefile.am b/src/Makefile.am index d83241a85..350548b74 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -293,6 +293,7 @@ supertuxkart_SOURCES = \ physics/physical_object.hpp \ physics/physics.cpp \ physics/physics.hpp \ + phsyics/stk_dynamics_world.hpp \ physics/triangle_mesh.cpp \ physics/triangle_mesh.hpp \ physics/user_pointer.hpp \ diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 10b285ebc..9ca188c09 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -38,6 +38,7 @@ STKConfig::~STKConfig() if(m_title_music) delete m_title_music; } // ~STKConfig + //----------------------------------------------------------------------------- /** Loads the stk configuration file. After loading it checks if all necessary * values are actually defined, otherwise an error message is printed and STK diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 38525dc29..a631022ed 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -389,6 +389,9 @@ namespace UserConfigParams /** Special debug camera being high over the kart. */ PARAM_PREFIX bool m_camera_debug PARAM_DEFAULT( false ); + /** True if physics debugging should be enabled. */ + PARAM_PREFIX bool m_physics_debug PARAM_DEFAULT( false ); + /** True if slipstream debugging is activated. */ PARAM_PREFIX bool m_slipstream_debug PARAM_DEFAULT( false ); diff --git a/src/ide/vc9/supertuxkart.vcproj b/src/ide/vc9/supertuxkart.vcproj index 58c57d325..778d7bdb5 100644 --- a/src/ide/vc9/supertuxkart.vcproj +++ b/src/ide/vc9/supertuxkart.vcproj @@ -414,6 +414,26 @@ > + + + + + + + + + + - - - - - - - - - - @@ -1712,6 +1712,10 @@ RelativePath="..\..\physics\physics.hpp" > + + diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index 9097aae76..60d170352 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -235,7 +235,7 @@ void InputManager::handleStaticAction(int key, int value) break; case KEY_F10: - if(world) history->Save(); + if(world && value) history->Save(); break; case KEY_F11: diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 237f63e5d..0c9ed7bd1 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -276,10 +276,8 @@ void Kart::createPhysics() // ------------------------- m_vehicle_raycaster = new btKartRaycaster(World::getWorld()->getPhysics()->getPhysicsWorld()); - m_tuning = new btKart::btVehicleTuning(); - m_tuning->m_maxSuspensionTravelCm = m_kart_properties->getSuspensionTravelCM(); - m_vehicle = new btKart(*m_tuning, m_body, m_vehicle_raycaster, - m_kart_properties->getTrackConnectionAccel()); + m_vehicle = new btKart(m_body, m_vehicle_raycaster, this); + //FIXMEJH m_kart_properties->getTrackConnectionAccel()); // never deactivate the vehicle m_body->setActivationState(DISABLE_DEACTIVATION); @@ -293,13 +291,16 @@ void Kart::createPhysics() btVector3 wheel_direction(0.0f, -1.0f, 0.0f); btVector3 wheel_axle(-1.0f, 0.0f, 0.0f); + btKart::btVehicleTuning tuning; + tuning.m_maxSuspensionTravelCm = m_kart_properties->getSuspensionTravelCM(); + for(unsigned int i=0; i<4; i++) { bool is_front_wheel = i<2; btWheelInfo& wheel = m_vehicle->addWheel( m_kart_model->getWheelPhysicsPosition(i), wheel_direction, wheel_axle, suspension_rest, - wheel_radius, *m_tuning, is_front_wheel); + wheel_radius, tuning, is_front_wheel); wheel.m_suspensionStiffness = m_kart_properties->getSuspensionStiffness(); wheel.m_wheelsDampingRelaxation = m_kart_properties->getWheelDampingRelaxation(); wheel.m_wheelsDampingCompression = m_kart_properties->getWheelDampingCompression(); @@ -416,7 +417,6 @@ Kart::~Kart() World::getWorld()->getPhysics()->removeKart(this); delete m_vehicle; - delete m_tuning; delete m_vehicle_raycaster; delete m_uprightConstraint; @@ -537,6 +537,7 @@ void Kart::reset() m_bounce_back_time = 0.0f; m_skidding = 1.0f; m_time_last_crash = 0.0f; + m_speed = 0.0f; m_view_blocked_by_plunger = 0.0f; if(m_terrain_sound) @@ -575,9 +576,12 @@ void Kart::reset() if (m_skidmarks) { m_skidmarks->reset(); - m_skidmarks->adjustFog( track_manager->getTrack( race_manager->getTrackName() )->isFogEnabled() ); + const Track *track = + track_manager->getTrack( race_manager->getTrackName() ); + m_skidmarks->adjustFog(track->isFogEnabled() ); } + m_vehicle->reset(); for(int j=0; jgetNumWheels(); j++) { m_vehicle->updateWheelTransform(j, true); @@ -751,12 +755,12 @@ float Kart::getActualWheelForce() */ bool Kart::isOnGround() const { - return (m_vehicle->getNumWheelsOnGround() == m_vehicle->getNumWheels() + return ((int)m_vehicle->getNumWheelsOnGround() == m_vehicle->getNumWheels() && !playingEmergencyAnimation()); } // isOnGround //----------------------------------------------------------------------------- -/** The kart is near the ground, but not necesarily on it (small jumps). This +/** The kart is near the ground, but not necessarily on it (small jumps). This * is used to determine when to switch off the upright constraint, so that * explosions can be more violent, while still */ @@ -1678,18 +1682,6 @@ void Kart::updatePhysics(float dt) } } // !m_brake } // not accelerating -#ifdef ENABLE_JUMP - if(m_controls.jump && isOnGround()) - { - //Vector3 impulse(0.0f, 0.0f, 10.0f); - // getVehicle()->getRigidBody()->applyCentralImpulse(impulse); - btVector3 velocity = m_body->getLinearVelocity(); - velocity.setZ( m_kart_properties->getJumpVelocity() ); - - getBody()->setLinearVelocity( velocity ); - - } -#endif if (isOnGround()) { if((fabs(m_controls.m_steer) > 0.001f) && m_controls.m_drift) @@ -1725,7 +1717,7 @@ void Kart::updatePhysics(float dt) // you have full traction; above 0.5 rad angles you have absolutely none; // inbetween there is a linear change in friction float friction = 1.0f; - bool enable_skidding = false; + bool enable_sliding = false; // This way the current skidding // handling can be disabled for certain material (e.g. the @@ -1745,7 +1737,7 @@ void Kart::updatePhysics(float dt) if (distanceFromUp < 0.85f) { friction = 0.0f; - enable_skidding = true; + enable_sliding = true; } else if (distanceFromUp > 0.9f) { @@ -1754,7 +1746,7 @@ void Kart::updatePhysics(float dt) else { friction = (distanceFromUp - 0.85f) / 0.5f; - enable_skidding = true; + enable_sliding = true; } } @@ -1764,7 +1756,7 @@ void Kart::updatePhysics(float dt) wheel.m_frictionSlip = friction*m_kart_properties->getFrictionSlip(); } - m_vehicle->enableSliding(enable_skidding); + m_vehicle->setSliding(enable_sliding); float steering = getMaxSteerAngle() * m_controls.m_steer*m_skidding; diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index 273d92b2c..31cb0e39b 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -27,7 +27,7 @@ * of karts. */ -#include "btBulletDynamicsCommon.h" +#include "LinearMath/btTransform.h" #include "items/attachment.hpp" #include "items/powerup.hpp" @@ -36,24 +36,23 @@ #include "karts/emergency_animation.hpp" #include "karts/max_speed.hpp" #include "karts/moveable.hpp" -#include "karts/kart_model.hpp" #include "karts/kart_properties.hpp" #include "tracks/terrain_info.hpp" #include "utils/no_copy.hpp" class btKart; class btUprightConstraint; -class btVehicleTuning; + class Camera; class Item; -class Quad; -class Shadow; -class SFXBase; -class SkidMarks; -class SlipStream; +class KartModel; class ParticleEmitter; class ParticleKind; class Rain; +class SFXBase; +class Shadow; +class SkidMarks; +class SlipStream; /** The main kart class. All type of karts are of this object, but with * different controllers. The controllers are what turn a kart into a @@ -133,8 +132,6 @@ private: // Bullet physics parameters // ------------------------- - btRaycastVehicle::btVehicleTuning - *m_tuning; btCompoundShape m_kart_chassis; btVehicleRaycaster *m_vehicle_raycaster; btKart *m_vehicle; @@ -416,7 +413,7 @@ public: const std::string& getIdent() const {return m_kart_properties->getIdent();} // ------------------------------------------------------------------------ /** Returns the start transform, i.e. position and rotation. */ - const btTransform getResetTransform() const {return m_reset_transform;} + const btTransform& getResetTransform() const {return m_reset_transform;} // ------------------------------------------------------------------------ /** Returns the controller of this kart. */ Controller* getController() { return m_controller; } diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 21d0b67e6..430138df7 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -29,6 +29,7 @@ #include "graphics/mesh_tools.hpp" #include "io/xml_node.hpp" #include "karts/kart.hpp" +#include "physics/btKart.hpp" #include "utils/constants.hpp" #define SKELETON_DEBUG 0 @@ -510,7 +511,9 @@ void KartModel::update(float rotation, float steer, const float suspension[4]) m_max_suspension[i]); float ratio = clamped_suspension[i] / suspension_length; const int sign = ratio < 0 ? -1 : 1; - ratio = sign * fabsf(ratio*(2-ratio)); // expanded form of 1 - (1 - x)^2, i.e. making suspension display quadratic and not linear + // expanded form of 1 - (1 - x)^2, i.e. making suspension display + // quadratic and not linear + ratio = sign * fabsf(ratio*(2-ratio)); clamped_suspension[i] = ratio*suspension_length; } // for i<4 @@ -521,6 +524,16 @@ void KartModel::update(float rotation, float steer, const float suspension[4]) for(unsigned int i=0; i<4; i++) { if(!m_wheel_node[i]) continue; +#ifdef DEBUG + if(UserConfigParams::m_physics_debug) + { + // Make wheels that are not touching the ground invisible + bool wheel_has_contact = + m_kart->getVehicle()->getWheelInfo(i).m_raycastInfo + .m_isInContact; + m_wheel_node[i]->setVisible(wheel_has_contact); + } +#endif core::vector3df pos = m_wheel_graphics_position[i].toIrrVector(); pos.Y += clamped_suspension[i]; m_wheel_node[i]->setPosition(pos); diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 43458e240..6f719e70a 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -72,7 +72,7 @@ KartProperties::KartProperties(const std::string &filename) m_wheel_damping_compression = m_friction_slip = m_roll_influence = m_wheel_radius = m_chassis_linear_damping = m_chassis_angular_damping = m_suspension_rest = - m_max_speed_reverse_ratio = m_jump_velocity = + m_max_speed_reverse_ratio = m_rescue_vert_offset = m_upright_tolerance = m_collision_side_impulse = m_upright_max_force = m_suspension_travel_cm = m_track_connection_accel = @@ -93,9 +93,10 @@ KartProperties::KartProperties(const std::string &filename) m_rescue_time = m_rescue_height = m_explosion_time = m_explosion_radius = m_ai_steering_variation = m_swatter_distance2 = m_swatter_duration = m_squash_slowdown = - m_squash_duration = UNDEFINED; + m_squash_duration = m_downward_impulse_factor = UNDEFINED; m_gravity_center_shift = Vec3(UNDEFINED); + m_exp_spring_response = false; m_has_skidmarks = true; m_version = 0; m_color = video::SColor(255, 0, 0, 0); @@ -384,9 +385,10 @@ void KartProperties::getAllData(const XMLNode * root) if(const XMLNode *suspension_node = root->getNode("suspension")) { - suspension_node->get("stiffness", &m_suspension_stiffness); - suspension_node->get("rest", &m_suspension_rest ); - suspension_node->get("travel-cm", &m_suspension_travel_cm); + suspension_node->get("stiffness", &m_suspension_stiffness); + suspension_node->get("rest", &m_suspension_rest ); + suspension_node->get("travel-cm", &m_suspension_travel_cm); + suspension_node->get("exp-spring-response", &m_exp_spring_response ); } if(const XMLNode *wheels_node = root->getNode("wheels")) @@ -401,9 +403,16 @@ void KartProperties::getAllData(const XMLNode * root) if(const XMLNode *stability_node = root->getNode("stability")) { - stability_node->get("roll-influence", &m_roll_influence); - stability_node->get("chassis-linear-damping", &m_chassis_linear_damping); - stability_node->get("chassis-angular-damping", &m_chassis_angular_damping); + stability_node->get("roll-influence", + &m_roll_influence ); + stability_node->get("chassis-linear-damping", + &m_chassis_linear_damping ); + stability_node->get("chassis-angular-damping", + &m_chassis_angular_damping); + stability_node->get("downward-impulse-factor", + &m_downward_impulse_factor); + stability_node->get("track-connection-accel", + &m_track_connection_accel ); } if(const XMLNode *upright_node = root->getNode("upright")) @@ -412,12 +421,6 @@ void KartProperties::getAllData(const XMLNode * root) upright_node->get("max-force", &m_upright_max_force); } - if(const XMLNode *track_connection_node = root->getNode("track-connection-accel")) - track_connection_node->get("value", &m_track_connection_accel); - - if(const XMLNode *jump_node = root->getNode("jump")) - jump_node->get("velocity", &m_jump_velocity); - if(const XMLNode *collision_node = root->getNode("collision")) collision_node->get("side-impulse", &m_collision_side_impulse); @@ -567,8 +570,10 @@ void KartProperties::checkAllSet(const std::string &filename) CHECK_NEG(m_wheel_radius, "wheels radius" ); CHECK_NEG(m_friction_slip, "friction slip" ); CHECK_NEG(m_roll_influence, "stability roll-influence" ); - CHECK_NEG(m_chassis_linear_damping, "stability chassis-linear-damping"); - CHECK_NEG(m_chassis_angular_damping, "stability chassis-angular-damping"); + CHECK_NEG(m_chassis_linear_damping, "stability chassis-linear-damping" ); + CHECK_NEG(m_chassis_angular_damping, "stability chassis-angular-damping"); + CHECK_NEG(m_downward_impulse_factor, "stability downward-impulse-factor"); + CHECK_NEG(m_track_connection_accel, "stability track-connection-accel" ); CHECK_NEG(m_engine_power[0], "engine power[0]" ); CHECK_NEG(m_engine_power[1], "engine power[1]" ); CHECK_NEG(m_engine_power[2], "engine power[2]" ); @@ -581,10 +586,8 @@ void KartProperties::checkAllSet(const std::string &filename) CHECK_NEG(m_suspension_rest, "suspension rest" ); CHECK_NEG(m_suspension_travel_cm, "suspension travel-cm" ); CHECK_NEG(m_collision_side_impulse, "collision side-impulse" ); - CHECK_NEG(m_jump_velocity, "jump velocity" ); CHECK_NEG(m_upright_tolerance, "upright tolerance" ); CHECK_NEG(m_upright_max_force, "upright max-force" ); - CHECK_NEG(m_track_connection_accel, "track-connection-accel" ); CHECK_NEG(m_plunger_in_face_duration[0],"plunger in-face-time[0]" ); CHECK_NEG(m_plunger_in_face_duration[1],"plunger in-face-time[1]" ); CHECK_NEG(m_plunger_in_face_duration[2],"plunger in-face-time[2]" ); diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index 383656d9f..79e66d22b 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -85,7 +85,7 @@ private: // Display and gui // --------------- - std::string m_name; /**< The human readable Name of the kart + std::string m_name; /**< The human readable Name of the kart * driver. */ std::string m_ident; /**< The computer readable-name of the * kart driver. */ @@ -217,21 +217,41 @@ private: float m_friction_slip; float m_roll_influence; float m_wheel_radius; + + /** An impulse pushing the kart down which is proportional to speed. So + * the actual impulse is speed * m_downward_impulse_factor. Set it to + * 0 to disable completely. Based on + * http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=6059\ + * &p=21240&hilit=vehicle#p21240 */ + float m_downward_impulse_factor; + + /** Artifical acceleration that pulls a kart down onto the track if one + * axis loses contact with the track. */ + float m_track_connection_accel; + + /** Linear damping of the chassis to prevent it from toppling over. */ float m_chassis_linear_damping; + + /** Angular damping to prevent it from turning too easily. */ float m_chassis_angular_damping; + float m_max_speed[3]; float m_max_speed_reverse_ratio; - Vec3 m_gravity_center_shift; /**< Shift of center of gravity. */ - float m_track_connection_accel; /**< Artifical acceleration that pulls a - * kart down onto the track if one axis - * loses contact with the track. */ + + /** Shift of center of gravity. */ + Vec3 m_gravity_center_shift; + + /** The suspension reaction is dampened to reach an exponential behaviour. + * See http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7369\ + * &p=25236&hilit=vehicle#p25236 for details. */ + bool m_exp_spring_response; + float m_suspension_rest; float m_suspension_travel_cm; /** An additional artifical side-impulse that pushes the slower kart * out of the way of the faster kart in case of a collision. */ float m_collision_side_impulse; - /** Vertical velocity set when jumping. */ - float m_jump_velocity; + float m_upright_tolerance; float m_upright_max_force; @@ -418,6 +438,12 @@ public: float getChassisAngularDamping () const {return m_chassis_angular_damping; } + /** Artifical downward impulse every frame. */ + float getDownwardImpulseFactor() const { return m_downward_impulse_factor;} + + /** Returns artificial acceleration to keep wheels on track. */ + float getTrackConnectionAccel () const {return m_track_connection_accel;} + /** Returns the maximum speed dependent on the difficult level. */ float getMaxSpeed () const {return m_max_speed[race_manager->getDifficulty()];} @@ -456,8 +482,8 @@ public: /** Returns the amount the suspension can extend. */ float getSuspensionTravelCM () const {return m_suspension_travel_cm; } - /** Returns jump velocity (unused atm). */ - float getJumpVelocity () const {return m_jump_velocity; } + /** Returns if the spring should be exponentially dampened. */ + bool getExpSpringResponse() const {return m_exp_spring_response; } /** Returns the (artificial) collision side impulse this kart will apply * to a slower kart in case of a collision. */ @@ -491,9 +517,6 @@ public: /** Returns the maximum value of the upright counteracting force. */ float getUprightMaxForce () const {return m_upright_max_force; } - /** Returns artificial acceleration to keep wheels on track. */ - float getTrackConnectionAccel () const {return m_track_connection_accel;} - /** Returns the maximum length of a rubber band before it breaks. */ float getRubberBandMaxLength () const {return m_rubber_band_max_length;} diff --git a/src/main.cpp b/src/main.cpp index b16f5fd0b..8391af0cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -457,6 +457,15 @@ int handleCmdLinePreliminary(int argc, char **argv) { UserConfigParams::m_verbosity |= UserConfigParams::LOG_MISC; } + else if( !strcmp(argv[i], "--log=terminal")) + { + UserConfigParams::m_log_errors=false; + } + else if( !strcmp(argv[i], "--log=file")) + { + UserConfigParams::m_log_errors=true; + } + else if ( !strcmp(argv[i], "--debug=all") ) { UserConfigParams::m_verbosity |= UserConfigParams::LOG_ALL; @@ -607,6 +616,11 @@ int handleCmdLine(int argc, char **argv) { UserConfigParams::m_camera_debug=1; } + else if(UserConfigParams::m_artist_debug_mode && + !strcmp(argv[i], "--physics-debug")) + { + UserConfigParams::m_physics_debug=1; + } else if(!strcmp(argv[i], "--kartsize-debug")) { for(unsigned int i=0; @@ -859,14 +873,7 @@ int handleCmdLine(int argc, char **argv) race_manager->setNumLaps(atoi(argv[i+1])); i++; } - else if( !strcmp(argv[i], "--log=terminal")) - { - UserConfigParams::m_log_errors=false; - } - else if( !strcmp(argv[i], "--log=file")) - { - UserConfigParams::m_log_errors=true; - } else if( sscanf(argv[i], "--profile-laps=%d", &n)==1) + else if( sscanf(argv[i], "--profile-laps=%d", &n)==1) { printf("Profiling %d laps\n",n); UserConfigParams::m_no_start_screen = true; @@ -923,6 +930,8 @@ int handleCmdLine(int argc, char **argv) else if( !strcmp(argv[i], "--debug=flyable") ) {} else if( !strcmp(argv[i], "--debug=misc" ) ) {} else if( !strcmp(argv[i], "--debug=all" ) ) {} + else if( !strcmp(argv[i], "--log=terminal" ) ) {} + else if( !strcmp(argv[i], "--log=file" ) ) {} else if( !strcmp(argv[i], "--screensize") || !strcmp(argv[i], "-s") ) {i++;} else if( !strcmp(argv[i], "--fullscreen") || !strcmp(argv[i], "-f")) {} diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 6a7f29af1..0e6f88f4f 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -368,6 +368,10 @@ void World::terminateRace() */ void World::resetAllKarts() { + // Reset the physics 'remaining' time to 0 so that the number + // of timesteps is reproducible if doing a physics-based history run + getPhysics()->getPhysicsWorld()->resetLocalTime(); + // If track checking is requested, check all rescue positions if // they are heigh enough. if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES && @@ -902,6 +906,9 @@ void World::restartRace() projectile_manager->cleanup(); race_manager->reset(); + // Make sure to overwrite the data from the previous race. + if(!history->replayHistory()) history->initRecording(); + } // restartRace //----------------------------------------------------------------------------- diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp index 493a8fa3c..03974c356 100644 --- a/src/physics/btKart.cpp +++ b/src/physics/btKart.cpp @@ -4,137 +4,864 @@ * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. - * Erwin Coumans makes no representations about the suitability - * of this software for any purpose. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ -/* Based on btRayCastVehicle, but modified for STK. - * projectVehicleToSurface function and shorter raycast functions added. - */ - -#include "physics/btKart.hpp" - -#include "LinearMath/btMinMax.h" #include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" +#include "btKart.hpp" + #include "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h" #include "BulletDynamics/ConstraintSolver/btJacobianEntry.h" +#include "LinearMath/btQuaternion.h" #include "BulletDynamics/Dynamics/btDynamicsWorld.h" #include "BulletDynamics/Vehicle/btVehicleRaycaster.h" #include "BulletDynamics/Vehicle/btWheelInfo.h" +#include "LinearMath/btMinMax.h" +#include "LinearMath/btIDebugDraw.h" #include "BulletDynamics/ConstraintSolver/btContactConstraint.h" -struct btWheelContactPoint; -btScalar calcRollingFriction(btWheelContactPoint& contactPoint); +#include "karts/kart.hpp" + +#define ROLLING_INFLUENCE_FIX -btKart::btKart(const btVehicleTuning& tuning,btRigidBody* chassis, - btVehicleRaycaster* raycaster, float track_connect_accel ) -: btRaycastVehicle(tuning, chassis, raycaster) +btRigidBody& btActionInterface::getFixedBody() { - m_track_connect_accel = track_connect_accel; - - m_num_wheels_on_ground = 0; - - m_zipper_active = false; - m_zipper_velocity = btScalar(0); - m_allow_sliding = false; + static btRigidBody s_fixed(0, 0,0); + s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.), + btScalar(0.),btScalar(0.))); + return s_fixed; } +// ============================================================================ +btKart::btKart(btRigidBody* chassis, btVehicleRaycaster* raycaster, + Kart *kart) + : m_vehicleRaycaster(raycaster) +{ + m_chassisBody = chassis; + m_indexRightAxis = 0; + m_indexUpAxis = 2; + m_indexForwardAxis = 1; + m_kart = kart; + reset(); +} // btKart + // ---------------------------------------------------------------------------- btKart::~btKart() { -} +} // ~btKart + +// ---------------------------------------------------------------------------- + +// +// basically most of the code is general for 2 or 4 wheel vehicles, but some +// of it needs to be reviewed +// +btWheelInfo& btKart::addWheel(const btVector3& connectionPointCS, + const btVector3& wheelDirectionCS0, + const btVector3& wheelAxleCS, + btScalar suspensionRestLength, + btScalar wheelRadius, + const btVehicleTuning& tuning, + bool isFrontWheel) +{ + + btWheelInfoConstructionInfo ci; + + ci.m_chassisConnectionCS = connectionPointCS; + ci.m_wheelDirectionCS = wheelDirectionCS0; + ci.m_wheelAxleCS = wheelAxleCS; + ci.m_suspensionRestLength = suspensionRestLength; + ci.m_wheelRadius = wheelRadius; + ci.m_bIsFrontWheel = isFrontWheel; + ci.m_suspensionStiffness = tuning.m_suspensionStiffness; + ci.m_wheelsDampingCompression = tuning.m_suspensionCompression; + ci.m_wheelsDampingRelaxation = tuning.m_suspensionDamping; + ci.m_frictionSlip = tuning.m_frictionSlip; + ci.m_maxSuspensionTravelCm = tuning.m_maxSuspensionTravelCm; + ci.m_maxSuspensionForce = tuning.m_maxSuspensionForce; + + m_wheelInfo.push_back( btWheelInfo(ci)); + + btWheelInfo& wheel = m_wheelInfo[getNumWheels()-1]; + + updateWheelTransformsWS( wheel , false ); + updateWheelTransform(getNumWheels()-1,false); + return wheel; +} // addWheel + +// ---------------------------------------------------------------------------- +/** Resets the kart before a (re)start, to make sure all physics variable + * are properly defined. This is especially important for physics replay. + */ +void btKart::reset() +{ + for(int i=0; igetMotionState())) + { + getRigidBody()->getMotionState()->getWorldTransform(chassisTrans); + } + + wheel.m_raycastInfo.m_hardPointWS = + chassisTrans( wheel.m_chassisConnectionPointCS ); + wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.getBasis() * + wheel.m_wheelDirectionCS ; + wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.getBasis() * + wheel.m_wheelAxleCS; +} // updateWheelTransformsWS // ---------------------------------------------------------------------------- btScalar btKart::rayCast(btWheelInfo& wheel) { - updateWheelTransformsWS( wheel,false); + updateWheelTransformsWS( wheel,false); + + btScalar depth = -1; + + btScalar raylen = wheel.getSuspensionRestLength()+wheel.m_wheelsRadius + + wheel.m_maxSuspensionTravelCm*0.01f; - btScalar depth = -1; + btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen); + const btVector3& source = wheel.m_raycastInfo.m_hardPointWS; + wheel.m_raycastInfo.m_contactPointWS = source + rayvector; + const btVector3& target = wheel.m_raycastInfo.m_contactPointWS; - btScalar raylen = wheel.getSuspensionRestLength()+wheel.m_wheelsRadius+ - wheel.m_maxSuspensionTravelCm*0.01f; + btScalar param = btScalar(0.); + + btVehicleRaycaster::btVehicleRaycasterResult rayResults; - btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen); - const btVector3& source = wheel.m_raycastInfo.m_hardPointWS; - wheel.m_raycastInfo.m_contactPointWS = source + rayvector; - const btVector3& target = wheel.m_raycastInfo.m_contactPointWS; + btAssert(m_vehicleRaycaster); - btScalar param = btScalar(0.); + void* object = m_vehicleRaycaster->castRay(source,target,rayResults); - btVehicleRaycaster::btVehicleRaycasterResult rayResults; + wheel.m_raycastInfo.m_groundObject = 0; - assert(m_vehicleRaycaster); + if (object) + { + param = rayResults.m_distFraction; + depth = raylen * rayResults.m_distFraction; + wheel.m_raycastInfo.m_contactNormalWS = rayResults.m_hitNormalInWorld; + wheel.m_raycastInfo.m_isInContact = true; + ///@todo for driving on dynamic/movable objects!; + wheel.m_raycastInfo.m_groundObject = &getFixedBody(); - void* object = m_vehicleRaycaster->castRay(source,target,rayResults); + btScalar hitDistance = param*raylen; + wheel.m_raycastInfo.m_suspensionLength = + hitDistance - wheel.m_wheelsRadius; + //clamp on max suspension travel - wheel.m_raycastInfo.m_groundObject = 0; + btScalar minSuspensionLength = wheel.getSuspensionRestLength() + - wheel.m_maxSuspensionTravelCm*btScalar(0.01); + btScalar maxSuspensionLength = wheel.getSuspensionRestLength() + + wheel.m_maxSuspensionTravelCm*btScalar(0.01); + if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength; + } + if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength; + } - if (object) + wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld; + + btScalar denominator = wheel.m_raycastInfo.m_contactNormalWS.dot( + wheel.m_raycastInfo.m_wheelDirectionWS ); + + btVector3 chassis_velocity_at_contactPoint; + btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS + - getRigidBody()->getCenterOfMassPosition(); + + chassis_velocity_at_contactPoint = + getRigidBody()->getVelocityInLocalPoint(relpos); + + btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( + chassis_velocity_at_contactPoint ); + + if ( denominator >= btScalar(-0.1)) + { + wheel.m_suspensionRelativeVelocity = btScalar(0.0); + wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); + } + else + { + btScalar inv = btScalar(-1.) / denominator; + wheel.m_suspensionRelativeVelocity = projVel * inv; + wheel.m_clippedInvContactDotSuspension = inv; + } + + } else + { + //put wheel info as in rest position + wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength(); + wheel.m_suspensionRelativeVelocity = btScalar(0.0); + wheel.m_raycastInfo.m_contactNormalWS = + - wheel.m_raycastInfo.m_wheelDirectionWS; + wheel.m_clippedInvContactDotSuspension = btScalar(1.0); + } + + return depth; +} // rayCast + +// ---------------------------------------------------------------------------- +const btTransform& btKart::getChassisWorldTransform() const +{ + return getRigidBody()->getCenterOfMassTransform(); +} // getChassisWorldTransform + +// ---------------------------------------------------------------------------- +void btKart::updateVehicle( btScalar step ) +{ + for (int i=0;i maxSuspensionLength) - { - wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength; - } - - wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld; - - btScalar denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS ); - - btVector3 chassis_velocity_at_contactPoint; - btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition(); - - chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos); - - btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); - - if ( denominator >= btScalar(-0.1)) - { - wheel.m_suspensionRelativeVelocity = btScalar(0.0); - wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); - } - else - { - btScalar inv = btScalar(-1.) / denominator; - wheel.m_suspensionRelativeVelocity = projVel * inv; - wheel.m_clippedInvContactDotSuspension = inv; - } - - } else - { - //put wheel info as in rest position - wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength(); - wheel.m_suspensionRelativeVelocity = btScalar(0.0); - wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS; - wheel.m_clippedInvContactDotSuspension = btScalar(1.0); - + updateWheelTransform(i,false); } - return depth; + m_currentVehicleSpeedKmHour = + btScalar(3.6) * getRigidBody()->getLinearVelocity().length(); + + const btTransform& chassisTrans = getChassisWorldTransform(); + + btVector3 forwardW(chassisTrans.getBasis()[0][m_indexForwardAxis], + chassisTrans.getBasis()[1][m_indexForwardAxis], + chassisTrans.getBasis()[2][m_indexForwardAxis]); + + if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.)) + { + m_currentVehicleSpeedKmHour *= btScalar(-1.); + } + + // Simulate suspension + // ------------------- + + int i=0; + m_num_wheels_on_ground = 0; + for (i=0;i wheel.m_maxSuspensionForce) + { + suspensionForce = wheel.m_maxSuspensionForce; + } + btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS + * suspensionForce * step; + btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS + - getRigidBody()->getCenterOfMassPosition(); + + getRigidBody()->applyImpulse(impulse, relpos); + + } + + updateFriction( step); + + + for (i=0;igetCenterOfMassPosition(); + btVector3 vel = getRigidBody()->getVelocityInLocalPoint(relpos); + + if (wheel.m_raycastInfo.m_isInContact) + { + const btTransform& chassisWorldTransform = + getChassisWorldTransform(); + + btVector3 fwd ( + chassisWorldTransform.getBasis()[0][m_indexForwardAxis], + chassisWorldTransform.getBasis()[1][m_indexForwardAxis], + chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); + + btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); + fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; + + btScalar proj2 = fwd.dot(vel); + + wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius); + wheel.m_rotation += wheel.m_deltaRotation; + + } else + { + wheel.m_rotation += wheel.m_deltaRotation; + } + //damping of rotation when not in contact + wheel.m_deltaRotation *= btScalar(0.99); + + } + float f = -m_kart->getSpeed() + * m_kart->getKartProperties()->getDownwardImpulseFactor(); + btVector3 downwards_impulse = m_chassisBody->getWorldTransform().getBasis() + * btVector3(0, f, 0); + + m_chassisBody->applyCentralImpulse(downwards_impulse); +} // updateVehicle + +// ---------------------------------------------------------------------------- +void btKart::setSteeringValue(btScalar steering, int wheel) +{ + btAssert(wheel>=0 && wheel < getNumWheels()); + + btWheelInfo& wheelInfo = getWheelInfo(wheel); + wheelInfo.m_steering = steering; +} // setSteeringValue + +// ---------------------------------------------------------------------------- +btScalar btKart::getSteeringValue(int wheel) const +{ + return getWheelInfo(wheel).m_steering; } +// ---------------------------------------------------------------------------- +void btKart::applyEngineForce(btScalar force, int wheel) +{ + btAssert(wheel>=0 && wheel < getNumWheels()); + btWheelInfo& wheelInfo = getWheelInfo(wheel); + wheelInfo.m_engineForce = force; +} + + +// ---------------------------------------------------------------------------- +const btWheelInfo& btKart::getWheelInfo(int index) const +{ + btAssert((index >= 0) && (index < getNumWheels())); + + return m_wheelInfo[index]; +} + +// ---------------------------------------------------------------------------- +btWheelInfo& btKart::getWheelInfo(int index) +{ + btAssert((index >= 0) && (index < getNumWheels())); + + return m_wheelInfo[index]; +} + +// ---------------------------------------------------------------------------- +void btKart::setBrake(btScalar brake,int wheelIndex) +{ + btAssert((wheelIndex >= 0) && (wheelIndex < getNumWheels())); + getWheelInfo(wheelIndex).m_brake = brake; +} + + +// ---------------------------------------------------------------------------- +void btKart::updateSuspension(btScalar deltaTime) +{ + (void)deltaTime; + + btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass(); + + for (int w_it=0; w_itgetKartProperties()->getTrackConnectionAccel() + * chassisMass; + continue; + } + + btScalar force; + + // Spring + btScalar susp_length = wheel_info.getSuspensionRestLength(); + btScalar current_length = wheel_info.m_raycastInfo.m_suspensionLength; + btScalar length_diff = (susp_length - current_length); + if(m_kart->getKartProperties()->getExpSpringResponse()) + length_diff *= length_diff/susp_length; + + force = wheel_info.m_suspensionStiffness * length_diff + * wheel_info.m_clippedInvContactDotSuspension; + + // Damper + btScalar projected_rel_vel = wheel_info.m_suspensionRelativeVelocity; + btScalar susp_damping = projected_rel_vel < btScalar(0.0) + ? wheel_info.m_wheelsDampingCompression + : wheel_info.m_wheelsDampingRelaxation; + force -= susp_damping * projected_rel_vel; + + // RESULT + wheel_info.m_wheelsSuspensionForce = force * chassisMass; + if (wheel_info.m_wheelsSuspensionForce < btScalar(0.)) + { + wheel_info.m_wheelsSuspensionForce = btScalar(0.); + } + } // for (int w_it=0; w_itcomputeImpulseDenominator(frictionPosWorld, + frictionDirectionWorld); + btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld, + frictionDirectionWorld); + btScalar relaxation = 1.f; + m_jacDiagABInv = relaxation/(denom0+denom1); + } + + + +}; // struct btWheelContactPoint + +// ---------------------------------------------------------------------------- +btScalar calcRollingFriction(btWheelContactPoint& contactPoint) +{ + + btScalar j1=0.f; + + const btVector3& contactPosWorld = contactPoint.m_frictionPositionWorld; + + btVector3 rel_pos1 = contactPosWorld + - contactPoint.m_body0->getCenterOfMassPosition(); + btVector3 rel_pos2 = contactPosWorld + - contactPoint.m_body1->getCenterOfMassPosition(); + + btScalar maxImpulse = contactPoint.m_maxImpulse; + + btVector3 vel1 = contactPoint.m_body0->getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = contactPoint.m_body1->getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel); + + // calculate j that moves us to zero relative velocity + j1 = -vrel * contactPoint.m_jacDiagABInv; + btSetMin(j1, maxImpulse); + btSetMax(j1, -maxImpulse); + + return j1; +} // calcRollingFriction + +// ---------------------------------------------------------------------------- + +void btKart::updateFriction(btScalar timeStep) +{ + + //calculate the impulse, so that the wheels don't move sidewards + int numWheel = getNumWheels(); + if (!numWheel) + return; + + m_forwardWS.resize(numWheel); + m_axle.resize(numWheel); + m_forwardImpulse.resize(numWheel); + m_sideImpulse.resize(numWheel); + + int numWheelsOnGround = 0; + + + //collapse all those loops into one! + for (int i=0;i 0) + { + if (wheel==2 || wheel==3) + { + // The zipper velocity is the speed that should be + // reached. So compute the impulse to accelerate the + // kart up to that speed: + m_forwardImpulse[wheel] = + 0.5f*(m_zipper_velocity - + getRigidBody()->getLinearVelocity().length()) + / m_chassisBody->getInvMass(); + } + + } + + btScalar rollingFriction = 0.f; + + if (wheelInfo.m_engineForce != 0.f) + { + rollingFriction = wheelInfo.m_engineForce* timeStep; + } + else + { + btScalar defaultRollingFrictionImpulse = 0.f; + btScalar maxImpulse = wheelInfo.m_brake + ? wheelInfo.m_brake + : defaultRollingFrictionImpulse; + btWheelContactPoint contactPt(m_chassisBody, groundObject, + wheelInfo.m_raycastInfo.m_contactPointWS, + m_forwardWS[wheel],maxImpulse); + rollingFriction = calcRollingFriction(contactPt); + // This is a work around for the problem that a kart shakes + // if it is braking: we get a minor impulse forward, which + // bullet then tries to offset by applying a backward + // impulse - which is a bit too big, causing a impulse + // backwards, ... till the kart is shaking backwards and + // forwards + if(wheelInfo.m_brake && fabsf(rollingFriction)<10) + rollingFriction=0; + } + + //switch between active rolling (throttle), braking and non-active + // rolling friction (no throttle/break) + + m_wheelInfo[wheel].m_skidInfo= btScalar(1.); + + btScalar maximp = wheelInfo.m_wheelsSuspensionForce + * timeStep * wheelInfo.m_frictionSlip; + btScalar maximpSide = maximp; + btScalar maximpSquared = maximp * maximpSide; + m_forwardImpulse[wheel] = rollingFriction; + + btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor; + btScalar y = (m_sideImpulse[wheel] ) * sideFactor; + + btScalar impulseSquared = (x*x + y*y); + + if (impulseSquared > maximpSquared) + { + sliding = true; + btScalar factor = maximp / btSqrt(impulseSquared); + m_wheelInfo[wheel].m_skidInfo *= factor; + } // if impulseSquared > maximpSquared + + } // for (int wheel=0; wheelgetCenterOfMassPosition(); + + if (m_forwardImpulse[wheel] != btScalar(0.)) + { + m_chassisBody->applyImpulse( + m_forwardWS[wheel]*(m_forwardImpulse[wheel]), +#define COMPATIBLE_0_7_3 +#ifdef COMPATIBLE_0_7_3 + // This was apparently done to help hexley + btVector3(0,0,0)); +#else + rel_pos); +#endif + } + if (m_sideImpulse[wheel] != btScalar(0.)) + { + btRigidBody* groundObject = + (btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; + btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS + - groundObject->getCenterOfMassPosition(); + //adjust relative position above ground so that force only + // acts sideways + btVector3 delta_vec = (wheelInfo.m_raycastInfo.m_hardPointWS + - wheelInfo.m_raycastInfo.m_contactPointWS); + if (delta_vec.length() != btScalar (0)) + { + delta_vec = delta_vec.normalize(); + rel_pos -= delta_vec * rel_pos.dot(delta_vec); + } + + btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; + +#if defined ROLLING_INFLUENCE_FIX && !defined COMPATIBLE_0_7_3 + // fix. It only worked if car's up was along Y - VT. + btVector3 vChassisWorldUp = + getRigidBody()->getCenterOfMassTransform() + .getBasis().getColumn(m_indexUpAxis); + rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * + (1.f-wheelInfo.m_rollInfluence) ); +#else + rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence; +#endif + m_chassisBody->applyImpulse(sideImp,rel_pos); + + //apply friction impulse on the ground + groundObject->applyImpulse(-sideImp,rel_pos2); + } // if (m_sideImpulse[wheel] != btScalar(0.)) + } // for wheeldrawLine(wheelPosWS,wheelPosWS+axle,wheelColor); + debugDrawer->drawLine(wheelPosWS, + getWheelInfo(v).m_raycastInfo.m_contactPointWS, + wheelColor); + + } // for i < getNumWheels +} // debugDraw + + +// ---------------------------------------------------------------------------- +/** Enables or disables sliding. + * \param active Enable (true) or disable sliding. + */ +void btKart::setSliding(bool active) +{ + m_allow_sliding = active; +} // setSliding + +// ---------------------------------------------------------------------------- +/** Activates an additional speedup for the kart so that it reaches the + * specified speed. + * \param speed The speed to reach. + */ +void btKart::activateZipper(float speed) +{ + m_zipper_active = true; + m_zipper_velocity = speed; +} // activateZipper + +// ---------------------------------------------------------------------------- +void btKart::deactivateZipper() +{ + m_zipper_active = false; +} // deactivateZipper // ---------------------------------------------------------------------------- //Shorter version of above raycast function. This is used when projecting @@ -153,7 +880,7 @@ btScalar btKart::rayCast(btWheelInfo& wheel, const btVector3& ray) assert(m_vehicleRaycaster); - void* object = m_vehicleRaycaster->castRay(source,target,rayResults); + void* object = m_vehicleRaycaster->castRay(source,target,rayResults); wheel.m_raycastInfo.m_groundObject = 0; @@ -167,13 +894,14 @@ btScalar btKart::rayCast(btWheelInfo& wheel, const btVector3& ray) } return depth; -} +} // rayCast(btWheelInfo& wheel, const btVector3& ray // ---------------------------------------------------------------------------- //Project vehicle onto surface in a particular direction. //Used in reseting kart positions. //Please align wheel direction with ray direction first. -bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicle) +bool btKart::projectVehicleToSurface(const btVector3& ray, + bool translate_vehicle) { if (ray.length() <= btScalar(0)) return false; @@ -254,35 +982,44 @@ bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicl btTransform offset_trans; offset_trans.setIdentity(); - btVector3 offset= min_wheel.m_raycastInfo.m_hardPointWS + min_wheel.m_wheelsRadius * ray_dir; + btVector3 offset = min_wheel.m_raycastInfo.m_hardPointWS + + min_wheel.m_wheelsRadius * ray_dir; offset -= getRigidBody()->getCenterOfMassPosition(); offset_trans.setOrigin(rot_trans*offset); - //the effect of the following rotations is to make the 3 wheels with initial - //minimum distance to surface (in the ray direction) in contact with the - //plane between the points of intersection (between the ray and surface). + // The effect of the following rotations is to make the 3 wheels with + // initial minimum distance to surface (in the ray direction) in contact + // with the plane between the points of intersection (between the ray and + // surface). - //Note - For possible complex surfaces with lots of bumps directly under vehicle, - // the raycast needs to be done from a slightly higher above the surface. - // For such surfaces, the end result should be that at least 1 wheel touches - // the surface, and no wheel goes below the surface. + //Note - For possible complex surfaces with lots of bumps directly under + // vehicle, the raycast needs to be done from a slightly higher + // above the surface. For such surfaces, the end result should be + // that at least 1 wheel touches the surface, and no wheel goes + // below the surface. //We need to rotate vehicle, using above contact point as a pivot to put //2nd closest wheel nearer to the surface of the track - btScalar d_hpws = (min_wheel.m_raycastInfo.m_hardPointWS - min_wheel2.m_raycastInfo.m_hardPointWS).length(); - btScalar d_depth = (min_wheel2.m_raycastInfo.m_contactPointWS - min_wheel2.m_raycastInfo.m_hardPointWS - ray_dir * min_wheel.m_wheelsRadius).length(); + btScalar d_hpws = ( min_wheel.m_raycastInfo.m_hardPointWS + - min_wheel2.m_raycastInfo.m_hardPointWS).length(); + btScalar d_depth = ( min_wheel2.m_raycastInfo.m_contactPointWS + - min_wheel2.m_raycastInfo.m_hardPointWS + - ray_dir * min_wheel.m_wheelsRadius).length(); d_depth -= min_depth; //calculate rotation angle from pivot point and plane perpendicular to ray float rot_angle = atanf(d_depth / d_hpws); - rot_angle -= atanf((min_wheel2.m_wheelsRadius - min_wheel.m_wheelsRadius) / d_hpws); + rot_angle -= atanf((min_wheel2.m_wheelsRadius - min_wheel.m_wheelsRadius) + / d_hpws); getRigidBody()->setAngularVelocity(btVector3(0,0,0)); getRigidBody()->setLinearVelocity(btVector3(0,0,0)); - btVector3 rot_axis = (min_wheel2.m_raycastInfo.m_hardPointWS - min_wheel.m_raycastInfo.m_hardPointWS).cross(ray_dir); + btVector3 rot_axis = + ( min_wheel2.m_raycastInfo.m_hardPointWS + - min_wheel.m_raycastInfo.m_hardPointWS).cross(ray_dir); btTransform operator_trans; operator_trans.setIdentity(); @@ -293,7 +1030,8 @@ bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicl //rotate kart about pivot point, about line perpendicular to //ray and vector between the 2 wheels operator_trans *= offset_trans; - operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(), rot_angle)); + operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(), + rot_angle)); offset_trans.setOrigin(-(rot_trans*offset)); operator_trans *= offset_trans; } @@ -305,33 +1043,43 @@ bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicl //next, rotate about axis which is a vector between 2 wheels above, so that //the 3rd wheel is correctly positioned. - rot_axis = min_wheel2.m_raycastInfo.m_contactPointWS - min_wheel.m_raycastInfo.m_contactPointWS; - btVector3 wheel_dist = min_wheel3.m_raycastInfo.m_hardPointWS - min_wheel.m_raycastInfo.m_hardPointWS; + rot_axis = min_wheel2.m_raycastInfo.m_contactPointWS + - min_wheel.m_raycastInfo.m_contactPointWS; + btVector3 wheel_dist = min_wheel3.m_raycastInfo.m_hardPointWS + - min_wheel.m_raycastInfo.m_hardPointWS; if (rot_axis.length() != btScalar(0)) { btVector3 proj = wheel_dist.dot(rot_axis) * rot_axis.normalize(); //calculate position on axis when a perpendicular line would go through - //3rd wheel position when translated in ray position and rotated as above - btVector3 pos_on_axis = min_wheel.m_raycastInfo.m_contactPointWS + proj; + //3rd wheel position when translated in ray position and rotated as + // above + btVector3 pos_on_axis = + min_wheel.m_raycastInfo.m_contactPointWS + proj; - btVector3 to_contact_pt = min_wheel3.m_raycastInfo.m_contactPointWS - pos_on_axis; + btVector3 to_contact_pt = min_wheel3.m_raycastInfo.m_contactPointWS + - pos_on_axis; btScalar dz = to_contact_pt.dot(ray_dir); btScalar dw = (to_contact_pt - dz * ray_dir).length(); rot_angle = atanf (dz / dw); - btVector3 rot_point = getRigidBody()->getCenterOfMassPosition() + min_depth * ray_dir - min_wheel.m_raycastInfo.m_contactPointWS; + btVector3 rot_point = getRigidBody()->getCenterOfMassPosition() + + min_depth * ray_dir + - min_wheel.m_raycastInfo.m_contactPointWS; rot_point = rot_point.dot(rot_axis) * rot_axis.normalize() - rot_point; - //calculate translation offset to axis from center of mass along perpendicular + //calculate translation offset to axis from center of mass along + // perpendicular offset_trans.setIdentity(); offset= rot_point; offset_trans.setOrigin(rot_trans*offset); - btVector3 a = min_wheel3.m_raycastInfo.m_hardPointWS - min_wheel.m_raycastInfo.m_hardPointWS; - btVector3 b = min_wheel2.m_raycastInfo.m_hardPointWS - min_wheel.m_raycastInfo.m_hardPointWS; + btVector3 a = min_wheel3.m_raycastInfo.m_hardPointWS + - min_wheel.m_raycastInfo.m_hardPointWS; + btVector3 b = min_wheel2.m_raycastInfo.m_hardPointWS + - min_wheel.m_raycastInfo.m_hardPointWS; if ( (a.cross(b)).dot(ray_dir) > 0 ) { @@ -341,7 +1089,8 @@ bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicl //rotate about new axis operator_trans.setIdentity(); operator_trans *= offset_trans; - operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(), rot_angle)); + operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(), + rot_angle)); offset_trans.setOrigin(-(rot_trans*offset)); operator_trans *= offset_trans; @@ -383,419 +1132,4 @@ bool btKart::projectVehicleToSurface(const btVector3& ray, bool translate_vehicl getRigidBody()->translate(-min_wheel.getSuspensionRestLength() * min_wheel.m_raycastInfo.m_wheelDirectionWS); return true; -} - - -// ---------------------------------------------------------------------------- -void btKart::updateVehicle( btScalar step ) -{ - { - for (int i=0;igetLinearVelocity().length(); - - const btTransform& chassisTrans = getChassisWorldTransform(); - - btVector3 forwardW ( - chassisTrans.getBasis()[0][m_indexForwardAxis], - chassisTrans.getBasis()[1][m_indexForwardAxis], - chassisTrans.getBasis()[2][m_indexForwardAxis]); - - if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.)) - { - m_currentVehicleSpeedKmHour *= btScalar(-1.); - } - - // - // simulate suspension - // - - int i=0; - m_num_wheels_on_ground = 0; - - for (i=0;i gMaxSuspensionForce) - { - suspensionForce = gMaxSuspensionForce; - } - btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; - btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); - - getRigidBody()->applyImpulse(impulse, relpos); - } - - - updateFriction( step); - - - for (i=0;igetCenterOfMassPosition(); - btVector3 vel = getRigidBody()->getVelocityInLocalPoint( relpos ); - - if (wheel.m_raycastInfo.m_isInContact) - { - const btTransform& chassisWorldTransform = getChassisWorldTransform(); - - btVector3 fwd ( - chassisWorldTransform.getBasis()[0][m_indexForwardAxis], - chassisWorldTransform.getBasis()[1][m_indexForwardAxis], - chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); - - btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); - fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; - - btScalar proj2 = fwd.dot(vel); - - wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius); - wheel.m_rotation += wheel.m_deltaRotation; - - } else - { - wheel.m_rotation += wheel.m_deltaRotation; - } - - wheel.m_deltaRotation *= btScalar(0.99);//damping of rotation when not in contact - - } - -} - -// ---------------------------------------------------------------------------- -void btKart::updateSuspension(btScalar deltaTime) -{ - (void)deltaTime; - - btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass(); - - for (int w_it=0; w_itcomputeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); - btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); - btScalar relaxation = 1.f; - m_jacDiagABInv = relaxation/(denom0+denom1); - } - - -}; - -// ---------------------------------------------------------------------------- -void btKart::updateFriction(btScalar timeStep) -{ - - //calculate the impulse, so that the wheels don't move sidewards - int numWheel = getNumWheels(); - if (!numWheel) - return; - - m_forwardWS.resize(numWheel); - m_axle.resize(numWheel); - m_forwardImpulse.resize(numWheel); - m_sideImpulse.resize(numWheel); - - - //collapse all those loops into one! - for (int i=0;igetLinearVelocity().length()) / m_chassisBody->getInvMass(); - } - } - else - { - - if (wheelInfo.m_engineForce != 0.f) - { - rollingFriction = wheelInfo.m_engineForce* timeStep; - } else - { - //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) - btScalar defaultRollingFrictionImpulse = 0.f; - btScalar maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse; - btWheelContactPoint contactPt(m_chassisBody,groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse); - rollingFriction = calcRollingFriction(contactPt); - // This is a work around for the problem that a kart shakes - // if it is braking: we get a minor impulse forward, which - // bullet then tries to offset by applying a backward - // impulse - which is a bit too big, causing a impulse - // backwards, ... till the kart is shaking backwards and - // forwards - if(wheelInfo.m_brake && fabsf(rollingFriction)<10) - rollingFriction=0; - } - - m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep; - } - btScalar maximp = wheelInfo.m_wheelsSuspensionForce * timeStep * wheelInfo.m_frictionSlip; - btScalar maximpSide = maximp; - - btScalar maximpSquared = maximp * maximpSide; - - btScalar x = (m_forwardImpulse[wheel] ) * fwdFactor; - btScalar y = (m_sideImpulse[wheel] ) * sideFactor; - - btScalar impulseSquared = (x*x + y*y); - - if (impulseSquared > maximpSquared) - { - sliding = true; - - btScalar factor = maximp / btSqrt(impulseSquared); - - m_wheelInfo[wheel].m_skidInfo *= factor; - } - } // if groundObject - - } // for wheelgetCenterOfMassPosition(); - - if (m_forwardImpulse[wheel] != btScalar(0.)) - { - m_chassisBody->applyImpulse(m_forwardWS[wheel]*(m_forwardImpulse[wheel]), - btVector3(0,0,0)); - } - if (m_sideImpulse[wheel] != btScalar(0.)) - { - class btRigidBody* groundObject = (class btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; - - btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - - groundObject->getCenterOfMassPosition(); - - //adjust relative position above ground so that force only acts sideways - btVector3 delta_vec = (wheelInfo.m_raycastInfo.m_hardPointWS - wheelInfo.m_raycastInfo.m_contactPointWS); - if (delta_vec.length() != btScalar (0)) - { - delta_vec = delta_vec.normalize(); - rel_pos -= delta_vec * rel_pos.dot(delta_vec); - } - - btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; - - rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence; - m_chassisBody->applyImpulse(sideImp,rel_pos); - - //apply friction impulse on the ground - groundObject->applyImpulse(-sideImp,rel_pos2); - } - } - } - - -} +} // projectVehicleToSurface diff --git a/src/physics/btKart.hpp b/src/physics/btKart.hpp index e860ffc38..333fc6059 100644 --- a/src/physics/btKart.hpp +++ b/src/physics/btKart.hpp @@ -4,61 +4,237 @@ * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. - * Erwin Coumans makes no representations about the suitability - * of this software for any purpose. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ -#ifndef HEADER_BT_KART_HPP -#define HEADER_BT_KART_HPP - -#include "btBulletDynamicsCommon.h" +#ifndef BT_KART_HPP +#define BT_KART_HPP +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include "physics/btKartRaycast.hpp" class btDynamicsWorld; -struct btWheelInfo; +#include "LinearMath/btAlignedObjectArray.h" +#include "BulletDynamics/Vehicle/btWheelInfo.h" +#include "BulletDynamics/Dynamics/btActionInterface.h" -/** The btKart is a raycast vehicle, that does not skid. It therefore solves - * the problems with the plain bullet physics that karts would often rotate - * on a spot if one of the wheels loses contact with the ground. - * \ingroup physics - */ -class btKart : public btRaycastVehicle +class btVehicleTuning; +class Kart; + +///rayCast vehicle, very special constraint that turn a rigidbody into a vehicle. +class btKart : public btActionInterface { - void defaultInit(const btVehicleTuning& tuning); - btScalar m_track_connect_accel; - int m_num_wheels_on_ground; - bool m_zipper_active; - btScalar m_zipper_velocity; +private: + btAlignedObjectArray m_forwardWS; + btAlignedObjectArray m_axle; + btAlignedObjectArray m_forwardImpulse; + btAlignedObjectArray m_sideImpulse; + + ///backwards compatibility + int m_userConstraintType; + int m_userConstraintId; + +public: + class btVehicleTuning + { + public: + + btVehicleTuning() + :m_suspensionStiffness(btScalar(5.88)), + m_suspensionCompression(btScalar(0.83)), + m_suspensionDamping(btScalar(0.88)), + m_maxSuspensionTravelCm(btScalar(500.)), + m_frictionSlip(btScalar(10.5)), + m_maxSuspensionForce(btScalar(6000.)) + { + } + btScalar m_suspensionStiffness; + btScalar m_suspensionCompression; + btScalar m_suspensionDamping; + btScalar m_maxSuspensionTravelCm; + btScalar m_frictionSlip; + btScalar m_maxSuspensionForce; + + }; +protected: + + btScalar m_damping; + btVehicleRaycaster *m_vehicleRaycaster; + btScalar m_currentVehicleSpeedKmHour; + bool m_zipper_active; + btScalar m_zipper_velocity; /** Sliding (skidding) will only be permited when this is true. Also check - * the friction parameter in the wheels since friction directly affects skidding - */ - bool m_allow_sliding; - + * the friction parameter in the wheels since friction directly affects + * skidding. + */ + bool m_allow_sliding; + + btRigidBody* m_chassisBody; + + int m_num_wheels_on_ground; + int m_indexRightAxis; + int m_indexUpAxis; + int m_indexForwardAxis; + + /** The STK kart object which uses this vehicle. This is mostly used to + * get access to the kart properties, which also define physics + * properties. */ + Kart *m_kart; + + void defaultInit(); + public: - - btKart(const btVehicleTuning& tuning,btRigidBody* chassis, - btVehicleRaycaster* raycaster, float track_connect_accel ); - virtual ~btKart() ; - btScalar rayCast(btWheelInfo& wheel); - btScalar rayCast(btWheelInfo& wheel, const btVector3& ray); - bool projectVehicleToSurface(const btVector3& ray, bool translate_vehicle); - virtual void updateVehicle(btScalar step); - void resetSuspension(); - int getNumWheelsOnGround() const { return m_num_wheels_on_ground; } - void setRaycastWheelInfo(int wheelIndex , bool isInContact, - const btVector3& hitPoint, - const btVector3& hitNormal,btScalar depth); - void setPitchControl(btScalar pitch) { m_pitchControl = pitch; } - void activateZipper(btScalar vel) { m_zipper_active = true; m_zipper_velocity = vel; } - void deactivateZipper() { m_zipper_active = false; } - void updateSuspension(btScalar deltaTime); - virtual void updateFriction(btScalar timeStep); - - /** Sliding (skidding) will only be permited when this is set to true. Also check - * the friction parameter in the wheels since friction directly affects skidding - */ - void enableSliding(bool enabled) { m_allow_sliding = enabled; } + + //constructor to create a car from an existing rigidbody + btKart(btRigidBody* chassis, btVehicleRaycaster* raycaster, + Kart *kart); + + virtual ~btKart() ; + + void reset(); + + ///btActionInterface interface + virtual void updateAction( btCollisionWorld* collisionWorld, btScalar step) + { + (void) collisionWorld; + updateVehicle(step); + } + + ///btActionInterface interface + void debugDraw(btIDebugDraw* debugDrawer); + + const btTransform& getChassisWorldTransform() const; + + btScalar rayCast(btWheelInfo& wheel); + + virtual void updateVehicle(btScalar step); + + + void resetSuspension(); + + btScalar getSteeringValue(int wheel) const; + + void setSteeringValue(btScalar steering,int wheel); + + + void applyEngineForce(btScalar force, int wheel); + + const btTransform& getWheelTransformWS( int wheelIndex ) const; + + void updateWheelTransform( int wheelIndex, bool interpolatedTransform = true ); + +// void setRaycastWheelInfo( int wheelIndex , bool isInContact, const btVector3& hitPoint, const btVector3& hitNormal,btScalar depth); + + btWheelInfo& addWheel( const btVector3& connectionPointCS0, const btVector3& wheelDirectionCS0,const btVector3& wheelAxleCS,btScalar suspensionRestLength,btScalar wheelRadius,const btVehicleTuning& tuning, bool isFrontWheel); + + inline int getNumWheels() const { + return int (m_wheelInfo.size()); + } + + btAlignedObjectArray m_wheelInfo; + + + const btWheelInfo& getWheelInfo(int index) const; + + btWheelInfo& getWheelInfo(int index); + + void updateWheelTransformsWS(btWheelInfo& wheel , bool interpolatedTransform = true); + + + void setBrake(btScalar brake,int wheelIndex); + + void updateSuspension(btScalar deltaTime); + + virtual void updateFriction(btScalar timeStep); + + + + inline btRigidBody* getRigidBody() + { + return m_chassisBody; + } + + const btRigidBody* getRigidBody() const + { + return m_chassisBody; + } + + inline int getRightAxis() const + { + return m_indexRightAxis; + } + inline int getUpAxis() const + { + return m_indexUpAxis; + } + + inline int getForwardAxis() const + { + return m_indexForwardAxis; + } + + + ///Worldspace forward vector + btVector3 getForwardVector() const + { + const btTransform& chassisTrans = getChassisWorldTransform(); + + btVector3 forwardW ( + chassisTrans.getBasis()[0][m_indexForwardAxis], + chassisTrans.getBasis()[1][m_indexForwardAxis], + chassisTrans.getBasis()[2][m_indexForwardAxis]); + + return forwardW; + } + + ///Velocity of vehicle (positive if velocity vector has same direction as foward vector) + btScalar getCurrentSpeedKmHour() const + { + return m_currentVehicleSpeedKmHour; + } + + virtual void setCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) + { + m_indexRightAxis = rightIndex; + m_indexUpAxis = upIndex; + m_indexForwardAxis = forwardIndex; + } + + + ///backwards compatibility + int getUserConstraintType() const + { + return m_userConstraintType ; + } + + void setUserConstraintType(int userConstraintType) + { + m_userConstraintType = userConstraintType; + }; + + void setUserConstraintId(int uid) + { + m_userConstraintId = uid; + } + + int getUserConstraintId() const + { + return m_userConstraintId; + } +private: + btScalar rayCast(btWheelInfo& wheel, const btVector3& ray); +public: + void setSliding(bool active); + void activateZipper(float speed); + void deactivateZipper(); + bool projectVehicleToSurface(const btVector3& ray, + bool translate_vehicle); + // ------------------------------------------------------------------------ + /** Returns the number of wheels on the ground. */ + unsigned int getNumWheelsOnGround() const {return m_num_wheels_on_ground;} }; -#endif //BT_KART_H +#endif //BT_RAYCASTVEHICLE_H diff --git a/src/physics/btKartRaycast.hpp b/src/physics/btKartRaycast.hpp index dc6f3fdf4..b05420066 100644 --- a/src/physics/btKartRaycast.hpp +++ b/src/physics/btKartRaycast.hpp @@ -8,8 +8,8 @@ * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ -#ifndef BTKARTRAYCASTER_HPP -#define BTKARTRAYCSATER_HPP +#ifndef BTKARTRAYCAST_HPP +#define BTKARTRAYCAST_HPP #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 5c4d4cf2c..6681df49a 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -27,6 +27,7 @@ #include "physics/btUprightConstraint.hpp" #include "physics/irr_debug_drawer.hpp" #include "physics/physical_object.hpp" +#include "physics/stk_dynamics_world.hpp" #include "physics/triangle_mesh.hpp" #include "tracks/track.hpp" @@ -48,10 +49,10 @@ Physics::Physics() : btSequentialImpulseConstraintSolver() void Physics::init(const Vec3 &world_min, const Vec3 &world_max) { m_axis_sweep = new btAxisSweep3(world_min, world_max); - m_dynamics_world = new btDiscreteDynamicsWorld(m_dispatcher, - m_axis_sweep, - this, - m_collision_conf); + m_dynamics_world = new STKDynamicsWorld(m_dispatcher, + m_axis_sweep, + this, + m_collision_conf); m_dynamics_world->setGravity(btVector3(0.0f, -World::getWorld()->getTrack()->getGravity(), 0.0f)); diff --git a/src/physics/physics.hpp b/src/physics/physics.hpp index bde791fd0..9739cba20 100644 --- a/src/physics/physics.hpp +++ b/src/physics/physics.hpp @@ -31,10 +31,12 @@ #include "btBulletDynamicsCommon.h" #include "physics/irr_debug_drawer.hpp" +#include "physics/stk_dynamics_world.hpp" #include "physics/user_pointer.hpp" -class Vec3; class Kart; +class STKDynamicsWorld; +class Vec3; /** * \ingroup physics @@ -89,7 +91,10 @@ private: } }; // CollisionList - btDynamicsWorld *m_dynamics_world; + /** Pointer to the physics dynamics world. */ + STKDynamicsWorld *m_dynamics_world; + + /** Used in physics debugging to draw the physics world. */ IrrDebugDrawer *m_debug_drawer; btCollisionDispatcher *m_dispatcher; btBroadphaseInterface *m_axis_sweep; @@ -107,7 +112,7 @@ public: void KartKartCollision(Kart *ka, Kart *kb); void update (float dt); void draw (); - btDynamicsWorld* + STKDynamicsWorld* getPhysicsWorld () const {return m_dynamics_world;} /** Activates the next debug mode (or switches it off again). */ diff --git a/src/physics/stk_dynamics_world.hpp b/src/physics/stk_dynamics_world.hpp new file mode 100644 index 000000000..3d5d7b677 --- /dev/null +++ b/src/physics/stk_dynamics_world.hpp @@ -0,0 +1,47 @@ +// $Id$ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2011 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_STK_DYNAMICS_WORLD_HPP +#define HEADER_STK_DYNAMICS_WORLD_HPP + +#include "btBulletDynamicsCommon.h" + +class STKDynamicsWorld : public btDiscreteDynamicsWorld +{ +public: + /** The standard constructor which just created a btDiscreteDynamicsWorld. */ + STKDynamicsWorld(btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration) + + : btDiscreteDynamicsWorld(dispatcher, pairCache, + constraintSolver, + collisionConfiguration) + { + } + + /** Resets m_localTime to 0. This allows more precise replay of + * physics, which is important for replaying histories. */ + virtual void resetLocalTime() { m_localTime = 0; } + +}; // STKDynamicsWorld +#endif +/* EOF */ + diff --git a/src/race/history.cpp b/src/race/history.cpp index 1ab411177..8ceae7fd1 100644 --- a/src/race/history.cpp +++ b/src/race/history.cpp @@ -24,6 +24,7 @@ #include "io/file_manager.hpp" #include "modes/world.hpp" #include "karts/kart.hpp" +#include "physics/physics.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" @@ -99,7 +100,9 @@ void History::updateSaving(float dt) } else { - m_size ++; + // m_size must be m_all_deltas.size() or smaller + if(m_size<(int)m_all_deltas.size()) + m_size ++; } m_all_deltas[m_current] = dt; @@ -122,12 +125,15 @@ void History::updateSaving(float dt) void History::updateReplay(float dt) { m_current++; + World *world = World::getWorld(); if(m_current>=(int)m_all_deltas.size()) { printf("Replay finished.\n"); - exit(2); + m_current = 0; + // Note that for physics replay all physics parameters + // need to be reset, e.g. velocity, ... + world->restartRace(); } - World *world = World::getWorld(); unsigned int num_karts = world->getNumKarts(); for(unsigned k=0; k m_all_deltas; + + /** Stores the kart controls being used (for physics replay). */ std::vector m_all_controls; + + /** Stores the coordinates (for simple replay). */ AlignedArray m_all_xyz; + + /** Stores the rotations of the karts. */ AlignedArray m_all_rotations; /** The identities of the karts to use. */ std::vector m_kart_ident; + void allocateMemory(int number_of_frames); void updateSaving(float dt); void updateReplay(float dt); @@ -70,7 +87,7 @@ public: void Save (); void Load (); - // ------------------------------------------------------------------------ + // -------------------I----------------------------------------------------- /** Returns the identifier of the n-th kart. */ const std::string& getKartIdent(unsigned int n) { diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 7d1ee8b5c..db3b79d1c 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -1234,7 +1234,8 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id) m_start_transforms[position].setOrigin(xyz); m_start_transforms[position].setRotation( - btQuaternion(btVector3(0,1,0),h ) ); + btQuaternion(btVector3(0,1,0), + h*DEGREE_TO_RAD ) ); } else if(name=="camera") {