Support proper actuator animation

This commit is contained in:
2025-09-27 01:23:16 +03:00
parent 7e06da700a
commit 25280a9cbe
16 changed files with 528 additions and 103 deletions

BIN
assets/blender/edited-normal-female.blend (Stored with Git LFS)

Binary file not shown.

BIN
assets/blender/edited-normal-male.blend (Stored with Git LFS)

Binary file not shown.

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

Binary file not shown.

View File

@@ -132,7 +132,7 @@ function Quest(name, book)
this.story:begin()
this:_narration()
end,
event = function(this, event)
event = function(this, event, event_data)
if not this.active then
return
end
@@ -250,11 +250,14 @@ function StartGameQuest()
end
quests = {}
-- ecs_set_debug_drawing(true)
setup_handler(function(event, entity)
setup_handler(function(event, trigger_entity, what_entity)
print(event)
for k, v in pairs(quests) do
if v.active then
v:event(event)
local event_data = {}
event_data.trigger_entity = trigger_entity
event_data.object_entity = what_entity
v:event(event, event_data)
end
end
if event == "startup" then
@@ -263,7 +266,6 @@ setup_handler(function(event, entity)
print("narration progress!")
elseif event == "narration_answered" then
local answer = narration_get_answer()
-- story:choose(answer)
print("answered:", answer)
elseif event == "new_game" then
ecs_character_params_set("player", "gravity", true)
@@ -274,5 +276,19 @@ setup_handler(function(event, entity)
print(k, v.active)
end
quest:activate()
elseif event == "actuator_enter" then
ecs_character_physics_control(what_entity, false)
ecs_character_set_actuator(what_entity, "swimming-hold-edge")
ecs_trigger_set_position(trigger_entity, what_entity)
local ent = ecs_get_entity(what_entity)
if (ent.is_character()) then
print("character")
end
if (ent.is_player()) then
print("player")
end
-- crash()
elseif event == "actuator_exit" then
crash()
end
end)

View File

@@ -15,12 +15,12 @@ BoatModule::BoatModule(flecs::world &ecs)
ecs.module<BoatModule>();
ecs.component<BoatBase>();
ecs.component<BoatBody>();
ecs.system<const EngineData, BoatType>("CreateBoat")
ecs.system<const EngineData, BoatType, Body2Entity>("CreateBoat")
.kind(flecs::OnUpdate)
.without<BoatBase>()
.without<BoatBody>()
.each([](flecs::entity e, const EngineData &eng,
BoatType &type) {
.each([](flecs::entity e, const EngineData &eng, BoatType &type,
Body2Entity &b2e) {
BoatBase &boat = e.ensure<BoatBase>();
if (type.resourceName.find(".glb") !=
std::string::npos) {
@@ -40,6 +40,7 @@ BoatModule::BoatModule(flecs::world &ecs)
0, boat.mEnt,
Ogre::Bullet::CT_TRIMESH,
nullptr, 2, 0x7fffffff);
b2e.entities[body.body] = e;
} else if (type.resourceName.find(".scene") !=
std::string::npos) {
boat.mNode =
@@ -90,13 +91,7 @@ BoatModule::BoatModule(flecs::world &ecs)
0, boat.mEnt,
Ogre::Bullet::CT_TRIMESH,
nullptr, 2, 0x7fffffff);
#if 0
boat.mEnt = eng.mScnMgr->getEntity("boat");
boat.mNode = boat.mEnt->get
/* no need to attach anything */
BoatBody &body =
e.ensure<BoatBody>();
#endif
b2e.entities[body.body] = e;
std::vector<Ogre::Node *> slots =
boat.mNode->getChildren();
for (i = 0; i < slots.size(); i++) {
@@ -114,8 +109,8 @@ BoatModule::BoatModule(flecs::world &ecs)
<< std::endl;
}
if (slots.size() > 0) {
VehicleSlots &vs =
e.ensure<VehicleSlots>();
ObjectSlots &vs =
e.ensure<ObjectSlots>();
for (i = 0; i < slots.size(); i++) {
Ogre::Any any =
static_cast<Ogre::SceneNode
@@ -142,7 +137,7 @@ BoatModule::BoatModule(flecs::world &ecs)
Ogre::any_cast<
Ogre::String>(
any);
vs.seats[obj_name] = {
vs.slots[obj_name] = {
obj_type,
static_cast<Ogre::SceneNode
*>(

View File

@@ -16,10 +16,12 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
int i, j;
ch.mSkeleton->setBlendMode(
Ogre::ANIMBLEND_CUMULATIVE);
Ogre::String animNames[] = { "idle", "walking",
"running",
"treading_water",
"swimming" };
Ogre::String animNames[] = {
"idle", "walking",
"running", "treading_water",
"swimming", "hanging-idle",
"hanging-climb", "swimming-hold-edge"
};
int state_count = sizeof(animNames) /
sizeof(animNames[0]);
anim.mAnimationSystem =
@@ -68,6 +70,19 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
->end()
->end()
->end()
->state("actuator")
->state_machine(ANIM_FADE_SPEED, "actuator-state")
->state("hanging-idle")
->animation("hanging-idle")
->end()
->state("swimming-hold-edge")
->animation("swimming-hold-edge")
->end()
->state("hanging-climb")
->animation("hanging-climb")
->end()
->end()
->end()
->end();
/* clang-format on */
@@ -107,10 +122,13 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
Ogre::Vector3 boneMotion = ch.mBoneMotion;
v.velocity = rot * boneMotion / eng.delta;
if (eng.startupDelay <= 0.0f)
v.velocity += v.gvelocity;
v.velocity.y = Ogre::Math::Clamp(v.velocity.y, -10.5f,
1000000.0f);
if (!e.has<CharacterDisablePhysics>() &&
!e.has<CharacterInActuator>()) {
if (eng.startupDelay <= 0.0f)
v.velocity += v.gvelocity;
v.velocity.y = Ogre::Math::Clamp(
v.velocity.y, -10.5f, 1000000.0f);
}
});
ecs.system<const EngineData, const AnimationControl,
const CharacterBase, CharacterVelocity>("HandleSwimming")
@@ -119,6 +137,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
.with<WaterReady>()
.with<InWater>()
.with<CharacterBuoyancy>()
.without<CharacterDisablePhysics>()
.without<CharacterInActuator>()
.each([this](flecs::entity e, const EngineData &eng,
const AnimationControl &anim,
const CharacterBase &ch, CharacterVelocity &gr) {
@@ -204,11 +224,51 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
next_state = "idle";
state_machine->setAnimation(next_state);
});
ecs.system<const CharacterBase, const CharacterInActuator,
AnimationControl>("HandlePlayerAnimationsActuator")
.kind(flecs::OnUpdate)
.with<Character>()
.each([](flecs::entity e, const CharacterBase &ch,
const CharacterInActuator &inact,
AnimationControl &anim) {
if (!anim.configured)
return;
AnimationNodeStateMachine *main_sm =
anim.mAnimationSystem
->get<AnimationNodeStateMachine>(
"main");
AnimationNodeStateMachine *actuator_sm =
anim.mAnimationSystem
->get<AnimationNodeStateMachine>(
"actuator-state");
Ogre::String current_state = main_sm->getCurrentState();
if (current_state != "actuator")
main_sm->setAnimation("actuator");
actuator_sm->setAnimation(inact.animationState);
});
ecs.system<const CharacterBase, AnimationControl>(
"HandlePlayerAnimationsNoActuator")
.kind(flecs::OnUpdate)
.with<Character>()
.without<CharacterInActuator>()
.each([](flecs::entity e, const CharacterBase &ch,
AnimationControl &anim) {
if (!anim.configured)
return;
AnimationNodeStateMachine *main_sm =
anim.mAnimationSystem
->get<AnimationNodeStateMachine>(
"main");
Ogre::String current_state = main_sm->getCurrentState();
if (current_state != "locomotion")
main_sm->setAnimation("locomotion");
});
ecs.system<const Input, const CharacterBase, AnimationControl>(
"HandlePlayerAnimations")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.without<CharacterInActuator>()
.each([](flecs::entity e, const Input &input,
const CharacterBase &ch, AnimationControl &anim) {
if (!anim.configured)

View File

@@ -2,8 +2,64 @@
#define CHARACTER_ANIMATION_MODULE_H_
#include <Ogre.h>
#include <flecs.h>
#include "GameData.h"
#include "LuaData.h"
namespace ECS
{
struct AnimationTrigger;
struct AnimationTriggerSubscriber {
virtual void operator()(const AnimationTrigger *trigger) = 0;
};
struct AnimationTrigger {
Ogre::String name;
float time;
float weight;
std::vector<AnimationTriggerSubscriber *> subscriber_list;
float getTriggerTime() const
{
return time;
}
float getMinWeight() const
{
return weight;
}
const Ogre::String &getName() const
{
return name;
}
void notify(float weight)
{
int i;
if (weight < this->weight)
return;
for (i = 0; i < subscriber_list.size(); i++)
(*subscriber_list[i])(this);
}
void addSubscriber(AnimationTriggerSubscriber *sub)
{
if (std::find(subscriber_list.begin(), subscriber_list.end(),
sub) != subscriber_list.end())
return;
subscriber_list.push_back(sub);
}
void removeSubscriber(AnimationTriggerSubscriber *sub)
{
auto it = std::find(subscriber_list.begin(),
subscriber_list.end(), sub);
if (it != subscriber_list.end())
subscriber_list.erase(it);
}
void clearSubscribers()
{
subscriber_list.clear();
}
AnimationTrigger(const Ogre::String name, float time, float weight)
: name(name)
, time(time)
, weight(weight)
{
}
};
struct Animation {
Ogre::AnimationState *mAnimationState;
Ogre::Animation *mSkelAnimation;
@@ -11,6 +67,7 @@ struct Animation {
Ogre::NodeAnimationTrack *mRootTrack;
float m_weight;
float m_accWeight;
std::multimap<float, AnimationTrigger *> trigger_list;
Animation(Ogre::AnimationState *animState,
Ogre::Animation *skelAnimation)
: mAnimationState(animState)
@@ -30,19 +87,25 @@ struct Animation {
// mRootTracks[i]->removeAllKeyFrames();
}
}
#if 0
OgreAssert(mHipsTrack, "no hips track");
OgreAssert(mRootTrack, "no Root track");
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) {
Ogre::Vector3 trans =
mRootTrack->getNodeKeyFrame(j)->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTrack->getNodeKeyFrame(j)->setTranslate(delta);
motion = trans;
#endif
if (mRootTrack) {
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) {
Ogre::Vector3 trans =
mRootTrack->getNodeKeyFrame(j)
->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTrack->getNodeKeyFrame(j)->setTranslate(
delta);
motion = trans;
}
}
}
Ogre::String getName()
@@ -78,7 +141,9 @@ struct Animation {
}
void addTime(float time)
{
preUpdateTriggers();
mAnimationState->addTime(time);
postUpdateTriggers(time);
}
void reset()
{
@@ -96,6 +161,67 @@ struct Animation {
{
return m_accWeight;
}
void addTrigger(AnimationTrigger *trigger)
{
trigger_list.insert(std::pair<float, AnimationTrigger *>(
trigger->getTriggerTime(), trigger));
}
void clearTriggers()
{
auto it = trigger_list.begin();
while (it != trigger_list.end()) {
delete it->second;
it++;
}
trigger_list.clear();
}
float mpreUpdateTime;
void preUpdateTriggers()
{
mpreUpdateTime = mAnimationState->getTimePosition() /
mAnimationState->getLength();
}
void postUpdateTriggers(float delta)
{
float postUpdateTime = mAnimationState->getTimePosition() /
mAnimationState->getLength();
bool positive = delta >= 0.0f;
if (positive)
updateTriggers(mpreUpdateTime, postUpdateTime);
else
updateTriggers(postUpdateTime, mpreUpdateTime);
}
void updateTriggers(float currentTime, float nextTime)
{
int i;
float weight = getWeight();
if (currentTime <= nextTime) {
auto it = trigger_list.lower_bound(currentTime);
while (it != trigger_list.end()) {
if (nextTime <=
it->second->getTriggerTime()) // in future, sorrted by time
return;
it->second->notify(weight);
}
} else {
updateTriggers(currentTime, 1);
updateTriggers(0, nextTime);
}
}
float getLength() const
{
if (getEnabled())
return mAnimationState->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (getEnabled())
return mAnimationState->getTimePosition();
else
return 0.0f;
}
};
struct AnimationNode {
@@ -109,6 +235,8 @@ struct AnimationNode {
virtual void addTime(float time) = 0;
virtual void setWeight(float weight) = 0;
virtual void reset() = 0;
virtual float getLength() const = 0;
virtual float getTimePosition() const = 0;
float getWeight()
{
return m_weight;
@@ -121,6 +249,13 @@ struct AnimationNode {
{
m_name = name;
}
virtual float getTime() const
{
float l = getLength();
if (l > 0.0f)
return getTimePosition() / l;
return 0.0f;
}
};
struct AnimationNodeAnimation : AnimationNode {
@@ -144,6 +279,20 @@ struct AnimationNodeAnimation : AnimationNode {
{
mAnimation->reset();
}
float getLength() const
{
if (enabled)
return mAnimation->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (enabled)
return mAnimation->getTimePosition();
else
return 0.0f;
}
};
struct AnimationNodeStateMachineState : AnimationNode {
AnimationNodeStateMachineState()
@@ -164,6 +313,14 @@ struct AnimationNodeStateMachineState : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
return children[0]->getLength();
}
float getTimePosition() const
{
return children[0]->getLength();
}
};
struct AnimationNodeSpeed : AnimationNode {
float m_speed;
@@ -187,6 +344,25 @@ struct AnimationNodeSpeed : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
if (m_speed > 0.0f || m_speed < 0.0f)
return children[0]->getLength() / m_speed;
return 0.0f;
}
float getTimePosition() const
{
if (m_speed > 0.0f || m_speed < 0.0f)
return children[0]->getTimePosition() / m_speed;
return 0.0f;
}
float getTime() const override
{
float l = children[0]->getLength();
if (l > 0.0f)
return children[0]->getTimePosition() / l;
return 0.0f;
}
};
struct AnimationNodeStateMachine : AnimationNode {
std::map<Ogre::String, AnimationNode *> stateMap;
@@ -215,8 +391,10 @@ struct AnimationNodeStateMachine : AnimationNode {
configured = true;
}
if (debug) {
std::cout<< "state machine addTime" << std::endl;
std::cout << "state machine children: " << children.size() << std::endl;
std::cout << "state machine addTime" << std::endl;
std::cout
<< "state machine children: " << children.size()
<< std::endl;
}
for (i = 0; i < children.size(); i++) {
if (debug)
@@ -230,8 +408,10 @@ struct AnimationNodeStateMachine : AnimationNode {
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
newWeight * m_weight, 0, m_weight));
if (debug) {
std::cout << "fade in: " << newWeight << std::endl;
std::cout << "m_weight: " << m_weight << std::endl;
std::cout << "fade in: " << newWeight
<< std::endl;
std::cout << "m_weight: " << m_weight
<< std::endl;
}
if (newWeight >= 1)
fade_in.erase(child);
@@ -254,7 +434,8 @@ struct AnimationNodeStateMachine : AnimationNode {
int i;
if (weight > m_weight && currentAnim)
fade_in.insert(currentAnim);
if (weight < m_weight && currentAnim && currentAnim->getWeight() > weight)
if (weight < m_weight && currentAnim &&
currentAnim->getWeight() > weight)
currentAnim->setWeight(weight);
m_weight = weight;
bool enabled = weight > 0.001f;
@@ -273,7 +454,8 @@ struct AnimationNodeStateMachine : AnimationNode {
{
int i;
if (debug)
std::cout << "children: " << children.size() << std::endl;
std::cout << "children: " << children.size()
<< std::endl;
for (i = 0; i < children.size(); i++)
addState(children[i]);
if (debug)
@@ -312,6 +494,20 @@ struct AnimationNodeStateMachine : AnimationNode {
{
return mCurrentStateName;
}
float getLength() const
{
if (currentAnim)
return currentAnim->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (currentAnim)
return currentAnim->getTimePosition();
else
return 0.0f;
}
};
#define ANIM_FADE_SPEED \
@@ -340,6 +536,14 @@ struct AnimationNodeOutput : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
return children[0]->getLength();
}
float getTimePosition() const
{
return children[0]->getTimePosition();
}
};
struct AnimationSystem : AnimationNode {
@@ -353,6 +557,7 @@ struct AnimationSystem : AnimationNode {
std::vector<Animation *> vanimation_list;
void add_animation(const Ogre::String &name, Animation *animation)
{
OgreAssert(animation, "No animation " + name);
animation_list[name] = animation;
vanimation_list.push_back(animation);
}
@@ -388,13 +593,49 @@ struct AnimationSystem : AnimationNode {
OgreAssert(parent, "bad parent");
Animation *animation =
mAnimationSystem->animation_list[animation_name];
OgreAssert(animation,
"bad animation " + animation_name);
AnimationNodeAnimation *onode =
new AnimationNodeAnimation(animation);
OgreAssert(onode, "bad animation");
OgreAssert(onode->mAnimation, "bad animation");
animation_nodes.push_back(onode);
parent->children.push_back(onode);
animationNodeList.push_back(onode);
return this;
}
AnimationSystemBuilder *trigger(flecs::entity e,
const Ogre::String &name,
float time,
const Ogre::String &event)
{
struct EventSubscriber : AnimationTriggerSubscriber {
flecs::entity ent;
Ogre::String event;
void operator()(const AnimationTrigger *trigger)
{
ECS::get_mut<LuaData>().call_handler(
event, ent, ent);
}
EventSubscriber(flecs::entity e,
const Ogre::String &event)
: ent(e)
, event(event)
{
}
};
OgreAssert(parent, "bad parent");
Animation *animation =
static_cast<AnimationNodeAnimation *>(parent)
->mAnimation;
OgreAssert(animation, "bad animation");
AnimationTrigger *trigger =
new AnimationTrigger(name, time, 0.1f);
EventSubscriber *sub = new EventSubscriber(e, event);
trigger->addSubscriber(sub);
animation->addTrigger(trigger);
return this;
}
AnimationSystemBuilder *speed(float speed,
const Ogre::String &anchor = "")
{
@@ -451,6 +692,7 @@ struct AnimationSystem : AnimationNode {
for (i = 0; i < m_builder.animationNodeList.size(); i++) {
AnimationNodeAnimation *anim =
m_builder.animationNodeList[i];
OgreAssert(anim->mAnimation, "No animation");
float weight = anim->getWeight();
anim->mAnimation->increaseAccWeight(weight);
#ifdef VDEBUG
@@ -490,6 +732,14 @@ struct AnimationSystem : AnimationNode {
{
return static_cast<T *>(m_builder.nodeMap[name]);
}
float getLength() const
{
return m_builder.animation_nodes[0]->getLength();
}
float getTimePosition() const
{
return m_builder.animation_nodes[0]->getTimePosition();
}
};
struct AnimationControl {

View File

@@ -20,6 +20,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
ecs.component<CharacterBody>();
ecs.component<CharacterDisablePhysics>();
ecs.component<CharacterUpdatePhysicsState>();
ecs.component<CharacterInActuator>();
ecs.system<EngineData, CharacterBase>("UpdateTimer")
.kind(flecs::OnUpdate)
.each([this](EngineData &eng, CharacterBase &ch) {
@@ -107,6 +108,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
.with<WaterReady>()
.with<InWater>()
.without<CharacterDisablePhysics>()
.without<CharacterUpdatePhysicsState>()
.each([this](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, CharacterVelocity &gr) {
Ogre::Vector3 gravity(0, -9.8f, 0);
@@ -162,6 +164,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.without<CharacterInActuator>()
.each([](flecs::entity e, const Input &input,
const Camera &camera, CharacterBase &ch) {
ch.mGoalDirection = Ogre::Vector3::ZERO;
@@ -225,14 +228,14 @@ CharacterModule::CharacterModule(flecs::world &ecs)
}
});
ecs.system<const EngineData, const CharacterLocation,
const CharacterConf>("SetupCharacter")
const CharacterConf, Body2Entity>("SetupCharacter")
.kind(flecs::OnUpdate)
.with<Character>()
.without<CharacterBase>()
.without<CharacterBody>()
.each([](flecs::entity e, const EngineData &eng,
const CharacterLocation &loc,
const CharacterConf &conf) {
const CharacterConf &conf, Body2Entity &b2e) {
CharacterBase &ch = e.ensure<CharacterBase>();
CharacterBody &body = e.ensure<CharacterBody>();
AnimationControl &anim = e.ensure<AnimationControl>();
@@ -256,6 +259,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
body.mGhostObject = nullptr;
body.mController = nullptr;
body.mGhostObject = new btPairCachingGhostObject();
b2e.entities[body.mGhostObject] = e;
body.mCollisionShape = new btCompoundShape(false);
body.mGhostObject->setCollisionShape(
body.mCollisionShape);
@@ -446,23 +450,23 @@ CharacterModule::CharacterModule(flecs::world &ecs)
<< "\n";
});
#endif
ecs.system<const EngineData, const CharacterBase, CharacterSlot>(
ecs.system<const EngineData, const CharacterBase, ParentSlot>(
"UpdatePhysics2")
.kind(flecs::OnUpdate)
.with<CharacterDisablePhysics>()
.each([](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, CharacterSlot &slot) {
if (slot.parent_e.has<VehicleSlots>()) {
const VehicleSlots &slots =
slot.parent_e.get<VehicleSlots>();
if (slots.seats.find(slot.slot_name) ==
slots.seats.end())
const CharacterBase &ch, ParentSlot &slot) {
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<CharacterSlot>();
e.remove<ParentSlot>();
if (slot.activated)
return;
Ogre::SceneNode *slot_base =
slots.seats.at(slot.slot_name).second;
slots.slots.at(slot.slot_name).second;
Ogre::Vector3 position =
slot_base->_getDerivedPosition();
Ogre::Quaternion orientation =

View File

@@ -11,11 +11,6 @@ struct CharacterGravity {};
struct CharacterBuoyancy {};
struct CharacterDisablePhysics {};
struct CharacterUpdatePhysicsState {};
struct CharacterSlot {
flecs::entity parent_e;
Ogre::String slot_name;
bool activated;
};
struct CharacterBase {
Ogre::String type;
float mTimer;
@@ -45,6 +40,9 @@ struct CharacterVelocity {
Ogre::Vector3 gvelocity;
Ogre::Vector3 velocity;
};
struct CharacterInActuator {
Ogre::String animationState;
};
struct CharacterModule {
CharacterModule(flecs::world &ecs);
void updateCameraGoal(Camera &camera, Ogre::Real deltaYaw,

View File

@@ -1,5 +1,6 @@
#ifndef COMPONENTS_H_
#define COMPONENTS_H_
#include <flecs.h>
#include <Ogre.h>
#include <OgreBullet.h>
namespace Ogre
@@ -76,10 +77,18 @@ struct InWater {};
struct TerrainReady {};
struct WaterReady {};
struct GroundCheckReady {};
struct VehicleSlots {
struct ParentSlot {
flecs::entity parent_e;
Ogre::String slot_name;
bool activated;
};
struct ObjectSlots {
std::unordered_map<Ogre::String,
std::pair<Ogre::String, Ogre::SceneNode *> >
seats;
slots;
};
struct Body2Entity {
std::unordered_map<btCollisionObject *, flecs::entity> entities;
};
}
#endif

View File

@@ -62,7 +62,7 @@ struct DeepPenetrationContactResultCallback : public btManifoldResult {
ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
{
ecs.module<EventTriggerModule>();
ecs.component<EventTriggerExit>();
ecs.component<EventTriggerData>();
ecs.component<TriggerBody>().on_add([](flecs::entity e,
TriggerBody &body) {
bool kinematic = false;
@@ -81,14 +81,6 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
e.get<EventTrigger>().position,
Ogre::Quaternion(0, 0, 0, 1));
}
/*
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().createManual(
"trigger", "General");
Ogre::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
body.mSceneNode->attachObject(ent);
*/
body.mBody = new btPairCachingGhostObject();
body.mBody->getWorldTransform().setOrigin(Ogre::Bullet::convert(
body.mSceneNode->_getDerivedPosition()));
@@ -102,10 +94,6 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
if (kinematic)
flags |= btCollisionObject::CF_STATIC_OBJECT;
body.mBody->setCollisionFlags(flags);
/*
ECS::get<EngineData>().mWorld->attachCollisionObject(
body.mBody, ent, 16, 0x1);
*/
ECS::get<EngineData>().mWorld->getBtWorld()->addCollisionObject(
body.mBody, 16, 0x1);
struct EntityCollisionListener {
@@ -142,12 +130,14 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
ecs.component<EventTrigger>().on_set(
[](flecs::entity e, EventTrigger &ev) {
e.add<TriggerBody>();
e.set<EventTriggerData>({});
});
ecs.system<const EngineData, const EventTrigger, TriggerBody>(
"CheckCollisions")
ecs.system<const EngineData, const EventTrigger, TriggerBody,
EventTriggerData>("CheckCollisions")
.kind(flecs::OnUpdate)
.each([](flecs::entity e, const EngineData &eng,
const EventTrigger &evt, TriggerBody &body) {
const EventTrigger &evt, TriggerBody &body,
EventTriggerData &data) {
btDispatcher *dispatch =
eng.mWorld->getBtWorld()->getDispatcher();
btHashedOverlappingPairCache *cache =
@@ -255,12 +245,33 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
.end()) {
body.contactBodies
.insert(other);
OgreAssert(
ECS::get<
Body2Entity>()
.entities
.find(const_cast<
btCollisionObject
*>(
other)) !=
ECS::get<
Body2Entity>()
.entities
.end(),
"No body to entity mapping");
ECS::get<
LuaBase>()
.mLua
->call_handler(
evt.event,
e);
evt.event +
"_enter",
e,
ECS::get<
Body2Entity>()
.entities
.at(const_cast<
btCollisionObject
*>(
other)));
}
}
}
@@ -272,18 +283,15 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
while (it != body.contactBodies.end()) {
if (currentContactBodies.find(*it) ==
currentContactBodies.end()) {
if (e.has<EventTriggerExit>()) {
const Ogre::String &exit_event =
ECS::get<
EventTriggerExit>()
.event;
ECS::get<LuaBase>()
.mLua->call_handler(
exit_event);
} else {
std::cout << "body exited"
<< std::endl;
}
ECS::get<LuaBase>().mLua->call_handler(
evt.event + "_exit", e,
ECS::get<Body2Entity>()
.entities
.at(const_cast<
btCollisionObject
*>(
*it)));
std::cout << "body exited" << std::endl;
it = body.contactBodies.erase(it);
if (it == body.contactBodies.end())
break;

View File

@@ -11,9 +11,10 @@ struct EventTrigger {
float radius;
Ogre::String event;
Ogre::SceneNode *node;
bool once;
};
struct EventTriggerExit {
Ogre::String event;
struct EventTriggerData {
std::set<flecs::entity_t> entities;
};
struct EventTriggerModule {
EventTriggerModule(flecs::world &ecs);

View File

@@ -38,6 +38,9 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
.add(flecs::Singleton);
/* lots of things depend on it */
ecs.component<TerrainReady>().add(flecs::Singleton);
ecs.component<ParentSlot>();
ecs.component<ObjectSlots>();
ecs.component<Body2Entity>().add(flecs::Singleton);
ecs.import <WaterModule>();
ecs.import <CharacterModule>();
ecs.import <TerrainModule>();
@@ -96,6 +99,7 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
nullptr,
false,
{ 0, 0, 0 } });
ecs.set<Body2Entity>({});
std::cout << "Setup GameData done\n";
/* Create player */

View File

@@ -63,7 +63,8 @@ int LuaData::call_handler(const Ogre::String &event)
lua_rawgeti(L, LUA_REGISTRYINDEX, setup_handlers[i]);
lua_pushstring(L, event.c_str());
lua_pushinteger(L, -1);
if (lua_pcall(L, 2, 0, 0)) {
lua_pushinteger(L, -1);
if (lua_pcall(L, 3, 0, 0)) {
Ogre::LogManager::getSingleton().stream()
<< lua_tostring(L, -1);
OgreAssert(false, "Lua error");
@@ -72,14 +73,16 @@ int LuaData::call_handler(const Ogre::String &event)
return 0;
}
int LuaData::call_handler(const Ogre::String &event, flecs::entity e)
int LuaData::call_handler(const Ogre::String &event, flecs::entity e,
flecs::entity o)
{
int i;
for (i = 0; i < setup_handlers.size(); i++) {
lua_rawgeti(L, LUA_REGISTRYINDEX, setup_handlers[i]);
lua_pushstring(L, event.c_str());
lua_pushinteger(L, idmap.add_entity(e));
if (lua_pcall(L, 2, 0, 0)) {
lua_pushinteger(L, idmap.add_entity(o));
if (lua_pcall(L, 3, 0, 0)) {
Ogre::LogManager::getSingleton().stream()
<< lua_tostring(L, -1);
OgreAssert(false, "Lua error");
@@ -373,6 +376,31 @@ LuaData::LuaData()
return 1;
});
lua_setglobal(L, "ecs_child_character_trigger");
lua_pushcfunction(L, [](lua_State *L) -> int {
luaL_checktype(L, 1, LUA_TNUMBER); // trigger
luaL_checktype(L, 2, LUA_TNUMBER); // object
int trigger = lua_tointeger(L, 1);
int object = lua_tointeger(L, 2);
flecs::entity trigger_e = idmap.get_entity(trigger);
flecs::entity object_e = idmap.get_entity(object);
Ogre::SceneNode *target_node = nullptr;
Ogre::Any targetAny = trigger_e.get<EventTrigger>()
.node->getUserObjectBindings()
.getUserAny("target");
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 (object_e.has<CharacterBase>()) {
object_e.get_mut<CharacterBase>()
.mBodyNode->_setDerivedPosition(position);
object_e.get_mut<CharacterBase>()
.mBodyNode->_setDerivedOrientation(orientation);
}
return 0;
});
lua_setglobal(L, "ecs_trigger_set_position");
lua_pushcfunction(L, [](lua_State *L) -> int {
OgreAssert(lua_gettop(L) == 5, "Invalid parameters");
luaL_checktype(L, 1, LUA_TSTRING); // type
@@ -444,6 +472,20 @@ LuaData::LuaData()
return 0;
});
lua_setglobal(L, "ecs_character_physics_control");
lua_pushcfunction(L, [](lua_State *L) -> int {
luaL_checktype(L, 1, LUA_TNUMBER); // object
luaL_checktype(L, 2, LUA_TSTRING); // animation
Ogre::String animation = lua_tostring(L, 2);
int object = lua_tointeger(L, 1);
flecs::entity object_e = idmap.get_entity(object);
if (animation.length())
object_e.set<CharacterInActuator>({ animation });
else
object_e.remove<CharacterInActuator>();
return 0;
});
lua_setglobal(L, "ecs_character_set_actuator");
lua_pushcfunction(L, [](lua_State *L) -> int {
OgreAssert(lua_gettop(L) == 3, "Bad parameters");
luaL_checktype(L, 1, LUA_TNUMBER); // parent
@@ -454,7 +496,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);
object_e.set<CharacterSlot>({ parent_e, slot, false });
object_e.set<ParentSlot>({ parent_e, slot, false });
return 0;
});
lua_setglobal(L, "ecs_set_slot");

View File

@@ -12,7 +12,8 @@ struct LuaData {
std::vector<int> setup_handlers;
int setup_handler();
int call_handler(const Ogre::String &event);
int call_handler(const Ogre::String &event, flecs::entity e);
int call_handler(const Ogre::String &event, flecs::entity e,
flecs::entity o);
LuaData();
virtual ~LuaData();

View File

@@ -561,6 +561,43 @@ void SceneLoader::processNode(pugi::xml_node &XMLNode, SceneNode *pParent)
r = Ogre::any_cast<float>(anyr);
e.set<ECS::EventTrigger>(
{ pNode, Ogre::Vector3(0, 0, 0), h, r, event, pNode });
Ogre::Node::ChildNodeMap children = pNode->getChildren();
if (children.size() == 1)
pNode->getUserObjectBindings().setUserAny(
"target",
static_cast<Ogre::SceneNode *>(children[0]));
else if (children.size() == 0)
pNode->getUserObjectBindings().setUserAny("target",
pNode);
else {
int i;
bool ok = false;
for (i = 0; i < children.size(); i++) {
Ogre::Any nodeName =
children[i]
->getUserObjectBindings()
.getUserAny("name");
if (nodeName.has_value()) {
Ogre::String snodeName =
Ogre::any_cast<Ogre::String>(
nodeName);
if (snodeName == "target") {
pNode->getUserObjectBindings().setUserAny(
"target",
static_cast<Ogre::SceneNode
*>(
children[i]));
ok = true;
break;
}
}
}
if (!ok)
pNode->getUserObjectBindings().setUserAny(
"target",
static_cast<Ogre::SceneNode *>(
children[0]));
}
}
}