1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-18 16:32:32 +02:00

Overhaul vehicle part system with VehicleObject::Part

This commit is contained in:
Daniel Evans 2014-12-14 01:32:00 +00:00
parent 27104f7b79
commit 25a3a0183b
3 changed files with 163 additions and 104 deletions

View File

@ -30,13 +30,17 @@ public:
btRigidBody* physBody;
btVehicleRaycaster* physRaycaster;
btRaycastVehicle* physVehicle;
struct HingeInfo {
struct Part
{
ModelFrame* dummy;
ModelFrame* normal;
ModelFrame* damaged;
btRigidBody* body;
btHingeConstraint* constraint;
};
std::map<ModelFrame*, HingeInfo> _hingedObjects;
std::map<std::string, Part> dynamicParts;
VehicleObject(GameWorld* engine,
const glm::vec3& pos,
@ -99,16 +103,19 @@ public:
BROKEN
};
void setFrameState(ModelFrame *f, FrameState state);
void setPartState(Part* part, FrameState state);
void setPartLocked(Part* part, bool locked);
Part* getPart(const std::string& name);
void applyWaterFloat(const glm::vec3& relPt);
void setHingeLocked(ModelFrame* frame, bool locked);
private:
void createObjectHinge(btTransform &local, ModelFrame* frame);
void destroyObjectHinge(HingeInfo& hinge);
void registerPart(ModelFrame* mf);
void createObjectHinge(btTransform &local, Part* part);
void destroyObjectHinge(Part* part);
};
/**

View File

@ -74,10 +74,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm:
}
if( isDum ) {
_hingedObjects[frame] = {
nullptr,
nullptr
};
registerPart(frame);
}
}
}
@ -282,16 +279,16 @@ void VehicleObject::tickPhysics(float dt)
_lastHeight = vH;
// Update hinge object rotations
for(auto it : _hingedObjects) {
for(auto it : dynamicParts) {
if(it.second.body == nullptr) continue;
auto inv = glm::inverse(getRotation());
auto rot = it.second.body->getWorldTransform().getRotation();
auto r2 = inv * glm::quat(rot.w(), rot.x(), rot.y(), rot.z());
auto& prev = skeleton->getData(it.first->getIndex()).a;
auto& prev = skeleton->getData(it.second.dummy->getIndex()).a;
auto next = prev;
next.rotation = r2;
skeleton->setData(it.first->getIndex(), { next, prev, true } );
skeleton->setData(it.second.dummy->getIndex(), { next, prev, true } );
}
}
}
@ -385,19 +382,22 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg)
dpoint -= getPosition();
dpoint = glm::inverse(getRotation()) * dpoint;
// find visible "_ok" frames and damage them.
for(ModelFrame* f : model->model->frames) {
auto& name = f->getName();
if( name.find("_ok") != name.npos ) {
auto& geom = model->model->geometries[f->getGeometries()[0]];
auto pp = f->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f);
// Set any parts within range to damaged state.
for(auto d : dynamicParts)
{
auto p = &d.second;
if( p->normal == nullptr ) continue;
if( skeleton->getData(p->normal->getIndex()).enabled )
{
auto& geom = model->model->geometries[p->normal->getGeometries()[0]];
auto pp = p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f);
float td = glm::distance(glm::vec3(pp)+geom->geometryBounds.center
, dpoint);
if( td < geom->geometryBounds.radius * 1.2f ) {
setFrameState(f, DAM);
// Disable the lock on damaged frames.
setHingeLocked(f->getParent(), false);
setPartState(p, DAM);
setPartLocked(p, false);
}
}
}
@ -406,25 +406,17 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg)
return true;
}
void VehicleObject::setFrameState(ModelFrame* f, FrameState state)
void VehicleObject::setPartState(VehicleObject::Part* part, VehicleObject::FrameState state)
{
bool isOkVis = skeleton->getData(f->getIndex()).enabled;
auto damName = f->getName();
damName.replace(damName.find("_ok"), 3, "_dam");
auto damage = model->model->findFrame(damName);
if(DAM == state) {
if( isOkVis ) {
skeleton->setEnabled(f, false);
skeleton->setEnabled(damage, true);
}
if( state == VehicleObject::OK )
{
if( part->normal ) skeleton->setEnabled(part->normal, true);
if( part->damaged ) skeleton->setEnabled(part->damaged, false);
}
else if(OK == state) {
if(!isOkVis ) {
skeleton->setEnabled(f, true);
skeleton->setEnabled(damage, false);
}
else if( state == VehicleObject::DAM )
{
if( part->normal ) skeleton->setEnabled(part->normal, false);
if( part->damaged ) skeleton->setEnabled(part->damaged, true);
}
}
@ -447,22 +439,67 @@ void VehicleObject::applyWaterFloat(const glm::vec3 &relPt)
}
}
void VehicleObject::setHingeLocked(ModelFrame *frame, bool locked)
void VehicleObject::setPartLocked(VehicleObject::Part* part, 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);
}
if( part->body == nullptr && locked == false )
{
createObjectHinge(physBody->getWorldTransform(), part);
}
else if( part->body != nullptr && locked == true )
{
destroyObjectHinge(part);
}
}
void VehicleObject::createObjectHinge(btTransform& local, ModelFrame *frame)
VehicleObject::Part* VehicleObject::getPart(const std::string& name)
{
float sign = glm::sign(frame->getDefaultTranslation().x);
auto f = dynamicParts.find(name);
if( f != dynamicParts.end() )
{
return &f->second;
}
return nullptr;
}
ModelFrame* findStateFrame(ModelFrame* f, const std::string& state)
{
auto it = std::find_if(
f->getChildren().begin(),
f->getChildren().end(),
[&](ModelFrame* c){ return c->getName().find(state) != std::string::npos; }
);
if( it != f->getChildren().end() )
{
return *it;
}
return nullptr;
}
void VehicleObject::registerPart(ModelFrame* mf)
{
auto normal = findStateFrame(mf, "_ok");
auto damage = findStateFrame(mf, "_dam");
if( normal == nullptr && damage == nullptr )
{
// Not actually a useful part, just a dummy.
return;
}
dynamicParts.insert(
{ mf->getName(),
{
mf,
normal,
damage,
nullptr, nullptr
}
});
}
void VehicleObject::createObjectHinge(btTransform& local, Part *part)
{
float sign = glm::sign(part->dummy->getDefaultTranslation().x);
btVector3 hingeAxis,
hingePosition;
btVector3 boxSize,
@ -470,13 +507,12 @@ void VehicleObject::createObjectHinge(btTransform& local, ModelFrame *frame)
float hingeMax = 1.f;
float hingeMin = 0.f;
auto& fn = frame->getName();
auto& fn = part->dummy->getName();
if( frame->getChildren().size() == 0 ) return;
ModelFrame* okframe = frame->getChildren()[0];
ModelFrame* okframe = part->normal;
if( okframe->getGeometries().size() == 0 ) return;
auto& geom = model->model->geometries[okframe->getGeometries()[0]];
auto gbounds = geom->geometryBounds;
@ -510,8 +546,8 @@ void VehicleObject::createObjectHinge(btTransform& local, ModelFrame *frame)
btDefaultMotionState* dms = new btDefaultMotionState();
btTransform tr = btTransform::getIdentity();
auto p = frame->getDefaultTranslation();
auto o = glm::toQuat(frame->getDefaultRotation());
auto p = part->dummy->getDefaultTranslation();
auto o = glm::toQuat(part->dummy->getDefaultRotation());
tr.setOrigin(btVector3(p.x, p.y, p.z));
tr.setRotation(btQuaternion(o.x, o.y, o.z, o.w));
@ -539,21 +575,21 @@ void VehicleObject::createObjectHinge(btTransform& local, ModelFrame *frame)
engine->dynamicsWorld->addRigidBody(subObject);
engine->dynamicsWorld->addConstraint(hinge, true);
_hingedObjects[frame].body = subObject;
_hingedObjects[frame].constraint = hinge;
part->body = subObject;
part->constraint = hinge;
}
void VehicleObject::destroyObjectHinge(VehicleObject::HingeInfo &hinge)
void VehicleObject::destroyObjectHinge(Part* part)
{
if( hinge.body ) {
engine->dynamicsWorld->removeRigidBody(hinge.body);
engine->dynamicsWorld->removeConstraint(hinge.constraint);
if( part->body ) {
engine->dynamicsWorld->removeRigidBody(part->body);
engine->dynamicsWorld->removeConstraint(part->constraint);
delete hinge.body;
delete hinge.constraint;
hinge.body = nullptr;
hinge.constraint = nullptr;
delete part->body;
delete part->constraint;
part->body = nullptr;
part->constraint = nullptr;
}
}

View File

@ -25,31 +25,45 @@ BOOST_AUTO_TEST_CASE(test_create_vehicle)
Global::get().e->destroyObject(vehicle);
}
BOOST_AUTO_TEST_CASE(vehicle_frame_vis)
BOOST_AUTO_TEST_CASE(vehicle_parts)
{
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
BOOST_REQUIRE(vehicle != nullptr);
BOOST_REQUIRE(vehicle->model != nullptr);
VehicleObject::Part* part = vehicle->getPart("bonnet_dummy");
BOOST_REQUIRE( part != nullptr );
BOOST_REQUIRE( part->normal != nullptr );
BOOST_REQUIRE( part->damaged != nullptr );
BOOST_CHECK_EQUAL( part->normal->getName(), "bonnet_hi_ok");
BOOST_CHECK_EQUAL( part->damaged->getName(), "bonnet_hi_dam");
Global::get().e->destroyObject(vehicle);
}
auto bonnet_ok = vehicle->model->model->findFrame("bonnet_hi_ok");
auto bonnet_dam = vehicle->model->model->findFrame("bonnet_hi_dam");
BOOST_AUTO_TEST_CASE(vehicle_part_vis)
{
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
BOOST_REQUIRE(bonnet_ok != nullptr);
BOOST_REQUIRE(bonnet_dam != nullptr);
BOOST_CHECK( vehicle->skeleton->getData(bonnet_ok->getIndex()).enabled );
BOOST_CHECK(!vehicle->skeleton->getData(bonnet_dam->getIndex()).enabled);
vehicle->setFrameState(bonnet_ok, VehicleObject::DAM);
BOOST_CHECK(!vehicle->skeleton->getData(bonnet_ok->getIndex()).enabled );
BOOST_CHECK( vehicle->skeleton->getData(bonnet_dam->getIndex()).enabled);
vehicle->setFrameState(bonnet_ok, VehicleObject::OK);
BOOST_CHECK( vehicle->skeleton->getData(bonnet_ok->getIndex()).enabled );
BOOST_CHECK(!vehicle->skeleton->getData(bonnet_dam->getIndex()).enabled);
BOOST_REQUIRE(vehicle != nullptr);
BOOST_REQUIRE(vehicle->model != nullptr);
VehicleObject::Part* bonnetpart = vehicle->getPart("bonnet_dummy");
auto skel = vehicle->skeleton;
vehicle->setPartState(bonnetpart, VehicleObject::DAM);
BOOST_CHECK(!skel->getData(bonnetpart->normal->getIndex()).enabled );
BOOST_CHECK( skel->getData(bonnetpart->damaged->getIndex()).enabled );
vehicle->setPartState(bonnetpart, VehicleObject::OK);
BOOST_CHECK( skel->getData(bonnetpart->normal->getIndex()).enabled );
BOOST_CHECK(!skel->getData(bonnetpart->damaged->getIndex()).enabled );
Global::get().e->destroyObject(vehicle);
}
@ -72,23 +86,25 @@ BOOST_AUTO_TEST_CASE(test_door_position)
BOOST_AUTO_TEST_CASE(test_hinges)
{
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
BOOST_REQUIRE( vehicle != nullptr );
BOOST_CHECK( vehicle->_hingedObjects.size() > 0 );
VehicleObject::Part* part = vehicle->getPart("door_lf_dummy");
BOOST_REQUIRE( part != nullptr );
BOOST_CHECK_EQUAL( part->constraint, nullptr );
BOOST_CHECK_EQUAL( part->body, nullptr );
vehicle->setPartLocked(part, false);
BOOST_CHECK_NE( part->body, nullptr );
BOOST_CHECK_NE( part->constraint, nullptr );
vehicle->setPartLocked(part, true);
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_CHECK_EQUAL( part->constraint, nullptr );
BOOST_CHECK_EQUAL( part->body, nullptr );
}
BOOST_AUTO_TEST_SUITE_END()