Now root motion works much better; raft/boat climbing
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include <iostream>
|
||||
#include "Components.h"
|
||||
#include "EventTriggerModule.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "CharacterAnimationModule.h"
|
||||
namespace ECS
|
||||
@@ -17,10 +18,18 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
ch.mSkeleton->setBlendMode(
|
||||
Ogre::ANIMBLEND_CUMULATIVE);
|
||||
Ogre::String animNames[] = {
|
||||
"idle", "walking",
|
||||
"running", "treading_water",
|
||||
"swimming", "hanging-idle",
|
||||
"hanging-climb", "swimming-hold-edge"
|
||||
"idle",
|
||||
"walking",
|
||||
"running",
|
||||
"treading_water",
|
||||
"swimming",
|
||||
"hanging-idle",
|
||||
"hanging-climb",
|
||||
"swimming-hold-edge",
|
||||
"swimming-edge-climb",
|
||||
"character-talk",
|
||||
"pass-character",
|
||||
"idle-act"
|
||||
};
|
||||
int state_count = sizeof(animNames) /
|
||||
sizeof(animNames[0]);
|
||||
@@ -28,15 +37,17 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
new AnimationSystem(false);
|
||||
for (i = 0; i < state_count; i++) {
|
||||
Animation *animation = new Animation(
|
||||
ch.mSkeleton,
|
||||
ch.mBodyEnt->getAnimationState(
|
||||
animNames[i]),
|
||||
ch.mSkeleton->getAnimation(
|
||||
animNames[i])
|
||||
|
||||
);
|
||||
animNames[i]),
|
||||
e);
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
<< "animation: " << animNames[i]
|
||||
<< std::endl;
|
||||
#endif
|
||||
animation->setLoop(true);
|
||||
anim.mAnimationSystem->add_animation(
|
||||
animNames[i], animation);
|
||||
@@ -71,16 +82,34 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
->end()
|
||||
->end()
|
||||
->state("actuator")
|
||||
->state_machine(ANIM_FADE_SPEED, "actuator-state")
|
||||
->state_machine(ANIM_FADE_SPEED * 10.0f, "actuator-state")
|
||||
->state("hanging-idle")
|
||||
->animation("hanging-idle")
|
||||
->end()
|
||||
->state("swimming-hold-edge")
|
||||
->animation("swimming-hold-edge")
|
||||
->end()
|
||||
->state("swimming-edge-climb")
|
||||
->animation("swimming-edge-climb")
|
||||
->trigger(e, "end_of_climb", 0.99f, "animation:swimming-edge-climb:end")
|
||||
->end()
|
||||
->state("hanging-climb")
|
||||
->animation("hanging-climb")
|
||||
->trigger(e, "end_of_climb2", 0.99f, "animation:hanging-climb:end")
|
||||
->end()
|
||||
->state("idle")
|
||||
->animation("idle-act")
|
||||
->end()
|
||||
->state("pass-character")
|
||||
->animation("pass-character")
|
||||
->trigger(e, "pass-character", 0.99f, "animation:pass-character:end")
|
||||
->end()
|
||||
->state("character-talk")
|
||||
->animation("character-talk")
|
||||
->end()
|
||||
->transition_end("swimming-edge-climb", "idle")
|
||||
->transition_end("hanging-climb", "idle")
|
||||
->transition_end("pass-character", "idle")
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
@@ -88,32 +117,85 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>("main")
|
||||
->setAnimation("locomotion");
|
||||
->setAnimation("locomotion", true);
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state")
|
||||
->setAnimation("idle");
|
||||
->setAnimation("idle", true);
|
||||
anim.configured = true;
|
||||
}
|
||||
});
|
||||
#if 0
|
||||
ecs.system<CharacterBase>("RootMotionStart")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, CharacterBase &ch) {
|
||||
ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
});
|
||||
#endif
|
||||
ecs.system<const EngineData, CharacterBase, AnimationControl>(
|
||||
"HandleAnimations1")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, AnimationControl &anim) {
|
||||
float delta = eng.delta;
|
||||
anim.mAnimationSystem->addTime(delta);
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
bool result = anim.mAnimationSystem->addTime(delta);
|
||||
if (!ch.mRootBone)
|
||||
return;
|
||||
ch.mBoneMotion += ch.mRootBone->getPosition();
|
||||
// The value we get is interpolated value. When result is true it is new step
|
||||
#if 0
|
||||
Ogre::Vector3 offset = ch.mRootBone->getPosition();
|
||||
ch.mBoneMotion = static_cast<RootMotionListener *>(
|
||||
anim.mListener)
|
||||
->getDeltaMotion();
|
||||
ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
Ogre::Vector3 d = offset - ch.mBonePrevMotion;
|
||||
ch.mBonePrevMotion = offset;
|
||||
|
||||
std::cout << "length: " << d.length() << std::endl;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = offset;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = Ogre::Vector3::ZERO;
|
||||
std::cout << "length2: " << d.length() << std::endl;
|
||||
OgreAssert(d.length() < 0.5f, "bad offset");
|
||||
ch.mBoneMotion = d;
|
||||
#endif
|
||||
#if 0
|
||||
if (result) {
|
||||
if (d.squaredLength() > 0.0f)
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
else
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition();
|
||||
} else {
|
||||
ch.mBoneMotion = ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef VDEBUG
|
||||
#ifdef VDEBUG
|
||||
std::cout << "root motion: " << delta << ": "
|
||||
<< ch.mBoneMotion << " - "
|
||||
<< ch.mRootBone->getPosition()
|
||||
<< " result: " << result << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
#if 0
|
||||
// ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
ch.mBonePrevMotion = offset;
|
||||
#endif
|
||||
});
|
||||
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
|
||||
ecs.system<const EngineData, CharacterBase, CharacterVelocity>(
|
||||
"HandleRootMotionVelocity")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &ch, CharacterVelocity &v) {
|
||||
CharacterBase &ch, CharacterVelocity &v) {
|
||||
if (eng.delta < 0.0000001f)
|
||||
return;
|
||||
if (!ch.mBodyNode)
|
||||
@@ -121,7 +203,9 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
v.velocity = rot * boneMotion / eng.delta;
|
||||
v.velocity = Ogre::Math::lerp(
|
||||
v.velocity, rot * boneMotion / eng.delta,
|
||||
0.99f);
|
||||
if (!e.has<CharacterDisablePhysics>() &&
|
||||
!e.has<CharacterInActuator>()) {
|
||||
if (eng.startupDelay <= 0.0f)
|
||||
@@ -129,6 +213,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
v.velocity.y = Ogre::Math::Clamp(
|
||||
v.velocity.y, -10.5f, 1000000.0f);
|
||||
}
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
});
|
||||
ecs.system<const EngineData, const AnimationControl,
|
||||
const CharacterBase, CharacterVelocity>("HandleSwimming")
|
||||
@@ -182,8 +267,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
penetration = body.mController
|
||||
->isPenetrating();
|
||||
if (is_on_floor)
|
||||
v.gvelocity = Ogre::Vector3(
|
||||
0.0f, 0.0f, 0.0f);
|
||||
v.gvelocity =
|
||||
Ogre::Vector3::ZERO;
|
||||
|
||||
btTransform from(
|
||||
Ogre::Bullet::convert(
|
||||
@@ -192,14 +277,21 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode
|
||||
->getPosition()));
|
||||
ch.mBodyNode->setPosition(
|
||||
ch.mBodyNode->getPosition() +
|
||||
ch.mBodyNode->_setDerivedPosition(
|
||||
ch.mBodyNode
|
||||
->_getDerivedPosition() +
|
||||
rotMotion);
|
||||
|
||||
ch.mBoneMotion = Ogre::Vector3(0, 0, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
ecs.system<CharacterVelocity, CharacterBase>("HandleRootMotionEnd")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, CharacterVelocity &v,
|
||||
CharacterBase &ch) {
|
||||
// zero the velocity;
|
||||
// v.velocity = Ogre::Vector3::ZERO;
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
});
|
||||
|
||||
ecs.system<const Input, const CharacterBase, AnimationControl>(
|
||||
"HandleNPCAnimations")
|
||||
@@ -243,8 +335,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
"actuator-state");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "actuator")
|
||||
main_sm->setAnimation("actuator");
|
||||
actuator_sm->setAnimation(inact.animationState);
|
||||
main_sm->setAnimation("actuator", true);
|
||||
actuator_sm->setAnimation(inact.animationState, true);
|
||||
});
|
||||
ecs.system<const CharacterBase, AnimationControl>(
|
||||
"HandlePlayerAnimationsNoActuator")
|
||||
@@ -261,7 +353,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
"main");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "locomotion")
|
||||
main_sm->setAnimation("locomotion");
|
||||
main_sm->setAnimation("locomotion", true);
|
||||
});
|
||||
ecs.system<const Input, const CharacterBase, AnimationControl>(
|
||||
"HandlePlayerAnimations")
|
||||
@@ -303,7 +395,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
else if (current_state != "idle" &&
|
||||
!ch.is_submerged)
|
||||
next_state = "idle";
|
||||
state_machine->setAnimation(next_state, true);
|
||||
state_machine->setAnimation(next_state);
|
||||
} else if (start_motion) {
|
||||
if (ch.is_submerged) {
|
||||
if (input.fast)
|
||||
@@ -343,5 +435,187 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
state_machine->setAnimation(next_state);
|
||||
}
|
||||
});
|
||||
ecs.system<const Input, const CharacterBase, AnimationControl,
|
||||
CharacterInActuator>("HandlePlayerAnimations2")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.with<Player>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const CharacterBase &ch, AnimationControl &anim,
|
||||
CharacterInActuator &act) {
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
if (!controls_idle) {
|
||||
std::cout << "motion.z: "
|
||||
<< Ogre::Math::Abs(input.motion.z -
|
||||
act.prevMotion.z)
|
||||
<< std::endl;
|
||||
bool trigger_event = false;
|
||||
e.each<InTrigger>([&](flecs::entity trig) {
|
||||
if (Ogre::Math::Abs(input.motion.z -
|
||||
act.prevMotion.z) >
|
||||
0.001f) {
|
||||
if (input.motion.z < 0)
|
||||
ECS::get<LuaBase>()
|
||||
.mLua
|
||||
->call_handler(
|
||||
"actuator_forward",
|
||||
trig,
|
||||
e);
|
||||
if (input.motion.z > 0)
|
||||
ECS::get_mut<LuaBase>()
|
||||
.mLua
|
||||
->call_handler(
|
||||
"actuator_backward",
|
||||
trig,
|
||||
e);
|
||||
}
|
||||
if (input.act_pressed)
|
||||
ECS::get_mut<LuaBase>()
|
||||
.mLua->call_handler(
|
||||
"actuator_action",
|
||||
trig, e);
|
||||
// ECS::get_mut<LuaData>().call_handler(
|
||||
// "actuator_update", trig, e);
|
||||
trigger_event = true;
|
||||
});
|
||||
if (!trigger_event) {
|
||||
if (Ogre::Math::Abs(input.motion.z -
|
||||
act.prevMotion.z) >
|
||||
0.001f) {
|
||||
if (input.motion.z < 0)
|
||||
ECS::get<LuaBase>()
|
||||
.mLua
|
||||
->call_handler(
|
||||
"_in_actuator_forward",
|
||||
e, e);
|
||||
if (input.motion.z > 0)
|
||||
ECS::get_mut<LuaBase>()
|
||||
.mLua
|
||||
->call_handler(
|
||||
"_in_actuator_backward",
|
||||
e, e);
|
||||
}
|
||||
if (input.act_pressed)
|
||||
ECS::get_mut<LuaBase>()
|
||||
.mLua->call_handler(
|
||||
"_in_actuator_action",
|
||||
e, e);
|
||||
// ECS::get_mut<LuaData>().call_handler(
|
||||
// "actuator_update", trig, e);
|
||||
}
|
||||
act.prevMotion.x = input.motion.x;
|
||||
act.prevMotion.y = input.motion.y;
|
||||
act.prevMotion.z = input.motion.z;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!controls_idle) {
|
||||
if (Ogre::Math::Abs(input.motion.z - act.prevMotion.z) > 0.001f) {
|
||||
if (input.motion.z < 0)
|
||||
ECS::get_mut<LuaData>().call_handler("actuator_forward", e);
|
||||
}
|
||||
ECS::get_mut<LuaData>().call_handler("actuator_controls_update");
|
||||
}
|
||||
#endif
|
||||
act.prevMotion = input.motion;
|
||||
});
|
||||
#ifdef VDEBUG
|
||||
ecs.system<const CharacterBase>("CharacterGravityStatus")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.with<Player>()
|
||||
.each([](flecs::entity e, const CharacterBase &ch) {
|
||||
if (e.has<CharacterGravity>())
|
||||
std::cout << "gravity\n";
|
||||
else
|
||||
std::cout << "no gravity\n";
|
||||
if (e.has<InWater>())
|
||||
std::cout << "in water\n";
|
||||
else
|
||||
std::cout << "out of water\n";
|
||||
std::cout
|
||||
<< "h=" << ch.mBodyNode->_getDerivedPosition().y
|
||||
<< std::endl;
|
||||
});
|
||||
#endif
|
||||
ecs.system<const EngineData, const CharacterBase, CharacterBody>(
|
||||
"UpdateBodyCast")
|
||||
.kind(flecs::OnUpdate)
|
||||
.without<CharacterInActuator>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &ch, CharacterBody &body) {
|
||||
struct ResultCallback
|
||||
: public btCollisionWorld::RayResultCallback {
|
||||
btCollisionObject *m_me;
|
||||
btVector3 m_from, m_to, m_hitNormalWorld,
|
||||
m_hitPointWorld;
|
||||
ResultCallback(btCollisionObject *me,
|
||||
const btVector3 &from,
|
||||
const btVector3 &to)
|
||||
: m_me(me)
|
||||
, m_from(from)
|
||||
, m_to(to)
|
||||
{
|
||||
}
|
||||
btScalar addSingleResult(
|
||||
btCollisionWorld::LocalRayResult
|
||||
&rayResult,
|
||||
bool normalInWorldSpace) override
|
||||
{
|
||||
if (rayResult.m_collisionObject == m_me)
|
||||
return 1.0f;
|
||||
if (!btPairCachingGhostObject::upcast(
|
||||
rayResult.m_collisionObject))
|
||||
return 1.0f;
|
||||
if (!(rayResult.m_collisionObject
|
||||
->getCollisionFlags() &
|
||||
btCollisionObject::
|
||||
CF_CHARACTER_OBJECT))
|
||||
return 1.0f;
|
||||
m_closestHitFraction =
|
||||
rayResult.m_hitFraction;
|
||||
m_collisionObject =
|
||||
rayResult.m_collisionObject;
|
||||
if (normalInWorldSpace)
|
||||
m_hitNormalWorld =
|
||||
rayResult
|
||||
.m_hitNormalLocal;
|
||||
else
|
||||
m_hitNormalWorld =
|
||||
m_collisionObject
|
||||
->getWorldTransform()
|
||||
.getBasis() *
|
||||
rayResult
|
||||
.m_hitNormalLocal;
|
||||
m_hitPointWorld.setInterpolate3(
|
||||
m_from, m_to,
|
||||
rayResult.m_hitFraction);
|
||||
return rayResult.m_hitFraction;
|
||||
}
|
||||
};
|
||||
Ogre::Vector3 offset(0.0f, 0.5f, 0.0f);
|
||||
float dist = 0.5f;
|
||||
btVector3 a = Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition() + offset),
|
||||
b(Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition() +
|
||||
ch.mBodyNode->getOrientation() *
|
||||
Ogre::Vector3(0, 0, dist) +
|
||||
offset));
|
||||
ResultCallback result(body.mGhostObject, a, b);
|
||||
// body.mGhostObject->rayTest(a, b, result);
|
||||
eng.mWorld->getBtWorld()->rayTest(a, b, result);
|
||||
if (result.hasHit()) {
|
||||
std::cout << "Hit!!! " << result.m_hitPointWorld
|
||||
<< std::endl;
|
||||
e.set<CharacterInActuator>(
|
||||
{ "idle", { 0, 0, 0 } });
|
||||
ECS::get<LuaBase>().mLua->call_handler(
|
||||
"character_enter", e,
|
||||
ECS::get<Body2Entity>().entities.at(
|
||||
const_cast<btCollisionObject *>(
|
||||
result.m_collisionObject)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user