diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index c1311c401d8..0fde95157d7 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -146,6 +146,7 @@ Material::Material(const XMLNode *node, int index, bool deprecated) node->get("water-splash", &m_water_splash ); node->get("jump", &m_is_jump_texture ); + node->get("has-gravity", &m_has_gravity ); if (m_collision_reaction != NORMAL) { @@ -344,6 +345,10 @@ Material::Material(const XMLNode *node, int index, bool deprecated) } } // for i getNumNodes() + + if(m_has_gravity) + m_high_tire_adhesion = true; + install(/*is_full_path*/false); } // Material @@ -410,6 +415,7 @@ void Material::init(unsigned int index) m_is_heightmap = false; m_water_splash = false; m_is_jump_texture = false; + m_has_gravity = false; for (int n=0; nupdate(getXYZ()); + m_terrain_info->update(getTrans()); // Reset is also called when the kart is created, at which time // m_controller is not yet defined, so this has to be tested here. @@ -1102,16 +1102,19 @@ void Kart::update(float dt) if (!m_flying) { - // When really on air, free fly, when near ground, try to glide / adjust for landing - // If zipped, be stable, so ramp+zipper can allow nice jumps without scripting the fly - if(!isNearGround() && - m_max_speed->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0.0f ) + // When really on air, free fly, when near ground, try to glide / + // adjust for landing. If zipped, be stable, so ramp+zipper can + // allow nice jumps without scripting the fly + // Also disable he upright constraint when gravity is changed by + // the terrain + if( (!isNearGround() && + m_max_speed->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0.0f ) || + (getMaterial() && getMaterial()->hasGravity()) ) m_uprightConstraint->setLimit(M_PI); else m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance()); } - // TODO: hiker said this probably will be moved to btKart or so when updating bullet engine. // Neutralize any yaw change if the kart leaves the ground, so the kart falls more or less // straight after jumping, but still allowing some "boat shake" (roll and pitch). @@ -1177,22 +1180,27 @@ void Kart::update(float dt) m_skid_sound->position ( getXYZ() ); m_boing_sound->position ( getXYZ() ); - // Check if a kart is (nearly) upside down and not moving much --> automatic rescue - if(World::getWorld()->getTrack()->isAutoRescueEnabled() && + // Check if a kart is (nearly) upside down and not moving much --> + // automatic rescue + // But only do this if auto-rescue is enabled (i.e. it will be disabled in + // battle mode), and the material the kart is driving on does not have + // gravity (which can + if(World::getWorld()->getTrack()->isAutoRescueEnabled() && + (!m_terrain_info->getMaterial() || + !m_terrain_info->getMaterial()->hasGravity()) && !getKartAnimation() && fabs(getRoll())>60*DEGREE_TO_RAD && fabs(getSpeed())<3.0f ) { new RescueAnimation(this, /*is_auto_rescue*/true); } - btTransform trans=getTrans(); // Add a certain epsilon (0.3) to the height of the kart. This avoids // problems of the ray being cast from under the track (which happened // e.g. on tux tollway when jumping down from the ramp, when the chassis // partly tunnels through the track). While tunneling should not be // happening (since Z velocity is clamped), the epsilon is left in place // just to be on the safe side (it will not hit the chassis itself). - Vec3 pos_plus_epsilon = trans.getOrigin()+btVector3(0,0.3f,0); + Vec3 epsilon(0,0.3f,0); // Make sure that the ray doesn't hit the kart. This is done by // resetting the collision filter group, so that this collision @@ -1203,7 +1211,8 @@ void Kart::update(float dt) old_group = m_body->getBroadphaseHandle()->m_collisionFilterGroup; m_body->getBroadphaseHandle()->m_collisionFilterGroup = 0; } - m_terrain_info->update(pos_plus_epsilon); + + m_terrain_info->update(getTrans(), epsilon); if(m_body->getBroadphaseHandle()) { m_body->getBroadphaseHandle()->m_collisionFilterGroup = old_group; @@ -1212,6 +1221,10 @@ void Kart::update(float dt) const Material* material=m_terrain_info->getMaterial(); if (!material) // kart falling off the track { + Vec3 gravity(0, -9.8f, 0); + btRigidBody *body = getVehicle()->getRigidBody(); + body->setGravity(gravity); + // let kart fall a bit before rescuing const Vec3 *min, *max; World::getWorld()->getTrack()->getAABB(&min, &max); @@ -1221,6 +1234,16 @@ void Kart::update(float dt) } else { + Vec3 gravity(0.0f, -9.8f, 0.0f); + btRigidBody *body = getVehicle()->getRigidBody(); + // If the material should overwrite the gravity, + if(material->hasGravity()) + { + Vec3 normal = m_terrain_info->getNormal(); + gravity = normal * -9.8f; + } + body->setGravity(gravity); + handleMaterialSFX(material); if (material->isDriveReset() && isOnGround()) new RescueAnimation(this); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 092c74dc574..74db8c726ff 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -454,16 +454,16 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, btPersistentManifold* contact_manifold = m_dynamics_world->getDispatcher()->getManifoldByIndexInternal(i); - btCollisionObject* objA = - static_cast(contact_manifold->getBody0()); - btCollisionObject* objB = - static_cast(contact_manifold->getBody1()); + const btCollisionObject* objA = + static_cast(contact_manifold->getBody0()); + const btCollisionObject* objB = + static_cast(contact_manifold->getBody1()); unsigned int num_contacts = contact_manifold->getNumContacts(); if(!num_contacts) continue; // no real collision - UserPointer *upA = (UserPointer*)(objA->getUserPointer()); - UserPointer *upB = (UserPointer*)(objB->getUserPointer()); + const UserPointer *upA = (UserPointer*)(objA->getUserPointer()); + const UserPointer *upB = (UserPointer*)(objB->getUserPointer()); if(!upA || !upB) continue; diff --git a/src/tracks/terrain_info.cpp b/src/tracks/terrain_info.cpp index 2ae1e977af7..b12f0d9d3b0 100644 --- a/src/tracks/terrain_info.cpp +++ b/src/tracks/terrain_info.cpp @@ -45,18 +45,33 @@ TerrainInfo::TerrainInfo(const Vec3 &pos) m_material = NULL; update(pos); } // TerrainInfo + +//----------------------------------------------------------------------------- +/** Update the terrain information based on the latest position. + * \param Position from which to start the rayast from. + */ +void TerrainInfo::update(const Vec3 &from) +{ + m_last_material = m_material; + btVector3 to(from); + to.setY(-10000.0f); + + const TriangleMesh &tm = World::getWorld()->getTrack()->getTriangleMesh(); + tm.castRay(from, to, &m_hit_point, &m_material, &m_normal); +} // update //----------------------------------------------------------------------------- /** Update the terrain information based on the latest position. * \param Position from which to start the rayast from. */ -void TerrainInfo::update(const Vec3& pos) +void TerrainInfo::update(const btTransform &trans, const Vec3 &offset) { m_last_material = m_material; - btVector3 to(pos); - to.setY(-100000.f); + btVector3 from = trans(offset); + btVector3 to(0, -10000.0f, 0); + to = trans(to); const TriangleMesh &tm = World::getWorld()->getTrack()->getTriangleMesh(); - tm.castRay(pos, to, &m_hit_point, &m_material, &m_normal); + tm.castRay(from, to, &m_hit_point, &m_material, &m_normal); } // update // ----------------------------------------------------------------------------- diff --git a/src/tracks/terrain_info.hpp b/src/tracks/terrain_info.hpp index b9f426911d8..68301718a97 100644 --- a/src/tracks/terrain_info.hpp +++ b/src/tracks/terrain_info.hpp @@ -21,6 +21,7 @@ #include "utils/vec3.hpp" +class btTransform; class Material; /** This class stores information about the triangle that's under an object, i.e.: @@ -44,10 +45,17 @@ class TerrainInfo TerrainInfo(const Vec3 &pos); virtual ~TerrainInfo() {}; - virtual void update(const Vec3 &pos); bool getSurfaceInfo(const Vec3 &from, Vec3 *position, const Material **m); + virtual void update(const btTransform &trans, const Vec3 &offset); + virtual void update(const Vec3 &from); + // ------------------------------------------------------------------------ + /** Simple wrapper with no offset. */ + virtual void update(const btTransform &trans) + { + update(trans, Vec3(0,0,0)); + } // ------------------------------------------------------------------------ /** Returns the height of the terrain. we're currently above */ float getHoT() const {return m_hit_point.getY(); }