1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-13 12:40:04 +00:00

Projectiles interact with the water surface (Fixes #2986)

This commit is contained in:
scrawl 2015-12-04 23:28:11 +01:00
parent 4a9b37aa53
commit 3f93af4181
9 changed files with 60 additions and 23 deletions

View File

@ -756,6 +756,11 @@ namespace MWRender
mWater->removeEmitter(ptr); mWater->removeEmitter(ptr);
} }
void RenderingManager::emitWaterRipple(const osg::Vec3f &pos)
{
mWater->emitRipple(pos);
}
void RenderingManager::updateProjectionMatrix() void RenderingManager::updateProjectionMatrix()
{ {
double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); double aspect = mViewer->getCamera()->getViewport()->aspectRatio();

View File

@ -138,6 +138,7 @@ namespace MWRender
void addWaterRippleEmitter(const MWWorld::Ptr& ptr); void addWaterRippleEmitter(const MWWorld::Ptr& ptr);
void removeWaterRippleEmitter(const MWWorld::Ptr& ptr); void removeWaterRippleEmitter(const MWWorld::Ptr& ptr);
void emitWaterRipple(const osg::Vec3f& pos);
void updatePlayerPtr(const MWWorld::Ptr &ptr); void updatePlayerPtr(const MWWorld::Ptr &ptr);

View File

@ -139,9 +139,7 @@ void RippleSimulation::update(float dt)
if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500) if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500)
continue; // TODO: remove the oldest particle to make room? continue; // TODO: remove the oldest particle to make room?
osgParticle::Particle* p = mParticleSystem->createParticle(NULL); emitRipple(currentPos);
p->setPosition(currentPos);
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));
} }
} }
} }
@ -194,6 +192,16 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store)
} }
} }
void RippleSimulation::emitRipple(const osg::Vec3f &pos)
{
if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20)
{
osgParticle::Particle* p = mParticleSystem->createParticle(NULL);
p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f));
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));
}
}
void RippleSimulation::setWaterHeight(float height) void RippleSimulation::setWaterHeight(float height)
{ {
mParticleNode->setPosition(osg::Vec3f(0,0,height)); mParticleNode->setPosition(osg::Vec3f(0,0,height));

View File

@ -52,6 +52,8 @@ namespace MWRender
void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
void removeCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store);
void emitRipple(const osg::Vec3f& pos);
/// Change the height of the water surface, thus moving all ripples with it /// Change the height of the water surface, thus moving all ripples with it
void setWaterHeight(float height); void setWaterHeight(float height);

View File

@ -731,6 +731,11 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
mSimulation->updateEmitterPtr(old, ptr); mSimulation->updateEmitterPtr(old, ptr);
} }
void Water::emitRipple(const osg::Vec3f &pos)
{
mSimulation->emitRipple(pos);
}
void Water::removeCell(const MWWorld::CellStore *store) void Water::removeCell(const MWWorld::CellStore *store)
{ {
mSimulation->removeCell(store); mSimulation->removeCell(store);

View File

@ -91,6 +91,8 @@ namespace MWRender
void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f);
void removeEmitter (const MWWorld::Ptr& ptr); void removeEmitter (const MWWorld::Ptr& ptr);
void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
void emitRipple(const osg::Vec3f& pos);
void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell
void clearRipples(); void clearRipples();

View File

@ -25,6 +25,7 @@
#include "../mwrender/effectmanager.hpp" #include "../mwrender/effectmanager.hpp"
#include "../mwrender/animation.hpp" #include "../mwrender/animation.hpp"
#include "../mwrender/vismask.hpp" #include "../mwrender/vismask.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwsound/sound.hpp" #include "../mwsound/sound.hpp"
@ -34,9 +35,11 @@
namespace MWWorld namespace MWWorld
{ {
ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem, MWPhysics::PhysicsSystem* physics) ProjectileManager::ProjectileManager(osg::Group* parent, Resource::ResourceSystem* resourceSystem,
MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics)
: mParent(parent) : mParent(parent)
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mRendering(rendering)
, mPhysics(physics) , mPhysics(physics)
{ {
@ -225,32 +228,38 @@ namespace MWWorld
// TODO: use a proper btRigidBody / btGhostObject? // TODO: use a proper btRigidBody / btGhostObject?
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile); MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile);
if (result.mHit) bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos);
if (result.mHit || underwater)
{ {
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); if (result.mHit)
// Try to get a Ptr to the bow that was used. It might no longer exist.
MWWorld::Ptr bow = projectileRef.getPtr();
if (!caster.isEmpty())
{ {
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId);
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) // Try to get a Ptr to the bow that was used. It might no longer exist.
bow = *invIt; MWWorld::Ptr bow = projectileRef.getPtr();
if (!caster.isEmpty())
{
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId))
bow = *invIt;
}
if (caster.isEmpty())
caster = result.mHitObject;
MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength);
} }
if (caster.isEmpty()) if (underwater)
caster = result.mHitObject; mRendering->emitWaterRipple(newPos);
MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength);
mParent->removeChild(it->mNode); mParent->removeChild(it->mNode);
it = mProjectiles.erase(it); it = mProjectiles.erase(it);
continue; continue;
} }
else
++it; ++it;
} }
} }

View File

@ -36,6 +36,7 @@ namespace Resource
namespace MWRender namespace MWRender
{ {
class EffectAnimationTime; class EffectAnimationTime;
class RenderingManager;
} }
namespace MWWorld namespace MWWorld
@ -45,7 +46,7 @@ namespace MWWorld
{ {
public: public:
ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem, ProjectileManager (osg::Group* parent, Resource::ResourceSystem* resourceSystem,
MWPhysics::PhysicsSystem* physics); MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics);
/// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used.
void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
@ -67,6 +68,7 @@ namespace MWWorld
private: private:
osg::ref_ptr<osg::Group> mParent; osg::ref_ptr<osg::Group> mParent;
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;
MWRender::RenderingManager* mRendering;
MWPhysics::PhysicsSystem* mPhysics; MWPhysics::PhysicsSystem* mPhysics;
struct State struct State
@ -120,6 +122,9 @@ namespace MWWorld
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient); void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient);
void update (State& state, float duration); void update (State& state, float duration);
void operator=(const ProjectileManager&);
ProjectileManager(const ProjectileManager&);
}; };
} }

View File

@ -163,8 +163,8 @@ namespace MWWorld
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0)
{ {
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics));
mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath);
mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mRendering, mPhysics));
mEsm.resize(contentFiles.size()); mEsm.resize(contentFiles.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();