refactor: Make creature handle all its animations

This commit is contained in:
Vsevolod Kremianskii 2020-11-16 17:55:28 +07:00
parent b5cd07126f
commit 47bf9485f6
11 changed files with 80 additions and 73 deletions

View file

@ -264,7 +264,7 @@ void ActionExecutor::executeOpenLock(Creature &actor, ObjectAction &action, floa
bool reached = navigateCreature(actor, door->position(), 1.0f, dt);
if (reached) {
actor.face(*door);
actor.playUnlockDoorAnimation();
actor.playAnimation(Creature::Animation::UnlockDoor);
door->setLocked(false);
door->open(&actor);
if (!door->blueprint().onOpen().empty()) {

View file

@ -224,6 +224,7 @@ shared_ptr<ModelSceneNode> CharacterGeneration::getCharacterModel(SceneGraph &sc
unique_ptr<Creature> creature(objectFactory->newCreature());
creature->load(_character);
creature->updateModelAnimation();
return creature->model();
}

View file

@ -202,6 +202,7 @@ shared_ptr<ModelSceneNode> ClassSelection::getCharacterModel(const CreatureConfi
unique_ptr<Creature> creature(objectFactory->newCreature());
creature->load(config);
creature->updateModelAnimation();
return creature->model();
}

View file

@ -182,11 +182,6 @@ void Creature::updateModel() {
rightWeaponModel = Models::instance().get(rightWeaponModelName);
}
_model->attach("rhand", rightWeaponModel);
// Animation
_model->setDefaultAnimation(getPauseAnimation());
_model->playDefaultAnimation();
}
string Creature::getBodyModelName() const {
@ -312,32 +307,64 @@ void Creature::loadPortrait(int appearance) {
_portrait = Textures::instance().get(resRef, TextureType::GUI);
}
void Creature::playDefaultAnimation() {
if (_model) {
_model->playDefaultAnimation();
}
void Creature::update(float dt) {
SpatialObject::update(dt);
updateModelAnimation();
}
void Creature::playGreetingAnimation() {
if (_movementType != MovementType::None) return;
playAnimation(g_animGreeting, kAnimationPropagate);
}
void Creature::playTalkAnimation() {
void Creature::updateModelAnimation() {
if (!_model) return;
_model->playAnimation(g_animTalkBody, kAnimationLoop | kAnimationPropagate);
if (_animFireForget) {
if (!_model->isAnimationFinished()) return;
if (_headModel) {
_headModel->playAnimation(g_animTalkHead, kAnimationLoop | kAnimationOverlay, 0.25f);
_animFireForget = false;
_animDirty = true;
}
if (!_animDirty) return;
switch (_movementType) {
case MovementType::Run:
_model->playAnimation(getRunAnimation(), kAnimationLoop | kAnimationPropagate | kAnimationBlend);
break;
case MovementType::Walk:
_model->playAnimation(getWalkAnimation(), kAnimationLoop | kAnimationPropagate | kAnimationBlend);
break;
default:
if (_talking) {
_model->playAnimation(g_animTalkBody, kAnimationLoop | kAnimationPropagate);
if (_headModel) {
_headModel->playAnimation(g_animTalkHead, kAnimationLoop | kAnimationOverlay, 0.25f);
}
} else {
_model->playAnimation(getPauseAnimation(), kAnimationLoop | kAnimationPropagate | kAnimationBlend);
}
break;
}
_animDirty = false;
}
void Creature::playUnlockDoorAnimation() {
if (!_model) return;
void Creature::clearAllActions() {
SpatialObject::clearAllActions();
setMovementType(MovementType::None);
}
_model->playAnimation(g_animUnlockDoor, kAnimationBlend);
void Creature::playAnimation(Animation anim) {
if (!_model || _movementType != MovementType::None) return;
string animName;
switch (anim) {
case Animation::UnlockDoor:
animName = g_animUnlockDoor;
break;
default:
break;
}
if (!animName.empty()) {
_model->playAnimation(animName, kAnimationPropagate | kAnimationBlend);
_animFireForget = true;
}
}
void Creature::equip(const string &resRef) {
@ -388,38 +415,18 @@ void Creature::setTag(const string &tag) {
}
void Creature::setMovementType(MovementType type) {
if (!_model || _movementType == type) return;
switch (type) {
case MovementType::Walk:
_model->playAnimation(getWalkAnimation(), kAnimationLoop | kAnimationPropagate | kAnimationBlend);
break;
case MovementType::Run:
_model->playAnimation(getRunAnimation(), kAnimationLoop | kAnimationPropagate | kAnimationBlend);
break;
default:
if (_talking) {
playTalkAnimation();
} else {
_model->playDefaultAnimation();
}
break;
}
if (_movementType == type) return;
_movementType = type;
_animDirty = true;
_animFireForget = false;
}
void Creature::setTalking(bool talking) {
if (_talking == talking) return;
if (_movementType == MovementType::None) {
if (talking) {
playTalkAnimation();
} else {
playDefaultAnimation();
}
}
_talking = talking;
_animDirty = true;
}
const string &Creature::getPauseAnimation() const {

View file

@ -44,6 +44,10 @@ public:
Run
};
enum class Animation {
UnlockDoor
};
struct Path {
glm::vec3 destination { 0.0f };
std::vector<glm::vec3> points;
@ -53,12 +57,18 @@ public:
Creature(uint32_t id, ObjectFactory *objectFactory, scene::SceneGraph *sceneGraph);
void update(float dt) override;
void clearAllActions() override;
glm::vec3 selectablePosition() const override;
void load(const resource::GffStruct &gffs);
void load(const std::shared_ptr<CreatureBlueprint> &blueprint);
void load(const CreatureConfiguration &config);
void playAnimation(Animation anim);
void updateModelAnimation();
Gender gender() const;
int appearance() const;
std::shared_ptr<render::Texture> portrait() const;
@ -68,17 +78,8 @@ public:
std::shared_ptr<CreatureBlueprint> blueprint() const;
void setTag(const std::string &tag);
virtual void setMovementType(MovementType type);
virtual void setTalking(bool talking);
// Animations
void playDefaultAnimation();
void playGreetingAnimation();
void playTalkAnimation();
void playUnlockDoorAnimation();
// END Animations
void setMovementType(MovementType type);
void setTalking(bool talking);
// Equipment
@ -121,6 +122,8 @@ private:
MovementType _movementType { MovementType::None };
bool _talking { false };
CreatureAttributes _attributes;
bool _animDirty { true };
bool _animFireForget { false };
// Scripts
@ -135,12 +138,14 @@ private:
// END Loading
void updateModel();
ModelType parseModelType(const std::string &s) const;
std::string getBodyModelName() const;
std::string getBodyTextureName() const;
std::string getHeadModelName() const;
std::string getWeaponModelName(InventorySlot slot) const;
ModelType parseModelType(const std::string &s) const;
void updateModel();
const std::string &getPauseAnimation() const;
const std::string &getRunAnimation() const;

View file

@ -36,6 +36,10 @@ void Object::update(float dt) {
_actionQueue.update();
}
void Object::clearAllActions() {
_actionQueue.clear();
}
void Object::runUserDefinedEvent(int eventNumber) {
if (!_onUserDefined.empty()) {
runScript(_onUserDefined, _id, kObjectInvalid, eventNumber);

View file

@ -34,6 +34,7 @@ public:
virtual ~Object() = default;
virtual void update(float dt);
virtual void clearAllActions();
void runUserDefinedEvent(int eventNumber);

View file

@ -78,12 +78,6 @@ void SpatialObject::update(float dt) {
}
}
void SpatialObject::playAnimation(const string &name, int flags, float speed) {
if (_model) {
_model->playAnimation(name, flags, speed);
}
}
bool SpatialObject::isSelectable() const {
return _selectable;
}

View file

@ -42,8 +42,6 @@ class SpatialObject : public Object {
public:
void update(float dt) override;
virtual void playAnimation(const std::string &name, int flags = 0, float speed = 1.0f);
void addItem(const std::shared_ptr<Item> &item);
float distanceTo(const glm::vec2 &point) const;

View file

@ -103,10 +103,6 @@ bool Player::handleKeyUp(const SDL_KeyboardEvent &event) {
_moveRight = false;
return true;
case SDL_SCANCODE_X:
_party->leader()->playGreetingAnimation();
return true;
default:
return false;
}

View file

@ -149,7 +149,7 @@ Variable Routines::actionCloseDoor(const vector<Variable> &args, ExecutionContex
Variable Routines::clearAllActions(const vector<Variable> &args, ExecutionContext &ctx) {
shared_ptr<Object> actor(getObjectById(ctx.callerId, ctx));
actor->actionQueue().clear();
actor->clearAllActions();
return Variable();
}