mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 02:12:45 +01:00
Initial, unstable, water dynamics
This commit is contained in:
parent
77aa71df7e
commit
2c16134abd
@ -260,6 +260,8 @@ public:
|
||||
* The "real" water heights
|
||||
*/
|
||||
uint8_t realWater[128*128];
|
||||
|
||||
int getWaterIndexAt(const glm::vec3& ws) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -27,14 +27,17 @@ struct GameObject
|
||||
GameWorld* engine;
|
||||
|
||||
Animator* animator; /// Object's animator.
|
||||
|
||||
|
||||
/**
|
||||
* Health value
|
||||
*/
|
||||
float mHealth;
|
||||
|
||||
bool _inWater;
|
||||
|
||||
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model)
|
||||
: position(pos), rotation(rot), model(model), engine(engine), animator(nullptr), mHealth(0.f)
|
||||
: position(pos), rotation(rot), model(model), engine(engine), animator(nullptr), mHealth(0.f),
|
||||
_inWater(false)
|
||||
{}
|
||||
|
||||
virtual ~GameObject() {}
|
||||
@ -96,6 +99,8 @@ struct GameObject
|
||||
virtual bool isFrameVisible(ModelFrame* frame) const { return true; }
|
||||
|
||||
virtual bool isAnimationFixed() const { return true; }
|
||||
|
||||
virtual bool isInWater() const { return _inWater; }
|
||||
};
|
||||
|
||||
#endif // __GAMEOBJECTS_HPP__
|
||||
|
@ -7,6 +7,12 @@
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#define NO_WATER_INDEX 48
|
||||
#define WATER_LQ_DATA_SIZE 64
|
||||
#define WATER_HQ_DATA_SIZE 128
|
||||
#define WATER_WORLD_SIZE 4096.f
|
||||
#define WATER_HQ_DISTANCE 128.f
|
||||
|
||||
class Animation;
|
||||
|
||||
typedef std::map<std::string, Animation*> AnimationSet;
|
||||
|
@ -36,6 +36,9 @@ private:
|
||||
float brake;
|
||||
bool handbrake;
|
||||
unsigned int damageFlags;
|
||||
|
||||
// Used to determine in water status
|
||||
float _lastHeight;
|
||||
public:
|
||||
|
||||
VehicleDataHandle vehicle;
|
||||
@ -103,6 +106,8 @@ public:
|
||||
void setPartDamaged(unsigned int flag, bool damaged);
|
||||
|
||||
virtual bool isFrameVisible(ModelFrame *frame) const;
|
||||
|
||||
void applyWaterFloat(const glm::vec3& relPt, float force, float waterOffset);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -91,6 +91,8 @@ glm::vec3 PlayerController::getTargetPosition()
|
||||
|
||||
void PlayerController::jump()
|
||||
{
|
||||
character->jump();
|
||||
if(! character->isInWater() ) {
|
||||
character->jump();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,3 +581,15 @@ TextureAtlas* GameData::getAtlas(size_t i)
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int GameData::getWaterIndexAt(const glm::vec3 &ws) const
|
||||
{
|
||||
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));
|
||||
|
||||
if( wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 && wY < WATER_HQ_DATA_SIZE ) {
|
||||
int i = (wX*WATER_HQ_DATA_SIZE) + wY;
|
||||
return engine->gameData.realWater[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,10 +224,27 @@ void CharacterObject::updateCharacter(float dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle above waist height water.
|
||||
auto wi = engine->gameData.getWaterIndexAt(getPosition());
|
||||
if( wi != NO_WATER_INDEX ) {
|
||||
float wh = engine->gameData.waterHeights[wi];
|
||||
auto ws = getPosition();
|
||||
if( ws.z < wh ) {
|
||||
ws.z = wh;
|
||||
setPosition(ws);
|
||||
physCharacter->setGravity(0.f);
|
||||
_inWater = true;
|
||||
}
|
||||
else {
|
||||
physCharacter->setGravity(9.81f);
|
||||
_inWater = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentActivity == CharacterObject::Jump)
|
||||
{
|
||||
if(physCharacter->onGround())
|
||||
if(physCharacter->onGround() || isInWater())
|
||||
{
|
||||
enterAction(CharacterObject::Idle);
|
||||
}
|
||||
|
@ -9,7 +9,8 @@
|
||||
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::vec3& prim, const glm::vec3& sec)
|
||||
: GameObject(engine, pos, rot, model),
|
||||
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false),
|
||||
damageFlags(0), vehicle(data), info(info), colourPrimary(prim),
|
||||
damageFlags(0), _lastHeight(0.f), vehicle(data),
|
||||
info(info), colourPrimary(prim),
|
||||
colourSecondary(sec), physBody(nullptr), physVehicle(nullptr)
|
||||
{
|
||||
mHealth = 100.f;
|
||||
@ -181,6 +182,63 @@ void VehicleObject::tick(float dt)
|
||||
//physVehicle->setSteeringValue(std::min(3.141f/2.f, std::abs(steerAngle)) * sign, w);
|
||||
}
|
||||
}
|
||||
|
||||
auto 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 - info->handling.dimensions.z;
|
||||
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->gameData.realWater[i];
|
||||
if( hI < NO_WATER_INDEX ) {
|
||||
wH = engine->gameData.waterHeights[hI];
|
||||
// If the vehicle is currently underwater
|
||||
if( vH <= wH ) {
|
||||
// and was not underwater here in the last tick
|
||||
if( _lastHeight >= wH ) {
|
||||
// we are for real, underwater
|
||||
_inWater = true;
|
||||
}
|
||||
else if( _inWater == false ) {
|
||||
// It's just a tunnel or something, we good.
|
||||
_inWater = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The water is beneath us
|
||||
_inWater = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_inWater = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( _inWater ) {
|
||||
float oZ = 0.f;
|
||||
if( vehicle->type != VehicleData::BOAT ) {
|
||||
oZ = -((-info->handling.dimensions.z/2.f) + info->handling.dimensions.z * (info->handling.percentSubmerged/100.f));
|
||||
}
|
||||
auto vFwd = getRotation() * glm::vec3(info->handling.dimensions.y, 0.f, 0.f);
|
||||
auto vRt = getRotation() * glm::vec3(0.f, info->handling.dimensions.x, 0.f);
|
||||
|
||||
float buoyancyForce = info->handling.mass * 9.81f * 0.75f;
|
||||
|
||||
// Damper motion
|
||||
physBody->setDamping(0.9f, 0.9f);
|
||||
|
||||
applyWaterFloat( vFwd, buoyancyForce, oZ);
|
||||
applyWaterFloat(-vFwd, buoyancyForce, oZ);
|
||||
applyWaterFloat( vRt, buoyancyForce, oZ);
|
||||
applyWaterFloat(-vRt, buoyancyForce, oZ);
|
||||
}
|
||||
else {
|
||||
physBody->setDamping(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
_lastHeight = vH;
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,6 +376,19 @@ bool VehicleObject::isFrameVisible(ModelFrame *frame) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void VehicleObject::applyWaterFloat(const glm::vec3 &relPt, float force, float waterOffset)
|
||||
{
|
||||
auto ws = getPosition() + relPt;
|
||||
auto wi = engine->gameData.getWaterIndexAt(ws);
|
||||
if(wi != NO_WATER_INDEX) {
|
||||
float h = engine->gameData.waterHeights[wi] + waterOffset;
|
||||
if ( ws.z <= h ) {
|
||||
physBody->applyForce(btVector3(0.f, 0.f, (1.f + h - ws.z) * force),
|
||||
btVector3(relPt.x, relPt.y, relPt.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dammnit Bullet
|
||||
|
||||
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||
|
@ -436,11 +436,6 @@ void GameRenderer::renderWorld(float alpha)
|
||||
glUseProgram( waterProgram );
|
||||
|
||||
// TODO: Add some kind of draw distance
|
||||
#define NO_WATER_INDEX 48
|
||||
#define WATER_LQ_DATA_SIZE 64
|
||||
#define WATER_HQ_DATA_SIZE 128
|
||||
#define WATER_WORLD_SIZE 4096.f
|
||||
#define WATER_HQ_DISTANCE 128.f
|
||||
|
||||
float blockLQSize = WATER_WORLD_SIZE/WATER_LQ_DATA_SIZE;
|
||||
float blockHQSize = WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE;
|
||||
|
@ -9,15 +9,17 @@
|
||||
IngameState::IngameState()
|
||||
: _player(nullptr), _playerCharacter(nullptr)
|
||||
{
|
||||
_playerCharacter = getWorld()->createPedestrian(1, {-1240.f, -875.f, 13.f});
|
||||
_playerCharacter = getWorld()->createPedestrian(1, {-1000.f, -990.f, 13.f});
|
||||
_player = new PlayerController(_playerCharacter);
|
||||
|
||||
setPlayerCharacter( _playerCharacter );
|
||||
|
||||
float j = 0;
|
||||
auto spawnPos = glm::vec3( -1200.f, -885.f, 14.f );
|
||||
auto spawnPos = glm::vec3( -1000.f, -1000.f, 14.f );
|
||||
for( auto& vi : getWorld()->vehicleTypes ) {
|
||||
auto v = getWorld()->createVehicle(vi.first, spawnPos, glm::quat());
|
||||
auto sp = spawnPos;
|
||||
if(vi.first == 120) sp = { -1000.f, -1050.f, 5.f };
|
||||
auto v = getWorld()->createVehicle(vi.first, sp, glm::quat());
|
||||
spawnPos -= glm::vec3( 2.f + v->info->handling.dimensions.x, 0.f, 0.f);
|
||||
if( ++j > 33 ) break;
|
||||
}
|
||||
|
61
tests/test_buoyancy.cpp
Normal file
61
tests/test_buoyancy.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "test_globals.hpp"
|
||||
#include <objects/VehicleObject.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(BuoyancyTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_vehicle_buoyancy)
|
||||
{
|
||||
glm::vec2 tpos(-WATER_WORLD_SIZE/2.f + 10.f);
|
||||
{
|
||||
VehicleObject* vehicle = Global::get().e->createVehicle(90u, glm::vec3(tpos, 100.f), glm::quat());
|
||||
|
||||
BOOST_REQUIRE(vehicle != nullptr);
|
||||
|
||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
||||
|
||||
// Relies on tile 0,0 being watered...
|
||||
|
||||
BOOST_CHECK( ! vehicle->isInWater() );
|
||||
|
||||
// Move it under the water
|
||||
vehicle->setPosition(glm::vec3(tpos, -5.f));
|
||||
|
||||
// Allow the object to update
|
||||
vehicle->tick(0.0016f);
|
||||
|
||||
BOOST_CHECK( vehicle->isInWater() );
|
||||
|
||||
// Ensure that the in water state sticks
|
||||
vehicle->tick(0.0016f);
|
||||
|
||||
BOOST_CHECK( vehicle->isInWater() );
|
||||
|
||||
vehicle->setPosition(glm::vec3(tpos, 5.f));
|
||||
vehicle->tick(0.0016f);
|
||||
BOOST_CHECK( ! vehicle->isInWater() );
|
||||
|
||||
// TODO: fix magic numbers
|
||||
auto orgval = Global::get().e->gameData.realWater[0];
|
||||
Global::get().e->gameData.realWater[0] = NO_WATER_INDEX;
|
||||
|
||||
vehicle->tick(0.0016f);
|
||||
BOOST_CHECK( ! vehicle->isInWater() );
|
||||
|
||||
vehicle->setPosition(glm::vec3(tpos, -5.f));
|
||||
|
||||
vehicle->tick(0.0016f);
|
||||
BOOST_CHECK( ! vehicle->isInWater() );
|
||||
|
||||
Global::get().e->gameData.realWater[0] = orgval;
|
||||
|
||||
vehicle->tick(0.0016f);
|
||||
BOOST_CHECK( ! vehicle->isInWater() );
|
||||
|
||||
Global::get().e->destroyObject(vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user