mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-10 12:39:53 +00:00
Change projectile behaviour to be like in vanilla wrt. water plane:
- enchanted arrow explode upon hit the water plane - non enchanted arrow disappear (or more accurately, they hit nothingness) - enchanted arrow shot underwater explode immediately - non enchanted arrow disappear immediately Also, solve a bug that occured previously and could theoritically still happens where we use the last tested collision position for instead of the last registered hit: Use the hit position as saved inside Projectile::hit() instead of the last position saved inside the callback. If a projectile collides with several objects (bottom of the sea and water surface for instance), the last collision tested won't necessarily be the impact position as we have no control over the order in which the tests are performed.
This commit is contained in:
parent
291195872e
commit
0bce6c09e1
@ -643,7 +643,7 @@ namespace MWPhysics
|
||||
|
||||
mTaskScheduler->convexSweepTest(projectile->getConvexShape(), from_, to_, resultCallback);
|
||||
|
||||
const auto newpos = projectile->isActive() ? position : Misc::Convert::toOsg(resultCallback.m_hitPointWorld);
|
||||
const auto newpos = projectile->isActive() ? position : Misc::Convert::toOsg(projectile->getHitPosition());
|
||||
projectile->setPosition(newpos);
|
||||
mTaskScheduler->updateSingleAabb(foundProjectile->second);
|
||||
}
|
||||
@ -713,7 +713,7 @@ namespace MWPhysics
|
||||
mActors.emplace(ptr, std::move(actor));
|
||||
}
|
||||
|
||||
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater)
|
||||
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius)
|
||||
{
|
||||
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
|
||||
assert(shapeInstance);
|
||||
@ -721,7 +721,7 @@ namespace MWPhysics
|
||||
|
||||
mProjectileId++;
|
||||
|
||||
auto projectile = std::make_shared<Projectile>(caster, position, radius, canTraverseWater, mTaskScheduler.get(), this);
|
||||
auto projectile = std::make_shared<Projectile>(caster, position, radius, mTaskScheduler.get(), this);
|
||||
mProjectiles.emplace(mProjectileId, std::move(projectile));
|
||||
|
||||
return mProjectileId;
|
||||
|
@ -130,7 +130,7 @@ namespace MWPhysics
|
||||
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType = CollisionType_World, bool skipAnimated = false);
|
||||
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||
|
||||
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater);
|
||||
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius);
|
||||
void setCaster(int projectileId, const MWWorld::Ptr& caster);
|
||||
void updateProjectile(const int projectileId, const osg::Vec3f &position) const;
|
||||
void removeProjectile(const int projectileId);
|
||||
|
@ -15,12 +15,10 @@
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canCrossWaterSurface, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem)
|
||||
: mCanCrossWaterSurface(canCrossWaterSurface)
|
||||
, mCrossedWaterSurface(false)
|
||||
Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem)
|
||||
: mHitWater(false)
|
||||
, mActive(true)
|
||||
, mHitTarget(nullptr)
|
||||
, mWaterHitPosition(std::nullopt)
|
||||
, mPhysics(physicssystem)
|
||||
, mTaskScheduler(scheduler)
|
||||
{
|
||||
@ -75,11 +73,6 @@ osg::Vec3f Projectile::getPosition() const
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
bool Projectile::canTraverseWater() const
|
||||
{
|
||||
return mCanCrossWaterSurface;
|
||||
}
|
||||
|
||||
void Projectile::hit(const btCollisionObject* target, btVector3 pos, btVector3 normal)
|
||||
{
|
||||
bool active = true;
|
||||
@ -143,17 +136,4 @@ bool Projectile::isValidTarget(const btCollisionObject* target) const
|
||||
[target](const btCollisionObject* actor) { return target == actor; });
|
||||
}
|
||||
|
||||
std::optional<btVector3> Projectile::getWaterHitPosition()
|
||||
{
|
||||
return std::exchange(mWaterHitPosition, std::nullopt);
|
||||
}
|
||||
|
||||
void Projectile::setWaterHitPosition(btVector3 pos)
|
||||
{
|
||||
if (mCrossedWaterSurface)
|
||||
return;
|
||||
mCrossedWaterSurface = true;
|
||||
mWaterHitPosition = pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include <LinearMath/btVector3.h>
|
||||
|
||||
@ -32,7 +31,7 @@ namespace MWPhysics
|
||||
class Projectile final : public PtrHolder
|
||||
{
|
||||
public:
|
||||
Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canCrossWaterSurface, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem);
|
||||
Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem);
|
||||
~Projectile() override;
|
||||
|
||||
btConvexShape* getConvexShape() const { return mConvexShape; }
|
||||
@ -56,15 +55,25 @@ namespace MWPhysics
|
||||
return mCasterColObj;
|
||||
}
|
||||
|
||||
bool canTraverseWater() const;
|
||||
void setHitWater()
|
||||
{
|
||||
mHitWater = true;
|
||||
}
|
||||
|
||||
bool getHitWater() const
|
||||
{
|
||||
return mHitWater;
|
||||
}
|
||||
|
||||
void hit(const btCollisionObject* target, btVector3 pos, btVector3 normal);
|
||||
|
||||
void setValidTargets(const std::vector<MWWorld::Ptr>& targets);
|
||||
bool isValidTarget(const btCollisionObject* target) const;
|
||||
|
||||
std::optional<btVector3> getWaterHitPosition();
|
||||
void setWaterHitPosition(btVector3 pos);
|
||||
btVector3 getHitPosition() const
|
||||
{
|
||||
return mHitPosition;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -72,13 +81,11 @@ namespace MWPhysics
|
||||
btConvexShape* mConvexShape;
|
||||
|
||||
bool mTransformUpdatePending;
|
||||
bool mCanCrossWaterSurface;
|
||||
bool mCrossedWaterSurface;
|
||||
bool mHitWater;
|
||||
std::atomic<bool> mActive;
|
||||
MWWorld::Ptr mCaster;
|
||||
const btCollisionObject* mCasterColObj;
|
||||
const btCollisionObject* mHitTarget;
|
||||
std::optional<btVector3> mWaterHitPosition;
|
||||
osg::Vec3f mPosition;
|
||||
btVector3 mHitPosition;
|
||||
btVector3 mHitNormal;
|
||||
|
@ -49,9 +49,7 @@ namespace MWPhysics
|
||||
}
|
||||
case CollisionType_Water:
|
||||
{
|
||||
mProjectile->setWaterHitPosition(m_hitPointWorld);
|
||||
if (mProjectile->canTraverseWater())
|
||||
return 1.f;
|
||||
mProjectile->setHitWater();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ namespace MWWorld
|
||||
// in case there are multiple effects, the model is a dummy without geometry. Use the second effect for physics shape
|
||||
if (state.mIdMagic.size() > 1)
|
||||
model = "meshes\\" + MWBase::Environment::get().getWorld()->getStore().get<ESM::Weapon>().find(state.mIdMagic[1])->mModel;
|
||||
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true, false);
|
||||
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true);
|
||||
state.mToDelete = false;
|
||||
mMagicBolts.push_back(state);
|
||||
}
|
||||
@ -342,7 +342,7 @@ namespace MWWorld
|
||||
if (!ptr.getClass().getEnchantment(ptr).empty())
|
||||
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
|
||||
|
||||
state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false, true);
|
||||
state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false);
|
||||
state.mToDelete = false;
|
||||
mProjectiles.push_back(state);
|
||||
}
|
||||
@ -493,9 +493,6 @@ namespace MWWorld
|
||||
|
||||
auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId);
|
||||
|
||||
if (const auto hitWaterPos = projectile->getWaterHitPosition())
|
||||
mRendering->emitWaterRipple(Misc::Convert::toOsg(*hitWaterPos));
|
||||
|
||||
const auto pos = projectile->getPosition();
|
||||
projectileState.mNode->setPosition(pos);
|
||||
|
||||
@ -519,6 +516,8 @@ namespace MWWorld
|
||||
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), projectileState.mBowId))
|
||||
bow = *invIt;
|
||||
}
|
||||
if (projectile->getHitWater())
|
||||
mRendering->emitWaterRipple(pos);
|
||||
|
||||
MWMechanics::projectileHit(caster, target, bow, projectileRef.getPtr(), pos, projectileState.mAttackStrength);
|
||||
projectileState.mToDelete = true;
|
||||
@ -663,7 +662,7 @@ namespace MWWorld
|
||||
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
||||
|
||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false, true);
|
||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -716,7 +715,7 @@ namespace MWWorld
|
||||
|
||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true, false);
|
||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true);
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
for (const std::string &soundid : state.mSoundIds)
|
||||
|
@ -3145,6 +3145,7 @@ namespace MWWorld
|
||||
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), worldPos);
|
||||
if (underwater)
|
||||
{
|
||||
MWMechanics::projectileHit(actor, Ptr(), bow, projectile, worldPos, attackStrength);
|
||||
mRendering->emitWaterRipple(worldPos);
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user