我一直在尝试通过创建指向敌人对象的指针矢量来更新游戏中的敌人精灵,然后使用更新功能为属于这些对象的精灵设置动画。尽管敌人的精灵会显示在屏幕上,但是它们不会被更新,因此看起来好像已经冻结了。
这是我编写代码的方式:
#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;
}
Enemy.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
};
Enemy.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 :(得分:0)
////////////////////////////////////////////////////////////
/// \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();
sf::Clock
的{{1}}代替dt
,并将其移出事件循环(您希望它在程序运行时累积,而不是每次都重置为0。< / li>
sf::Time
与
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
如果游戏时间是浮动的,则您不想运行与游戏时间有关的动画。之所以不是这样,是因为浮点数在不同的值范围内具有不同的精度,该数字越接近0,则精度越高;距离0越远,精度就越低。这意味着随着游戏时间的推移,您的动画将不会以恒定的速率运行(经过足够的时间后,它们似乎会变得不稳定,不一致,不流畅)。
一种更好的方法是使用一个包装动画计数器,该计数器可以将增量时间相加,然后包装回零(或者可以包装回0 +一些余数,也许使用类似fmod的函数)。这样可以确保您的动画帧频在整个游戏过程中保持一致。