761 lines
23 KiB
C++
761 lines
23 KiB
C++
#include <iostream>
|
|
#include <Ogre.h>
|
|
#include <Jolt/Jolt.h>
|
|
#include <Jolt/Physics/Body/BodyID.h>
|
|
#include <Jolt/Physics/Character/CharacterBase.h>
|
|
#include <Jolt/Physics/Character/Character.h>
|
|
#include <Jolt/Physics/Collision/BroadPhase/BroadPhase.h>
|
|
#include <Jolt/Physics/Body/BodyLock.h>
|
|
#include <Jolt/Physics/Collision/ContactListener.h>
|
|
#include "Components.h"
|
|
#include "GameData.h"
|
|
#include "CharacterModule.h"
|
|
#include "WaterModule.h"
|
|
#include "BoatModule.h"
|
|
#include "EventTriggerModule.h"
|
|
#include "LuaData.h"
|
|
#include "physics.h"
|
|
#include "loader.h"
|
|
#include "EventModule.h"
|
|
#include "TerrainModule.h"
|
|
#include "PhysicsModule.h"
|
|
namespace ECS
|
|
{
|
|
struct PhysicsShape {
|
|
JPH::ShapeRefC shape;
|
|
};
|
|
struct ConvexHull {};
|
|
struct WaterBody {
|
|
std::set<JPH::BodyID> inWater;
|
|
bool isInWater(const JPH::BodyID &id) const;
|
|
};
|
|
struct TriggerBody {
|
|
void *foo;
|
|
};
|
|
PhysicsModule::PhysicsModule(flecs::world &ecs)
|
|
{
|
|
ecs.module<PhysicsModule>();
|
|
ecs.import <EventModule>();
|
|
ecs.import <EventTriggerModule>();
|
|
ecs.import <BoatModule>();
|
|
flecs::entity PhysicsPreUpdate =
|
|
ecs.entity().add(flecs::Phase).depends_on(flecs::OnUpdate);
|
|
flecs::entity PhysicsUpdate =
|
|
ecs.entity().add(flecs::Phase).depends_on(PhysicsPreUpdate);
|
|
flecs::entity PhysicsPostUpdate =
|
|
ecs.entity().add(flecs::Phase).depends_on(PhysicsUpdate);
|
|
ecs.component<Physics>().add(flecs::Singleton);
|
|
ecs.component<JPH::BodyID>().member<uint32_t>("mID");
|
|
/* for terrain */
|
|
ecs.component<PhysicsBody>();
|
|
ecs.component<PhysicsShape>();
|
|
ecs.component<PhysicsNode>();
|
|
ecs.component<PhysicsMeshName>();
|
|
ecs.component<PhysicsMeshPtr>();
|
|
ecs.component<PhysicsHeightfieldData>();
|
|
|
|
ecs.component<CharacterBody>();
|
|
ecs.component<TriggerBody>();
|
|
ecs.component<CharacterVelocity>();
|
|
ecs.component<WaterBody>().add(flecs::Singleton);
|
|
ecs.component<CachedMass>();
|
|
ecs.import <TerrainModule>();
|
|
ecs.import <WaterModule>();
|
|
ecs.system<const EngineData, const Camera>("physics_init")
|
|
.kind(PhysicsPreUpdate)
|
|
.without<Physics>()
|
|
.each([&](const EngineData &e, const Camera &c) {
|
|
Physics &ph = ECS::get().ensure<Physics>();
|
|
ph.physics = new JoltPhysicsWrapper(e.mScnMgr,
|
|
c.mCameraNode);
|
|
ECS::modified<Physics>();
|
|
});
|
|
#if 0
|
|
ecs.system<PhysicsBody>("create_body")
|
|
.kind(flecs::OnUpdate)
|
|
.without<JPH::BodyID>()
|
|
.each([&](flecs::entity e, PhysicsBody &rb) {
|
|
JPH::BodyID id =
|
|
JoltPhysicsWrapper::getSingleton().createBody(
|
|
rb.shape.get(), rb.node,
|
|
(JPH::EMotionType)rb.motion,
|
|
(JPH::ObjectLayer)rb.layer);
|
|
e.set<JPH::BodyID>(id);
|
|
});
|
|
#endif
|
|
ecs.system<EngineData, Physics>("physics_update")
|
|
.kind(PhysicsUpdate)
|
|
.each([&](EngineData &e, Physics &ph) {
|
|
ph.physics->update(e.delta);
|
|
});
|
|
ecs.observer<const EngineData, PhysicsMeshName>(
|
|
"create_shape_mesh_name")
|
|
.event(flecs::OnSet)
|
|
.without<PhysicsShape>()
|
|
.with<Physics>()
|
|
.write<PhysicsShape>()
|
|
.each([&](flecs::entity e, const EngineData &eng,
|
|
PhysicsMeshName &name) {
|
|
Ogre::DefaultHardwareBufferManagerBase dmgr;
|
|
Ogre::MeshPtr mesh =
|
|
Ogre::MeshManager::getSingleton().getByName(
|
|
name.meshName);
|
|
mesh->setHardwareBufferManager(&dmgr);
|
|
mesh->load();
|
|
JPH::ShapeRefC shape =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.createMeshShape(mesh);
|
|
PhysicsShape &s = e.ensure<PhysicsShape>();
|
|
s.shape = shape;
|
|
e.modified<PhysicsShape>();
|
|
});
|
|
ecs.observer<const EngineData, PhysicsMeshPtr>("create_shape_mesh_ptr")
|
|
.event(flecs::OnSet)
|
|
.without<PhysicsShape>()
|
|
.with<Physics>()
|
|
.write<PhysicsShape>()
|
|
.each([&](flecs::entity e, const EngineData &eng,
|
|
PhysicsMeshPtr &meshPtr) {
|
|
Ogre::DefaultHardwareBufferManager dmgr;
|
|
Ogre::MeshPtr mesh = meshPtr.mesh;
|
|
if (!mesh->isLoaded()) {
|
|
mesh->setHardwareBufferManager(&dmgr);
|
|
mesh->load();
|
|
}
|
|
JPH::ShapeRefC shape =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.createMeshShape(mesh);
|
|
PhysicsShape &s = e.ensure<PhysicsShape>();
|
|
s.shape = shape;
|
|
e.modified<PhysicsShape>();
|
|
});
|
|
ecs.observer<const EngineData, PhysicsHeightfieldData>(
|
|
"create_shape_heightfield")
|
|
.event(flecs::OnSet)
|
|
.without<PhysicsShape>()
|
|
.with<Physics>()
|
|
.write<PhysicsShape>()
|
|
.each([&](flecs::entity e, const EngineData &eng,
|
|
PhysicsHeightfieldData &hfd) {
|
|
JPH::ShapeRefC shape =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.createHeightfieldShape(
|
|
hfd.samples, hfd.offset,
|
|
hfd.scale, hfd.sampleCount);
|
|
PhysicsShape &s = e.ensure<PhysicsShape>();
|
|
s.shape = shape;
|
|
e.modified<PhysicsShape>();
|
|
e.remove<PhysicsHeightfieldData>();
|
|
});
|
|
#if 1
|
|
ecs.observer<const EngineData, const PhysicsShape, const PhysicsNode,
|
|
const PhysicsBody>("create_body_from_shape")
|
|
.event(flecs::OnSet)
|
|
.without<JPH::BodyID>()
|
|
.with<Physics>()
|
|
.write<PhysicsShape>()
|
|
.write<JPH::BodyID>()
|
|
.each([&](flecs::entity e, const EngineData &eng,
|
|
const PhysicsShape &shape, const PhysicsNode &node,
|
|
const PhysicsBody &body) {
|
|
JPH::BodyID id =
|
|
JoltPhysicsWrapper::getSingleton().createBody(
|
|
shape.shape.GetPtr(), 0.0f, node.node,
|
|
(JPH::EMotionType)body.motion,
|
|
(JPH::ObjectLayer)body.layer);
|
|
e.set<JPH::BodyID>(id);
|
|
JoltPhysicsWrapper::getSingleton().addBody(
|
|
id, JPH::EActivation::Activate);
|
|
});
|
|
#endif
|
|
ecs.observer<const JPH::BodyID>("remove_body")
|
|
.event(flecs::OnRemove)
|
|
.each([&](flecs::entity e, const JPH::BodyID &id) {
|
|
JoltPhysicsWrapper::getSingleton().removeBody(id);
|
|
JoltPhysicsWrapper::getSingleton().destroyBody(id);
|
|
std::cout << "body destroyed" << std::endl;
|
|
});
|
|
ecs.observer<const EngineData, const CharacterBase>("SetupCharacterPh")
|
|
.event(flecs::OnSet)
|
|
.with<Character>()
|
|
.without<CharacterBody>()
|
|
.write<CharacterBody>()
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const CharacterBase &base) {
|
|
CharacterBody &b = e.ensure<CharacterBody>();
|
|
b.ch.reset(JoltPhysicsWrapper::getSingleton()
|
|
.createCharacter(base.mBodyNode,
|
|
1.75f, 0.23f));
|
|
if (!e.has<CharacterDisablePhysics>())
|
|
static_cast<JPH::Character *>(b.ch.get())
|
|
->AddToPhysicsSystem(
|
|
JPH::EActivation::Activate);
|
|
e.set<JPH::BodyID>(
|
|
static_cast<JPH::Character *>(b.ch.get())
|
|
->GetBodyID());
|
|
e.modified<CharacterBody>();
|
|
});
|
|
ecs.observer<const EngineData, const EventTrigger>(
|
|
"CreateTriggerPhysics")
|
|
.event(flecs::OnSet)
|
|
.without<JPH::BodyID>()
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const EventTrigger &trigger) {
|
|
JPH::ShapeRefC shape =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.createCylinderShape(trigger.halfheight,
|
|
trigger.radius);
|
|
JPH::BodyID id =
|
|
JoltPhysicsWrapper::getSingleton().createSensor(
|
|
shape.GetPtr(), trigger.node,
|
|
JPH::EMotionType::Kinematic,
|
|
Layers::MOVING);
|
|
e.set<JPH::BodyID>(id);
|
|
// JoltPhysicsWrapper::getSingleton().setDebugDraw(true);
|
|
JoltPhysicsWrapper::getSingleton().addBody(
|
|
id, JPH::EActivation::Activate);
|
|
JoltPhysicsWrapper::getSingleton().addContactListener(
|
|
id,
|
|
[](const JoltPhysics::ContactListener::
|
|
ContactReport &report) -> void {
|
|
flecs::entity trigger_e =
|
|
ECS::get()
|
|
.query_builder<
|
|
const JPH::
|
|
BodyID>()
|
|
.with<EventTrigger>()
|
|
.build()
|
|
.find([&](const JPH::BodyID
|
|
&id) {
|
|
return id == report.id1 ||
|
|
id == report.id2;
|
|
});
|
|
flecs::entity parent_e =
|
|
trigger_e.parent();
|
|
const JPH::BodyID &trigger_body =
|
|
trigger_e.get<JPH::BodyID>();
|
|
const JPH::BodyID &other_body =
|
|
(trigger_body == report.id1) ?
|
|
report.id2 :
|
|
report.id1;
|
|
flecs::entity other_e =
|
|
ECS::get()
|
|
.query_builder<
|
|
const JPH::
|
|
BodyID>()
|
|
.without<EventTrigger>()
|
|
.build()
|
|
.find([&](const JPH::BodyID
|
|
&id) {
|
|
return id ==
|
|
other_body;
|
|
});
|
|
if (!trigger_e.is_valid() ||
|
|
!other_e.is_valid())
|
|
return;
|
|
if (parent_e.is_valid() &&
|
|
parent_e == other_e)
|
|
return;
|
|
OgreAssert(
|
|
trigger_e.is_valid(),
|
|
"trigger entity is not valid");
|
|
OgreAssert(other_e.is_valid(),
|
|
"other entity is not valid");
|
|
const EventTrigger &trg =
|
|
trigger_e.get<EventTrigger>();
|
|
if (report.entered) {
|
|
trigger_e.get_mut<EventData>()
|
|
.add(trigger_e,
|
|
trg.event +
|
|
"_enter",
|
|
trigger_e,
|
|
other_e);
|
|
other_e.add<InTrigger>(
|
|
trigger_e);
|
|
trigger_e.add<TriggeredBy>(
|
|
other_e);
|
|
} else {
|
|
trigger_e.get_mut<EventData>()
|
|
.add(trigger_e,
|
|
trg.event +
|
|
"_exit",
|
|
trigger_e,
|
|
other_e);
|
|
#if 0
|
|
/* do not delete triggers until exit from actuator */
|
|
other_e.remove<InTrigger>(
|
|
trigger_e);
|
|
trigger_e.remove<TriggeredBy>(
|
|
other_e);
|
|
#endif
|
|
}
|
|
ECS::modified<LuaEvent>();
|
|
});
|
|
});
|
|
#if 0
|
|
ecs.system<const EngineData, const EventTrigger, const JPH::BodyID>(
|
|
"UpdateTriggerPhysicsPre")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<WaterBody>()
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const EventTrigger &trigger, const JPH::BodyID &id) {
|
|
/* FIXME: update positions for triggers, probably need to move somewhere */
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.setPositionAndRotation(
|
|
id, trigger.node->_getDerivedPosition(),
|
|
trigger.node->_getDerivedOrientation());
|
|
#if 0
|
|
std::cout << trigger.node->_getDerivedPosition() << " "
|
|
<< trigger.node->getPosition() << " "
|
|
<< trigger.node->getParent()->getName()
|
|
<< ": " << trigger.node->getName()
|
|
<< std::endl;
|
|
// OgreAssert(false, "update triggers");
|
|
#endif
|
|
});
|
|
ecs.system<const EngineData, const EventTrigger, const JPH::BodyID>(
|
|
"UpdateTriggerPhysicsPost")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<WaterBody>()
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const EventTrigger &trigger, const JPH::BodyID &id) {
|
|
/* FIXME: update positions for triggers, probably need to move somewhere */
|
|
Ogre::Vector3 position;
|
|
Ogre::Quaternion rotation;
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.getPositionAndRotation(id, position, rotation);
|
|
trigger.node->_setDerivedPosition(position);
|
|
trigger.node->_setDerivedOrientation(rotation);
|
|
});
|
|
#endif
|
|
ecs.system<const EngineData>("init_water")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterAlmostReady>()
|
|
.without<WaterBody>()
|
|
.each([this](const EngineData &eng) {
|
|
ECS::get().set<WaterBody>({});
|
|
});
|
|
#if 0
|
|
ecs.system<const EngineData>("DebugData")
|
|
.kind(PhysicsPostUpdate)
|
|
.each([this](const EngineData &eng) {
|
|
std::cout << "TerrainReady: "
|
|
<< ECS::get().has<TerrainReady>();
|
|
std::cout << " WaterReady: "
|
|
<< ECS::get().has<WaterReady>() << std::endl;
|
|
});
|
|
#endif
|
|
ecs.system<const EngineData, WaterBody>("update_water")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterAlmostReady>()
|
|
.each([this](const EngineData &eng, WaterBody &body) {
|
|
const WaterSurface &water = ECS::get<WaterSurface>();
|
|
body.inWater.clear();
|
|
JoltPhysicsWrapper::getSingleton().broadphaseQuery(
|
|
eng.delta,
|
|
water.mWaterNode->_getDerivedPosition(),
|
|
body.inWater);
|
|
#if 0
|
|
for (JPH::BodyID inBodyID : body.inWater) {
|
|
if (JoltPhysicsWrapper::getSingleton().isActive(
|
|
inBodyID)) {
|
|
float my =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.getPosition(inBodyID)
|
|
.y;
|
|
float myv =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.getLinearVelocity(
|
|
inBodyID)
|
|
.y;
|
|
float b = 1.0f;
|
|
float drag = 0.5f;
|
|
float adrag = 0.05f;
|
|
float level = -1.3f;
|
|
float mdec = 1.0f;
|
|
float minc = 1.0f;
|
|
float h = -my + level;
|
|
if (h < 0)
|
|
h = 0;
|
|
if (my < level - 0.1f)
|
|
b *= 1.1f * (1.0f + 1.2f * h);
|
|
else if (my > level + 0.1f) {
|
|
b *= 0.8f;
|
|
if (myv > 0.1f)
|
|
b *= 0.9f;
|
|
if (my > level + 0.4f)
|
|
b *= 0.5f;
|
|
}
|
|
if (myv < 0.0f)
|
|
drag = 0.7f;
|
|
JoltPhysicsWrapper::getSingleton().applyBuoyancyImpulse(
|
|
inBodyID,
|
|
water.mWaterNode->_getDerivedPosition() -
|
|
Ogre::Vector3(0, 0.1f,
|
|
0),
|
|
Ogre::Vector3::UNIT_Y, b, drag,
|
|
adrag, Ogre::Vector3::ZERO,
|
|
eng.delta);
|
|
// std::cout << b << std::endl;
|
|
#if 0
|
|
std::cout << "addHit: "
|
|
<< JoltPhysics::convert(
|
|
body.GetPosition())
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
ECS::get().add<WaterReady>();
|
|
});
|
|
ecs.system<const JPH::BodyID, const WaterBody>("update_water_status1")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<InWater>()
|
|
.each([this](flecs::entity e, const JPH::BodyID &id,
|
|
const WaterBody &body) {
|
|
if (!body.isInWater(id))
|
|
e.remove<InWater>();
|
|
});
|
|
ecs.system<const JPH::BodyID, const WaterBody>("update_water_status2")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.without<InWater>()
|
|
.each([this](flecs::entity e, const JPH::BodyID &id,
|
|
const WaterBody &body) {
|
|
if (body.isInWater(id))
|
|
e.add<InWater>();
|
|
});
|
|
ecs.system<const CharacterBody, const WaterBody>(
|
|
"update_water_character1")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<InWater>()
|
|
.each([this](flecs::entity e, const CharacterBody &ch,
|
|
const WaterBody &body) {
|
|
JPH::Character *chptr =
|
|
static_cast<JPH::Character *>(ch.ch.get());
|
|
if (!body.isInWater(chptr->GetBodyID()))
|
|
e.remove<InWater>();
|
|
});
|
|
ecs.system<const CharacterBody, const WaterBody>(
|
|
"update_water_character2")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.without<InWater>()
|
|
.each([this](flecs::entity e, const CharacterBody &ch,
|
|
const WaterBody &body) {
|
|
JPH::Character *chptr =
|
|
static_cast<JPH::Character *>(ch.ch.get());
|
|
if (body.isInWater(chptr->GetBodyID()))
|
|
e.add<InWater>();
|
|
});
|
|
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
|
const JPH::BodyID>("update_water_boat_enable")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
const BoatBase &boat, const WaterBody &body,
|
|
const JPH::BodyID &id) {
|
|
if (!JoltPhysicsWrapper::getSingleton().isAdded(id))
|
|
JoltPhysicsWrapper::getSingleton().addBody(
|
|
id, JPH::EActivation::Activate);
|
|
});
|
|
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
|
const JPH::BodyID>("update_water_boat_activation")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<InWater>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
const BoatBase &boat, const WaterBody &body,
|
|
const JPH::BodyID &id) {
|
|
if (!JoltPhysicsWrapper::getSingleton().isActive(id))
|
|
JoltPhysicsWrapper::getSingleton().activate(id);
|
|
});
|
|
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
|
const JPH::BodyID, const CachedMass>(
|
|
"update_water_boat_buoyancy")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<InWater>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
const BoatBase &boat, const WaterBody &body,
|
|
const JPH::BodyID &id, const CachedMass &mass) {
|
|
const WaterSurface &water = ECS::get<WaterSurface>();
|
|
float b = 1.0f, drag = 0.5f, adrag = 0.5f;
|
|
float level = 0.25f;
|
|
float my = JoltPhysicsWrapper::getSingleton()
|
|
.getPosition(id)
|
|
.y;
|
|
float myv = JoltPhysicsWrapper::getSingleton()
|
|
.getLinearVelocity(id)
|
|
.y;
|
|
#if 0
|
|
if (my < level && myv < 0)
|
|
b = 10.0f;
|
|
else if (my > level && myv > 0)
|
|
b = 0.8f;
|
|
#endif
|
|
/* max = 2.7; min = 1.7 */
|
|
if (my < level)
|
|
b = 2.2f;
|
|
else if (my > level)
|
|
b = 0.9f;
|
|
// std::cout << my << std::endl;
|
|
JoltPhysicsWrapper::getSingleton().applyBuoyancyImpulse(
|
|
id, water.mWaterNode->_getDerivedPosition(),
|
|
Ogre::Vector3::UNIT_Y, b, drag, adrag,
|
|
Ogre::Vector3::ZERO, eng.delta);
|
|
/* stabilisation */
|
|
Ogre::Vector3 currentAngularVelocity =
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.getAngularVelocity(id);
|
|
Ogre::Quaternion rotation =
|
|
JoltPhysicsWrapper::getSingleton().getRotation(
|
|
id);
|
|
Ogre::Vector3 rotComp =
|
|
rotation.Inverse() * Ogre::Vector3::UNIT_Y;
|
|
rotComp.y = 0;
|
|
if (Ogre::Math::Abs(rotComp.x) > 0.1f ||
|
|
Ogre::Math::Abs(rotComp.z) > 0.1f) {
|
|
Ogre::Vector3 localAngularVelocity =
|
|
rotation.Inverse() *
|
|
currentAngularVelocity;
|
|
Ogre::Vector3 localAngularVelocityChange(
|
|
-localAngularVelocity.x, 0,
|
|
-localAngularVelocity.z);
|
|
localAngularVelocityChange -=
|
|
rotComp * 20.0f * eng.delta;
|
|
Ogre::Vector3 angularVelocityChange =
|
|
rotation * localAngularVelocityChange;
|
|
Ogre::Vector3 angularImpulse =
|
|
mass.mass * angularVelocityChange;
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.addAngularImpulse(id, angularImpulse);
|
|
}
|
|
});
|
|
ecs.system<const EngineData, const CharacterBody, const WaterBody>(
|
|
"update_water_character_buoyancy")
|
|
.kind(PhysicsPreUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<InWater>()
|
|
.without<CharacterDisablePhysics>()
|
|
.with<CharacterBuoyancy>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
const CharacterBody &ch, const WaterBody &body) {
|
|
JPH::Character *chptr =
|
|
static_cast<JPH::Character *>(ch.ch.get());
|
|
JPH::BodyID id = chptr->GetBodyID();
|
|
if (JoltPhysicsWrapper::getSingleton().isActive(id)) {
|
|
const WaterSurface &water =
|
|
ECS::get<WaterSurface>();
|
|
float my = JoltPhysicsWrapper::getSingleton()
|
|
.getPosition(id)
|
|
.y;
|
|
float myv = JoltPhysicsWrapper::getSingleton()
|
|
.getLinearVelocity(id)
|
|
.y;
|
|
float b = 1.0f;
|
|
float drag = 0.5f;
|
|
float adrag = 0.05f;
|
|
float level = -1.3f;
|
|
float mdec = 1.0f;
|
|
float minc = 1.0f;
|
|
float h = -my + level;
|
|
if (h < 0)
|
|
h = 0;
|
|
if (my < level - 0.1f)
|
|
b *= 1.1f * (1.0f + 1.2f * h);
|
|
else if (my > level + 0.1f) {
|
|
b *= 0.8f;
|
|
if (myv > 0.1f)
|
|
b *= 0.9f;
|
|
if (my > level + 0.4f)
|
|
b *= 0.5f;
|
|
}
|
|
if (myv < 0.0f)
|
|
drag = 0.7f;
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.applyBuoyancyImpulse(
|
|
id,
|
|
water.mWaterNode
|
|
->_getDerivedPosition(),
|
|
Ogre::Vector3::UNIT_Y, b, drag,
|
|
adrag, Ogre::Vector3::ZERO,
|
|
eng.delta);
|
|
// std::cout << b << std::endl;
|
|
#if 0
|
|
std::cout << "addHit: "
|
|
<< JoltPhysics::convert(
|
|
body.GetPosition())
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
});
|
|
ecs.system<const EngineData, const CharacterBody>("UpdatePhysics")
|
|
.kind(flecs::OnUpdate)
|
|
.with<CharacterUpdatePhysicsState>()
|
|
.write<CharacterUpdatePhysicsState>()
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const CharacterBody &body) {
|
|
if (e.has<CharacterDisablePhysics>())
|
|
PhysicsModule::controlPhysics(e, false);
|
|
else
|
|
PhysicsModule::controlPhysics(e, true);
|
|
e.remove<CharacterUpdatePhysicsState>();
|
|
});
|
|
ecs.system<const EngineData, const CharacterBase, const CharacterBody,
|
|
CharacterVelocity>("HandleVelocity")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.without<CharacterDisablePhysics>()
|
|
.without<CharacterUpdatePhysicsState>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
const CharacterBase &chbase,
|
|
const CharacterBody &body, CharacterVelocity &gr) {
|
|
if (e.has<InWater>() &&
|
|
chbase.mBodyNode->_getDerivedPosition().y > -0.5f)
|
|
e.remove<InWater>();
|
|
Ogre::Vector3 v = gr.velocity;
|
|
v.y = 0.0f;
|
|
JPH::Character *ch =
|
|
static_cast<JPH::Character *>(body.ch.get());
|
|
if (!e.has<InWater>()) {
|
|
if (ch->IsSupported()) {
|
|
v.y = gr.velocity.y;
|
|
gr.gvelocity.y = 0;
|
|
} else {
|
|
v.y = gr.velocity.y;
|
|
v.y += gr.gvelocity.y;
|
|
gr.gvelocity.y += -9.8f * eng.delta;
|
|
}
|
|
} else {
|
|
v = JoltPhysics::convert(
|
|
ch->GetLinearVelocity());
|
|
v.x = gr.velocity.x;
|
|
v.z = gr.velocity.z;
|
|
}
|
|
// gr.velocity.y = 0.0f;
|
|
// v.y = 0.0f;
|
|
ch->SetLinearVelocity(JoltPhysics::convert(v));
|
|
gr.velocity = Ogre::Vector3::ZERO;
|
|
});
|
|
ecs.system<const EngineData, CharacterBase, const CharacterBody,
|
|
CharacterVelocity>("HandleVelocityNoPhysics")
|
|
.kind(PhysicsPostUpdate)
|
|
.with<TerrainReady>()
|
|
.with<WaterReady>()
|
|
.with<CharacterDisablePhysics>()
|
|
.without<CharacterUpdatePhysicsState>()
|
|
.each([this](flecs::entity e, const EngineData &eng,
|
|
CharacterBase &ch, const CharacterBody &body,
|
|
CharacterVelocity &gr) {
|
|
Ogre::Vector3 v = gr.velocity;
|
|
// v.y = 0.0f;
|
|
ch.mBodyNode->_setDerivedPosition(
|
|
ch.mBodyNode->_getDerivedPosition() +
|
|
v * eng.delta);
|
|
gr.velocity = Ogre::Vector3::ZERO;
|
|
if (e.has<JPH::BodyID>())
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.setPositionAndRotation(
|
|
e.get<JPH::BodyID>(),
|
|
ch.mBodyNode
|
|
->_getDerivedPosition(),
|
|
ch.mBodyNode
|
|
->_getDerivedOrientation(),
|
|
false);
|
|
if (e.has<InWater>() &&
|
|
ch.mBodyNode->_getDerivedPosition().y > -0.5f) {
|
|
e.remove<InWater>();
|
|
ch.is_submerged = false;
|
|
}
|
|
if (!e.has<InWater>() && ch.is_submerged)
|
|
ch.is_submerged = false;
|
|
});
|
|
}
|
|
flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *node,
|
|
float *samples,
|
|
const Ogre::Vector3 &offset,
|
|
const Ogre::Vector3 &scale,
|
|
int sampleCount)
|
|
{
|
|
flecs::entity e = ECS::get().entity();
|
|
e.set<PhysicsHeightfieldData>({ samples, offset, scale, sampleCount });
|
|
e.set<PhysicsBody>({ (uint32_t)JPH::EMotionType::Static,
|
|
(uint32_t)Layers::NON_MOVING });
|
|
e.set<PhysicsNode>({ node });
|
|
|
|
return e;
|
|
}
|
|
void PhysicsModule::controlPhysics(flecs::entity e, bool enable)
|
|
{
|
|
if (enable) {
|
|
if (e.has<CharacterBase>()) {
|
|
e.remove<CharacterDisablePhysics>();
|
|
OgreAssert(e.has<CharacterBody>(), "No body component");
|
|
OgreAssert(e.has<JPH::BodyID>(),
|
|
"No body id in entity");
|
|
}
|
|
if (!JoltPhysicsWrapper::getSingleton().isAdded(
|
|
e.get<JPH::BodyID>())) {
|
|
Ogre::Vector3 position =
|
|
e.get<CharacterBase>()
|
|
.mBodyNode->_getDerivedPosition();
|
|
Ogre::Quaternion orientation =
|
|
e.get<CharacterBase>()
|
|
.mBodyNode->_getDerivedOrientation();
|
|
if (position.y >= -0.5f)
|
|
e.remove<InWater>();
|
|
JoltPhysicsWrapper::getSingleton()
|
|
.setPositionAndRotation(e.get<JPH::BodyID>(),
|
|
position, orientation,
|
|
false);
|
|
JoltPhysicsWrapper::getSingleton().addBody(
|
|
e.get<JPH::BodyID>(),
|
|
JPH::EActivation::Activate);
|
|
}
|
|
} else {
|
|
if (e.has<CharacterBase>()) {
|
|
e.add<CharacterDisablePhysics>();
|
|
if (!e.has<CharacterBody>())
|
|
return;
|
|
OgreAssert(e.has<CharacterBody>(), "No body component");
|
|
OgreAssert(e.has<JPH::BodyID>(),
|
|
"No body id in entity");
|
|
}
|
|
if (JoltPhysicsWrapper::getSingleton().isAdded(
|
|
e.get<JPH::BodyID>()))
|
|
JoltPhysicsWrapper::getSingleton().removeBody(
|
|
e.get<JPH::BodyID>());
|
|
Ogre::Vector3 position =
|
|
e.get<CharacterBase>().mBodyNode->_getDerivedPosition();
|
|
e.remove<InWater>();
|
|
}
|
|
}
|
|
bool WaterBody::isInWater(const JPH::BodyID &id) const
|
|
{
|
|
flecs::entity e =
|
|
ECS::get().query_builder<const JPH::BodyID>().build().find(
|
|
[&](const JPH::BodyID &bodyid) {
|
|
return bodyid == id;
|
|
});
|
|
return inWater.find(id) != inWater.end();
|
|
}
|
|
}
|