mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
Improved vehicle door dynamics with opening doors
This commit is contained in:
parent
25a3a0183b
commit
77f2277a68
@ -38,6 +38,8 @@ public:
|
||||
ModelFrame* damaged;
|
||||
btRigidBody* body;
|
||||
btHingeConstraint* constraint;
|
||||
bool holdAngle;
|
||||
float targetAngle;
|
||||
};
|
||||
|
||||
std::map<std::string, Part> dynamicParts;
|
||||
@ -95,6 +97,8 @@ public:
|
||||
return getPosition() + getRotation() * pos;
|
||||
}
|
||||
|
||||
Part* getSeatEntryDoor(size_t seat);
|
||||
|
||||
virtual bool takeDamage(const DamageInfo& damage);
|
||||
|
||||
enum FrameState {
|
||||
@ -107,6 +111,8 @@ public:
|
||||
|
||||
void setPartLocked(Part* part, bool locked);
|
||||
|
||||
void setPartTarget(Part* part, bool enable, float target);
|
||||
|
||||
Part* getPart(const std::string& name);
|
||||
|
||||
void applyWaterFloat(const glm::vec3& relPt);
|
||||
|
@ -218,12 +218,18 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr
|
||||
auto anm_open = character->animations.car_open_lhs;
|
||||
auto anm_enter = character->animations.car_getin_lhs;
|
||||
|
||||
auto entryDoor = vehicle->getSeatEntryDoor(seat);
|
||||
|
||||
if( entering ) {
|
||||
if( character->animator->getAnimation() == anm_open ) {
|
||||
if( character->animator->isCompleted() ) {
|
||||
character->playAnimation(anm_enter, false);
|
||||
character->enterVehicle(vehicle, seat);
|
||||
}
|
||||
else if( entryDoor && character->animator->getAnimationTime() >= 0.5f )
|
||||
{
|
||||
vehicle->setPartTarget(entryDoor, true, 1.f);
|
||||
}
|
||||
else {
|
||||
//character->setPosition(vehicle->getSeatEntryPosition(seat));
|
||||
character->rotation = vehicle->getRotation();
|
||||
@ -231,6 +237,11 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr
|
||||
}
|
||||
else if( character->animator->getAnimation() == anm_enter ) {
|
||||
if( character->animator->isCompleted() ) {
|
||||
if( entryDoor )
|
||||
{
|
||||
vehicle->setPartTarget(entryDoor, true, 0.f);
|
||||
}
|
||||
|
||||
// VehicleGetIn is over, finish activity
|
||||
return true;
|
||||
}
|
||||
@ -248,8 +259,18 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr
|
||||
// Warp character to vehicle orientation
|
||||
character->controller->setRawMovement({0.f, 0.f, 0.f});
|
||||
character->rotation = vehicle->getRotation();
|
||||
|
||||
// Determine if the door open animation should be skipped.
|
||||
if( entryDoor == nullptr || (entryDoor->constraint != nullptr && entryDoor->constraint->getHingeAngle() >= 0.6f ) )
|
||||
{
|
||||
character->playAnimation(anm_enter, false);
|
||||
character->enterVehicle(vehicle, seat);
|
||||
}
|
||||
else
|
||||
{
|
||||
character->playAnimation(anm_open, false);
|
||||
}
|
||||
}
|
||||
else if( targetDistance > 15.f ) {
|
||||
return true; // Give up if the vehicle is too far away.
|
||||
}
|
||||
@ -289,6 +310,12 @@ bool Activities::ExitVehicle::update(CharacterObject *character, CharacterContro
|
||||
}
|
||||
else {
|
||||
character->playAnimation(anm_exit, false);
|
||||
|
||||
auto door = vehicle->getSeatEntryDoor(character->getCurrentSeat());
|
||||
if( door )
|
||||
{
|
||||
vehicle->setPartTarget(door, true, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <render/Model.hpp>
|
||||
#include <engine/Animator.hpp>
|
||||
|
||||
#define PART_CLOSE_VELOCITY 0.5f
|
||||
|
||||
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec)
|
||||
: GameObject(engine, pos, rot, model),
|
||||
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false),
|
||||
@ -131,6 +133,7 @@ glm::quat VehicleObject::getRotation() const
|
||||
}
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
void VehicleObject::tick(float dt)
|
||||
{
|
||||
@ -279,7 +282,7 @@ void VehicleObject::tickPhysics(float dt)
|
||||
_lastHeight = vH;
|
||||
|
||||
// Update hinge object rotations
|
||||
for(auto it : dynamicParts) {
|
||||
for(auto& it : dynamicParts) {
|
||||
if(it.second.body == nullptr) continue;
|
||||
auto inv = glm::inverse(getRotation());
|
||||
auto rot = it.second.body->getWorldTransform().getRotation();
|
||||
@ -289,6 +292,22 @@ void VehicleObject::tickPhysics(float dt)
|
||||
auto next = prev;
|
||||
next.rotation = r2;
|
||||
skeleton->setData(it.second.dummy->getIndex(), { next, prev, true } );
|
||||
|
||||
if( it.second.holdAngle )
|
||||
{
|
||||
it.second.constraint->setMotorTarget(it.second.targetAngle, 0.1f);
|
||||
}
|
||||
|
||||
// If the part is moving quite fast and near the limit, lock it.
|
||||
/// @TODO not all parts rotate in the z axis.
|
||||
if(it.second.body->getAngularVelocity().getZ() >= PART_CLOSE_VELOCITY)
|
||||
{
|
||||
auto d = it.second.constraint->getHingeAngle() - it.second.constraint->getLowerLimit();
|
||||
if( std::abs(d) < 0.01f )
|
||||
{
|
||||
setPartLocked(&(it.second), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,6 +390,23 @@ void VehicleObject::setOccupant(size_t seat, GameObject* occupant)
|
||||
}
|
||||
}
|
||||
|
||||
VehicleObject::Part* VehicleObject::getSeatEntryDoor(size_t seat)
|
||||
{
|
||||
auto pos = info->seats.at(seat).offset + glm::vec3(0.f, 0.5f, 0.f);
|
||||
Part* nearestDoor = nullptr;
|
||||
float d = std::numeric_limits<float>::max();
|
||||
for(auto& p : dynamicParts)
|
||||
{
|
||||
float partDist = glm::distance(p.second.dummy->getDefaultTranslation(), pos);
|
||||
if( partDist < d && p.second.dummy->getName().substr(0, 5) == "door_" )
|
||||
{
|
||||
d = partDist;
|
||||
nearestDoor = &p.second;
|
||||
}
|
||||
}
|
||||
return nearestDoor;
|
||||
}
|
||||
|
||||
bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg)
|
||||
{
|
||||
mHealth -= dmg.hitpoints;
|
||||
@ -448,6 +484,39 @@ void VehicleObject::setPartLocked(VehicleObject::Part* part, bool locked)
|
||||
else if( part->body != nullptr && locked == true )
|
||||
{
|
||||
destroyObjectHinge(part);
|
||||
|
||||
// Restore default bone transform
|
||||
auto dt = part->dummy->getDefaultTranslation();
|
||||
auto dr = glm::quat_cast(part->dummy->getDefaultRotation());
|
||||
Skeleton::FrameTransform tf { dt, dr };
|
||||
skeleton->setData(part->dummy->getIndex(), { tf, tf, true });
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleObject::setPartTarget(VehicleObject::Part* part, bool enable, float target)
|
||||
{
|
||||
if( enable )
|
||||
{
|
||||
if( part->body == nullptr )
|
||||
{
|
||||
setPartLocked(part, false);
|
||||
}
|
||||
|
||||
part->targetAngle = target;
|
||||
part->holdAngle = true;
|
||||
|
||||
part->constraint->enableMotor(true);
|
||||
part->body->activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
part->targetAngle = target;
|
||||
part->holdAngle = false;
|
||||
|
||||
if( part->constraint )
|
||||
{
|
||||
part->constraint->enableMotor(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,7 +561,8 @@ void VehicleObject::registerPart(ModelFrame* mf)
|
||||
mf,
|
||||
normal,
|
||||
damage,
|
||||
nullptr, nullptr
|
||||
nullptr, nullptr,
|
||||
false, 0.f
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -582,14 +652,18 @@ void VehicleObject::createObjectHinge(btTransform& local, Part *part)
|
||||
|
||||
void VehicleObject::destroyObjectHinge(Part* part)
|
||||
{
|
||||
if( part->body ) {
|
||||
engine->dynamicsWorld->removeRigidBody(part->body);
|
||||
if( part->body != nullptr ) {
|
||||
engine->dynamicsWorld->removeConstraint(part->constraint);
|
||||
engine->dynamicsWorld->removeRigidBody(part->body);
|
||||
|
||||
delete part->body;
|
||||
delete part->constraint;
|
||||
|
||||
part->body = nullptr;
|
||||
part->constraint = nullptr;
|
||||
|
||||
// Reset target.
|
||||
part->holdAngle = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,28 @@ BOOST_AUTO_TEST_CASE(test_hinges)
|
||||
|
||||
BOOST_CHECK_EQUAL( part->constraint, nullptr );
|
||||
BOOST_CHECK_EQUAL( part->body, nullptr );
|
||||
|
||||
Global::get().e->destroyObject(vehicle);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_open_part)
|
||||
{
|
||||
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
|
||||
|
||||
BOOST_REQUIRE( vehicle != nullptr );
|
||||
|
||||
VehicleObject::Part* part = vehicle->getPart("door_lf_dummy");
|
||||
|
||||
BOOST_REQUIRE( part != nullptr );
|
||||
|
||||
BOOST_CHECK_EQUAL( part->body, nullptr );
|
||||
|
||||
vehicle->setPartLocked(part, true);
|
||||
vehicle->setPartTarget(part, true, 1.f);
|
||||
|
||||
/// @todo a reasonable test
|
||||
|
||||
Global::get().e->destroyObject(vehicle);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user