1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

Skeleton collision effect handling

This commit is contained in:
Daniel Evans 2018-01-13 00:29:21 +00:00
parent 4f0109b17e
commit 65f51bc3c2
6 changed files with 141 additions and 112 deletions

View File

@ -463,24 +463,32 @@ struct DynamicObjectData {
float mass; // Kg float mass; // Kg
float turnMass; // Kg m^3 float turnMass; // Kg m^3
float airRes; // fraction float airRes; // fraction
float elacticity; // " float elasticity; // "
float bouancy; float buoyancy;
float uprootForce; // Force float uprootForce; // Force
float collDamageMulti; float collDamageMulti;
/*
* 1: change model enum {
* 2: split model Damage_ChangeModel = 1,
* 3: smash Damage_SplitModel = 2,
* 4: change and smash Damage_Smash = 3,
*/ Damage_ChangeThenSmash = 4,
uint8_t collDamageFlags; Damage_SmashCardboard = 50,
/* Damage_SmashWoodenBox = 60,
* 1: lampost Damage_SmashTrafficCone = 70,
* 2: smallbox Damage_SmashBarPost = 80,
* 3: bigbox };
* 4: fencepart uint8_t collDamageEffect;
*/
enum {
Response_None = 0,
Response_LampPost = 1,
Response_SmallBox = 2,
Response_BigBox = 3,
Response_FencePart = 4,
};
uint8_t collResponseFlags; uint8_t collResponseFlags;
bool cameraAvoid; bool cameraAvoid;
}; };

View File

@ -587,9 +587,12 @@ void handleInstanceResponse(InstanceObject *instance, const btManifoldPoint &mp,
auto impulse = mp.getAppliedImpulse(); auto impulse = mp.getAppliedImpulse();
if (impulse > 0.0f) { if (impulse > 0.0f) {
///@ todo Correctness: object damage calculation
constexpr auto kMinimumDamageImpulse = 500.f;
const auto hp = std::max(0.f, impulse - kMinimumDamageImpulse);
instance->takeDamage({{dmg.x(), dmg.y(), dmg.z()}, instance->takeDamage({{dmg.x(), dmg.y(), dmg.z()},
{dmg.x(), dmg.y(), dmg.z()}, {dmg.x(), dmg.y(), dmg.z()},
0.f, hp,
GameObject::DamageInfo::Physics, GameObject::DamageInfo::Physics,
impulse}); impulse});
} }

View File

@ -37,9 +37,9 @@ void GenericDATLoader::loadDynamicObjects(const std::string& name,
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
ss >> dyndata->airRes; ss >> dyndata->airRes;
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
ss >> dyndata->elacticity; ss >> dyndata->elasticity;
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
ss >> dyndata->bouancy; ss >> dyndata->buoyancy;
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
ss >> dyndata->uprootForce; ss >> dyndata->uprootForce;
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
@ -47,7 +47,7 @@ void GenericDATLoader::loadDynamicObjects(const std::string& name,
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
int tmp; int tmp;
ss >> tmp; ss >> tmp;
dyndata->collDamageFlags = tmp; dyndata->collDamageEffect = tmp;
if (ss.peek() == ',') ss.ignore(1); if (ss.peek() == ',') ss.ignore(1);
ss >> tmp; ss >> tmp;
dyndata->collResponseFlags = tmp; dyndata->collResponseFlags = tmp;

View File

@ -47,86 +47,81 @@ InstanceObject::~InstanceObject() {
} }
void InstanceObject::tick(float dt) { void InstanceObject::tick(float dt) {
if (dynamics && body) { if (animator) animator->tick(dt);
if (_enablePhysics) {
if (body->getBulletBody()->isStaticObject()) {
body->changeMass(dynamics->mass);
}
}
const glm::vec3& ws = getPosition(); if (!body || !dynamics) {
auto wX = (int)((ws.x + WATER_WORLD_SIZE / 2.f) / return;
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE)); }
auto wY = (int)((ws.y + WATER_WORLD_SIZE / 2.f) /
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE));
float vH = ws.z; // - _collisionHeight/2.f;
float wH = 0.f;
if (wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 && if (changeAtomic != -1) {
wY < WATER_HQ_DATA_SIZE) { RW_ASSERT(getModelInfo<SimpleModelInfo>()->getNumAtomics() >
int i = (wX * WATER_HQ_DATA_SIZE) + wY; changeAtomic);
int hI = engine->data->realWater[i]; changeModel(getModelInfo<SimpleModelInfo>(), changeAtomic);
if (hI < NO_WATER_INDEX) { changeAtomic = -1;
wH = engine->data->waterHeights[hI]; }
wH += engine->data->getWaveHeightAt(ws); if (_enablePhysics) {
inWater = vH <= wH; if (body->getBulletBody()->isStaticObject()) {
} else { body->changeMass(dynamics->mass);
inWater = false;
}
}
_lastHeight = ws.z;
if (inWater) {
float oZ =
-(body->getBoundingHeight() * (dynamics->bouancy / 100.f));
body->getBulletBody()->activate(true);
// Damper motion
body->getBulletBody()->setDamping(0.95f, 0.9f);
auto wi = engine->data->getWaterIndexAt(ws);
if (wi != NO_WATER_INDEX) {
float h = engine->data->waterHeights[wi] + oZ;
// Calculate wave height
h += engine->data->getWaveHeightAt(ws);
if (ws.z <= h) {
/*if( dynamics->uprootForce > 0.f &&
(body->body->getCollisionFlags() &
btRigidBody::CF_STATIC_OBJECT) != 0 ) {
// Apparently bodies must be removed and re-added if
their mass changes.
engine->dynamicsWorld->removeRigidBody(body->body);
btVector3 inert;
body->getCollisionShape()->calculateLocalInertia(dynamics->mass,
inert);
body->setMassProps(dynamics->mass, inert);
engine->dynamicsWorld->addRigidBody(body);
}*/
float x = (h - ws.z);
float F =
WATER_BUOYANCY_K * x +
-WATER_BUOYANCY_C *
body->getBulletBody()->getLinearVelocity().z();
btVector3 forcePos = btVector3(0.f, 0.f, 2.f)
.rotate(body->getBulletBody()
->getOrientation()
.getAxis(),
body->getBulletBody()
->getOrientation()
.getAngle());
body->getBulletBody()->applyForce(btVector3(0.f, 0.f, F),
forcePos);
}
}
} }
} }
if (animator) animator->tick(dt); const glm::vec3& ws = getPosition();
auto wX = (int)((ws.x + WATER_WORLD_SIZE / 2.f) /
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE));
auto wY = (int)((ws.y + WATER_WORLD_SIZE / 2.f) /
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE));
float vH = ws.z; // - _collisionHeight/2.f;
float wH = 0.f;
if (wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 &&
wY < WATER_HQ_DATA_SIZE) {
int i = (wX * WATER_HQ_DATA_SIZE) + wY;
int hI = engine->data->realWater[i];
if (hI < NO_WATER_INDEX) {
wH = engine->data->waterHeights[hI];
wH += engine->data->getWaveHeightAt(ws);
inWater = vH <= wH;
} else {
inWater = false;
}
}
_lastHeight = ws.z;
if (inWater) {
float oZ =
-(body->getBoundingHeight() * (dynamics->buoyancy / 100.f));
body->getBulletBody()->activate(true);
// Damper motion
body->getBulletBody()->setDamping(0.95f, 0.9f);
auto wi = engine->data->getWaterIndexAt(ws);
if (wi != NO_WATER_INDEX) {
float h = engine->data->waterHeights[wi] + oZ;
// Calculate wave height
h += engine->data->getWaveHeightAt(ws);
if (ws.z <= h) {
float x = (h - ws.z);
float F =
WATER_BUOYANCY_K * x +
-WATER_BUOYANCY_C *
body->getBulletBody()->getLinearVelocity().z();
btVector3 forcePos = btVector3(0.f, 0.f, 2.f)
.rotate(body->getBulletBody()
->getOrientation()
.getAxis(),
body->getBulletBody()
->getOrientation()
.getAngle());
body->getBulletBody()->applyForce(btVector3(0.f, 0.f, F),
forcePos);
}
}
}
} }
void InstanceObject::changeModel(BaseModelInfo* incoming) { void InstanceObject::changeModel(BaseModelInfo* incoming, int atomicNumber) {
if (body) { if (body) {
body.reset(); body.reset();
} }
@ -141,12 +136,13 @@ void InstanceObject::changeModel(BaseModelInfo* incoming) {
setModel(getModelInfo<SimpleModelInfo>()->getModel()); setModel(getModelInfo<SimpleModelInfo>()->getModel());
auto collision = getModelInfo<SimpleModelInfo>()->getCollision(); auto collision = getModelInfo<SimpleModelInfo>()->getCollision();
auto modelatomic = getModelInfo<SimpleModelInfo>()->getAtomic(0); RW_ASSERT(getModelInfo<SimpleModelInfo>()->getNumAtomics() > atomicNumber);
if (modelatomic) { auto atomic = getModelInfo<SimpleModelInfo>()->getAtomic(atomicNumber);
auto previousatomic = atomic_; if (atomic) {
atomic_ = modelatomic->clone(); auto previous = atomic_;
if (previousatomic) { atomic_ = atomic->clone();
atomic_->setFrame(previousatomic->getFrame()); if (previous) {
atomic_->setFrame(previous->getFrame());
} else { } else {
atomic_->setFrame(std::make_shared<ModelFrame>()); atomic_->setFrame(std::make_shared<ModelFrame>());
} }
@ -182,20 +178,41 @@ void InstanceObject::setRotation(const glm::quat& r) {
} }
bool InstanceObject::takeDamage(const GameObject::DamageInfo& dmg) { bool InstanceObject::takeDamage(const GameObject::DamageInfo& dmg) {
bool smash = false; if (!dynamics) {
if (dynamics) { return false;
smash = dynamics->collDamageFlags == 80; }
if (dmg.impulse >= dynamics->uprootForce && const auto effect = dynamics->collDamageEffect;
body->getBulletBody()->isStaticObject()) {
_enablePhysics = true; if (dmg.hitpoints > 0.f) {
switch (effect) {
case DynamicObjectData::Damage_ChangeModel:
changeAtomic = 1;
break;
case DynamicObjectData::Damage_ChangeThenSmash:
changeAtomic = 1;
RW_UNIMPLEMENTED("Collision Damage Effect: Changing, then Smashing");
break;
case DynamicObjectData::Damage_Smash:
RW_UNIMPLEMENTED("Collision Damage Effect: Smashing");
break;
case DynamicObjectData::Damage_SmashCardboard:
case DynamicObjectData::Damage_SmashWoodenBox:
case DynamicObjectData::Damage_SmashTrafficCone:
case DynamicObjectData::Damage_SmashBarPost:
RW_UNIMPLEMENTED("Collision Damage Effect");
break;
default:
break;
} }
} }
if (smash) {
health -= dmg.hitpoints; if (dmg.impulse >= dynamics->uprootForce &&
return true; body->getBulletBody()->isStaticObject()) {
_enablePhysics = true;
} }
return false;
return true;
} }
void InstanceObject::setSolid(bool solid) { void InstanceObject::setSolid(bool solid) {

View File

@ -19,6 +19,7 @@ class GameWorld;
class InstanceObject : public GameObject { class InstanceObject : public GameObject {
float health; float health;
bool visible = true; bool visible = true;
int changeAtomic = -1;
/** /**
* The Atomic instance for this object * The Atomic instance for this object
@ -47,7 +48,7 @@ public:
void tick(float dt) override; void tick(float dt) override;
void changeModel(BaseModelInfo* incoming); void changeModel(BaseModelInfo* incoming, int atomicNumber = 0);
void setPosition(const glm::vec3& pos) override; void setPosition(const glm::vec3& pos) override;

View File

@ -59,11 +59,11 @@ BOOST_AUTO_TEST_CASE(test_dynamic_dat_loader) {
BOOST_CHECK_EQUAL(lamp->mass, 600.0); BOOST_CHECK_EQUAL(lamp->mass, 600.0);
BOOST_CHECK_EQUAL(lamp->turnMass, 4000.0); BOOST_CHECK_EQUAL(lamp->turnMass, 4000.0);
BOOST_CHECK_CLOSE(lamp->airRes, 0.99, 1.0); BOOST_CHECK_CLOSE(lamp->airRes, 0.99, 1.0);
BOOST_CHECK_CLOSE(lamp->elacticity, 0.05, 0.01); BOOST_CHECK_CLOSE(lamp->elasticity, 0.05, 0.01);
BOOST_CHECK_EQUAL(lamp->bouancy, 50.0); BOOST_CHECK_EQUAL(lamp->buoyancy, 50.0);
BOOST_CHECK_EQUAL(lamp->uprootForce, 400); BOOST_CHECK_EQUAL(lamp->uprootForce, 400);
BOOST_CHECK_EQUAL(lamp->collDamageMulti, 1.0); BOOST_CHECK_EQUAL(lamp->collDamageMulti, 1.0);
BOOST_CHECK_EQUAL(lamp->collDamageFlags, 1); BOOST_CHECK_EQUAL(lamp->collDamageEffect, 1);
BOOST_CHECK_EQUAL(lamp->collResponseFlags, 1); BOOST_CHECK_EQUAL(lamp->collResponseFlags, 1);
BOOST_CHECK_EQUAL(lamp->cameraAvoid, false); BOOST_CHECK_EQUAL(lamp->cameraAvoid, false);
} }