假设我有 4 张图像,我想使用这 4 张图像为角色设置动画。4 个图像代表角色行走。我希望动画在我按下键移动时重复自己,但在我松开它时停止。如果你不知道,它不需要是特定于 SFML 的,只是基本理论会对我有帮助。
谢谢你。
您可能需要某种简单的状态机。当按键按下时(参见sf::Input 的 IsKeyDown 方法),让角色处于“动画”状态。当键未按下时,使角色处于“未动画”状态。当然,你总是可以跳过这个“状态”,只做我下面提到的(具体取决于你在做什么)。
然后,如果角色处于“动画”状态,则获取下一个“图像”(有关详细信息,请参见下一段)。例如,如果您将图像存储在一个简单的 4 元素数组中,则下一个图像将位于(currentIndex + 1) % ARRAY_SIZE
. 根据您所做的事情,您可能希望将图像帧存储在更复杂的数据结构中。如果角色不处于“动画”状态,那么您将不会在此处进行任何更新。
如果您的“4 张图像”在同一个图像文件中,您可以使用 sf::Sprite 的SetSubRect方法更改显示的图像部分。如果您实际上有 4 个不同的图像,那么您可能需要使用 sf::Sprite 的SetImage方法来切换图像。
您将如何强制执行帧速率以使动画不会发生得太快?
您好,请在此处查看我的答案并接受此帖子作为最佳解决方案。
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 = ⌖
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; }