mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 02:12:45 +01:00
Refactor Animator to support multiple animations
This commit is contained in:
parent
04842a628a
commit
052ce629c4
@ -4,8 +4,7 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <cstdint>
|
||||
|
||||
class Animation;
|
||||
@ -18,17 +17,25 @@ class ModelFrame;
|
||||
*/
|
||||
class Animator
|
||||
{
|
||||
Animation* animation;
|
||||
/**
|
||||
* @brief _animations Queue of animations to play.
|
||||
*/
|
||||
std::queue<Animation*> _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<Animation*> getAnimationQueue() const
|
||||
{ return _animations; }
|
||||
|
||||
const Animation* getAnimation() const
|
||||
{ return _animations.empty() ? nullptr : _animations.front(); }
|
||||
|
||||
void setModel(Model* model);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user