Better boat handling

This commit is contained in:
2025-11-30 18:28:26 +03:00
parent cd82fb0eed
commit 5b014dcb65
21 changed files with 938 additions and 230 deletions

BIN
assets/blender/vehicles/boat.blend (Stored with Git LFS)

Binary file not shown.

View File

@@ -413,9 +413,34 @@ local vehicles = {}
local player_vehicles = {}
local actuators = {}
function create_vehicle(vtype, passengers, position)
local vehicle = {}
vehicle.id = ecs_vehicle_set(vtype, position[1], position[2], position[3], position[4])
vehicle.passengers = {}
vehicle.actuators = {}
vehicle.add_passenger = function(this, data)
local npc_id = ecs_npc_set(data.model, data.position[1], data.position[2], data.position[3], data.position[4])
table.insert(this.passengers, npc_id)
ecs_character("physics-control", npc_id, false)
ecs_character("params-set", npc_id, "gravity", false)
ecs_character("params-set", npc_id, "buoyancy", false)
ecs_set_slot(this.id, npc_id, data.slot)
ecs_character("set-actuator", npc_id, data.animation)
end
for i, v in ipairs(passengers) do
vehicle:add_passenger(v)
end
return vehicle
end
function create_boat()
local boat = {}
boat.boat_id = ecs_vehicle_set("boat", 0, 0, -10, 1.75)
local boat = create_vehicle("boat", {
model = "normal-female.glb",
position = {0, 2, -10, 1.75},
slot = "captain_seat",
animation = "sitting"}, {0, 0, -10, 1.75})
--[[
boat.id = ecs_vehicle_set("boat", 0, 0, -10, 1.75)
local npc_id = ecs_npc_set("normal-female.glb", 0, 2, -10, 1.75)
boat.passengers = {npc_id}
ecs_character("physics-control", npc_id, false)
@@ -426,6 +451,7 @@ function create_boat()
ecs_character("set-actuator", npc_id, "sitting")
-- ecs_set_animation_state(npc_id, "main", "actuator", true)
-- ecs_set_animation_state(npc_id, "actuator-state", "sitting", true)
]]--
boat.event = function(this, event, event_data)
print("boat: ", event)
if event == "boat_control_enter" then

View File

@@ -6,6 +6,9 @@
#include "Components.h"
#include "GameData.h"
#include "PhysicsModule.h"
#include "EventModule.h"
#include "EventTriggerModule.h"
#include "CharacterModule.h"
#include "BoatModule.h"
namespace ECS
@@ -17,13 +20,19 @@ BoatModule::BoatModule(flecs::world &ecs)
ecs.component<BoatBase>();
ecs.component<BoatType>();
ecs.component<SpawnBoat>();
ecs.import <EventModule>();
ecs.import <EventTriggerModule>();
ecs.import <CharacterModule>();
ecs.observer<const EngineData, const BoatType>("CreateBoat")
.event(flecs::OnSet)
.without<BoatBase>()
.without<SpawnBoat>()
.each([&](flecs::entity e, const EngineData &eng,
const BoatType &type) { e.add<SpawnBoat>(); });
ecs.system<const EngineData, const BoatType>("CreateBoat")
const BoatType &type) {
e.add<SpawnBoat>();
e.set<EventData>({});
});
ecs.system<const EngineData, const BoatType>("CreateBoatS")
.kind(flecs::OnUpdate)
.without<BoatBase>()
.with<WaterReady>()
@@ -115,6 +124,165 @@ BoatModule::BoatModule(flecs::world &ecs)
// ECS::modified<ECS::EngineData>();
// e.modified<BoatBody>();
});
ecs.observer<const BoatBase, EventData>("HandleBoatEvents")
.event(flecs::OnSet)
.each([](flecs::entity e, const BoatBase &boat,
EventData &evt) {
for (auto ev : evt.events) {
std::cout << "event: " << ev.event << " "
<< ev.sender.name() << " "
<< ev.e1.name() << " " << ev.e2.name()
<< std::endl;
if (ev.event == "actuator_created") {
continue;
} else if (ev.event == "actuator_enter") {
if (ev.sender.has<EventTrigger>()) {
if (ev.e2.has<Player>())
PhysicsModule::
controlPhysics(
ev.e2,
false);
const EventTrigger &trigger =
ev.sender.get<
EventTrigger>();
Ogre::SceneNode *node =
trigger.node;
Ogre::Any animationAny =
node->getUserObjectBindings()
.getUserAny(
"trigger_animation");
if (animationAny.has_value()) {
Ogre::String animation =
Ogre::any_cast<
Ogre::String>(
animationAny);
ev.e2.set<
CharacterVelocity>(
{ { 0, 0, 0 },
{ 0, 0,
0 } });
if (animation.length() >
0)
ev.e2.set<
CharacterInActuator>(
{ animation,
{ 0,
0,
0 } });
else
ev.e2.remove<
CharacterInActuator>();
}
Ogre::SceneNode *target_node =
nullptr;
Ogre::Any targetAny =
node->getUserObjectBindings()
.getUserAny(
"target");
if (targetAny.has_value()) {
OgreAssert(
targetAny
.has_value(),
"need target");
target_node = Ogre::any_cast<
Ogre::SceneNode
*>(
targetAny);
Ogre::Vector3 position =
target_node
->_getDerivedPosition();
Ogre::Quaternion orientation =
target_node
->_getDerivedOrientation();
if (ev.e2.has<
CharacterBase>()) {
ev.e2.get_mut<
CharacterBase>()
.mBodyNode
->_setDerivedPosition(
position);
ev.e2.get_mut<
CharacterBase>()
.mBodyNode
->_setDerivedOrientation(
orientation);
}
}
}
} else if (ev.event == "actuator_forward") {
/* */
ev.e2.set<CharacterInActuator>(
{ "swimming-edge-climb",
{ 0, 0, 0 } });
} else if (ev.event == "actuator_backward") {
/* */
} else if (ev.event ==
"animation:swimming-edge-climb:end") {
ev.e2.remove<CharacterInActuator>();
PhysicsModule::controlPhysics(ev.e2,
true);
ev.e2.remove<InTrigger>(ev.e1);
ev.e1.remove<TriggeredBy>(ev.e2);
ev.e2.add<CharacterGravity>();
ev.e2.add<CharacterBuoyancy>();
} else if (ev.event == "boat_control_enter") {
Ogre::SceneNode *captainSeat = nullptr;
std::vector<Ogre::Node *> children =
boat.mNode->getChildren();
for (auto child : children) {
Ogre::Any nameAny =
child->getUserObjectBindings()
.getUserAny(
"name");
if (nameAny.has_value()) {
Ogre::String name =
Ogre::any_cast<
Ogre::String>(
nameAny);
std::cout << "name: "
<< name
<< std::endl;
if (name ==
"captain_seat") {
captainSeat = static_cast<
Ogre::SceneNode
*>(
child);
break;
}
}
}
OgreAssert(captainSeat, "seats");
PhysicsModule::controlPhysics(ev.e2,
false);
ev.e2.set<CharacterVelocity>(
{ { 0, 0, 0 }, { 0, 0, 0 } });
ev.e2.set<CharacterInActuator>(
{ "sitting", { 0, 0, 0 } });
Ogre::Vector3 position =
captainSeat
->_getDerivedPosition();
Ogre::Quaternion orientation =
captainSeat
->_getDerivedOrientation();
if (ev.e2.has<CharacterBase>()) {
ev.e2.get_mut<CharacterBase>()
.mBodyNode
->_setDerivedPosition(
position);
ev.e2.get_mut<CharacterBase>()
.mBodyNode
->_setDerivedOrientation(
orientation);
}
} else if (ev.event == "boat_control_exit") {
} else if (ev.event == "actuator_exit") {
/* */
} else
OgreAssert(false, "event");
}
evt.events.clear();
});
#if 0
ecs.system<const EngineData, BoatType, Body2Entity>("CreateBoat")
.kind(flecs::OnUpdate)

View File

@@ -3,7 +3,7 @@ set(CMAKE_CXX_STANDARD 17)
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG)
find_package(Bullet REQUIRED)
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp LuaData.cpp WorldMapModule.cpp
BoatModule.cpp EventTriggerModule.cpp CharacterAnimationModule.cpp PhysicsModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp)
BoatModule.cpp EventTriggerModule.cpp CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp)
target_link_libraries(GameData PUBLIC lua flecs::flecs_static OgreMain OgreBites
OgrePaging OgreTerrain OgreOverlay
PRIVATE sceneloader world-build physics)

View File

@@ -4,6 +4,7 @@
#include "CharacterModule.h"
#include "PhysicsModule.h"
#include "CharacterAnimationModule.h"
#include "EventModule.h"
#include "world-build.h"
namespace ECS
{
@@ -11,12 +12,14 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
{
ecs.module<CharacterAnimationModule>();
ecs.component<AnimationControl>();
ecs.import <EventModule>();
ecs.system<const CharacterBase, AnimationControl>("HandleAnimations")
.kind(flecs::OnUpdate)
.each([this](flecs::entity e, const CharacterBase &ch,
AnimationControl &anim) {
if (!anim.configured && ch.mSkeleton) {
int i, j;
e.set<EventData>({});
ch.mSkeleton->setBlendMode(
Ogre::ANIMBLEND_CUMULATIVE);
Ogre::String animNames[] = {
@@ -504,26 +507,29 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
if (Ogre::Math::Abs(input.motion.z -
act.prevMotion.z) >
0.001f) {
if (input.motion.z < 0)
ECS::get<LuaBase>()
.mLua
->call_handler(
"actuator_forward",
trig,
e);
if (input.motion.z > 0)
ECS::get_mut<LuaBase>()
.mLua
->call_handler(
"actuator_backward",
trig,
e);
if (input.motion.z < 0) {
trig.get_mut<EventData>()
.add(e,
"actuator_forward",
trig, e);
trig.modified<
EventData>();
}
if (input.motion.z > 0) {
trig.get_mut<EventData>()
.add(e,
"actuator_backward",
trig, e);
trig.modified<
EventData>();
}
}
if (input.act_pressed) {
trig.get_mut<EventData>().add(
e, "actuator_action",
trig, e);
trig.modified<EventData>();
}
if (input.act_pressed)
ECS::get_mut<LuaBase>()
.mLua->call_handler(
"actuator_action",
trig, e);
// ECS::get_mut<LuaData>().call_handler(
// "actuator_update", trig, e);
trigger_event = true;
@@ -532,26 +538,25 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
if (Ogre::Math::Abs(input.motion.z -
act.prevMotion.z) >
0.001f) {
if (input.motion.z < 0)
ECS::get<LuaBase>()
.mLua
->call_handler(
"_in_actuator_forward",
e, e);
if (input.motion.z > 0)
ECS::get_mut<LuaBase>()
.mLua
->call_handler(
"_in_actuator_backward",
e, e);
}
if (input.act_pressed)
ECS::get_mut<LuaBase>()
.mLua->call_handler(
"_in_actuator_action",
if (input.motion.z < 0) {
e.get_mut<EventData>().add(
e,
"_in_actuator_forward",
e, e);
// ECS::get_mut<LuaData>().call_handler(
// "actuator_update", trig, e);
}
if (input.motion.z > 0) {
e.get_mut<EventData>().add(
e,
"_in_actuator_backward",
e, e);
}
}
if (input.act_pressed) {
e.get_mut<EventData>().add(
e,
"_in_actuator_action",
e, e);
}
}
act.prevMotion.x = input.motion.x;
act.prevMotion.y = input.motion.y;
@@ -569,6 +574,25 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
#endif
act.prevMotion = input.motion;
});
ecs.system<EventData>("UpdateEvents")
.kind(flecs::OnUpdate)
.with<Character>()
.each([](flecs::entity e, EventData &evt) {
for (auto ev : evt.events) {
std::cout << "character event: " << ev.event
<< std::endl;
/* parse character events */
e.each<InTrigger>([&](flecs::entity trig) {
/* if triggered, dispatch events to trigger */
trig.get_mut<EventData>().add(
ev.sender, ev.event,
trig, // it is easier this way to identify trigger entity
ev.e2);
});
}
evt.events.clear();
});
#ifdef VDEBUG
ecs.system<const CharacterBase>("CharacterGravityStatus")
.kind(flecs::OnUpdate)

View File

@@ -5,6 +5,7 @@
#include "GameData.h"
#include "CharacterModule.h"
#include "LuaData.h"
#include "EventModule.h"
namespace ECS
{
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
@@ -713,9 +714,8 @@ struct AnimationSystem : AnimationNode {
Ogre::String event;
void operator()(const AnimationTrigger *trigger)
{
ECS::get_mut<LuaBase>()
.mLua->call_handler(event, ent,
ent);
ent.get_mut<EventData>().add(ent, event,
ent, ent);
}
EventSubscriber(flecs::entity e,
const Ogre::String &event)

View File

@@ -546,23 +546,6 @@ CharacterModule::CharacterModule(flecs::world &ecs)
});
#endif
#if 0
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 0
if (e.has<CharacterDisablePhysics>()) {
eng.mWorld->getBtWorld()->removeAction(
body.mController);
} else {
eng.mWorld->getBtWorld()->addAction(
body.mController);
}
#endif
e.remove<CharacterUpdatePhysicsState>();
});
#endif
}

View File

@@ -0,0 +1,13 @@
#include "EventModule.h"
namespace ECS
{
EventModule::EventModule(flecs::world &ecs)
{
ecs.module<EventModule>();
ecs.component<EventData>();
}
void EventModule::send_event(flecs::entity from, const Ogre::String &event,
flecs::entity to)
{
}
}

View File

@@ -0,0 +1,29 @@
#ifndef _EVENT_MODULE_H_
#define _EVENT_MODULE_H_
#include <flecs.h>
#include <Ogre.h>
namespace ECS
{
struct EventData {
struct EventArgs {
int type;
};
struct Event {
flecs::entity sender;
Ogre::String event;
flecs::entity e1, e2;
};
std::list<Event> events;
void add(flecs::entity sender, const Ogre::String &event,
flecs::entity e1, flecs::entity e2)
{
events.push_back({ sender, event, e1, e2 });
}
};
struct EventModule {
EventModule(flecs::world &ecs);
void send_event(flecs::entity from, const Ogre::String &event,
flecs::entity to);
};
}
#endif

View File

@@ -1,11 +0,0 @@
#ifndef EVENT_SYSTEM_H_
#define EVENT_SYSTEM_H_
struct EventSystem {
struct CommonEvent {
int event_type;
};
void send_event(const EventSystem &event)
{
}
};
#endif

View File

@@ -3,6 +3,7 @@
#include "Components.h"
#include "GameData.h"
#include "LuaData.h"
#include "EventModule.h"
#include "EventTriggerModule.h"
struct TriggerBody {
@@ -68,13 +69,40 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
ecs.module<EventTriggerModule>();
ecs.component<EventTrigger>();
ecs.component<EventTriggerData>();
ecs.component<InTrigger>();
ecs.component<TriggeredBy>();
ecs.import <EventModule>();
ecs.import <LuaModule>();
ecs.observer<const EngineData, const EventTrigger>("CreateTrigger")
.event(flecs::OnSet)
.each([](flecs::entity e, const EngineData &eng,
const EventTrigger &trigger) {
e.set<EventTriggerData>({});
ECS::get<LuaBase>().mLua->call_handler(
"actuator_created", e, e);
e.set<EventData>({});
});
ecs.observer<const EventTrigger, EventData>("CreateTriggerEvent")
.event(flecs::OnSet)
.each([](flecs::entity e, const EventTrigger &trigger,
EventData &evt) {
evt.add(e, "actuator_created", e, e);
});
ecs.system<const EventTrigger, EventData>("HandleEventSystem")
.kind(flecs::OnUpdate)
.each([](flecs::entity e, const EventTrigger &trigger,
EventData &evt) {
if (e.parent().is_valid() &&
e.parent().has<EventData>()) {
bool added = false;
for (auto ev : evt.events) {
e.parent().get_mut<EventData>().add(
ev.sender, ev.event, ev.e1,
ev.e2);
added = true;
}
evt.events.clear();
if (added)
e.parent().modified<EventData>();
}
});
#if 0
ecs.component<EventTriggerData>();

View File

@@ -13,6 +13,7 @@
#include "EventTriggerModule.h"
#include "CharacterAnimationModule.h"
#include "PhysicsModule.h"
#include "EventModule.h"
#include "world-build.h"
namespace ECS
@@ -26,6 +27,7 @@ void setup_minimal()
ecs.component<Input>().add(flecs::Singleton);
ecs.component<Camera>().add(flecs::Singleton);
ecs.import <GameWorldModule>();
ecs.import <EventModule>();
ecs.component<InWater>();
ecs.component<WaterReady>().add(flecs::Singleton);
ecs.component<WaterAlmostReady>().add(flecs::Singleton);

View File

@@ -415,6 +415,15 @@ LuaData::LuaData()
return 1;
});
lua_setglobal(L, "ecs_character_trigger");
lua_pushcfunction(L, [](lua_State *L) -> int {
luaL_checktype(L, 1, LUA_TNUMBER); // object
int object = lua_tointeger(L, 1);
flecs::entity object_e = idmap.get_entity(object);
flecs::entity parent_e = object_e.parent();
lua_pushinteger(L, idmap.add_entity(parent_e));
return 1;
});
lua_setglobal(L, "ecs_parent");
lua_pushcfunction(L, [](lua_State *L) -> int {
OgreAssert(lua_gettop(L) == 7, "bad parameters");
luaL_checktype(L, 1, LUA_TNUMBER); // parent
@@ -551,10 +560,9 @@ LuaData::LuaData()
int object = lua_tointeger(L, 2);
flecs::entity object_e = idmap.get_entity(object);
bool enable = lua_toboolean(L, 3);
if (enable)
object_e.remove<CharacterDisablePhysics>();
else
object_e.add<CharacterDisablePhysics>();
OgreAssert(object_e.has<CharacterBase>(),
"Not a character");
PhysicsModule::controlPhysics(object_e, enable);
object_e.add<CharacterUpdatePhysicsState>();
return 0;
} else if (command == "is-player") {
@@ -659,8 +667,7 @@ LuaData::LuaData()
Ogre::String slot = lua_tostring(L, 3);
flecs::entity parent_e = idmap.get_entity(parent);
flecs::entity object_e = idmap.get_entity(object);
if (!object_e.has<CharacterDisablePhysics>())
object_e.add<CharacterDisablePhysics>();
PhysicsModule::controlPhysics(object_e, false);
object_e.set<ParentSlot>({ parent_e, slot });
return 0;
});
@@ -840,7 +847,11 @@ LuaModule::LuaModule(flecs::world &ecs)
lua.startup_called = false;
})
.add(flecs::Singleton);
ecs.add<LuaBase>();
ecs.component<LuaEvent>().add(flecs::Singleton);
if (!ecs.has<LuaBase>())
ecs.add<LuaBase>();
if (!ecs.has<LuaEvent>())
ecs.set<LuaEvent>({});
ecs.system<const EngineData, LuaBase>("LuaUpdate")
.kind(flecs::OnUpdate)
@@ -888,5 +899,14 @@ LuaModule::LuaModule(flecs::world &ecs)
trigger.parent = parentNode;
e.modified<EventTrigger>();
});
ecs.system<LuaBase, LuaEvent>("HandleLuaEvents")
.kind(flecs::OnUpdate)
.each([](LuaBase &base, LuaEvent &evt) {
while (!evt.events.empty()) {
LuaEvent::Event &ev = evt.events.front();
base.mLua->call_handler(ev.event, ev.e1, ev.e2);
evt.events.pop_front();
}
});
}
}

View File

@@ -27,5 +27,16 @@ struct LuaBase {
struct LuaModule {
LuaModule(flecs::world &ecs);
};
struct LuaEvent {
struct Event {
Ogre::String event;
flecs::entity e1, e2;
};
std::list<Event> events;
void add(const Ogre::String &event, flecs::entity e1, flecs::entity e2)
{
events.push_back({ event, e1, e2 });
}
};
}
#endif

View File

@@ -6,14 +6,17 @@
#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 "PhysicsModule.h"
namespace ECS
{
@@ -28,10 +31,10 @@ struct WaterBody {
struct TriggerBody {
void *foo;
};
PhysicsModule::PhysicsModule(flecs::world &ecs)
{
ecs.module<PhysicsModule>();
ecs.import <EventModule>();
ecs.import <EventTriggerModule>();
ecs.import <BoatModule>();
flecs::entity PhysicsPreUpdate =
@@ -54,6 +57,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
ecs.component<TriggerBody>();
ecs.component<CharacterVelocity>();
ecs.component<WaterBody>().add(flecs::Singleton);
ecs.component<CachedMass>();
ecs.system<const EngineData, const Camera>("physics_init")
.kind(PhysicsPreUpdate)
.without<Physics>()
@@ -184,6 +188,9 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
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>(
@@ -205,6 +212,83 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
// 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>(
@@ -260,6 +344,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
.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(),
@@ -388,17 +473,18 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
JoltPhysicsWrapper::getSingleton().activate(id);
});
ecs.system<const EngineData, const BoatBase, const WaterBody,
const JPH::BodyID>("update_water_boat_buoyancy")
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 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.1f;
float level = 0.25f;
float my = JoltPhysicsWrapper::getSingleton()
.getPosition(id)
.y;
@@ -411,8 +497,9 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
else if (my > level && myv > 0)
b = 0.8f;
#endif
/* max = 2.7; min = 1.7 */
if (my < level)
b = 1.7f;
b = 2.2f;
else if (my > level)
b = 0.9f;
// std::cout << my << std::endl;
@@ -420,6 +507,33 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
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")
@@ -480,15 +594,31 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
#endif
}
});
ecs.system<const EngineData, const CharacterBody, CharacterVelocity>(
"HandleVelocity")
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 =
@@ -513,6 +643,39 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
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,
@@ -528,8 +691,58 @@ flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *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();
}
}
}

View File

@@ -6,6 +6,7 @@ namespace JPH
{
class Shape;
class CharacterBase;
class BodyID;
}
namespace Ogre
{
@@ -45,6 +46,9 @@ struct CharacterVelocity {
Ogre::Vector3 gvelocity;
Ogre::Vector3 velocity;
};
struct CachedMass {
float mass;
};
struct PhysicsModule {
PhysicsModule(flecs::world &ecs);
static flecs::entity createTerrainChunkBody(Ogre::SceneNode *node,
@@ -52,6 +56,7 @@ struct PhysicsModule {
const Ogre::Vector3 &offset,
const Ogre::Vector3 &scale,
int sampleCount);
static void controlPhysics(flecs::entity e, bool enable);
};
}
#endif
#endif

View File

@@ -15,139 +15,165 @@ SlotsModule::SlotsModule(flecs::world &ecs)
ecs.component<ObjectSlots>();
ecs.observer<const EngineData, const BoatBase>("CreateBoatSlots")
.event(flecs::OnSet)
.each([](flecs::entity e, const EngineData &eng,
const BoatBase &boat) {
int i;
std::vector<Ogre::Node *> slots =
boat.mNode->getChildren();
for (i = 0; i < slots.size(); i++) {
Ogre::Any any =
static_cast<Ogre::SceneNode *>(slots[i])
->getUserObjectBindings()
.getUserAny("type");
if (!any.has_value())
continue;
Ogre::String obj_type =
Ogre::any_cast<Ogre::String>(any);
std::cout << "child type: " << obj_type
<< std::endl;
}
if (slots.size() > 0) {
ObjectSlots &vs = e.ensure<ObjectSlots>();
for (i = 0; i < slots.size(); i++) {
Ogre::Any any =
static_cast<Ogre::SceneNode *>(
slots[i])
->getUserObjectBindings()
.getUserAny("type");
if (!any.has_value())
continue;
Ogre::String obj_type =
Ogre::any_cast<Ogre::String>(
any);
any = static_cast<Ogre::SceneNode *>(
slots[i])
->getUserObjectBindings()
.getUserAny("name");
if (!any.has_value())
continue;
Ogre::String obj_name =
Ogre::any_cast<Ogre::String>(
any);
vs.slots[obj_name] = {
obj_type,
static_cast<Ogre::SceneNode *>(
slots[i])
};
}
}
});
ecs.system<const EngineData, const CharacterBase, ParentSlot,
ParentSlotData>("UpdatePhysics2a")
.each([&](flecs::entity e, const EngineData &eng,
const BoatBase &boat) { createBoatSlots(e); });
#if 1
ecs.system<const EngineData, const CharacterBase, ParentSlot>(
"UpdateSlotData")
.kind(flecs::OnUpdate)
.with<CharacterDisablePhysics>()
.each([](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, ParentSlot &slot,
ParentSlotData &psdata) {
.without<ParentSlotData>()
.each([&](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, ParentSlot &slot) {
if (slot.slot_name == "") {
e.remove<ParentSlot>();
e.remove<ParentSlotData>();
slot.removeSlot(e);
return;
}
if (slot.parent_e.has<ObjectSlots>()) {
const ObjectSlots &slots =
slot.parent_e.get<ObjectSlots>();
if (slots.slots.find(slot.slot_name) ==
slots.slots.end()) {
// invalid setting
e.remove<ParentSlot>();
if (slot.parentIsValid()) {
if (!slot.check()) {
slot.removeSlot(e);
return;
}
Ogre::SceneNode *slot_base =
slots.slots.at(slot.slot_name).second;
#if 0
ch.mBodyNode->getParent()->removeChild(
ch.mBodyNode);
#endif
slot_base->addChild(ch.mBodyNode);
Ogre::Vector3 position =
slot_base->_getDerivedPosition();
Ogre::Quaternion orientation =
slot_base->_getDerivedOrientation();
ch.mBodyNode->_setDerivedPosition(position);
ch.mBodyNode->_setDerivedOrientation(
orientation);
psdata.parent_e = slot.parent_e;
psdata.parentNode = slot_base;
psdata.slot_name = slot.slot_name;
slot.addChild(ch.mBodyNode);
slot.createSlotData(e);
std::cout << "base: "
<< slot.getSlotBase()->getName();
e.remove<ParentSlot>();
e.modified<ParentSlotData>();
std::cout << "base: " << slot_base->getName();
}
});
#endif
#if 0
ecs.system<const EngineData, const CharacterBase, ParentSlot>(
"UpdatePhysics2")
"UpdateSlotCharacterTransforms")
.kind(flecs::OnUpdate)
.with<CharacterDisablePhysics>()
.without<ParentSlotData>()
.with<WaterReady>()
.each([](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, ParentSlot &slot) {
.each([&](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, ParentSlot &slot) {
std::cout << e.name() << std::endl;
if (!slot.parent_e.has<ObjectSlots>())
if (!slot.parentIsValid())
return;
OgreAssert(slot.parent_e.has<ObjectSlots>(),
"parent has no slots");
OgreAssert(e.has<Character>(), "not a character");
if (slot.parent_e.has<ObjectSlots>()) {
const ObjectSlots &slots =
slot.parent_e.get<ObjectSlots>();
if (slot.slot_name == "")
return;
if (slots.slots.find(slot.slot_name) ==
slots.slots.end()) {
// invalid setting
e.remove<ParentSlot>();
if (slot.parentIsValid()) {
if (!slot.check()) {
slot.removeSlot(e);
OgreAssert(false, "bad slot");
return;
}
ParentSlotData &psdata =
e.ensure<ParentSlotData>();
Ogre::SceneNode *slot_base =
slots.slots.at(slot.slot_name).second;
Ogre::Vector3 position =
slot_base->_getDerivedPosition();
Ogre::Quaternion orientation =
slot_base->_getDerivedOrientation();
ch.mBodyNode->_setDerivedPosition(position);
ch.mBodyNode->_setDerivedOrientation(
orientation);
psdata.parent_e = slot.parent_e;
psdata.parentNode = slot_base;
psdata.slot_name = slot.slot_name;
e.remove<ParentSlot>();
e.modified<ParentSlotData>();
slot.createSlot(e);
slot.createSlotData(e);
}
});
#endif
}
void SlotsModule::createBoatSlots(flecs::entity e)
{
const EngineData &eng = e.world().get<EngineData>();
const BoatBase &boat = e.get<BoatBase>();
int i;
std::vector<Ogre::Node *> slots = boat.mNode->getChildren();
for (i = 0; i < slots.size(); i++) {
Ogre::Any any = static_cast<Ogre::SceneNode *>(slots[i])
->getUserObjectBindings()
.getUserAny("type");
if (!any.has_value())
continue;
Ogre::String obj_type = Ogre::any_cast<Ogre::String>(any);
std::cout << "child type: " << obj_type << std::endl;
}
if (slots.size() > 0) {
ObjectSlots &vs = e.ensure<ObjectSlots>();
for (i = 0; i < slots.size(); i++) {
Ogre::Any any = static_cast<Ogre::SceneNode *>(slots[i])
->getUserObjectBindings()
.getUserAny("type");
if (!any.has_value())
continue;
Ogre::String obj_type =
Ogre::any_cast<Ogre::String>(any);
any = static_cast<Ogre::SceneNode *>(slots[i])
->getUserObjectBindings()
.getUserAny("name");
if (!any.has_value())
continue;
Ogre::String obj_name =
Ogre::any_cast<Ogre::String>(any);
vs.slots[obj_name] = { obj_type,
static_cast<Ogre::SceneNode *>(
slots[i]) };
}
}
}
void ParentSlot::createSlot(flecs::entity e)
{
if (e.has<CharacterBase>()) {
createCharacterSlot(e);
}
}
void ParentSlot::createCharacterSlot(flecs::entity e)
{
}
void ParentSlot::removeSlot(flecs::entity e)
{
if (e.has<ParentSlot>())
e.remove<ParentSlot>();
if (e.has<ParentSlot>())
e.remove<ParentSlotData>();
}
bool ParentSlot::check() const
{
if (!parent_e.has<ObjectSlots>())
return false;
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
if (!slots.exists(slot_name))
return false;
return true;
}
bool ParentSlot::parentIsValid()
{
if (!parent_e.has<ObjectSlots>())
return false;
return true;
}
Ogre::SceneNode *ParentSlot::getSlotBase() const
{
if (!check())
return nullptr;
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
Ogre::SceneNode *slot_base = slots.slots.at(slot_name).second;
return slot_base;
}
void ParentSlot::addChild(Ogre::SceneNode *childNode)
{
Ogre::SceneNode *parentNode = getSlotBase();
if (childNode->getParentSceneNode())
childNode->getParentSceneNode()->removeChild(childNode);
parentNode->addChild(childNode);
childNode->_setDerivedPosition(parentNode->_getDerivedPosition());
childNode->_setDerivedOrientation(parentNode->_getDerivedOrientation());
}
void ParentSlot::createSlotData(flecs::entity e)
{
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
ParentSlotData &psdata = e.ensure<ParentSlotData>();
Ogre::SceneNode *slot_base = getSlotBase();
// Ogre::Vector3 position = slot_base->_getDerivedPosition();
// Ogre::Quaternion orientation = slot_base->_getDerivedOrientation();
// ch.mBodyNode->_setDerivedPosition(position);
// ch.mBodyNode->_setDerivedOrientation(orientation);
psdata.parent_e = parent_e;
psdata.parentNode = slot_base;
psdata.slot_name = slot_name;
e.remove<ParentSlot>();
e.modified<ParentSlotData>();
}
bool ObjectSlots::exists(const Ogre::String &name) const
{
return slots.find(name) != slots.end();
}
}

View File

@@ -7,6 +7,14 @@ namespace ECS
struct ParentSlot {
flecs::entity parent_e;
Ogre::String slot_name;
void createSlot(flecs::entity e);
void createCharacterSlot(flecs::entity e);
void removeSlot(flecs::entity e);
bool check() const;
bool parentIsValid();
Ogre::SceneNode *getSlotBase() const;
void addChild(Ogre::SceneNode *childNode);
void createSlotData(flecs::entity e);
};
struct ParentSlotData {
Ogre::String slot_name;
@@ -17,9 +25,11 @@ struct ObjectSlots {
std::unordered_map<Ogre::String,
std::pair<Ogre::String, Ogre::SceneNode *> >
slots;
bool exists(const Ogre::String &name) const;
};
struct SlotsModule {
SlotsModule(flecs::world &ecs);
void createBoatSlots(flecs::entity e);
};
}
#endif

View File

@@ -29,6 +29,7 @@
#include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
#include <Jolt/Physics/Collision/Shape/HeightFieldShape.h>
#include <Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h>
#include <Jolt/Physics/Collision/ContactListener.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Physics/Body/BodyActivationListener.h>
#include <Jolt/Renderer/DebugRendererSimple.h>
@@ -156,6 +157,7 @@ public:
}
};
#if 0
// An example contact listener
class MyContactListener : public JPH::ContactListener {
public:
@@ -209,6 +211,7 @@ public:
std::cout << "A body went to sleep" << std::endl;
}
};
#endif
class MyCollector : public JPH::CollideShapeBodyCollector {
public:
MyCollector(JPH::PhysicsSystem *inSystem,
@@ -453,6 +456,56 @@ JPH::ShapeRefC CompoundShapeBuilder::build()
JPH::ShapeSettings::ShapeResult result = shapeSettings.Create();
return result.Get();
}
ContactListener::ContactListener()
: JPH::ContactListener()
, dispatch(nullptr)
{
}
JPH::ValidateResult ContactListener::OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult)
{
return JPH::ValidateResult::AcceptAllContactsForThisBodyPair;
}
void ContactListener::OnContactAdded(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings)
{
reports.push_back({ true, inBody1.GetID(), inBody2.GetID(), inManifold,
ioSettings });
}
void ContactListener::OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings)
{
}
void ContactListener::OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair)
{
reports.push_back({ false, inSubShapePair.GetBody1ID(),
inSubShapePair.GetBody2ID(), JPH::ContactManifold(),
JPH::ContactSettings() });
}
void ContactListener::update()
{
for (auto contact : reports) {
bool handled = false;
if (listeners.find(contact.id1) != listeners.end()) {
listeners[contact.id1](contact);
handled = true;
}
if (listeners.find(contact.id2) != listeners.end()) {
listeners[contact.id2](contact);
handled = true;
}
if (!handled && dispatch) {
dispatch(contact);
}
}
reports.clear();
}
}
class Physics {
@@ -498,29 +551,9 @@ public:
virtual void OnBodyDeactivated(const JPH::BodyID &inBodyID,
JPH::uint64 inBodyUserData) = 0;
};
class ContactListener : public JPH::ContactListener {
public:
virtual JPH::ValidateResult OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult) = 0;
virtual void
OnContactAdded(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) = 0;
virtual void
OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) = 0;
virtual void
OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) = 0;
};
Physics(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
ActivationListener *activationListener = nullptr,
ContactListener *contactListener = nullptr)
JPH::ContactListener *contactListener = nullptr)
: temp_allocator(10 * 1024 * 1024)
, job_system(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers,
std::thread::hardware_concurrency() - 1)
@@ -740,8 +773,10 @@ public:
node->_setDerivedPosition(JoltPhysics::convert(p));
node->_setDerivedOrientation(JoltPhysics::convert(q));
}
for (JPH::Character *ch : characters)
ch->PostSimulation(0.1f);
for (JPH::Character *ch : characters) {
if (body_interface.IsAdded(ch->GetBodyID()))
ch->PostSimulation(0.1f);
}
if (debugDraw)
physics_system.DrawBodies(
@@ -873,7 +908,7 @@ public:
if (shape->GetType() == JPH::EShapeType::HeightField) {
JPH::BodyInterface &body_interface =
physics_system.GetBodyInterface();
body_interface.SetFriction(id, 0.7f);
body_interface.SetFriction(id, 1.0f);
}
id2node[id] = node;
node2id[node] = id;
@@ -1385,6 +1420,21 @@ public:
physics_system.GetBodyInterface().GetLinearVelocity(
id));
}
Ogre::Vector3 getAngularVelocity(JPH::BodyID id)
{
return JoltPhysics::convert(
physics_system.GetBodyInterface().GetAngularVelocity(
id));
}
float getFriction(JPH::BodyID id)
{
return physics_system.GetBodyInterface().GetFriction(id);
}
void setFriction(JPH::BodyID id, float friction)
{
return physics_system.GetBodyInterface().SetFriction(id,
friction);
}
void broadphaseQuery(float dt, const Ogre::Vector3 &position,
std::set<JPH::BodyID> &inWater)
{
@@ -1434,7 +1484,7 @@ JoltPhysicsWrapper::JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
JPH::Trace = TraceImpl;
JPH_IF_ENABLE_ASSERTS(JPH::AssertFailed = AssertFailedImpl;)
phys = new Physics(scnMgr, cameraNode);
phys = new Physics(scnMgr, cameraNode, nullptr, &contacts);
}
JoltPhysicsWrapper::~JoltPhysicsWrapper()
@@ -1446,6 +1496,7 @@ JoltPhysicsWrapper::~JoltPhysicsWrapper()
void JoltPhysicsWrapper::update(float dt)
{
phys->update(dt);
contacts.update();
}
void JoltPhysicsWrapper::addBody(const JPH::BodyID &body,
@@ -1629,6 +1680,10 @@ void JoltPhysicsWrapper::setPosition(JPH::BodyID id,
{
return phys->setPosition(id, position, activate);
}
Ogre::Quaternion JoltPhysicsWrapper::getRotation(JPH::BodyID id)
{
return phys->getRotation(id);
}
void JoltPhysicsWrapper::setRotation(JPH::BodyID id,
const Ogre::Quaternion &rotation,
bool activate)
@@ -1651,10 +1706,41 @@ Ogre::Vector3 JoltPhysicsWrapper::getLinearVelocity(JPH::BodyID id)
{
return phys->getLinearVelocity(id);
}
Ogre::Vector3 JoltPhysicsWrapper::getAngularVelocity(JPH::BodyID id)
{
return phys->getAngularVelocity(id);
}
float JoltPhysicsWrapper::getFriction(JPH::BodyID id)
{
return phys->getFriction(id);
}
void JoltPhysicsWrapper::setFriction(JPH::BodyID id, float friction)
{
phys->setFriction(id, friction);
}
void JoltPhysicsWrapper::addAngularImpulse(const JPH::BodyID &id,
const Ogre::Vector3 &impulse)
{
return phys->addAngularImpulse(id, impulse);
}
void JoltPhysicsWrapper::setDispatch(
std::function<
void(const JoltPhysics::ContactListener::ContactReport &report)>
dispatcher)
{
contacts.setDispatch(dispatcher);
}
void JoltPhysicsWrapper::addContactListener(
const JPH::BodyID &id,
std::function<
void(const JoltPhysics::ContactListener::ContactReport &report)>
listener)
{
contacts.addListener(id, listener);
}
void JoltPhysicsWrapper::removeContactListener(const JPH::BodyID &id)
{
contacts.removeListener(id);
}
template <>
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;

View File

@@ -6,6 +6,7 @@
#include <Jolt/Physics/Collision/Shape/Shape.h>
#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
#include <Jolt/Physics/Collision/ObjectLayer.h>
#include <Jolt/Physics/Collision/ContactListener.h>
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Physics/EActivation.h>
@@ -13,6 +14,9 @@ void physics();
namespace JPH
{
class CharacterBase;
class ContactManifold;
class ContactSettings;
class SubShapeIDPair;
}
// Layer that objects can be in, determines which other objects it can collide with
// Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more
@@ -50,10 +54,58 @@ struct CompoundShapeBuilder {
const Ogre::Quaternion &rotation);
JPH::ShapeRefC build();
};
class ContactListener : public JPH::ContactListener {
public:
struct ContactReport {
bool entered;
JPH::BodyID id1, id2;
JPH::ContactManifold manifold;
JPH::ContactSettings settings;
};
private:
std::list<ContactReport> reports;
std::function<void(const ContactReport &report)> dispatch;
std::map<JPH::BodyID, std::function<void(const ContactReport &report)> >
listeners;
public:
ContactListener();
JPH::ValidateResult OnContactValidate(
const JPH::Body &inBody1, const JPH::Body &inBody2,
JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult &inCollisionResult) override;
void OnContactAdded(const JPH::Body &inBody1, const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) override;
void OnContactPersisted(const JPH::Body &inBody1,
const JPH::Body &inBody2,
const JPH::ContactManifold &inManifold,
JPH::ContactSettings &ioSettings) override;
void
OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) override;
void setDispatch(const std::function<void(const ContactReport &report)>
dispatcher)
{
dispatch = dispatcher;
}
void addListener(
const JPH::BodyID &id,
const std::function<void(const ContactReport &report)> listener)
{
listeners[id] = listener;
}
void removeListener(const JPH::BodyID &id)
{
listeners.erase(id);
}
void update();
};
}
class JoltPhysicsWrapper : public Ogre::Singleton<JoltPhysicsWrapper> {
public:
JoltPhysics::ContactListener contacts;
JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
Ogre::SceneNode *cameraNode);
~JoltPhysicsWrapper();
@@ -128,6 +180,7 @@ public:
Ogre::Vector3 getPosition(JPH::BodyID id);
void setPosition(JPH::BodyID id, const Ogre::Vector3 &position,
bool activate = true);
Ogre::Quaternion getRotation(JPH::BodyID id);
void setRotation(JPH::BodyID id, const Ogre::Quaternion &rotation,
bool activate = true);
void getPositionAndRotation(JPH::BodyID id, Ogre::Vector3 &position,
@@ -137,7 +190,19 @@ public:
const Ogre::Quaternion &rotation,
bool activate = true);
Ogre::Vector3 getLinearVelocity(JPH::BodyID id);
Ogre::Vector3 getAngularVelocity(JPH::BodyID id);
float getFriction(JPH::BodyID id);
void setFriction(JPH::BodyID id, float friction);
void addAngularImpulse(const JPH::BodyID &id,
const Ogre::Vector3 &impulse);
void setDispatch(std::function<void(const JoltPhysics::ContactListener::
ContactReport &report)>
dispatcher);
void addContactListener(
const JPH::BodyID &id,
const std::function<void(const JoltPhysics::ContactListener::
ContactReport &report)>
listener);
void removeContactListener(const JPH::BodyID &id);
};
#endif
#endif

View File

@@ -6,6 +6,7 @@
#include "GameData.h"
#include "Components.h"
#include "EventTriggerModule.h"
#include "PhysicsModule.h"
#include "physics.h"
#include "loader.h"
@@ -1868,15 +1869,23 @@ void SceneLoader::setupPhysicsBody(Ogre::SceneNode *node,
layer = Layers::NON_MOVING;
mass = 0.0f;
}
#if 1
JPH::ShapeRefC com_shape =
JoltPhysicsWrapper::getSingleton()
.createOffsetCenterOfMassShape(
Ogre::Vector3(0, -5.5f, 0.5f),
Ogre::Vector3(0, 0, 0.45f),
shape);
JPH::BodyID id =
JoltPhysicsWrapper::getSingleton().createBody(
com_shape.GetPtr(), mass, pNode, motion,
layer);
JoltPhysicsWrapper::getSingleton().setFriction(id, 0.95f);
#else
JPH::BodyID id =
JoltPhysicsWrapper::getSingleton().createBody(
shape.GetPtr(), mass, pNode, motion,
layer);
#endif
LogManager::getSingleton().logMessage(
"[SceneLoader] Node: " + pNode->getName() +
" btRigidBody created: " + collisionBodyType);
@@ -1887,6 +1896,7 @@ void SceneLoader::setupPhysicsBody(Ogre::SceneNode *node,
id);
/* do not add body to physics yet */
base_e.set<JPH::BodyID>(id);
base_e.set<ECS::CachedMass>({mass});
} else if (collisionBodyType == "ghost") {
/* TODO: later */
}