193 lines
7.0 KiB
C++
193 lines
7.0 KiB
C++
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2004-2015 Steve Baker <sjbaker1@airmail.net>
|
|
// Copyright (C) 2006-2015 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 <math.h>
|
|
#include "karts/moveable.hpp"
|
|
|
|
#include "graphics/irr_driver.hpp"
|
|
#include "graphics/material.hpp"
|
|
#include "graphics/material_manager.hpp"
|
|
#include "modes/world.hpp"
|
|
#include "tracks/track.hpp"
|
|
|
|
#include "ISceneNode.h"
|
|
|
|
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;
|
|
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
|
|
btFuzzyZero(r_all.getZ()) && btFuzzyZero(r_all.getW()-0.70710677f) )
|
|
r_all.setX(0.000001f);
|
|
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);
|
|
Vec3 forw_vec = m_transform.getBasis().getColumn(0);
|
|
m_heading = -atan2f(forw_vec.getZ(), forw_vec.getX());
|
|
|
|
} // reset
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void Moveable::flyUp()
|
|
{
|
|
m_body->setGravity(btVector3(0.0, 8.0, 0.0));
|
|
m_body->applyCentralImpulse(btVector3(0.0, 100.0, 0.0));
|
|
} // flyUp
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void Moveable::flyDown()
|
|
{
|
|
m_body->applyCentralImpulse(btVector3(0.0, -100.0, 0.0));
|
|
} // flyDown
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void Moveable::stopFlying()
|
|
{
|
|
m_body->setGravity(btVector3(0.0, -World::getWorld()->getTrack()->getGravity(), 0.0));
|
|
} // stopFlying
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/** 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)
|
|
{
|
|
if(m_body->getInvMass()!=0)
|
|
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,
|
|
float restitution)
|
|
{
|
|
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 = restitution;
|
|
|
|
// Then create a rigid body
|
|
// ------------------------
|
|
m_body = new btRigidBody(info);
|
|
if(mass==0)
|
|
{
|
|
// Create a kinematic object
|
|
m_body->setCollisionFlags(m_body->getCollisionFlags() |
|
|
btCollisionObject::CF_KINEMATIC_OBJECT );
|
|
m_body->setActivationState(DISABLE_DEACTIVATION);
|
|
}
|
|
|
|
// 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;
|
|
if(m_motion_state)
|
|
m_motion_state->setWorldTransform(t);
|
|
} // setTrans
|