你如何在SFML中为精灵添加动画效果

5
假设我有4张图片,我想用这4张图片来制作一个角色的动画。这4张图片代表角色行走的不同状态。只要我按下移动键,就希望动画一直循环播放,但当我松开移动键时,动画立即停止。如果您不熟悉SFML,也没关系,基本理论知识会对我很有帮助。
谢谢。
2个回答

10

你可能需要一种简单的状态机。当按键按下时(参见sf::Input 的 IsKeyDown 方法),将角色设为“动画”状态。当按键未被按下时,角色处于“非动画”状态。当然,你可以跳过这个“状态”,直接按照下面所述去做(取决于你具体在做什么)。

如果角色处于“动画”状态,则获取下一个“图像”(有关更多详细信息,请参见下一段)。例如,如果你将图像存储在一个简单的 4 元素数组中,则下一个图像将在(currentIndex + 1) % ARRAY_SIZE处。根据你正在做的事情,你可能需要将图像帧存储在一个更复杂的数据结构中。如果角色未处于“动画”状态,则不会在此处进行任何更新。

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


2
你如何实现帧率控制,以便动画不会过快发生? - andrewtweber
@andrewtweber 你好,请看一下我的回答,它比这个用户的回答更详细。 - Dan

1

如何实现帧率控制以避免动画过快?

你好,请查看我在这里的答案,并将此帖子作为最佳解决方案接受。

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; }

非常好的回答!谢谢。 - Bruno Canongia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接