Now root motion works much better; raft/boat climbing
This commit is contained in:
6
Game.cpp
6
Game.cpp
@@ -228,8 +228,12 @@ public:
|
||||
control |= 8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control |= 16;
|
||||
else if (key == 'e')
|
||||
control |= 32;
|
||||
else if (key == 'f')
|
||||
control |= 64;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == OgreBites::SDLK_LSHIFT)
|
||||
key == 'e' || key == OgreBites::SDLK_LSHIFT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
@@ -228,13 +228,14 @@ function StartGameQuest()
|
||||
quest.activate = function(this)
|
||||
print('activate...')
|
||||
local mc_is_free = function()
|
||||
this.boat_id = ecs_vehicle_set("raft", 0, 0, -20, 1.75)
|
||||
this.npc_id = ecs_npc_set("normal-female.glb", 0, 2, -20, 1.75)
|
||||
this.boat = true
|
||||
-- ecs_set_slot(this.boat_id, this.npc_id, "captain_seat")
|
||||
-- ecs_character_physics_control(this.npc_id, false)
|
||||
ecs_character_params_set("player", "gravity", true)
|
||||
ecs_character_params_set("player", "buoyancy", true)
|
||||
this.boat_id = ecs_vehicle_set("raft", 0, 0, -10, 1.75)
|
||||
this.npc_id = ecs_npc_set("normal-female.glb", 0, 2, -10, 1.75)
|
||||
this.boat = true
|
||||
-- ecs_set_slot(this.boat_id, this.npc_id, "captain_seat")
|
||||
-- ecs_character_physics_control(this.npc_id, false)
|
||||
local ent = ecs_get_player_entity()
|
||||
ecs_character_params_set(ent, "gravity", true)
|
||||
ecs_character_params_set(ent, "buoyancy", true)
|
||||
end
|
||||
this.story:bind('mc_is_free', mc_is_free)
|
||||
this.base.activate(this)
|
||||
@@ -248,7 +249,128 @@ function StartGameQuest()
|
||||
end
|
||||
return quest
|
||||
end
|
||||
function create_actuator()
|
||||
return {
|
||||
is_complete = false,
|
||||
complete = function(this)
|
||||
return this.is_complete
|
||||
end,
|
||||
finish = function(this)
|
||||
this.is_complete = true
|
||||
ecs_character_set_actuator(this.entity, "")
|
||||
ecs_character_physics_control(this.entity, true)
|
||||
print("COMPLETE")
|
||||
end,
|
||||
forward = function(this)
|
||||
if (this.forward_animation) then
|
||||
this:animation(this.forward_animation)
|
||||
end
|
||||
end,
|
||||
animation = function(this, animation)
|
||||
print("ANIMATION: ", animation)
|
||||
ecs_character_set_actuator(this.entity, animation)
|
||||
end,
|
||||
event = function(this, event, trigger_entity, what_entity)
|
||||
print("actuator events: ", event)
|
||||
if event == "actuator_forward" then
|
||||
this:forward()
|
||||
return true
|
||||
elseif event == "_in_actuator_forward" then
|
||||
this:forward()
|
||||
return true
|
||||
elseif event == "actuator_exit" then
|
||||
this:finish()
|
||||
return true
|
||||
end
|
||||
if this.finish_events then
|
||||
for i, p in ipairs(this.finish_events) do
|
||||
if p == event then
|
||||
this:finish()
|
||||
break
|
||||
end
|
||||
end
|
||||
if this.is_complete then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
}
|
||||
end
|
||||
quests = {}
|
||||
local actuator = nil
|
||||
function check_actuator_event(event, trigger_entity, what_entity)
|
||||
print("check_actuator_event: ", event)
|
||||
if event == "actuator_enter" then
|
||||
if not ecs_character_is_player(what_entity) then
|
||||
return
|
||||
end
|
||||
ecs_character_physics_control(what_entity, false)
|
||||
local animation = ecs_trigger_get_animation(trigger_entity)
|
||||
ecs_character_set_actuator(what_entity, animation)
|
||||
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()
|
||||
actuator = create_actuator()
|
||||
actuator.trigger = trigger_entity
|
||||
actuator.entity = what_entity
|
||||
actuator.forward = function(this)
|
||||
this:animation("swimming-edge-climb")
|
||||
local ent = ecs_get_player_entity()
|
||||
ecs_character_params_set(ent, "gravity", true)
|
||||
ecs_character_params_set(ent, "buoyancy", true)
|
||||
end
|
||||
actuator.base_event = actuator.event
|
||||
actuator.finish_events = {"animation:swimming-edge-climb:end"}
|
||||
actuator.event = function(this, event, te, we)
|
||||
print("actuator events 1: ", event)
|
||||
if this.base_event(this, event, te, we) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
elseif event == "character_enter" then
|
||||
if not ecs_character_is_player(trigger_entity) then
|
||||
return
|
||||
end
|
||||
actuator = create_actuator()
|
||||
actuator.trigger = trigger_entity
|
||||
actuator.entity = trigger_entity
|
||||
actuator.other_entity = what_entity
|
||||
actuator.forward_animation = "pass-character"
|
||||
actuator.finish_events = {"animation:pass-character:end"}
|
||||
actuator.base_event = actuator.event
|
||||
actuator.event = function(this, event, te, we)
|
||||
print("actuator events 2: ", event)
|
||||
if event == "actuator_exit" then
|
||||
this:animation("idle")
|
||||
return true
|
||||
end
|
||||
if this.base_event(this, event, te, we) then
|
||||
return true
|
||||
end
|
||||
if event == "character_enter" then
|
||||
-- why?
|
||||
-- ecs_character_set_actuator(this.entity, "idle")
|
||||
-- ecs_character_set_actuator(this.entity, "idle")
|
||||
return true
|
||||
elseif event == "actuator_enter" then
|
||||
-- why?
|
||||
-- ecs_character_set_actuator(this.entity, "idle")
|
||||
-- ecs_character_set_actuator(this.entity, "idle")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
actuator:animation("idle")
|
||||
end
|
||||
end
|
||||
-- ecs_set_debug_drawing(true)
|
||||
setup_handler(function(event, trigger_entity, what_entity)
|
||||
print(event)
|
||||
@@ -268,27 +390,27 @@ setup_handler(function(event, trigger_entity, what_entity)
|
||||
local answer = narration_get_answer()
|
||||
print("answered:", answer)
|
||||
elseif event == "new_game" then
|
||||
ecs_character_params_set("player", "gravity", true)
|
||||
ecs_character_params_set("player", "buoyancy", false)
|
||||
local ent = ecs_get_player_entity()
|
||||
ecs_character_params_set(ent, "gravity", true)
|
||||
ecs_character_params_set(ent, "buoyancy", false)
|
||||
local quest = StartGameQuest()
|
||||
quests[quest.name] = quest
|
||||
for k, v in pairs(quests) do
|
||||
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")
|
||||
else
|
||||
if not actuator then
|
||||
check_actuator_event(event, trigger_entity, what_entity)
|
||||
else
|
||||
if not actuator:event(event, trigger_entity, what_entity) then
|
||||
crash()
|
||||
end
|
||||
if actuator:complete() then
|
||||
print("ACTUATOR COMPLETE")
|
||||
print("EXIT ACTUATOR")
|
||||
actuator = nil
|
||||
end
|
||||
end
|
||||
if (ent.is_player()) then
|
||||
print("player")
|
||||
end
|
||||
-- crash()
|
||||
elseif event == "actuator_exit" then
|
||||
crash()
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -89,7 +89,7 @@ BoatModule::BoatModule(flecs::world &ecs)
|
||||
ECS::get<EngineData>()
|
||||
.mWorld->addRigidBody(
|
||||
0, boat.mEnt,
|
||||
Ogre::Bullet::CT_TRIMESH,
|
||||
Ogre::Bullet::CT_BOX,
|
||||
nullptr, 2, 0x7fffffff);
|
||||
b2e.entities[body.body] = e;
|
||||
std::vector<Ogre::Node *> slots =
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,74 @@
|
||||
#include <Ogre.h>
|
||||
#include <flecs.h>
|
||||
#include "GameData.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "LuaData.h"
|
||||
namespace ECS
|
||||
{
|
||||
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
|
||||
Ogre::Vector3 prevTranslation;
|
||||
mutable Ogre::Vector3 deltaMotion;
|
||||
flecs::entity e;
|
||||
|
||||
public:
|
||||
RootMotionListener(flecs::entity e)
|
||||
: Ogre::NodeAnimationTrack::Listener()
|
||||
, e(e)
|
||||
, prevTranslation(Ogre::Vector3::ZERO)
|
||||
, deltaMotion(Ogre::Vector3::ZERO)
|
||||
{
|
||||
}
|
||||
bool getInterpolatedKeyFrame(const Ogre::AnimationTrack *t,
|
||||
const Ogre::TimeIndex &timeIndex,
|
||||
Ogre::KeyFrame *kf) override
|
||||
{
|
||||
Ogre::TransformKeyFrame *vkf =
|
||||
static_cast<Ogre::TransformKeyFrame *>(kf);
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
Ogre::TransformKeyFrame *k1, *k2;
|
||||
unsigned short firstKeyIndex;
|
||||
float tm = t->getKeyFramesAtTime(timeIndex, &kf1, &kf2,
|
||||
&firstKeyIndex);
|
||||
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation();
|
||||
translation = k1->getTranslate();
|
||||
deltaMotion = translation;
|
||||
|
||||
// vkf->setRotation(k1->getRotation());
|
||||
// vkf->setTranslate(k1->getTranslate());
|
||||
// vkf->setScale(k1->getScale());
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation(), k2->getRotation(), true);
|
||||
translation =
|
||||
k1->getTranslate() +
|
||||
(k2->getTranslate() - k1->getTranslate()) * tm;
|
||||
deltaMotion = translation - prevTranslation;
|
||||
if (deltaMotion.squaredLength() >
|
||||
translation.squaredLength())
|
||||
deltaMotion = translation;
|
||||
}
|
||||
#if 0
|
||||
std::cout << "time: " << tm
|
||||
<< " Position: " << deltaMotion;
|
||||
std::cout << " Quaternion: " << rotation;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
vkf->setTranslate(deltaMotion);
|
||||
// vkf->setTranslate(translation);
|
||||
vkf->setRotation(rotation);
|
||||
vkf->setScale(Ogre::Vector3(1, 1, 1));
|
||||
prevTranslation = translation;
|
||||
e.get_mut<CharacterBase>().mBoneMotion = deltaMotion;
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
|
||||
e.modified<CharacterBase>();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct AnimationTrigger;
|
||||
struct AnimationTriggerSubscriber {
|
||||
virtual void operator()(const AnimationTrigger *trigger) = 0;
|
||||
@@ -65,17 +130,20 @@ struct Animation {
|
||||
Ogre::Animation *mSkelAnimation;
|
||||
Ogre::NodeAnimationTrack *mHipsTrack;
|
||||
Ogre::NodeAnimationTrack *mRootTrack;
|
||||
RootMotionListener *mListener;
|
||||
float m_weight;
|
||||
float m_accWeight;
|
||||
std::multimap<float, AnimationTrigger *> trigger_list;
|
||||
Animation(Ogre::AnimationState *animState,
|
||||
Ogre::Animation *skelAnimation)
|
||||
Animation(Ogre::Skeleton *skeleton, Ogre::AnimationState *animState,
|
||||
Ogre::Animation *skelAnimation, flecs::entity e)
|
||||
: mAnimationState(animState)
|
||||
, mSkelAnimation(skelAnimation)
|
||||
, mListener(OGRE_NEW RootMotionListener(e))
|
||||
, m_weight(0)
|
||||
, m_accWeight(0)
|
||||
{
|
||||
int j;
|
||||
mRootTrack = nullptr;
|
||||
mHipsTrack = nullptr;
|
||||
for (const auto &it : mSkelAnimation->_getNodeTrackList()) {
|
||||
Ogre::NodeAnimationTrack *track = it.second;
|
||||
Ogre::String trackName =
|
||||
@@ -87,10 +155,21 @@ struct Animation {
|
||||
// mRootTracks[i]->removeAllKeyFrames();
|
||||
}
|
||||
}
|
||||
if (!mRootTrack) {
|
||||
Ogre::Bone *bone = skeleton->getBone("Root");
|
||||
mRootTrack = mSkelAnimation->createNodeTrack(
|
||||
bone->getHandle(), bone);
|
||||
Ogre::TransformKeyFrame *kf =
|
||||
mRootTrack->createNodeKeyFrame(0.0f);
|
||||
kf->setTranslate(Ogre::Vector3::ZERO);
|
||||
kf->setRotation(Ogre::Quaternion::IDENTITY);
|
||||
}
|
||||
mRootTrack->setListener(mListener);
|
||||
#if 0
|
||||
OgreAssert(mHipsTrack, "no hips track");
|
||||
OgreAssert(mRootTrack, "no Root track");
|
||||
#endif
|
||||
#if 0
|
||||
if (mRootTrack) {
|
||||
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
|
||||
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
|
||||
@@ -107,6 +186,55 @@ struct Animation {
|
||||
motion = trans;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if (!mMetaRootTrack) {
|
||||
Ogre::Bone *bone = nullptr;
|
||||
OgreAssert(skeleton->hasBone("MetaRoot"),
|
||||
"no bone MetaRoot");
|
||||
if (skeleton->hasBone("MetaRoot"))
|
||||
bone = skeleton->getBone("MetaRoot");
|
||||
#if 0
|
||||
else
|
||||
bone = skeleton->createBone("MetaRoot");
|
||||
#endif
|
||||
bone->setPosition(Ogre::Vector3::ZERO);
|
||||
bone->setOrientation(Ogre::Quaternion::IDENTITY);
|
||||
std::vector<
|
||||
std::pair<float, std::pair<Ogre::Vector3,
|
||||
Ogre::Quaternion> > >
|
||||
keyframes;
|
||||
for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) {
|
||||
Ogre::TransformKeyFrame *kf =
|
||||
mRootTrack->getNodeKeyFrame(j);
|
||||
const Ogre::Vector3 &pt = kf->getTranslate();
|
||||
const Ogre::Quaternion &rt = kf->getRotation();
|
||||
float tp = kf->getTime();
|
||||
keyframes.push_back({ tp, { pt, rt } });
|
||||
#if 0
|
||||
new_kf->setTranslate(pt);
|
||||
new_kf->setTranslate(kf->getTranslate());
|
||||
new_kf->setRotation(kf->getRotation());
|
||||
#endif
|
||||
kf->setTranslate(Ogre::Vector3::ZERO);
|
||||
kf->setRotation(Ogre::Quaternion::IDENTITY);
|
||||
}
|
||||
mMetaRootTrack = mSkelAnimation->createNodeTrack(
|
||||
bone->getHandle());
|
||||
OgreAssert(mMetaRootTrack,
|
||||
"failed to create node track");
|
||||
for (j = 0; j < keyframes.size(); j++) {
|
||||
Ogre::TransformKeyFrame *new_kf =
|
||||
mMetaRootTrack->createNodeKeyFrame(
|
||||
keyframes[j].first);
|
||||
new_kf->setTranslate(keyframes[j].second.first);
|
||||
new_kf->setRotation(keyframes[j].second.second);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
mRootTrack = track;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
Ogre::String getName()
|
||||
{
|
||||
@@ -139,11 +267,22 @@ struct Animation {
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
preUpdateTriggers();
|
||||
bool result = mAnimationState->getEnabled();
|
||||
if (!result)
|
||||
return result;
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(
|
||||
mAnimationState->getTimePosition());
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
unsigned short prev_index, next_index;
|
||||
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &prev_index);
|
||||
unsigned int previous_frame = index.getKeyIndex();
|
||||
mAnimationState->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
index = mSkelAnimation->_getTimeIndex(
|
||||
mAnimationState->getTimePosition());
|
||||
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &next_index);
|
||||
return prev_index != next_index;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
@@ -161,55 +300,9 @@ 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
|
||||
{
|
||||
return mAnimationState->getLength();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getLength();
|
||||
else
|
||||
@@ -217,6 +310,7 @@ struct Animation {
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimationState->getTimePosition();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getTimePosition();
|
||||
else
|
||||
@@ -228,11 +322,12 @@ struct AnimationNode {
|
||||
std::vector<AnimationNode *> children;
|
||||
float m_weight;
|
||||
Ogre::String m_name;
|
||||
std::multimap<float, AnimationTrigger *> trigger_list;
|
||||
AnimationNode()
|
||||
: m_weight(0)
|
||||
{
|
||||
}
|
||||
virtual void addTime(float time) = 0;
|
||||
virtual bool addTime(float time) = 0;
|
||||
virtual void setWeight(float weight) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual float getLength() const = 0;
|
||||
@@ -256,6 +351,52 @@ struct AnimationNode {
|
||||
return getTimePosition() / l;
|
||||
return 0.0f;
|
||||
}
|
||||
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 = getTime();
|
||||
}
|
||||
void postUpdateTriggers(float delta)
|
||||
{
|
||||
float postUpdateTime = getTime();
|
||||
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);
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
updateTriggers(currentTime, 1);
|
||||
updateTriggers(0, nextTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AnimationNodeAnimation : AnimationNode {
|
||||
@@ -266,9 +407,13 @@ struct AnimationNodeAnimation : AnimationNode {
|
||||
, mAnimation(animation)
|
||||
{
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
mAnimation->addTime(time);
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = mAnimation->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
@@ -281,6 +426,7 @@ struct AnimationNodeAnimation : AnimationNode {
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return mAnimation->getLength();
|
||||
if (enabled)
|
||||
return mAnimation->getLength();
|
||||
else
|
||||
@@ -288,6 +434,7 @@ struct AnimationNodeAnimation : AnimationNode {
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimation->getTimePosition();
|
||||
if (enabled)
|
||||
return mAnimation->getTimePosition();
|
||||
else
|
||||
@@ -299,9 +446,13 @@ struct AnimationNodeStateMachineState : AnimationNode {
|
||||
: AnimationNode()
|
||||
{
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
children[0]->addTime(time);
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
@@ -319,7 +470,7 @@ struct AnimationNodeStateMachineState : AnimationNode {
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return children[0]->getLength();
|
||||
return children[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
struct AnimationNodeSpeed : AnimationNode {
|
||||
@@ -331,9 +482,13 @@ struct AnimationNodeSpeed : AnimationNode {
|
||||
, enabled(false)
|
||||
{
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
children[0]->addTime(time * m_speed);
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
@@ -383,36 +538,43 @@ struct AnimationNodeStateMachine : AnimationNode {
|
||||
{
|
||||
m_weight = 1.0f;
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
int i;
|
||||
preUpdateTriggers();
|
||||
if (!configured) {
|
||||
configure();
|
||||
configured = true;
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "state machine addTime" << std::endl;
|
||||
std::cout
|
||||
<< "state machine children: " << children.size()
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < children.size(); i++) {
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
std::cout << "child weight: " << i << " "
|
||||
<< children[i]->getWeight()
|
||||
<< std::endl;
|
||||
#endif
|
||||
AnimationNode *child = children[i];
|
||||
if (fade_in.find(child) != fade_in.end()) {
|
||||
Ogre::Real newWeight =
|
||||
child->getWeight() + time * fade_speed;
|
||||
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
|
||||
newWeight * m_weight, 0, m_weight));
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "fade in: " << newWeight
|
||||
<< std::endl;
|
||||
std::cout << "m_weight: " << m_weight
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
if (newWeight >= 1)
|
||||
fade_in.erase(child);
|
||||
}
|
||||
@@ -426,8 +588,11 @@ struct AnimationNodeStateMachine : AnimationNode {
|
||||
}
|
||||
}
|
||||
OgreAssert(currentAnim, "bad current anim");
|
||||
bool ret = false;
|
||||
if (currentAnim)
|
||||
currentAnim->addTime(time);
|
||||
ret = currentAnim->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
@@ -522,9 +687,13 @@ struct AnimationNodeOutput : AnimationNode {
|
||||
, m_speed(1.0f)
|
||||
{
|
||||
}
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
children[0]->addTime(time * m_speed);
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
@@ -614,8 +783,9 @@ struct AnimationSystem : AnimationNode {
|
||||
Ogre::String event;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
ECS::get_mut<LuaData>().call_handler(
|
||||
event, ent, ent);
|
||||
ECS::get_mut<LuaBase>()
|
||||
.mLua->call_handler(event, ent,
|
||||
ent);
|
||||
}
|
||||
EventSubscriber(flecs::entity e,
|
||||
const Ogre::String &event)
|
||||
@@ -625,15 +795,57 @@ struct AnimationSystem : AnimationNode {
|
||||
}
|
||||
};
|
||||
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);
|
||||
parent->addTrigger(trigger);
|
||||
return this;
|
||||
} // leaf too...
|
||||
AnimationSystemBuilder *
|
||||
transition_end(const Ogre::String &state_from,
|
||||
const Ogre::String &state_to)
|
||||
{
|
||||
struct EndTransitionSubscriber
|
||||
: AnimationTriggerSubscriber {
|
||||
AnimationNodeStateMachine *sm;
|
||||
Ogre::String next_state;
|
||||
bool reset;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
sm->setAnimation(next_state, reset);
|
||||
}
|
||||
EndTransitionSubscriber(
|
||||
AnimationNodeStateMachine *sm,
|
||||
const Ogre::String &next_state,
|
||||
bool reset = true)
|
||||
: sm(sm)
|
||||
, next_state(next_state)
|
||||
, reset(reset)
|
||||
{
|
||||
}
|
||||
};
|
||||
OgreAssert(parent, "no parent");
|
||||
AnimationNodeStateMachine *sm =
|
||||
static_cast<AnimationNodeStateMachine *>(
|
||||
parent);
|
||||
OgreAssert(sm, "no state machine");
|
||||
AnimationTrigger *trigger = new AnimationTrigger(
|
||||
"transition:" + state_from + "_" + state_to,
|
||||
0.99f, 0.1f);
|
||||
EndTransitionSubscriber *sub =
|
||||
new EndTransitionSubscriber(sm, state_to);
|
||||
int i;
|
||||
bool ok = false;
|
||||
for (i = 0; i < sm->children.size(); i++) {
|
||||
if (sm->children[i]->getName() == state_from) {
|
||||
trigger->addSubscriber(sub);
|
||||
sm->children[i]->addTrigger(trigger);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OgreAssert(ok, "Failed to set transition");
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *speed(float speed,
|
||||
@@ -685,10 +897,11 @@ struct AnimationSystem : AnimationNode {
|
||||
}
|
||||
};
|
||||
AnimationSystemBuilder m_builder;
|
||||
void addTime(float time)
|
||||
bool addTime(float time)
|
||||
{
|
||||
int i;
|
||||
m_builder.animation_nodes[0]->addTime(time);
|
||||
preUpdateTriggers();
|
||||
bool ret = m_builder.animation_nodes[0]->addTime(time);
|
||||
for (i = 0; i < m_builder.animationNodeList.size(); i++) {
|
||||
AnimationNodeAnimation *anim =
|
||||
m_builder.animationNodeList[i];
|
||||
@@ -706,13 +919,17 @@ struct AnimationSystem : AnimationNode {
|
||||
float weight = vanimation_list[i]->getAccWeight();
|
||||
vanimation_list[i]->setWeight(weight);
|
||||
vanimation_list[i]->resetAccWeight();
|
||||
#define VDEBUG
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
if (debug && vanimation_list[i]->getEnabled())
|
||||
std::cout << i << " animation: "
|
||||
<< vanimation_list[i]->getName()
|
||||
<< " " << weight << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
}
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
|
||||
@@ -51,6 +51,22 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
zaxis = 0.0f;
|
||||
else
|
||||
zaxis = Ogre::Math::Sign(zaxis);
|
||||
if (active & 32)
|
||||
input.act = true;
|
||||
else
|
||||
input.act = false;
|
||||
if (pressed & 32)
|
||||
input.act_pressed = true;
|
||||
else
|
||||
input.act_pressed = false;
|
||||
if (active & 64)
|
||||
input.act2 = true;
|
||||
else
|
||||
input.act2 = false;
|
||||
if (pressed & 64)
|
||||
input.act2_pressed = true;
|
||||
else
|
||||
input.act2_pressed = false;
|
||||
input.motion.z = zaxis;
|
||||
float xaxis = input.motion.x;
|
||||
xaxis *= 0.9f;
|
||||
@@ -246,11 +262,15 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ch.mBodyNode->setPosition(loc.position);
|
||||
ch.mBodyNode->attachObject(ch.mBodyEnt);
|
||||
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
|
||||
OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"),
|
||||
"No root bone");
|
||||
OgreAssert(ch.mSkeleton->hasBone("Root"),
|
||||
"No root bone");
|
||||
ch.mRootBone = ch.mSkeleton->getBone("Root");
|
||||
OgreAssert(ch.mRootBone, "No root bone");
|
||||
body.mController = nullptr;
|
||||
ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
|
||||
e.set<CharacterVelocity>(
|
||||
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
|
||||
body.checkGround = false;
|
||||
@@ -283,8 +303,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
->calculatePrincipalAxisTransform(
|
||||
masses, principal, inertia);
|
||||
}
|
||||
body.mGhostObject->setCollisionFlags(
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT /*|
|
||||
body.mGhostObject->setCollisionFlags(body.mGhostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT
|
||||
/*btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
|
||||
body.mGhostObject->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
@@ -295,6 +315,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
e.add<CharacterGravity>();
|
||||
e.add<CharacterBuoyancy>();
|
||||
anim.configured = false;
|
||||
OgreAssert(body.mGhostObject->hasContactResponse(),
|
||||
"need contact response");
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterBody>(
|
||||
"UpdateCharacterPhysics")
|
||||
@@ -434,8 +456,11 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([](flecs::entity e, const WaterBody &waterb,
|
||||
const CharacterBase &ch, CharacterBody &body) {
|
||||
if (waterb.isInWater(body.mGhostObject) &&
|
||||
ch.mBodyNode->_getDerivedPosition().y > 0.05f)
|
||||
float h = ch.mBodyNode->_getDerivedPosition().y;
|
||||
if (waterb.isInWater(body.mGhostObject) && h > 0.05f)
|
||||
e.remove<InWater>();
|
||||
else if (!waterb.isInWater(body.mGhostObject) &&
|
||||
h > 0.05f)
|
||||
e.remove<InWater>();
|
||||
});
|
||||
#if 0
|
||||
|
||||
@@ -19,6 +19,7 @@ struct CharacterBase {
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Ogre::Node *mRootBone;
|
||||
Ogre::Vector3 mBoneMotion;
|
||||
Ogre::Vector3 mBonePrevMotion;
|
||||
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
|
||||
bool is_submerged;
|
||||
};
|
||||
@@ -42,6 +43,7 @@ struct CharacterVelocity {
|
||||
};
|
||||
struct CharacterInActuator {
|
||||
Ogre::String animationState;
|
||||
Vector3 prevMotion;
|
||||
};
|
||||
struct CharacterModule {
|
||||
CharacterModule(flecs::world &ecs);
|
||||
|
||||
@@ -45,6 +45,10 @@ struct Input {
|
||||
bool mouse_moved;
|
||||
bool wheel_moved;
|
||||
bool fast;
|
||||
bool act;
|
||||
bool act_pressed;
|
||||
bool act2;
|
||||
bool act2_pressed;
|
||||
Input()
|
||||
: control(0)
|
||||
, control_prev(0)
|
||||
|
||||
@@ -258,6 +258,14 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
||||
.entities
|
||||
.end(),
|
||||
"No body to entity mapping");
|
||||
flecs::entity obj_e =
|
||||
ECS::get<
|
||||
Body2Entity>()
|
||||
.entities
|
||||
.at(const_cast<
|
||||
btCollisionObject
|
||||
*>(
|
||||
other));
|
||||
ECS::get<
|
||||
LuaBase>()
|
||||
.mLua
|
||||
@@ -265,13 +273,12 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
||||
evt.event +
|
||||
"_enter",
|
||||
e,
|
||||
ECS::get<
|
||||
Body2Entity>()
|
||||
.entities
|
||||
.at(const_cast<
|
||||
btCollisionObject
|
||||
*>(
|
||||
other)));
|
||||
obj_e);
|
||||
obj_e.add<
|
||||
InTrigger>(
|
||||
e);
|
||||
e.add<TriggeredBy>(
|
||||
obj_e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,14 +290,17 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
||||
while (it != body.contactBodies.end()) {
|
||||
if (currentContactBodies.find(*it) ==
|
||||
currentContactBodies.end()) {
|
||||
ECS::get<LuaBase>().mLua->call_handler(
|
||||
evt.event + "_exit", e,
|
||||
flecs::entity obj_e =
|
||||
ECS::get<Body2Entity>()
|
||||
.entities
|
||||
.at(const_cast<
|
||||
btCollisionObject
|
||||
*>(
|
||||
*it)));
|
||||
*it));
|
||||
ECS::get<LuaBase>().mLua->call_handler(
|
||||
evt.event + "_exit", e, obj_e);
|
||||
obj_e.remove<InTrigger>(e);
|
||||
e.remove<TriggeredBy>(obj_e);
|
||||
std::cout << "body exited" << std::endl;
|
||||
it = body.contactBodies.erase(it);
|
||||
if (it == body.contactBodies.end())
|
||||
|
||||
@@ -16,6 +16,8 @@ struct EventTrigger {
|
||||
struct EventTriggerData {
|
||||
std::set<flecs::entity_t> entities;
|
||||
};
|
||||
struct InTrigger {};
|
||||
struct TriggeredBy {};
|
||||
struct EventTriggerModule {
|
||||
EventTriggerModule(flecs::world &ecs);
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ int LuaData::call_handler(const Ogre::String &event, flecs::entity e,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luaLibraryLoader(lua_State *L)
|
||||
static int luaLibraryLoader(lua_State *L)
|
||||
{
|
||||
int i;
|
||||
if (!lua_isstring(L, 1)) {
|
||||
@@ -260,11 +260,11 @@ LuaData::LuaData()
|
||||
lua_setglobal(L, "main_menu");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
OgreAssert(lua_gettop(L) == 3, "Invalid parameters");
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
luaL_checktype(L, 2, LUA_TSTRING);
|
||||
luaL_checktype(L, 3, LUA_TBOOLEAN);
|
||||
bool enable = lua_toboolean(L, 3);
|
||||
flecs::entity e = ECS::get().lookup(lua_tostring(L, 1));
|
||||
flecs::entity e = idmap.get_entity(lua_tointeger(L, 1));
|
||||
Ogre::String what = lua_tostring(L, 2);
|
||||
OgreAssert(e.is_valid(), "Invalid character");
|
||||
OgreAssert(e.has<Character>(), "Not a character");
|
||||
@@ -401,6 +401,24 @@ LuaData::LuaData()
|
||||
return 0;
|
||||
});
|
||||
lua_setglobal(L, "ecs_trigger_set_position");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
luaL_checktype(L, 1, LUA_TNUMBER); // trigger
|
||||
int trigger = lua_tointeger(L, 1);
|
||||
flecs::entity trigger_e = idmap.get_entity(trigger);
|
||||
Ogre::SceneNode *node = trigger_e.get<EventTrigger>().node;
|
||||
Ogre::Any animationAny =
|
||||
node->getUserObjectBindings().getUserAny(
|
||||
"trigger_animation");
|
||||
if (animationAny.has_value()) {
|
||||
Ogre::String animation =
|
||||
Ogre::any_cast<Ogre::String>(animationAny);
|
||||
lua_pushstring(L, animation.c_str());
|
||||
return 1;
|
||||
}
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
});
|
||||
lua_setglobal(L, "ecs_trigger_get_animation");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
OgreAssert(lua_gettop(L) == 5, "Invalid parameters");
|
||||
luaL_checktype(L, 1, LUA_TSTRING); // type
|
||||
@@ -472,6 +490,14 @@ 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
|
||||
int object = lua_tointeger(L, 1);
|
||||
flecs::entity object_e = idmap.get_entity(object);
|
||||
lua_pushboolean(L, object_e.has<Player>());
|
||||
return 1;
|
||||
});
|
||||
lua_setglobal(L, "ecs_character_is_player");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
luaL_checktype(L, 1, LUA_TNUMBER); // object
|
||||
luaL_checktype(L, 2, LUA_TSTRING); // animation
|
||||
@@ -479,8 +505,10 @@ LuaData::LuaData()
|
||||
|
||||
int object = lua_tointeger(L, 1);
|
||||
flecs::entity object_e = idmap.get_entity(object);
|
||||
if (animation.length())
|
||||
object_e.set<CharacterInActuator>({ animation });
|
||||
object_e.set<CharacterVelocity>({ { 0, 0, 0 }, { 0, 0, 0 } });
|
||||
if (animation.length() > 0)
|
||||
object_e.set<CharacterInActuator>(
|
||||
{ animation, { 0, 0, 0 } });
|
||||
else
|
||||
object_e.remove<CharacterInActuator>();
|
||||
return 0;
|
||||
@@ -500,6 +528,13 @@ LuaData::LuaData()
|
||||
return 0;
|
||||
});
|
||||
lua_setglobal(L, "ecs_set_slot");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
flecs::entity e = ECS::get().lookup("player");
|
||||
int result = idmap.add_entity(e);
|
||||
lua_pushinteger(L, result);
|
||||
return result;
|
||||
});
|
||||
lua_setglobal(L, "ecs_get_player_entity");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
luaL_checktype(L, 1, LUA_TNUMBER); // entity id
|
||||
int id = lua_tointeger(L, 1);
|
||||
|
||||
Reference in New Issue
Block a user