From 052ce629c4a03fae51572afdad68a8dc3206b6cf Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 31 May 2014 12:15:20 +0100 Subject: [PATCH] Refactor Animator to support multiple animations --- rwengine/include/engine/Animator.hpp | 26 +++++++-- rwengine/src/ai/GTAAIController.cpp | 7 +-- rwengine/src/engine/Animator.cpp | 79 ++++++++++++++++----------- rwengine/src/objects/GTACharacter.cpp | 2 +- tests/test_character.cpp | 3 +- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/rwengine/include/engine/Animator.hpp b/rwengine/include/engine/Animator.hpp index db504e2c..6d03e1d2 100644 --- a/rwengine/include/engine/Animator.hpp +++ b/rwengine/include/engine/Animator.hpp @@ -4,8 +4,7 @@ #include #include -#include -#include +#include #include class Animation; @@ -18,17 +17,25 @@ class ModelFrame; */ class Animator { - Animation* animation; + /** + * @brief _animations Queue of animations to play. + */ + std::queue _animations; + /** + * @brief model The model being animated. + */ Model* model; + // Used in determining how far the skeleton being animated has moved + // From it's local origin. glm::vec3 lastRootPosition; glm::quat lastRootRotation; float time; float serverTime; float lastServerTime; - + bool repeat; void reset(); @@ -45,8 +52,15 @@ public: */ void setAnimation(Animation* animation, bool repeat = true); - Animation* getAnimation() const - { return animation; } + void queueAnimation(Animation* animation); + + void next(); + + const std::queue getAnimationQueue() const + { return _animations; } + + const Animation* getAnimation() const + { return _animations.empty() ? nullptr : _animations.front(); } void setModel(Model* model); diff --git a/rwengine/src/ai/GTAAIController.cpp b/rwengine/src/ai/GTAAIController.cpp index 6256efc8..7b78142b 100644 --- a/rwengine/src/ai/GTAAIController.cpp +++ b/rwengine/src/ai/GTAAIController.cpp @@ -77,9 +77,8 @@ bool Activities::GoTo::update(GTACharacter *character, GTAAIController *controll bool Activities::EnterVehicle::update(GTACharacter *character, GTAAIController *controller) { if( entering ) { - std::cout << "Checking" << std::endl; - if( character->currentActivity == GTACharacter::Idle ) { - std::cout << "was idle" << std::endl; + // TODO: decouple from the character's animator. + if( character->animator->isCompleted() ) { character->enterVehicle(vehicle, seat); return true; } @@ -87,9 +86,9 @@ bool Activities::EnterVehicle::update(GTACharacter *character, GTAAIController * else { glm::vec3 target = vehicle->getSeatEntryPosition(seat); glm::vec3 targetDirection = target - character->getPosition(); + targetDirection.z = 0.f; if( glm::length(targetDirection) <= 0.4f ) { - std::cout << "enter started" << std::endl; entering = true; character->enterAction(GTACharacter::VehicleGetIn); } diff --git a/rwengine/src/engine/Animator.cpp b/rwengine/src/engine/Animator.cpp index db868dfb..fab1a2c6 100644 --- a/rwengine/src/engine/Animator.cpp +++ b/rwengine/src/engine/Animator.cpp @@ -5,7 +5,7 @@ #include Animator::Animator() - : animation(nullptr), model(nullptr), time(0.f), serverTime(0.f), lastServerTime(0.f), repeat(true) + : model(nullptr), time(0.f), serverTime(0.f), lastServerTime(0.f), repeat(true) { } @@ -15,24 +15,32 @@ void Animator::reset() time = 0.f; serverTime = 0.f; lastServerTime= 0.f; - - if(model && animation) { - - } } void Animator::setAnimation(Animation *animation, bool repeat) { - if(animation == this->animation) { + if(!_animations.empty() && animation == _animations.front()) { return; } - this->animation = animation; + while(!_animations.empty()) _animations.pop(); + queueAnimation(animation); this->repeat = repeat; reset(); } +void Animator::queueAnimation(Animation *animation) +{ + _animations.push(animation); +} + +void Animator::next() +{ + _animations.pop(); + reset(); +} + void Animator::setModel(Model *model) { if(model == this->model) { @@ -46,23 +54,27 @@ void Animator::setModel(Model *model) void Animator::tick(float dt) { - if(! (animation && model)) { + if( model == nullptr || _animations.empty() ) { return; } lastServerTime = serverTime; serverTime += dt; + if( isCompleted() && ! repeat && _animations.size() > 1 ) { + next(); + } } glm::vec3 Animator::getRootTranslation() const { // This is a pretty poor assumption. - if(model->frames[model->rootFrameIdx]->getChildren().size() > 0) { + if(!model->frames[model->rootFrameIdx]->getChildren().empty() + && !_animations.empty()) { ModelFrame* realRoot = model->frames[model->rootFrameIdx]->getChildren()[0]; - auto it = animation->bones.find(realRoot->getName()); - if(it != animation->bones.end()) { - float df = fmod(lastServerTime, this->animation->duration); + auto it = getAnimation()->bones.find(realRoot->getName()); + if(it != getAnimation()->bones.end()) { + float df = fmod(lastServerTime, getAnimation()->duration); float rt = getAnimationTime(); if(df < rt) { auto lastKF = it->second->getInterpolatedKeyframe(df); @@ -82,38 +94,39 @@ glm::quat Animator::getRootRotation() const glm::mat4 Animator::getFrameMatrix(ModelFrame* frame, float alpha) const { - auto it = animation->bones.find(frame->getName()); - if(it != animation->bones.end()) { - auto kf = it->second->getInterpolatedKeyframe(getAnimationTime(alpha)); - glm::mat4 m; - if(it->second->type == AnimationBone::R00 || frame->getName() == "swaist") { - m = glm::translate(m, frame->getDefaultTranslation()); - m = m * glm::mat4_cast(kf.rotation); + if(getAnimation()) { + auto it = getAnimation()->bones.find(frame->getName()); + if(it != getAnimation()->bones.end()) { + auto kf = it->second->getInterpolatedKeyframe(getAnimationTime(alpha)); + glm::mat4 m; + if(it->second->type == AnimationBone::R00 || frame->getName() == "swaist") { + m = glm::translate(m, frame->getDefaultTranslation()); + m = m * glm::mat4_cast(kf.rotation); + } + else if(it->second->type == AnimationBone::RT0) { + m = glm::translate(m, kf.position); + m = m * glm::mat4_cast(kf.rotation); + } + else { + m = glm::translate(m, kf.position); + m = m * glm::mat4_cast(kf.rotation); + } + return m; } - else if(it->second->type == AnimationBone::RT0) { - m = glm::translate(m, kf.position); - m = m * glm::mat4_cast(kf.rotation); - } - else { - m = glm::translate(m, kf.position); - m = m * glm::mat4_cast(kf.rotation); - } - return m; - } - else { - return frame->getTransform(); } + + return frame->getTransform(); } bool Animator::isCompleted() const { - return serverTime >= animation->duration; + return getAnimation() ? serverTime >= getAnimation()->duration : true; } float Animator::getAnimationTime(float alpha) const { if(repeat) { - return fmod(serverTime + alpha, this->animation->duration); + return fmod(serverTime + alpha, getAnimation()->duration); } return serverTime + alpha; } diff --git a/rwengine/src/objects/GTACharacter.cpp b/rwengine/src/objects/GTACharacter.cpp index e0720d58..4a06a509 100644 --- a/rwengine/src/objects/GTACharacter.cpp +++ b/rwengine/src/objects/GTACharacter.cpp @@ -139,7 +139,7 @@ void GTACharacter::tick(float dt) if(animator->getAnimation() != animations.car_getin_lhs) { animator->setAnimation(animations.car_getin_lhs, false); } - else if( animator->isCompleted() ) { + else if( animator->getAnimation() == nullptr ) { enterAction(Idle); } } break; diff --git a/tests/test_character.cpp b/tests/test_character.cpp index a51896f4..c76fa67c 100644 --- a/tests/test_character.cpp +++ b/tests/test_character.cpp @@ -75,8 +75,7 @@ BOOST_AUTO_TEST_CASE(test_activities) BOOST_CHECK_EQUAL( nullptr, character->getCurrentVehicle() ); - for(float t = 0.f; t < 8.f; t+=(1.f/60.f)) { - controller->update(1.f/60.f); + for(float t = 0.f; t < 9.0f; t+=(1.f/60.f)) { character->tick(1.f/60.f); Global::get().e->dynamicsWorld->stepSimulation(1.f/60.f); }