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:
parent
8cbf1eaefe
commit
3ccf5ebaa2
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user