// $Id$ // // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2004-2005 Steve Baker // Copyright (C) 2006 Joerg Henrichs, Steve Baker // // 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. #include "karts/moveable.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "modes/world.hpp" #include "tracks/track.hpp" Moveable::Moveable() { m_body = 0; m_motion_state = 0; m_mesh = NULL; m_node = NULL; m_heading = 0; } // Moveable //----------------------------------------------------------------------------- Moveable::~Moveable() { // The body is being removed from the world in kart/projectile if(m_body) delete m_body; if(m_motion_state) delete m_motion_state; if(m_node) irr_driver->removeNode(m_node); if(m_mesh) irr_driver->removeMeshFromCache(m_mesh); } // ~Moveable //----------------------------------------------------------------------------- /** Sets the mesh for this model. * \param n The scene node. */ void Moveable::setNode(scene::ISceneNode *n) { m_node = n; } // setNode //----------------------------------------------------------------------------- /** Updates the graphics model. Mainly set the graphical position to be the * same as the physics position, but uses offsets to position and rotation * for special gfx effects (e.g. skidding will turn the karts more). * \param offset_xyz Offset to be added to the position. * \param rotation Additional rotation. */ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz, const btQuaternion& rotation) { Vec3 xyz=getXYZ()+offset_xyz; m_node->setPosition(xyz.toIrrVector()); btQuaternion r_all = getRotation()*rotation; Vec3 hpr; hpr.setHPR(r_all); m_node->setRotation(hpr.toIrrHPR()); } // updateGraphics //----------------------------------------------------------------------------- // The reset position must be set before calling reset void Moveable::reset() { if(m_body) { m_body->setLinearVelocity(btVector3(0.0, 0.0, 0.0)); m_body->setAngularVelocity(btVector3(0, 0, 0)); m_body->setCenterOfMassTransform(m_transform); } m_node->setVisible(true); // In case that the objects was eliminated Vec3 up = getTrans().getBasis().getColumn(1); m_pitch = atan2(up.getZ(), fabsf(up.getY())); m_roll = atan2(up.getX(), up.getY()); m_velocityLC = Vec3(0, 0, 0); } // reset //----------------------------------------------------------------------------- void Moveable::flyUp() { m_body->setGravity(btVector3(0.0, 8.0, 0.0)); m_body->applyCentralImpulse(btVector3(0.0, 100.0, 0.0)); } void Moveable::flyDown() { m_body->applyCentralImpulse(btVector3(0.0, -100.0, 0.0)); } void Moveable::stopFlying() { m_body->setGravity(btVector3(0.0, -World::getWorld()->getTrack()->getGravity(), 0.0)); } //----------------------------------------------------------------------------- /** Updates the current position and rotation from the corresponding physics * body, and then calls updateGraphics to position the model correctly. * \param float dt Time step size. */ void Moveable::update(float dt) { m_motion_state->getWorldTransform(m_transform); m_velocityLC = getVelocity()*m_transform.getBasis(); Vec3 forw_vec = m_transform.getBasis().getColumn(0); m_heading = -atan2f(forw_vec.getZ(), forw_vec.getX()); // The pitch in hpr is in between -pi and pi. But for the camera it // must be restricted to -pi/2 and pi/2 - so recompute it by restricting // y to positive values, i.e. no pitch of more than pi/2. Vec3 up = getTrans().getBasis().getColumn(1); m_pitch = atan2(up.getZ(), fabsf(up.getY())); m_roll = atan2(up.getX(), up.getY()); updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1)); } // update //----------------------------------------------------------------------------- /** Creates the bullet rigid body for this moveable. * \param mass Mass of this object. * \param trans Transform (=position and orientation) for this object). * \param shape Bullet collision shape for this object. */ void Moveable::createBody(float mass, btTransform& trans, btCollisionShape *shape) { btVector3 inertia; shape->calculateLocalInertia(mass, inertia); m_transform = trans; m_motion_state = new KartMotionState(trans); btRigidBody::btRigidBodyConstructionInfo info(mass, m_motion_state, shape, inertia); info.m_restitution=0.5f; // Then create a rigid body // ------------------------ m_body = new btRigidBody(info); // The value of user_pointer must be set from the actual class, otherwise this // is only a pointer to moveable, not to (say) kart, and virtual // functions are not called correctly. So only init the pointer to zero. m_user_pointer.zero(); m_body->setUserPointer(&m_user_pointer); } // createBody //----------------------------------------------------------------------------- /** Places this moveable at a certain location and stores this transform in * this Moveable, so that it can be accessed easily. * \param t New transform for this moveable. */ void Moveable::setTrans(const btTransform &t) { m_transform=t; m_motion_state->setWorldTransform(t); } // setTrans