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

Initial dynamic object implementation

This commit is contained in:
Daniel Evans 2014-06-11 21:00:53 +01:00
parent 0cdbb0c09c
commit 65b5c84b92
9 changed files with 142 additions and 18 deletions

View File

@ -84,6 +84,11 @@ struct GameObject
* Type of the damage
*/
DamageType type;
/**
* Physics impulse.
*/
float impulse;
};
virtual bool takeDamage(const DamageInfo& damage) { return false; }

View File

@ -196,6 +196,12 @@ public:
btSequentialImpulseConstraintSolver* solver;
btDiscreteDynamicsWorld* dynamicsWorld;
/**
* @brief handleCollisionResponses performs physics response checking
* for collisions between vehicles, objects etc.
*/
void handleCollisionResponses();
/**
* Work related
*/

View File

@ -2,6 +2,7 @@
#ifndef _OBJECTINSTANCE_HPP_
#define _OBJECTINSTANCE_HPP_
#include <engine/GameObject.hpp>
#include <btBulletDynamicsCommon.h>
/**
* @struct InstanceObject
@ -10,8 +11,10 @@
struct InstanceObject : public GameObject
{
glm::vec3 scale;
btRigidBody* body = nullptr;
std::shared_ptr<ObjectData> object;
std::shared_ptr<InstanceObject> LODinstance;
std::shared_ptr<DynamicObjectData> dynamics;
InstanceObject(
GameWorld* engine,
@ -20,12 +23,13 @@ struct InstanceObject : public GameObject
ModelHandle* model,
const glm::vec3& scale,
std::shared_ptr<ObjectData> obj,
std::shared_ptr<InstanceObject> lod
std::shared_ptr<InstanceObject> lod,
std::shared_ptr<DynamicObjectData> dyn
);
Type type() { return Instance; }
virtual bool takeDamage(const DamageInfo& damage);
virtual bool takeDamage(const DamageInfo& damage);
};

View File

@ -474,15 +474,31 @@ void GameData::loadDynamicObjects(const std::string& name)
std::shared_ptr<DynamicObjectData> dyndata(new DynamicObjectData);
ss >> dyndata->modelName;
auto cpos = dyndata->modelName.find(',');
if( cpos != dyndata->modelName.npos ) {
dyndata->modelName.erase(cpos);
}
ss >> dyndata->mass;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->turnMass;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->airRes;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->elacticity;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->bouancy;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->uprootForce;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->collDamageMulti;
ss >> dyndata->collDamageFlags;
ss >> dyndata->collResponseFlags;
if(ss.peek() == ',') ss.ignore(1);
int tmp;
ss >> tmp;
dyndata->collDamageFlags = tmp;
if(ss.peek() == ',') ss.ignore(1);
ss >> tmp;
dyndata->collResponseFlags = tmp;
if(ss.peek() == ',') ss.ignore(1);
ss >> dyndata->cameraAvoid;
dynamicObjectData.insert({dyndata->modelName, dyndata});

View File

@ -187,6 +187,13 @@ InstanceObject *GameWorld::createInstance(const uint16_t id, const glm::vec3& po
if(! oi->second->textureName.empty()) {
gameData.loadTXD(oi->second->textureName + ".txd", true);
}
// Check for dynamic data.
auto dyit = gameData.dynamicObjectData.find(oi->second->modelName);
std::shared_ptr<DynamicObjectData> dydata;
if( dyit != gameData.dynamicObjectData.end() ) {
dydata = dyit->second;
}
auto instance = std::shared_ptr<InstanceObject>(new InstanceObject(
this,
@ -194,7 +201,7 @@ InstanceObject *GameWorld::createInstance(const uint16_t id, const glm::vec3& po
rot,
gameData.models[oi->second->modelName],
glm::vec3(1.f, 1.f, 1.f),
oi->second, nullptr
oi->second, nullptr, dydata
));
objectInstances.push_back(instance);
@ -350,3 +357,59 @@ int GameWorld::getMinute()
{
return fmod(gameTime, 60.f);
}
void GameWorld::handleCollisionResponses()
{
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
for (int i = 0; i < numManifolds; i++)
{
btPersistentManifold* contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
auto obA = static_cast<const btCollisionObject*>(contactManifold->getBody0());
auto obB = static_cast<const btCollisionObject*>(contactManifold->getBody1());
int numContacts = contactManifold->getNumContacts();
for (int j = 0; j < numContacts; j++)
{
// Check that at least one of the objects involved is an instance.
GameObject* a = static_cast<GameObject*>(obA->getUserPointer());
GameObject* b = static_cast<GameObject*>(obB->getUserPointer());
btManifoldPoint& pt = contactManifold->getContactPoint(j);
if(a && a->type() == GameObject::Instance) {
auto inst = static_cast<InstanceObject*>(a);
if( inst->dynamics ) {
if( pt.getAppliedImpulse() > inst->dynamics->uprootForce ) {
auto dmg = pt.getPositionWorldOnA();
auto src = pt.getPositionWorldOnB();
inst->takeDamage({
{dmg.x(), dmg.y(), dmg.z()},
{src.x(), src.y(), src.z()},
0.f,
GameObject::DamageInfo::Physics,
pt.getAppliedImpulse()
});
}
}
}
if(b && b->type() == GameObject::Instance) {
auto inst = static_cast<InstanceObject*>(b);
if( inst->dynamics ) {
if( pt.getAppliedImpulse() > inst->dynamics->uprootForce ) {
auto dmg = pt.getPositionWorldOnB();
auto src = pt.getPositionWorldOnA();
inst->takeDamage({
{dmg.x(), dmg.y(), dmg.z()},
{src.x(), src.y(), src.z()},
0.f,
GameObject::DamageInfo::Physics,
pt.getAppliedImpulse()
});
}
}
}
}
}
}

View File

@ -8,11 +8,11 @@ InstanceObject::InstanceObject(GameWorld* engine,
ModelHandle *model,
const glm::vec3& scale,
std::shared_ptr<ObjectData> obj,
std::shared_ptr<InstanceObject> lod
)
: GameObject(engine, pos, rot, model), scale(scale), object(obj), LODinstance(lod)
std::shared_ptr<InstanceObject> lod,
std::shared_ptr<DynamicObjectData> dyn)
: GameObject(engine, pos, rot, model), scale(scale), object(obj),
LODinstance(lod), dynamics(dyn)
{
btRigidBody* body = nullptr;
auto phyit = engine->gameData.collisions.find(obj->modelName);
if( phyit != engine->gameData.collisions.end()) {
btCompoundShape* cmpShape = new btCompoundShape;
@ -62,9 +62,23 @@ InstanceObject::InstanceObject(GameWorld* engine,
cmpShape->addChildShape(t, trishape);
}
if( dynamics ) {
if( dynamics->uprootForce > 0.f ) {
info.m_mass = 0.f;
}
else {
btVector3 inert;
cmpShape->calculateLocalInertia(dynamics->mass, inert);
info.m_mass = dynamics->mass;
info.m_localInertia = inert;
}
}
body = new btRigidBody(info);
body->setUserPointer(this);
engine->dynamicsWorld->addRigidBody(body);
body->setActivationState(ISLAND_SLEEPING);
}
auto pathit = engine->objectNodes.find(obj->ID);
@ -81,6 +95,18 @@ bool InstanceObject::takeDamage(const GameObject::DamageInfo& dmg)
{
bool explodeOnHit = (object->flags&ObjectData::EXPLODEONHIT) == ObjectData::EXPLODEONHIT;
bool smash = (object->flags&ObjectData::SMASHABLE) == ObjectData::SMASHABLE;
if( dynamics ) {
smash = dynamics->collDamageFlags == 80;
if( dmg.impulse >= dynamics->uprootForce && (body->getCollisionFlags() & btRigidBody::CF_STATIC_OBJECT) != 0 ) {
// Apparently bodies must be removed and re-added if their mass changes.
engine->dynamicsWorld->removeRigidBody(body);
btVector3 inert;
body->getCollisionShape()->calculateLocalInertia(dynamics->mass, inert);
body->setMassProps(dynamics->mass, inert);
engine->dynamicsWorld->addRigidBody(body);
}
}
if(explodeOnHit || smash)
{
if(explodeOnHit) {
@ -95,3 +121,4 @@ bool InstanceObject::takeDamage(const GameObject::DamageInfo& dmg)
return false;
}

View File

@ -327,9 +327,14 @@ void GameRenderer::renderWorld(float alpha)
}
glm::mat4 matrixModel;
matrixModel = glm::translate(matrixModel, inst.position);
matrixModel = glm::scale(matrixModel, inst.scale);
matrixModel = matrixModel * glm::mat4_cast(inst.rotation);
if( inst.body ) {
inst.body->getWorldTransform().getOpenGLMatrix(glm::value_ptr(matrixModel));
}
else {
matrixModel = glm::translate(matrixModel, inst.position);
matrixModel = glm::scale(matrixModel, inst.scale);
matrixModel = matrixModel * glm::mat4_cast(inst.rotation);
}
float mindist = 100000.f;
for (size_t g = 0; g < inst.model->model->geometries.size(); g++)

View File

@ -345,10 +345,10 @@ void update(float dt)
v--;
}
}
gta->dynamicsWorld->stepSimulation(dt, 2, dt);
gta->handleCollisionResponses();
}
}

View File

@ -12,8 +12,7 @@ BOOST_AUTO_TEST_CASE(instance_test_damage)
glm::vec3(0.f, 0.f, 0.f),
glm::quat(), nullptr,
glm::vec3(1.f),
object,
nullptr
object, nullptr, nullptr
);
GameObject::DamageInfo dmg;
dmg.type = GameObject::DamageInfo::Bullet;
@ -40,8 +39,7 @@ BOOST_AUTO_TEST_CASE(instance_test_destroy)
glm::vec3(0.f, 0.f, 0.f),
glm::quat(), nullptr,
glm::vec3(1.f),
object,
nullptr
object, nullptr, nullptr
);
GameObject::DamageInfo dmg;
dmg.type = GameObject::DamageInfo::Bullet;