Support proper actuator animation
This commit is contained in:
BIN
assets/blender/edited-normal-female.blend
(Stored with Git LFS)
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)
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)
BIN
assets/blender/vehicles/raft.blend
(Stored with Git LFS)
Binary file not shown.
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*>(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user