精灵没有动画

Sprites aren't animating

本文关键字:动画 精灵      更新时间:2023-10-16

我一直在尝试更新游戏中的敌人精灵,方法是创建一个指向敌人对象的指针向量,然后使用更新函数对属于这些对象的精灵进行动画处理。虽然敌人的精灵显示在屏幕上,但它们不会更新,所以它们看起来就像被冻结了一样。

以下是我编写代码的方式:

#include<iostream>
#include<SFML/Graphics.hpp>
#include<math.h>
#include<vector>
#include<cstdlib>
#include "Enemy.h"

sf::RenderWindow window(sf::VideoMode(1920, 1080), "Zombie game", sf::Style::Default);
std::vector<Enemy*>enemies;
int main()
{
window.setFramerateLimit(60);
sf::Clock clock;
Enemy *enemy = new Enemy();
enemy->init("Assets/graphics/zombieSpriteSheetWalk.png", 4, 1.0f, sf::Vector2f(200.0f, 200.0f), sf::Vector2i(100, 107));
enemies.push_back(enemy);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape) window.close();
}
sf::Time dt = clock.restart();
for (int i = 0; i < enemies.size(); i++)
{
Enemy *enemy = enemies[i];
enemy->update(dt.asSeconds());
}
window.clear();
for (Enemy* enemy : enemies) window.draw(enemy->getSprite());
window.display();
}
return 0;
}

敌人.h文件:

#pragma once
#include<SFML/Graphics.hpp>
#include <iostream>
class Enemy
{
public:
Enemy();
~Enemy();
void init(std::string textureName, int frameCount, float animDuration, sf::Vector2f position, sf::Vector2i spriteSize);
void update(float dt);
sf::Sprite& getSprite();
void test();
private:
sf::Texture m_texture;
sf::Sprite m_sprite;
sf::Vector2f m_position;
int m_frameCount; //no. of frames in animation
float m_animDuration; //How long animation lasts (speed)
float m_elapsedTime; //keeps track of how long game has been running
sf::Vector2i m_spriteSize; //Size of each frame
};

敌人.cpp文件:

#include "Enemy.h"
Enemy::Enemy()
{
}

Enemy::~Enemy()
{
}
void Enemy::init(std::string textureName, int frameCount, float animDuration, sf::Vector2f position, sf::Vector2i spriteSize)
{
m_position = position;
m_frameCount = frameCount;
m_animDuration = animDuration;
m_spriteSize = spriteSize;
m_texture.loadFromFile(textureName.c_str()); 
m_sprite.setTexture(m_texture);
m_sprite.setTextureRect(sf::IntRect(0, 0, m_spriteSize.x, m_spriteSize.y));//sets which part of sprite sheet we want to display
m_sprite.setPosition(m_position);
m_sprite.setOrigin((m_texture.getSize().x / frameCount) - 25.0f, m_texture.getSize().y / 2);
}
void Enemy::update(float dt)
{
m_elapsedTime += dt;
int animFrame = static_cast<int>((m_elapsedTime / m_animDuration) * m_frameCount) % m_frameCount; //calculates current animation frame number. static_class converts float to int
m_sprite.setTextureRect(sf::IntRect(animFrame * m_spriteSize.x, 0, m_spriteSize.x, m_spriteSize.y)); //updates part of sprite sheet to be displayed
}

sf::Sprite& Enemy::getSprite()
{
return m_sprite;
}

你总是在时间 0

从 SFML 时钟标头:

////////////////////////////////////////////////////////////
/// brief Restart the clock
///
/// This function puts the time counter back to zero.
/// It also returns the time elapsed since the clock was started.
///
/// return Time elapsed
///
////////////////////////////////////////////////////////////
Time restart();

可能的修复

  1. 使用sf::Clock表示dt而不是sf::Time并将其移出事件循环(您希望它在程序运行时累积,而不是每次都重置为 0。
  2. 取代:
    enemy->update(dt.asSeconds());
    
    enemy->update(dt.getElapsedTime());
    

更多注意事项

我在这个类型的答案中做了一些假设,因为你的例子不完整。您所做的一个重大遗漏是不包括class Enemy定义(尤其是成员变量的类型(。

根据Enemy::init的定义,我假设它将包含以下内容:

class Enemy
{
float m_elapsedTime;
float m_animDuration;
int m_frameCount;
...

但是,这些定义会导致您的Enemy::update版本中出现以下编译错误:

enemy.cpp: In member function ‘void Enemy::update(float)’:
enemy.cpp:14:88: error: invalid operands of types ‘float’ and ‘int’ to binary ‘operator%’
int animFrame = static_cast<int>(((m_elapsedTime / m_animDuration) * m_frameCount) % m_frameCount);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~ 

如果游戏时间是浮动的,则您不希望运行作为游戏时间函数的动画。原因是浮点数在不同的值范围内具有不同的精度,数字越接近 0,您拥有的精度就越高,并且您离 0 越远,您的精度就越低。这意味着随着游戏时间的进行,您的动画将不会以恒定的速率运行(经过足够的时间后,它们会显得断断续续、不一致、不流畅(。

更好的方法是有一个包装动画计数器,该计数器将增量时间相加,然后回绕到零(或者可能回绕到 0 + 一些余数,也许使用 fmod 之类的函数(。这将确保您的动画帧速率在整个游戏期间保持一致。