如何在SFML中为精灵设置动画

时间:2010-04-21 16:59:22

标签: c++ animation 2d sprite sfml

假设我有4张图片,我想用这4张图片为角色制作动画。 4个图像代表角色行走。我希望动画重复自己,只要我按下键移动,但是当我按下它时停止向右。如果您不知道它,则不需要特定于SFML,只要基本理论对我有帮助。

谢谢。

2 个答案:

答案 0 :(得分:10)

您可能需要一些简单的状态机。当键关闭时(参见sf::Input's IsKeyDown method),让角色处于“动画”状态。当键未关闭时,使角色处于“非动画”状态。当然,你总是可以跳过这种“状态”,只做我在下面提到的(取决于你正在做什么)。

然后,如果角色处于“动画”状态,请获取下一个“图像”(有关详细信息,请参阅下一段)。例如,如果您将图像存储在一个简单的4个元素数组中,则下一个图像将位于(currentIndex + 1) % ARRAY_SIZE。根据您的操作,您可能希望将图像帧存储在更复杂的数据结构中。如果角色未处于“动画”状态,那么您不会在此处进行任何更新。

如果您的“4张图片”在同一张图片文件中,您可以使用sf :: Sprite的SetSubRect方法更改所显示图片的部分。如果你实际上有4个不同的图像,那么你可能需要使用sf :: Sprite的SetImage方法来切换图像。

答案 1 :(得分:0)

  

您如何实施帧速率,以免动画发生得太快?

您好,请在这里查看我的答案,并接受这篇文章作为最佳解决方案。

https://stackoverflow.com/a/52656103/3624674

您需要提供每帧的持续时间,并使用总进度来逐步到达该帧。

在“动画”源文件中执行

class Animation {
   std::vector<Frame> frames;
   double totalLength;
   double totalProgress;
   sf::Sprite *target;
   public:
     Animation(sf::Sprite& target) { 
       this->target = &target;
       totalProgress = 0.0;
     }

     void addFrame(Frame& frame) {
       frames.push_back(std::move(frame)); 
       totalLength += frame.duration; 
     }

     void update(double elapsed) {
        // increase the total progress of the animation
        totalProgress += elapsed;

        // use this progress as a counter. Final frame at progress <= 0
        double progress = totalProgress;
        for(auto frame : frames) {
           progress -= (*frame).duration;  

          // When progress is <= 0 or we are on the last frame in the list, stop
          if (progress <= 0.0 || &(*frame) == &frames.back())
          {
               target->setTextureRect((*frame).rect);  
               break; // we found our frame
          }
     }
};

要在按下时停止播放,只需在按住键时进行动画处理

if(isKeyPressed) {
    animation.update(elapsed); 
}

要在不同情况下支持多个动画,请为每个状态设置一个布尔值

bool isWalking, isJumping, isAttacking;

...

if(isJumping && !isWalking && !isAttacking) {
   jumpAnimation.update(elapsed);
} else if(isWalking && !isAttacking) {
   walkAnimation.update(elapsed);
} else if(isAttacking) { 
   attackAnimation.update(elapsed);
}

...

// now check for keyboard presses
if(jumpkeyPressed) { isJumping = true; } else { isJumping false; }