1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 02:12:45 +01: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 turnMass; // Kg m^3
float airRes; // fraction
float elacticity; // "
float bouancy;
float elasticity; // "
float buoyancy;
float uprootForce; // Force
float collDamageMulti;
/*
* 1: change model
* 2: split model
* 3: smash
* 4: change and smash
*/
uint8_t collDamageFlags;
/*
* 1: lampost
* 2: smallbox
* 3: bigbox
* 4: fencepart
*/
enum {
Damage_ChangeModel = 1,
Damage_SplitModel = 2,
Damage_Smash = 3,
Damage_ChangeThenSmash = 4,
Damage_SmashCardboard = 50,
Damage_SmashWoodenBox = 60,
Damage_SmashTrafficCone = 70,
Damage_SmashBarPost = 80,
};
uint8_t collDamageEffect;
enum {
Response_None = 0,
Response_LampPost = 1,
Response_SmallBox = 2,
Response_BigBox = 3,
Response_FencePart = 4,
};
uint8_t collResponseFlags;
bool cameraAvoid;
};

View File

@ -587,9 +587,12 @@ void handleInstanceResponse(InstanceObject *instance, const btManifoldPoint &mp,
auto impulse = mp.getAppliedImpulse();
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()},
{dmg.x(), dmg.y(), dmg.z()},
0.f,
hp,
GameObject::DamageInfo::Physics,
impulse});
}

View File

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

View File

@ -47,86 +47,81 @@ InstanceObject::~InstanceObject() {
}
void InstanceObject::tick(float dt) {
if (dynamics && body) {
if (_enablePhysics) {
if (body->getBulletBody()->isStaticObject()) {
body->changeMass(dynamics->mass);
}
}
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 (!body || !dynamics) {
return;
}
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->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 (changeAtomic != -1) {
RW_ASSERT(getModelInfo<SimpleModelInfo>()->getNumAtomics() >
changeAtomic);
changeModel(getModelInfo<SimpleModelInfo>(), changeAtomic);
changeAtomic = -1;
}
if (_enablePhysics) {
if (body->getBulletBody()->isStaticObject()) {
body->changeMass(dynamics->mass);
}
}
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) {
body.reset();
}
@ -141,12 +136,13 @@ void InstanceObject::changeModel(BaseModelInfo* incoming) {
setModel(getModelInfo<SimpleModelInfo>()->getModel());
auto collision = getModelInfo<SimpleModelInfo>()->getCollision();
auto modelatomic = getModelInfo<SimpleModelInfo>()->getAtomic(0);
if (modelatomic) {
auto previousatomic = atomic_;
atomic_ = modelatomic->clone();
if (previousatomic) {
atomic_->setFrame(previousatomic->getFrame());
RW_ASSERT(getModelInfo<SimpleModelInfo>()->getNumAtomics() > atomicNumber);
auto atomic = getModelInfo<SimpleModelInfo>()->getAtomic(atomicNumber);
if (atomic) {
auto previous = atomic_;
atomic_ = atomic->clone();
if (previous) {
atomic_->setFrame(previous->getFrame());
} else {
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 smash = false;
if (dynamics) {
smash = dynamics->collDamageFlags == 80;
if (!dynamics) {
return false;
}
if (dmg.impulse >= dynamics->uprootForce &&
body->getBulletBody()->isStaticObject()) {
_enablePhysics = true;
const auto effect = dynamics->collDamageEffect;
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;
return true;
if (dmg.impulse >= dynamics->uprootForce &&
body->getBulletBody()->isStaticObject()) {
_enablePhysics = true;
}
return false;
return true;
}
void InstanceObject::setSolid(bool solid) {

View File

@ -19,6 +19,7 @@ class GameWorld;
class InstanceObject : public GameObject {
float health;
bool visible = true;
int changeAtomic = -1;
/**
* The Atomic instance for this object
@ -47,7 +48,7 @@ public:
void tick(float dt) override;
void changeModel(BaseModelInfo* incoming);
void changeModel(BaseModelInfo* incoming, int atomicNumber = 0);
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->turnMass, 4000.0);
BOOST_CHECK_CLOSE(lamp->airRes, 0.99, 1.0);
BOOST_CHECK_CLOSE(lamp->elacticity, 0.05, 0.01);
BOOST_CHECK_EQUAL(lamp->bouancy, 50.0);
BOOST_CHECK_CLOSE(lamp->elasticity, 0.05, 0.01);
BOOST_CHECK_EQUAL(lamp->buoyancy, 50.0);
BOOST_CHECK_EQUAL(lamp->uprootForce, 400);
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->cameraAvoid, false);
}