dc07415ee3
match for the pots in hacienda). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7629 178a84e3-b1eb-0310-8ba1-8eac791a3b58
247 lines
9.0 KiB
C++
247 lines
9.0 KiB
C++
// $Id$
|
|
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2006 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.
|
|
|
|
#include "physics/physical_object.hpp"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "irrlicht.h"
|
|
using namespace irr;
|
|
|
|
#include "graphics/irr_driver.hpp"
|
|
#include "graphics/mesh_tools.hpp"
|
|
#include "io/file_manager.hpp"
|
|
#include "io/xml_node.hpp"
|
|
#include "modes/world.hpp"
|
|
#include "tracks/track.hpp"
|
|
#include "utils/constants.hpp"
|
|
#include "utils/string_utils.hpp"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
PhysicalObject::PhysicalObject(const XMLNode &xml_node)
|
|
: TrackObject(xml_node)
|
|
{
|
|
|
|
m_shape = NULL;
|
|
m_body = NULL;
|
|
m_motion_state = NULL;
|
|
m_mass = 1;
|
|
m_radius = -1;
|
|
|
|
std::string shape;
|
|
xml_node.get("mass", &m_mass );
|
|
xml_node.get("radius", &m_radius);
|
|
xml_node.get("shape", &shape );
|
|
|
|
m_body_type = MP_NONE;
|
|
if (shape=="cone" ||
|
|
shape=="coneY" ) m_body_type = MP_CONE_Y;
|
|
else if(shape=="coneX" ) m_body_type = MP_CONE_X;
|
|
else if(shape=="coneZ" ) m_body_type = MP_CONE_Z;
|
|
else if(shape=="cylinder"||
|
|
shape=="cylinderY") m_body_type = MP_CYLINDER_Y;
|
|
else if(shape=="cylinderX") m_body_type = MP_CYLINDER_X;
|
|
else if(shape=="cylinderZ") m_body_type = MP_CYLINDER_Z;
|
|
|
|
else if(shape=="box" ) m_body_type = MP_BOX;
|
|
else if(shape=="sphere" ) m_body_type = MP_SPHERE;
|
|
else fprintf(stderr, "Unknown shape type : %s\n", shape.c_str());
|
|
|
|
m_init_pos.setIdentity();
|
|
Vec3 hpr(m_init_hpr);
|
|
hpr.degreeToRad();
|
|
btQuaternion q;
|
|
q.setEuler(hpr.getX(), hpr.getY(), hpr.getZ());
|
|
m_init_pos.setRotation(q);
|
|
Vec3 init_xyz(m_init_xyz);
|
|
m_init_pos.setOrigin(init_xyz);
|
|
|
|
} // PhysicalObject
|
|
|
|
// -----------------------------------------------------------------------------
|
|
PhysicalObject::~PhysicalObject()
|
|
{
|
|
World::getWorld()->getPhysics()->removeBody(m_body);
|
|
delete m_body;
|
|
delete m_motion_state;
|
|
delete m_shape;
|
|
} // ~PhysicalObject
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/** Additional initialisation after loading of the model is finished.
|
|
*/
|
|
void PhysicalObject::init()
|
|
{
|
|
// 1. Determine size of the object
|
|
// -------------------------------
|
|
Vec3 min, max;
|
|
scene::IAnimatedMesh *mesh
|
|
= ((scene::IAnimatedMeshSceneNode*)m_node)->getMesh();
|
|
MeshTools::minMax3D(mesh, &min, &max);
|
|
Vec3 extend = max-min;
|
|
// Adjust the mesth of the graphical object so that its center is where it
|
|
// is in bullet (usually at (0,0,0)). It can be changed in the case clause
|
|
// if this is not correct for a particular shape.
|
|
Vec3 offset_from_center = -0.5f*(max+min);
|
|
switch (m_body_type)
|
|
{
|
|
case MP_CONE_Y: {
|
|
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
|
|
m_shape = new btConeShape(m_radius, extend.getY());
|
|
break;
|
|
}
|
|
case MP_CONE_X: {
|
|
if(m_radius<0)
|
|
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
|
|
extend.getZ()*extend.getZ());
|
|
m_shape = new btConeShapeX(m_radius, extend.getY());
|
|
break;
|
|
}
|
|
case MP_CONE_Z: {
|
|
if(m_radius<0)
|
|
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
|
|
extend.getY()*extend.getY());
|
|
m_shape = new btConeShapeZ(m_radius, extend.getY());
|
|
break;
|
|
}
|
|
case MP_CYLINDER_Y: {
|
|
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
|
|
m_shape = new btCylinderShape(0.5f*extend);
|
|
break;
|
|
}
|
|
case MP_CYLINDER_X: {
|
|
if(m_radius<0)
|
|
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
|
|
extend.getZ()*extend.getZ());
|
|
m_shape = new btCylinderShapeX(0.5f*extend);
|
|
break;
|
|
}
|
|
case MP_CYLINDER_Z: {
|
|
if(m_radius<0)
|
|
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
|
|
extend.getY()*extend.getY());
|
|
m_shape = new btCylinderShapeZ(0.5f*extend);
|
|
break;
|
|
}
|
|
case MP_BOX: m_shape = new btBoxShape(0.5*extend);
|
|
break;
|
|
case MP_SPHERE: {
|
|
if(m_radius<0)
|
|
{
|
|
m_radius = std::max(extend.getX(), extend.getY());
|
|
m_radius = 0.5f*std::max(m_radius, extend.getZ());
|
|
}
|
|
m_shape = new btSphereShape(m_radius);
|
|
break;
|
|
}
|
|
case MP_NONE: fprintf(stderr, "WARNING: Uninitialised moving shape\n");
|
|
break;
|
|
}
|
|
|
|
// 2. Adjust the mesh so that its center is where it is in bullet
|
|
// --------------------------------------------------------------
|
|
// This means that the graphical and physical position are identical
|
|
// which simplifies drawing later on.
|
|
scene::IMeshManipulator *mesh_manipulator =
|
|
irr_driver->getSceneManager()->getMeshManipulator();
|
|
core::matrix4 transform(core::matrix4::EM4CONST_IDENTITY); //
|
|
transform.setTranslation(offset_from_center.toIrrVector());
|
|
mesh_manipulator->transformMesh(mesh, transform);
|
|
|
|
// 2. Create the rigid object
|
|
// --------------------------
|
|
// m_init_pos is the point on the track - add the offset
|
|
m_init_pos.setOrigin(m_init_pos.getOrigin()+btVector3(0,extend.getY()*0.5f, 0));
|
|
m_motion_state = new btDefaultMotionState(m_init_pos);
|
|
btVector3 inertia;
|
|
m_shape->calculateLocalInertia(m_mass, inertia);
|
|
btRigidBody::btRigidBodyConstructionInfo info(m_mass, m_motion_state, m_shape, inertia);
|
|
|
|
// Make sure that the cones stop rolling by defining angular friction != 0.
|
|
info.m_angularDamping = 0.5f;
|
|
m_body = new btRigidBody(info);
|
|
m_user_pointer.set(this);
|
|
m_body->setUserPointer(&m_user_pointer);
|
|
|
|
World::getWorld()->getPhysics()->addBody(m_body);
|
|
} // init
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void PhysicalObject::update(float dt)
|
|
{
|
|
btTransform t;
|
|
m_motion_state->getWorldTransform(t);
|
|
|
|
Vec3 xyz = t.getOrigin();
|
|
if(xyz.getY()<-100)
|
|
{
|
|
m_body->setCenterOfMassTransform(m_init_pos);
|
|
m_body->setLinearVelocity (btVector3(0,0,0));
|
|
m_body->setAngularVelocity(btVector3(0,0,0));
|
|
xyz = Vec3(m_init_pos.getOrigin());
|
|
}
|
|
m_node->setPosition(xyz.toIrrVector());
|
|
Vec3 hpr;
|
|
hpr.setHPR(t.getRotation());
|
|
m_node->setRotation(hpr.toIrrHPR());
|
|
return;
|
|
} // update
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void PhysicalObject::reset()
|
|
{
|
|
m_body->setCenterOfMassTransform(m_init_pos);
|
|
m_body->setAngularVelocity(btVector3(0,0,0));
|
|
m_body->setLinearVelocity(btVector3(0,0,0));
|
|
m_body->activate();
|
|
} // reset
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void PhysicalObject::handleExplosion(const Vec3& pos, bool direct_hit) {
|
|
if(direct_hit) {
|
|
btVector3 impulse(0.0f, 0.0f, stk_config->m_explosion_impulse_objects);
|
|
m_body->applyCentralImpulse(impulse);
|
|
}
|
|
else // only affected by a distant explosion
|
|
{
|
|
btTransform t;
|
|
m_motion_state->getWorldTransform(t);
|
|
btVector3 diff=t.getOrigin()-pos;
|
|
|
|
float len2=diff.length2();
|
|
|
|
// The correct formhale would be to first normalise diff,
|
|
// then apply the impulse (which decreases 1/r^2 depending
|
|
// on the distance r), so:
|
|
// diff/len(diff) * impulseSize/len(diff)^2
|
|
// = diff*impulseSize/len(diff)^3
|
|
// We use diff*impulseSize/len(diff)^2 here, this makes the impulse
|
|
// somewhat larger, which is actually more fun :)
|
|
btVector3 impulse=diff*stk_config->m_explosion_impulse_objects/len2;
|
|
m_body->applyCentralImpulse(impulse);
|
|
}
|
|
m_body->activate();
|
|
|
|
} // handleExplosion
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/* EOF */
|
|
|