1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 03:12:36 +01:00

Door and bonnet dynamics

This commit is contained in:
Daniel Evans 2014-06-20 00:47:13 +01:00
parent 8cbf1eaefe
commit 3ccf5ebaa2
4 changed files with 198 additions and 28 deletions

View File

@ -49,6 +49,13 @@ public:
btVehicleRaycaster* physRaycaster;
btRaycastVehicle* physVehicle;
struct HingeInfo {
btRigidBody* body;
btHingeConstraint* constraint;
};
std::map<ModelFrame*, HingeInfo> _hingedObjects;
VehicleObject(GameWorld* engine,
const glm::vec3& pos,
const glm::quat& rot,
@ -111,6 +118,13 @@ public:
void setFrameState(ModelFrame *f, FrameState state);
void applyWaterFloat(const glm::vec3& relPt);
void setHingeLocked(ModelFrame* frame, bool locked);
private:
void createObjectHinge(btTransform &local, ModelFrame* frame);
void destroyObjectHinge(HingeInfo& hinge);
};
/**

View File

@ -15,18 +15,19 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm:
{
mHealth = 100.f;
if(! data->modelName.empty()) {
btTransform wt(
btQuaternion(
rot.x, rot.y, rot.z, rot.w
),
btVector3(
pos.x, pos.y, pos.z
));
auto phyit = engine->gameData.collisions.find(data->modelName);
if( phyit != engine->gameData.collisions.end()) {
btCompoundShape* cmpShape = new btCompoundShape;
btDefaultMotionState* msta = new btDefaultMotionState;
msta->setWorldTransform(btTransform(
btQuaternion(
rot.x, rot.y, rot.z, rot.w
),
btVector3(
pos.x, pos.y, pos.z
)
));
msta->setWorldTransform(wt);
CollisionModel& physInst = *phyit->second.get();
btVector3 com(info->handling.centerOfMass.x, info->handling.centerOfMass.y, info->handling.centerOfMass.z);
@ -111,31 +112,29 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm:
}
}
}
// Hide all LOD and damage frames.
animator = new Animator;
animator->setModel(model->model);
// Hide all LOD and damage frames.
animator = new Animator;
animator->setModel(model->model);
for(ModelFrame* f : model->model->frames) {
auto& name = f->getName();
bool isDam = name.find("_dam") != name.npos;
bool isLod = name.find("lo") != name.npos;
bool isDum = name.find("_dummy") != name.npos;
bool isOk = name.find("_ok") != name.npos;
if(isDam || isLod || isDum ) {
animator->setFrameVisibility(f, false);
}
if( isDum ) {
if( name.find("door") != name.npos ) {
float a = glm::half_pi<float>() - glm::quarter_pi<float>() * 0.5f;
animator->setFrameOrientation(f, glm::normalize(
glm::quat( a, glm::vec3(0.f, 0.f, glm::sign(f->getDefaultTranslation().x)) )));
std::cout << name << std::endl;
for(ModelFrame* f : model->model->frames) {
auto& name = f->getName();
bool isDam = name.find("_dam") != name.npos;
bool isLod = name.find("lo") != name.npos;
bool isDum = name.find("_dummy") != name.npos;
bool isOk = name.find("_ok") != name.npos;
if(isDam || isLod || isDum ) {
animator->setFrameVisibility(f, false);
}
if( isDum ) {
_hingedObjects[f] = {
nullptr,
nullptr
};
}
}
}
}
VehicleObject::~VehicleObject()
@ -325,6 +324,15 @@ void VehicleObject::tickPhysics(float dt)
}
_lastHeight = vH;
// Update hinge object rotations
for(auto it : _hingedObjects) {
if(it.second.body == nullptr) continue;
auto inv = glm::inverse(getRotation());
auto rot = it.second.body->getWorldTransform().getRotation();
animator->setFrameOrientation(it.first,
inv * glm::quat(rot.w(), rot.x(), rot.y(), rot.z()));
}
}
}
@ -427,6 +435,9 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg)
, dpoint);
if( td < geom->geometryBounds.radius * 1.2f ) {
setFrameState(f, DAM);
// Disable the lock on damaged frames.
setHingeLocked(f->getParent(), false);
}
}
}
@ -494,6 +505,118 @@ void VehicleObject::applyWaterFloat(const glm::vec3 &relPt)
}
}
void VehicleObject::setHingeLocked(ModelFrame *frame, bool locked)
{
auto hit = _hingedObjects.find(frame);
if( hit != _hingedObjects.end() ) {
if( !locked && hit->second.body == nullptr ) {
createObjectHinge(physBody->getWorldTransform(), frame);
}
else if( locked && hit->second.body ) {
destroyObjectHinge(hit->second);
}
}
}
void VehicleObject::createObjectHinge(btTransform& local, ModelFrame *frame)
{
float sign = glm::sign(frame->getDefaultTranslation().x);
btVector3 hingeAxis,
hingePosition;
btVector3 boxSize,
boxOffset;
float hingeMax = 1.f;
float hingeMin = 0.f;
auto& fn = frame->getName();
if( frame->getChildren().size() == 0 ) return;
ModelFrame* okframe = frame->getChildren()[0];
if( okframe->getGeometries().size() == 0 ) return;
auto& geom = model->model->geometries[okframe->getGeometries()[0]];
auto gbounds = geom->geometryBounds;
if( fn.find("door") != fn.npos ) {
std::cout << fn << std::endl;
hingeAxis = {0.f, 0.f, 1.f};
hingePosition = {0.f, 0.2f, 0.f};
boxSize = {0.1f, 0.4f, gbounds.radius/2.f};
boxOffset = {0.f,-0.2f, gbounds.center.z/2.f};
if( sign > 0.f ) {
hingeMin = -glm::quarter_pi<float>() * 1.5f;
hingeMax = 0.f;
}
else {
hingeMax = glm::quarter_pi<float>() * 1.5f;
hingeMin = 0.f;
}
}
else if( fn.find("bonnet") != fn.npos ) {
hingeAxis = {1.f, 0.f, 0.f};
hingePosition = {0.f, -0.2f, 0.f};
hingeMax = 0.f;
hingeMin = -glm::quarter_pi<float>() * 1.5f;
boxSize = {0.4f, 0.4f, 0.1f};
boxOffset = {0.f, 0.2f, 0.f};
}
else {
// TODO: boot, bumper
return;
}
btDefaultMotionState* dms = new btDefaultMotionState();
btTransform tr = btTransform::getIdentity();
auto p = frame->getDefaultTranslation();
auto o = glm::toQuat(frame->getDefaultRotation());
auto bp = btVector3(p.x, p.y, p.z);
tr.setOrigin(bp);
tr.setRotation(btQuaternion(o.x, o.y, o.z, o.w));
dms->setWorldTransform(local * tr);
btCompoundShape* cs = new btCompoundShape;
btCollisionShape* bshape = new btBoxShape( boxSize );
btTransform t; t.setIdentity();
t.setOrigin(boxOffset);
cs->addChildShape(t, bshape);
btVector3 inertia;
cs->calculateLocalInertia(10.f, inertia);
btRigidBody::btRigidBodyConstructionInfo rginfo(10.f, dms, cs, inertia);
btRigidBody* subObject = new btRigidBody(rginfo);
subObject->setUserPointer(this);
auto hinge = new btHingeConstraint(
*physBody,
*subObject,
bp, hingePosition,
hingeAxis, hingeAxis);
hinge->setLimit(hingeMin, hingeMax);
engine->dynamicsWorld->addRigidBody(subObject);
engine->dynamicsWorld->addConstraint(hinge, true);
_hingedObjects[frame].body = subObject;
_hingedObjects[frame].constraint = hinge;
}
void VehicleObject::destroyObjectHinge(VehicleObject::HingeInfo &hinge)
{
if( hinge.body ) {
engine->dynamicsWorld->removeRigidBody(hinge.body);
engine->dynamicsWorld->removeConstraint(hinge.constraint);
delete hinge.body;
delete hinge.constraint;
hinge.body = nullptr;
hinge.constraint = nullptr;
}
}
// Dammnit Bullet
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback

View File

@ -1,6 +1,7 @@
#include "debugstate.hpp"
#include "game.hpp"
#include <objects/CharacterObject.hpp>
#include <objects/VehicleObject.hpp>
DebugState::DebugState()
: _freeLook( false ), _sonicMode( false )
@ -16,6 +17,15 @@ DebugState::DebugState()
}
spawnVehicle(it->first);
}, entryHeight));
m->addEntry(Menu::lambda("Open All Doors/Flaps", [this] {
auto pc = getPlayerCharacter();
auto pv = pc->getCurrentVehicle();
if( pv ) {
for(auto& it : pv->_hingedObjects) {
pv->setHingeLocked(it.first, false);
}
}
}, entryHeight));
int vehiclesMax = 16, i = 0;
for( auto& v : getWorld()->vehicleTypes ) {
if( (i++) > vehiclesMax ) break;

View File

@ -68,5 +68,28 @@ BOOST_AUTO_TEST_CASE(test_door_position)
Global::get().e->destroyObject(vehicle);
}
BOOST_AUTO_TEST_CASE(test_hinges)
{
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
BOOST_CHECK( vehicle->_hingedObjects.size() > 0 );
for(auto& ho : vehicle->_hingedObjects) {
// All Hinge objects should initalize, but not be locked.
BOOST_CHECK( ho.second.body == nullptr );
}
auto fld = vehicle->model->model->findFrame("door_lf_dummy");
vehicle->setHingeLocked(fld, false);
BOOST_REQUIRE( vehicle->_hingedObjects[fld].body != nullptr );
vehicle->setHingeLocked(fld, true);
BOOST_CHECK( vehicle->_hingedObjects[fld].body == nullptr );
}
BOOST_AUTO_TEST_SUITE_END()