diff --git a/assets/blender/vehicles/boat.blend b/assets/blender/vehicles/boat.blend index f8f1291..0fb33d8 100644 --- a/assets/blender/vehicles/boat.blend +++ b/assets/blender/vehicles/boat.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e601f89fd12f060fa92778b6f6554c67b9b411c72967b1538cddb9b55608a34c -size 509752 +oid sha256:cf018cf9fa59b606139f8504e2855a2afe3d068aa1cda6b3b4079e6498d54c15 +size 507761 diff --git a/lua-scripts/data.lua b/lua-scripts/data.lua index 912a07a..3bd9d8d 100644 --- a/lua-scripts/data.lua +++ b/lua-scripts/data.lua @@ -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 diff --git a/src/gamedata/BoatModule.cpp b/src/gamedata/BoatModule.cpp index a52cb36..5e61523 100644 --- a/src/gamedata/BoatModule.cpp +++ b/src/gamedata/BoatModule.cpp @@ -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(); ecs.component(); ecs.component(); + ecs.import (); + ecs.import (); + ecs.import (); ecs.observer("CreateBoat") .event(flecs::OnSet) .without() .without() .each([&](flecs::entity e, const EngineData &eng, - const BoatType &type) { e.add(); }); - ecs.system("CreateBoat") + const BoatType &type) { + e.add(); + e.set({}); + }); + ecs.system("CreateBoatS") .kind(flecs::OnUpdate) .without() .with() @@ -115,6 +124,165 @@ BoatModule::BoatModule(flecs::world &ecs) // ECS::modified(); // e.modified(); }); + ecs.observer("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()) { + if (ev.e2.has()) + 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( + { "swimming-edge-climb", + { 0, 0, 0 } }); + } else if (ev.event == "actuator_backward") { + /* */ + } else if (ev.event == + "animation:swimming-edge-climb:end") { + ev.e2.remove(); + PhysicsModule::controlPhysics(ev.e2, + true); + ev.e2.remove(ev.e1); + ev.e1.remove(ev.e2); + ev.e2.add(); + ev.e2.add(); + } else if (ev.event == "boat_control_enter") { + Ogre::SceneNode *captainSeat = nullptr; + std::vector 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( + { { 0, 0, 0 }, { 0, 0, 0 } }); + ev.e2.set( + { "sitting", { 0, 0, 0 } }); + Ogre::Vector3 position = + captainSeat + ->_getDerivedPosition(); + Ogre::Quaternion orientation = + captainSeat + ->_getDerivedOrientation(); + if (ev.e2.has()) { + ev.e2.get_mut() + .mBodyNode + ->_setDerivedPosition( + position); + ev.e2.get_mut() + .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("CreateBoat") .kind(flecs::OnUpdate) diff --git a/src/gamedata/CMakeLists.txt b/src/gamedata/CMakeLists.txt index a52bf94..c38965a 100644 --- a/src/gamedata/CMakeLists.txt +++ b/src/gamedata/CMakeLists.txt @@ -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) diff --git a/src/gamedata/CharacterAnimationModule.cpp b/src/gamedata/CharacterAnimationModule.cpp index ad36275..0e99a67 100644 --- a/src/gamedata/CharacterAnimationModule.cpp +++ b/src/gamedata/CharacterAnimationModule.cpp @@ -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(); ecs.component(); + ecs.import (); ecs.system("HandleAnimations") .kind(flecs::OnUpdate) .each([this](flecs::entity e, const CharacterBase &ch, AnimationControl &anim) { if (!anim.configured && ch.mSkeleton) { int i, j; + e.set({}); 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() - .mLua - ->call_handler( - "actuator_forward", - trig, - e); - if (input.motion.z > 0) - ECS::get_mut() - .mLua - ->call_handler( - "actuator_backward", - trig, - e); + if (input.motion.z < 0) { + trig.get_mut() + .add(e, + "actuator_forward", + trig, e); + trig.modified< + EventData>(); + } + if (input.motion.z > 0) { + trig.get_mut() + .add(e, + "actuator_backward", + trig, e); + trig.modified< + EventData>(); + } + } + if (input.act_pressed) { + trig.get_mut().add( + e, "actuator_action", + trig, e); + trig.modified(); } - if (input.act_pressed) - ECS::get_mut() - .mLua->call_handler( - "actuator_action", - trig, e); // ECS::get_mut().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() - .mLua - ->call_handler( - "_in_actuator_forward", - e, e); - if (input.motion.z > 0) - ECS::get_mut() - .mLua - ->call_handler( - "_in_actuator_backward", - e, e); - } - if (input.act_pressed) - ECS::get_mut() - .mLua->call_handler( - "_in_actuator_action", + if (input.motion.z < 0) { + e.get_mut().add( + e, + "_in_actuator_forward", e, e); - // ECS::get_mut().call_handler( - // "actuator_update", trig, e); + } + if (input.motion.z > 0) { + e.get_mut().add( + e, + "_in_actuator_backward", + e, e); + } + } + if (input.act_pressed) { + e.get_mut().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("UpdateEvents") + .kind(flecs::OnUpdate) + .with() + .each([](flecs::entity e, EventData &evt) { + for (auto ev : evt.events) { + std::cout << "character event: " << ev.event + << std::endl; + /* parse character events */ + e.each([&](flecs::entity trig) { + /* if triggered, dispatch events to trigger */ + trig.get_mut().add( + ev.sender, ev.event, + trig, // it is easier this way to identify trigger entity + ev.e2); + }); + } + evt.events.clear(); + }); + #ifdef VDEBUG ecs.system("CharacterGravityStatus") .kind(flecs::OnUpdate) diff --git a/src/gamedata/CharacterAnimationModule.h b/src/gamedata/CharacterAnimationModule.h index 73e050b..d5684ff 100644 --- a/src/gamedata/CharacterAnimationModule.h +++ b/src/gamedata/CharacterAnimationModule.h @@ -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() - .mLua->call_handler(event, ent, - ent); + ent.get_mut().add(ent, event, + ent, ent); } EventSubscriber(flecs::entity e, const Ogre::String &event) diff --git a/src/gamedata/CharacterModule.cpp b/src/gamedata/CharacterModule.cpp index 0d6c27d..260fd7b 100644 --- a/src/gamedata/CharacterModule.cpp +++ b/src/gamedata/CharacterModule.cpp @@ -546,23 +546,6 @@ CharacterModule::CharacterModule(flecs::world &ecs) }); #endif #if 0 - ecs.system("UpdatePhysics") - .kind(flecs::OnUpdate) - .with() - .write() - .each([](flecs::entity e, const EngineData &eng, - const CharacterBody &body) { -#if 0 - if (e.has()) { - eng.mWorld->getBtWorld()->removeAction( - body.mController); - } else { - eng.mWorld->getBtWorld()->addAction( - body.mController); - } -#endif - e.remove(); - }); #endif } diff --git a/src/gamedata/EventModule.cpp b/src/gamedata/EventModule.cpp new file mode 100644 index 0000000..cfc8cc9 --- /dev/null +++ b/src/gamedata/EventModule.cpp @@ -0,0 +1,13 @@ +#include "EventModule.h" +namespace ECS +{ +EventModule::EventModule(flecs::world &ecs) +{ + ecs.module(); + ecs.component(); +} +void EventModule::send_event(flecs::entity from, const Ogre::String &event, + flecs::entity to) +{ +} +} \ No newline at end of file diff --git a/src/gamedata/EventModule.h b/src/gamedata/EventModule.h new file mode 100644 index 0000000..1a2447a --- /dev/null +++ b/src/gamedata/EventModule.h @@ -0,0 +1,29 @@ +#ifndef _EVENT_MODULE_H_ +#define _EVENT_MODULE_H_ +#include +#include +namespace ECS +{ +struct EventData { + struct EventArgs { + int type; + }; + struct Event { + flecs::entity sender; + Ogre::String event; + flecs::entity e1, e2; + }; + std::list 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 \ No newline at end of file diff --git a/src/gamedata/EventSystem.h b/src/gamedata/EventSystem.h deleted file mode 100644 index 7c0d212..0000000 --- a/src/gamedata/EventSystem.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/src/gamedata/EventTriggerModule.cpp b/src/gamedata/EventTriggerModule.cpp index fc1bff6..a573a84 100644 --- a/src/gamedata/EventTriggerModule.cpp +++ b/src/gamedata/EventTriggerModule.cpp @@ -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(); ecs.component(); ecs.component(); + ecs.component(); + ecs.component(); + ecs.import (); + ecs.import (); ecs.observer("CreateTrigger") .event(flecs::OnSet) .each([](flecs::entity e, const EngineData &eng, const EventTrigger &trigger) { e.set({}); - ECS::get().mLua->call_handler( - "actuator_created", e, e); + e.set({}); + }); + ecs.observer("CreateTriggerEvent") + .event(flecs::OnSet) + .each([](flecs::entity e, const EventTrigger &trigger, + EventData &evt) { + evt.add(e, "actuator_created", e, e); + }); + ecs.system("HandleEventSystem") + .kind(flecs::OnUpdate) + .each([](flecs::entity e, const EventTrigger &trigger, + EventData &evt) { + if (e.parent().is_valid() && + e.parent().has()) { + bool added = false; + for (auto ev : evt.events) { + e.parent().get_mut().add( + ev.sender, ev.event, ev.e1, + ev.e2); + added = true; + } + evt.events.clear(); + if (added) + e.parent().modified(); + } }); #if 0 ecs.component(); diff --git a/src/gamedata/GameData.cpp b/src/gamedata/GameData.cpp index a0b720f..b9c218d 100644 --- a/src/gamedata/GameData.cpp +++ b/src/gamedata/GameData.cpp @@ -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().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.import (); + ecs.import (); ecs.component(); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); diff --git a/src/gamedata/LuaData.cpp b/src/gamedata/LuaData.cpp index c3d9907..fa819cd 100644 --- a/src/gamedata/LuaData.cpp +++ b/src/gamedata/LuaData.cpp @@ -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(); - else - object_e.add(); + OgreAssert(object_e.has(), + "Not a character"); + PhysicsModule::controlPhysics(object_e, enable); object_e.add(); 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()) - object_e.add(); + PhysicsModule::controlPhysics(object_e, false); object_e.set({ parent_e, slot }); return 0; }); @@ -840,7 +847,11 @@ LuaModule::LuaModule(flecs::world &ecs) lua.startup_called = false; }) .add(flecs::Singleton); - ecs.add(); + ecs.component().add(flecs::Singleton); + if (!ecs.has()) + ecs.add(); + if (!ecs.has()) + ecs.set({}); ecs.system("LuaUpdate") .kind(flecs::OnUpdate) @@ -888,5 +899,14 @@ LuaModule::LuaModule(flecs::world &ecs) trigger.parent = parentNode; e.modified(); }); + ecs.system("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(); + } + }); } } \ No newline at end of file diff --git a/src/gamedata/LuaData.h b/src/gamedata/LuaData.h index b904cf7..f482aaa 100644 --- a/src/gamedata/LuaData.h +++ b/src/gamedata/LuaData.h @@ -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 events; + void add(const Ogre::String &event, flecs::entity e1, flecs::entity e2) + { + events.push_back({ event, e1, e2 }); + } +}; } #endif diff --git a/src/gamedata/PhysicsModule.cpp b/src/gamedata/PhysicsModule.cpp index 03ee4b2..6385323 100644 --- a/src/gamedata/PhysicsModule.cpp +++ b/src/gamedata/PhysicsModule.cpp @@ -6,14 +6,17 @@ #include #include #include +#include #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(); + ecs.import (); ecs.import (); ecs.import (); flecs::entity PhysicsPreUpdate = @@ -54,6 +57,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs) ecs.component(); ecs.component(); ecs.component().add(flecs::Singleton); + ecs.component(); ecs.system("physics_init") .kind(PhysicsPreUpdate) .without() @@ -184,6 +188,9 @@ PhysicsModule::PhysicsModule(flecs::world &ecs) static_cast(b.ch.get()) ->AddToPhysicsSystem( JPH::EActivation::Activate); + e.set( + static_cast(b.ch.get()) + ->GetBodyID()); e.modified(); }); ecs.observer( @@ -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() + .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(); + 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() + .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(); + if (report.entered) { + trigger_e.get_mut() + .add(trigger_e, + trg.event + + "_enter", + trigger_e, + other_e); + other_e.add( + trigger_e); + trigger_e.add( + other_e); + } else { + trigger_e.get_mut() + .add(trigger_e, + trg.event + + "_exit", + trigger_e, + other_e); +#if 0 +/* do not delete triggers until exit from actuator */ + other_e.remove( + trigger_e); + trigger_e.remove( + other_e); +#endif + } + ECS::modified(); + }); }); #if 0 ecs.system( @@ -260,6 +344,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs) .with() .each([this](const EngineData &eng, WaterBody &body) { const WaterSurface &water = ECS::get(); + 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("update_water_boat_buoyancy") + const JPH::BodyID, const CachedMass>( + "update_water_boat_buoyancy") .kind(PhysicsPreUpdate) .with() .with() .with() .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(); 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( "update_water_character_buoyancy") @@ -480,15 +594,31 @@ PhysicsModule::PhysicsModule(flecs::world &ecs) #endif } }); - ecs.system( - "HandleVelocity") + ecs.system("UpdatePhysics") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::entity e, const EngineData &eng, + const CharacterBody &body) { + if (e.has()) + PhysicsModule::controlPhysics(e, false); + else + PhysicsModule::controlPhysics(e, true); + e.remove(); + }); + ecs.system("HandleVelocity") .kind(PhysicsPostUpdate) .with() .with() .without() .without() .each([this](flecs::entity e, const EngineData &eng, + const CharacterBase &chbase, const CharacterBody &body, CharacterVelocity &gr) { + if (e.has() && + chbase.mBodyNode->_getDerivedPosition().y > -0.5f) + e.remove(); 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("HandleVelocityNoPhysics") + .kind(PhysicsPostUpdate) + .with() + .with() + .with() + .without() + .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()) + JoltPhysicsWrapper::getSingleton() + .setPositionAndRotation( + e.get(), + ch.mBodyNode + ->_getDerivedPosition(), + ch.mBodyNode + ->_getDerivedOrientation(), + false); + if (e.has() && + ch.mBodyNode->_getDerivedPosition().y > -0.5f) { + e.remove(); + ch.is_submerged = false; + } + if (!e.has() && 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()) { + e.remove(); + OgreAssert(e.has(), "No body component"); + OgreAssert(e.has(), + "No body id in entity"); + } + if (!JoltPhysicsWrapper::getSingleton().isAdded( + e.get())) { + Ogre::Vector3 position = + e.get() + .mBodyNode->_getDerivedPosition(); + Ogre::Quaternion orientation = + e.get() + .mBodyNode->_getDerivedOrientation(); + if (position.y >= -0.5f) + e.remove(); + JoltPhysicsWrapper::getSingleton() + .setPositionAndRotation(e.get(), + position, orientation, + false); + JoltPhysicsWrapper::getSingleton().addBody( + e.get(), + JPH::EActivation::Activate); + } + } else { + if (e.has()) { + e.add(); + if (!e.has()) + return; + OgreAssert(e.has(), "No body component"); + OgreAssert(e.has(), + "No body id in entity"); + } + if (JoltPhysicsWrapper::getSingleton().isAdded( + e.get())) + JoltPhysicsWrapper::getSingleton().removeBody( + e.get()); + Ogre::Vector3 position = + e.get().mBodyNode->_getDerivedPosition(); + e.remove(); + } +} bool WaterBody::isInWater(const JPH::BodyID &id) const { + flecs::entity e = + ECS::get().query_builder().build().find( + [&](const JPH::BodyID &bodyid) { + return bodyid == id; + }); return inWater.find(id) != inWater.end(); } -} \ No newline at end of file +} diff --git a/src/gamedata/PhysicsModule.h b/src/gamedata/PhysicsModule.h index 232fc81..527ddbb 100644 --- a/src/gamedata/PhysicsModule.h +++ b/src/gamedata/PhysicsModule.h @@ -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 \ No newline at end of file +#endif diff --git a/src/gamedata/SlotsModule.cpp b/src/gamedata/SlotsModule.cpp index d9d7592..56d25c5 100644 --- a/src/gamedata/SlotsModule.cpp +++ b/src/gamedata/SlotsModule.cpp @@ -15,139 +15,165 @@ SlotsModule::SlotsModule(flecs::world &ecs) ecs.component(); ecs.observer("CreateBoatSlots") .event(flecs::OnSet) - .each([](flecs::entity e, const EngineData &eng, - const BoatBase &boat) { - int i; - std::vector slots = - boat.mNode->getChildren(); - for (i = 0; i < slots.size(); i++) { - Ogre::Any any = - static_cast(slots[i]) - ->getUserObjectBindings() - .getUserAny("type"); - if (!any.has_value()) - continue; - Ogre::String obj_type = - Ogre::any_cast(any); - std::cout << "child type: " << obj_type - << std::endl; - } - if (slots.size() > 0) { - ObjectSlots &vs = e.ensure(); - for (i = 0; i < slots.size(); i++) { - Ogre::Any any = - static_cast( - slots[i]) - ->getUserObjectBindings() - .getUserAny("type"); - if (!any.has_value()) - continue; - Ogre::String obj_type = - Ogre::any_cast( - any); - any = static_cast( - slots[i]) - ->getUserObjectBindings() - .getUserAny("name"); - if (!any.has_value()) - continue; - Ogre::String obj_name = - Ogre::any_cast( - any); - vs.slots[obj_name] = { - obj_type, - static_cast( - slots[i]) - }; - } - } - }); - ecs.system("UpdatePhysics2a") + .each([&](flecs::entity e, const EngineData &eng, + const BoatBase &boat) { createBoatSlots(e); }); +#if 1 + ecs.system( + "UpdateSlotData") .kind(flecs::OnUpdate) .with() - .each([](flecs::entity e, const EngineData &eng, - const CharacterBase &ch, ParentSlot &slot, - ParentSlotData &psdata) { + .without() + .each([&](flecs::entity e, const EngineData &eng, + const CharacterBase &ch, ParentSlot &slot) { if (slot.slot_name == "") { - e.remove(); - e.remove(); + slot.removeSlot(e); + return; } - if (slot.parent_e.has()) { - const ObjectSlots &slots = - slot.parent_e.get(); - if (slots.slots.find(slot.slot_name) == - slots.slots.end()) { - // invalid setting - e.remove(); + 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(); e.modified(); - std::cout << "base: " << slot_base->getName(); } }); +#endif +#if 0 ecs.system( - "UpdatePhysics2") + "UpdateSlotCharacterTransforms") .kind(flecs::OnUpdate) .with() .without() .with() - .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()) + if (!slot.parentIsValid()) return; OgreAssert(slot.parent_e.has(), "parent has no slots"); OgreAssert(e.has(), "not a character"); - if (slot.parent_e.has()) { - const ObjectSlots &slots = - slot.parent_e.get(); - if (slot.slot_name == "") - return; - if (slots.slots.find(slot.slot_name) == - slots.slots.end()) { - // invalid setting - e.remove(); + if (slot.parentIsValid()) { + if (!slot.check()) { + slot.removeSlot(e); OgreAssert(false, "bad slot"); return; } - ParentSlotData &psdata = - e.ensure(); - 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(); - e.modified(); + slot.createSlot(e); + slot.createSlotData(e); } }); +#endif +} +void SlotsModule::createBoatSlots(flecs::entity e) +{ + const EngineData &eng = e.world().get(); + const BoatBase &boat = e.get(); + int i; + std::vector slots = boat.mNode->getChildren(); + for (i = 0; i < slots.size(); i++) { + Ogre::Any any = static_cast(slots[i]) + ->getUserObjectBindings() + .getUserAny("type"); + if (!any.has_value()) + continue; + Ogre::String obj_type = Ogre::any_cast(any); + std::cout << "child type: " << obj_type << std::endl; + } + if (slots.size() > 0) { + ObjectSlots &vs = e.ensure(); + for (i = 0; i < slots.size(); i++) { + Ogre::Any any = static_cast(slots[i]) + ->getUserObjectBindings() + .getUserAny("type"); + if (!any.has_value()) + continue; + Ogre::String obj_type = + Ogre::any_cast(any); + any = static_cast(slots[i]) + ->getUserObjectBindings() + .getUserAny("name"); + if (!any.has_value()) + continue; + Ogre::String obj_name = + Ogre::any_cast(any); + vs.slots[obj_name] = { obj_type, + static_cast( + slots[i]) }; + } + } +} +void ParentSlot::createSlot(flecs::entity e) +{ + if (e.has()) { + createCharacterSlot(e); + } +} +void ParentSlot::createCharacterSlot(flecs::entity e) +{ +} +void ParentSlot::removeSlot(flecs::entity e) +{ + if (e.has()) + e.remove(); + if (e.has()) + e.remove(); +} +bool ParentSlot::check() const +{ + if (!parent_e.has()) + return false; + const ObjectSlots &slots = parent_e.get(); + if (!slots.exists(slot_name)) + return false; + return true; +} +bool ParentSlot::parentIsValid() +{ + if (!parent_e.has()) + return false; + return true; +} +Ogre::SceneNode *ParentSlot::getSlotBase() const +{ + if (!check()) + return nullptr; + const ObjectSlots &slots = parent_e.get(); + 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(); + ParentSlotData &psdata = e.ensure(); + 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(); + e.modified(); +} +bool ObjectSlots::exists(const Ogre::String &name) const +{ + return slots.find(name) != slots.end(); } } diff --git a/src/gamedata/SlotsModule.h b/src/gamedata/SlotsModule.h index 39d61de..b86f572 100644 --- a/src/gamedata/SlotsModule.h +++ b/src/gamedata/SlotsModule.h @@ -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 > slots; + bool exists(const Ogre::String &name) const; }; struct SlotsModule { SlotsModule(flecs::world &ecs); + void createBoatSlots(flecs::entity e); }; } #endif \ No newline at end of file diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index f72e7f6..7d2235c 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -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 &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::msSingleton = 0; \ No newline at end of file +JoltPhysicsWrapper *Ogre::Singleton::msSingleton = 0; diff --git a/src/physics/physics.h b/src/physics/physics.h index dda5b12..8e9996b 100644 --- a/src/physics/physics.h +++ b/src/physics/physics.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -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 reports; + std::function dispatch; + std::map > + 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 + dispatcher) + { + dispatch = dispatcher; + } + void addListener( + const JPH::BodyID &id, + const std::function listener) + { + listeners[id] = listener; + } + void removeListener(const JPH::BodyID &id) + { + listeners.erase(id); + } + void update(); +}; } class JoltPhysicsWrapper : public Ogre::Singleton { 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 + dispatcher); + void addContactListener( + const JPH::BodyID &id, + const std::function + listener); + void removeContactListener(const JPH::BodyID &id); }; -#endif \ No newline at end of file +#endif diff --git a/src/sceneloader/loader.cpp b/src/sceneloader/loader.cpp index ff9f45b..79aea0c 100644 --- a/src/sceneloader/loader.cpp +++ b/src/sceneloader/loader.cpp @@ -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(id); + base_e.set({mass}); } else if (collisionBodyType == "ghost") { /* TODO: later */ }