PlayMaker Posted July 15, 2024 Posted July 15, 2024 Здравствуйте!!! Помогите пожалуйста разобраться с кодом, пример брал здесь: Проблема заключается в том, при нажатии на пробел, анимация удара по мячу часто проигрывается не до конца, затем при следующем нажатии доигрывается остаток анимации, иногда проигрывается два раза ((( Вот код: #pragma once #include <Unigine.h> class AnimationState : public Unigine::ComponentBase { public: COMPONENT_DEFINE(AnimationState, ComponentBase) COMPONENT_INIT(Init) COMPONENT_UPDATE(Update) PROP_PARAM(File, IdleAnim) PROP_PARAM(File, WalkAnim) PROP_PARAM(File, R_WalkAnim) PROP_PARAM(File, RunAnim) struct AnimationData final : public Unigine::ComponentStruct { PROP_PARAM(File, Source, nullptr, "Source", nullptr, nullptr, "filter=.anim") float currentFrame{}; int numFrames{}; bool playing {true}; // флаг что анимация играет. по дефолту лучше чтобы не играла. int isFinished() const // тут измерение в кадрах. 0.5 кадра это анимация уже точно закончилась и начала уже возвращаться к первому кадру. // поэтому лучше поставить чтото больше чем 1 чтобы не увидеть бленда с первым кадром {return Unigine::Math::compare(static_cast<float>(numFrames), currentFrame, 0.5f);} //{return (static_cast<float>(numFrames) == currentFrame);} }; // declaration of the structured parameter named "ShootingAnimation" of the AnimationData type declared above PROP_STRUCT(AnimationData, ShootingAnimation); // declaration of the structured parameter named "PassAnimation" of the AnimationData type declared above PROP_STRUCT(AnimationData, PassAnimation); protected: void Init(); void Update(); private: Unigine::ObjectMeshSkinnedPtr MainCharacter; float Weight = 0; bool isWeightChanged = false; enum ANIM_STATE {PROCEDURAL = 0, IDLE, WALK, REVERSE_WALK, RUN, SHOOTING, PASS, COUNT}; ANIM_STATE MainState = ANIM_STATE::IDLE, PrevState = ANIM_STATE::IDLE; void ChangeState(); void ResetWeight(); }; #include "AnimationState.h" REGISTER_COMPONENT(AnimationState) void AnimationState::ResetWeight() { isWeightChanged = true; if (isWeightChanged) { Weight = 0; isWeightChanged = false; } } void AnimationState::ChangeState() { switch (MainState) { case AnimationState::IDLE: if (Unigine::Input::isKeyPressed(Unigine::Input::KEY_W) && Unigine::Input::isKeyPressed(Unigine::Input::KEY_LEFT_SHIFT)) {ResetWeight(); MainState = ANIM_STATE::RUN; PrevState = ANIM_STATE::IDLE;} if (Unigine::Input::isKeyPressed(Unigine::Input::KEY_W)) {ResetWeight(); MainState = ANIM_STATE::WALK; PrevState = ANIM_STATE::IDLE;} if (Unigine::Input::isKeyPressed(Unigine::Input::KEY_S)) {ResetWeight(); MainState = ANIM_STATE::REVERSE_WALK; PrevState = ANIM_STATE::IDLE;} if (Unigine::Input::isKeyUp(Unigine::Input::KEY_SPACE)) {ShootingAnimation->playing = true; ResetWeight(); MainState = ANIM_STATE::SHOOTING; PrevState = ANIM_STATE::IDLE;} if (Unigine::Input::isKeyUp(Unigine::Input::KEY_J)) {PassAnimation->playing = true; ResetWeight(); MainState = ANIM_STATE::PASS; PrevState = ANIM_STATE::IDLE;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::IDLE, Weight * 2); break; case AnimationState::WALK: if (Unigine::Input::isKeyPressed(Unigine::Input::KEY_LEFT_SHIFT)) {ResetWeight(); MainState = ANIM_STATE::RUN; PrevState = ANIM_STATE::WALK;} if (Unigine::Input::isKeyUp(Unigine::Input::KEY_W)) {ResetWeight(); MainState = ANIM_STATE::IDLE; PrevState = ANIM_STATE::WALK;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::WALK, Weight * 1.65f); break; case AnimationState::REVERSE_WALK: if (Unigine::Input::isKeyUp(Unigine::Input::KEY_S)) {ResetWeight(); MainState = ANIM_STATE::IDLE; PrevState = ANIM_STATE::REVERSE_WALK;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::REVERSE_WALK, Weight * 1.65f); break; case AnimationState::RUN: if (Unigine::Input::isKeyUp(Unigine::Input::KEY_LEFT_SHIFT)) {ResetWeight(); MainState = ANIM_STATE::WALK; PrevState = ANIM_STATE::RUN;} if (Unigine::Input::isKeyUp(Unigine::Input::KEY_W)) {ResetWeight(); MainState = ANIM_STATE::IDLE; PrevState = ANIM_STATE::RUN;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::RUN, Weight * 3); break; case AnimationState::SHOOTING: if (ShootingAnimation->isFinished()) {ShootingAnimation->playing = false; ResetWeight(); MainState = ANIM_STATE::IDLE; PrevState = ANIM_STATE::SHOOTING;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::SHOOTING, Weight * 6); break; case AnimationState::PASS: if (PassAnimation->isFinished()) {PassAnimation->playing = false; ResetWeight(); MainState = ANIM_STATE::IDLE; PrevState = ANIM_STATE::PASS;} MainCharacter->lerpLayer(ANIM_STATE::PROCEDURAL, PrevState, ANIM_STATE::PASS, Weight * 6); break; default: break; } } void AnimationState::Init() { const char* Idle = Unigine::FileSystem::getGUID(IdleAnim.getRaw()).getFileSystemString(); const char* Walk = Unigine::FileSystem::getGUID(WalkAnim.getRaw()).getFileSystemString(); const char* RWalk = Unigine::FileSystem::getGUID(R_WalkAnim.getRaw()).getFileSystemString(); const char* Run = Unigine::FileSystem::getGUID(RunAnim.getRaw()).getFileSystemString(); MainCharacter = Unigine::checked_ptr_cast<Unigine::ObjectMeshSkinned>(node); MainCharacter->setNumLayers(ANIM_STATE::COUNT); int IdleNum = MainCharacter->addAnimation(Idle); int WalkNum = MainCharacter->addAnimation(Walk); int R_WalkNum = MainCharacter->addAnimation(RWalk); int RunNum = MainCharacter->addAnimation(Run); MainCharacter->setAnimation(ANIM_STATE::PROCEDURAL, IdleNum); // Procedural MainCharacter->setAnimation(ANIM_STATE::IDLE, IdleNum); MainCharacter->setAnimation(ANIM_STATE::WALK, WalkNum); MainCharacter->setAnimation(ANIM_STATE::REVERSE_WALK, R_WalkNum); MainCharacter->setAnimation(ANIM_STATE::RUN, RunNum); MainCharacter->setAnimation(ANIM_STATE::SHOOTING, Unigine::FileSystem::getGUID(ShootingAnimation->Source).getFileSystemString()); ShootingAnimation->numFrames = MainCharacter->getNumFrames(ANIM_STATE::SHOOTING); ShootingAnimation->playing = false; // не надо играть сразу MainCharacter->setAnimation(ANIM_STATE::PASS, Unigine::FileSystem::getGUID(PassAnimation->Source).getFileSystemString()); PassAnimation->numFrames = MainCharacter->getNumFrames(ANIM_STATE::PASS); PassAnimation->playing = false; // не надо играть сразу } void AnimationState::Update() { float anim_ifps = Unigine::Game::getIFps() * 30; // deltaTime MainCharacter->setFrame(ANIM_STATE::PROCEDURAL, Unigine::Game::getTime() * 30); MainCharacter->setFrame(ANIM_STATE::IDLE, Unigine::Game::getTime() * 30); MainCharacter->setFrame(ANIM_STATE::WALK, Unigine::Game::getTime() * 30); MainCharacter->setFrame(ANIM_STATE::REVERSE_WALK, Unigine::Game::getTime() * 30); MainCharacter->setFrame(ANIM_STATE::RUN, Unigine::Game::getTime() * 30); if (ShootingAnimation->playing) { // запускаем только если надо играть ShootingAnimation->currentFrame = MainCharacter->setFrame(ANIM_STATE::SHOOTING, ShootingAnimation->currentFrame + anim_ifps); } if (PassAnimation->playing) { // запускаем только если надо играть PassAnimation->currentFrame = MainCharacter->setFrame(ANIM_STATE::PASS, PassAnimation->currentFrame + anim_ifps); } Weight = Unigine::Math::clamp(Weight + Unigine::Game::getIFps(), 0.0f, 1.0f); ChangeState(); //Unigine::Console::message("Weight is: %f \n", Weight); Unigine::Console::message("Current frame from ShootingAnimation is: %f \n", ShootingAnimation->currentFrame); Unigine::Console::message("ShootingAnimation isFinished: %f \n", ShootingAnimation->isFinished()); } Видео: 2024-07-16 01-17-12.mp4 Иногда в состоянии IDLE, в isFinished() пролетают какие то космические значения, фото ниже (в конце видео данный глюк так же можно заметить): Помогите пожалуйста разобраться, что я сделал не так?
silent Posted July 16, 2024 Posted July 16, 2024 Выглядит так, что проще прикрутить простейшую стейт-машину для воспроизведения анимаций. В аттаче как раз пример как можно это сделать (на пробел осуществляется пинок, движение на t, g, f, h): Для работы примера можно импортнуть пекедж в пустой проект, добавить файлы SimpleStateMachine.cpp/h в проект и после чего собрать. Мир для тестов: state_machine.world. Спасибо. simple_state_machine.upackage How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
PlayMaker Posted July 16, 2024 Author Posted July 16, 2024 Согласен ))), так проще и эффективней: 2024-07-17 00-08-09.mp4 Спасибо большое!!!
Recommended Posts