【问题标题】:SFML - program crashes when trying to draw sprite from vectorSFML - 尝试从矢量绘制精灵时程序崩溃
【发布时间】:2014-05-17 23:36:24
【问题描述】:

我正在编写这个相对简单的程序,以在按下空格键时从移动的角色发射一个小弹丸。

程序编译没有任何错误(在代码块中)并运行直到按下空格键。程序没有发射弹丸,而是立即崩溃。

我想我已经能够将崩溃隔离到我将弹丸绘制到屏幕上的线(ln. 83)。我只是在之前和之后的行中使用了 cout 语句,而第二个语句没有显示。

for (int ii = 0; ii < inMotion.size(); ii++)
{
    window.draw(inMotion[ii].bulletSprite);
}

我相信我的所有代码都是解决这个问题所必需的,所以我已经发布了所有代码。

#include <iostream>
#include <SFML/Graphics.hpp>
#include <string.h>
#include <math.h>
#include <vector>

using namespace std;
class Projectile
{
public:
    Projectile(int, string);
    void moveBullet();
    sf::Sprite bulletSprite;
private:
    sf::Texture bulletTexture;
    int speed;
    string bulletTextureString;
};

Projectile::Projectile(int s, string t)
{
    speed = s;
    bulletTextureString = t;
    if(!bulletTexture.loadFromFile((bulletTextureString).c_str()))
    {
        cout << "error";
    }
    bulletSprite.setTexture(bulletTexture);
}
void Projectile::moveBullet()
{
    bulletSprite.move(speed, 0);
}

class thePlayer
{
public:
    void Fire(sf::Time);
    void Walk();
    void Draw(sf::RenderWindow&);
    void Create(string);
    sf::Time lastShot;
private:
    vector<Projectile> inMotion;
    sf::Texture playerTexture;
    sf::Sprite playerSprite;
    string playerTextureString;
    int moveSpeed = 5;

}; 

void thePlayer::Create(string s)
{
    playerTextureString = s;

    if(!playerTexture.loadFromFile((playerTextureString).c_str()))
    {
        cout << "error";
    }
    playerSprite.setTexture(playerTexture);
}
void thePlayer::Fire(sf::Time time)
{
    sf::Time shotDelay = sf::milliseconds(100);
    if(time - lastShot >= shotDelay)
    {
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
        {
            Projectile bullet(15, "fireball.png");
            bullet.bulletSprite.setPosition(playerSprite.getPosition());
            inMotion.push_back(bullet);
        }
    } 
    for(int ii = 0; ii < inMotion.size(); ii++)
    {
        inMotion[ii].moveBullet();
    }
}
void thePlayer::Draw(sf::RenderWindow& window)
{
    for (int ii = 0; ii < inMotion.size(); ii++)
    {
        window.draw(inMotion[ii].bulletSprite);
    }
    window.draw(playerSprite);
}
void thePlayer::Walk()//awsd standart movement
{
    int x = 0;
    int y = 0;
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
    {
        x-= moveSpeed;
    }
    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
    {
        x+= moveSpeed;
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    {
        y-= moveSpeed;
    }
    else if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
    {
        y+= moveSpeed;
    }
    playerSprite.move(x, y);
}

class Game
{
public:
    void Update(sf::RenderWindow&, sf::Time);
    void Start(sf::Time);
    sf::Clock clock;
    thePlayer player;

private:

};

void Game::Start(sf::Time time)
{
    player.Create("block.png");
    player.lastShot = time;
}
void Game::Update(sf::RenderWindow& window, sf::Time time)
{
    player.Fire(time);
    player.Walk();
    player.Draw(window);
}

int main()
{
    sf::RenderWindow window(sf::VideoMode(1000, 1000), "Menu");
    window.setFramerateLimit(60);
    Game theGame;
    sf::Clock clock;
    sf::Time startTime = clock.restart();
    theGame.Start(startTime);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear(sf::Color::White);
        sf::Time elapsed = clock.getElapsedTime();
        theGame.Update(window, elapsed);
        window.display();
    }
    return 0;
}

非常感谢您的帮助。

编辑:我尝试使用调试器但无法解决任何问题。一个关于代码块调试的好文章的链接会很棒。

【问题讨论】:

    标签: c++ vector sfml


    【解决方案1】:

    我自己解决了这个问题。我发现我必须通过指针引用 Bullet 类,并确保纹理也是公开的。我也错误地使用了构造函数,并摆脱了那些。

    我的大致解决方案是这样的......

    void thePlayer::Fire(sf::Time time)
    {
        sf::Time shotDelay = sf::milliseconds(100);
        if(time - lastShot >= shotDelay)
        {
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
            {
                Projectile *bullet = new Bullet;
                bullet->bulletSprite.setPosition(playerSprite.getPosition());
                inMotion.push_back(bullet);
            }
        } 
        for(int ii = 0; ii < inMotion.size(); ii++)
        {
            inMotion[ii]->moveBullet();
        }
    

    还必须更改类中的向量声明

    //...
    vector<Bullet*> Bullets;
    //...
    

    再次感谢尝试回答的人。

    【讨论】:

      【解决方案2】:

      好吧,你的游戏编码完全错误!

      我的建议:

      • 您应该创建一个播放器和一个子弹类,

      • 每个类作为一个渲染方法和一个更新方法——更新方法有一个 dt(到最后一帧的经过时间)参数,

      • 玩家类有一个“move”和一个“fire”方法,

      • 在游戏循环中,您首先读取输入(并在需要时调用 move 或 fire 方法),更新所有对象(玩家和子弹位置)并绘制所有对象,

      • move 方法应该为玩家提供速度,

      • fire 方法应该创建具有速度的子弹,

      • 更新方法应计算新位置(使用速度和 dt),

      • 玩家和子弹可以派生自基础游戏元素类(女巫计算位置、碰撞等...)。

      【讨论】:

      • 感谢您的回复。虽然我同意我的代码可以写得更好,但你没有回答我的问题。我希望能更深入地了解导致程序崩溃的实际原因。
      • 是的,但我已经尝试过你的代码(在 OSX 下) - 它可以编译,玩家根据键移动,但子弹不起作用。
      【解决方案3】:

      你必须重置时钟:

      sf::Time elapsed = clock.restart();
      

      您应该只加载一次弹丸的纹理,并在 Projectile 类的所有实例中使用它。

      【讨论】:

      • 那行不通。重置时钟只是防止弹丸发射(因此不调用导致崩溃的函数)。也许您的答案背后还有其他想法?
      • 对不起,我认为elapsed 必须包含自上一帧以来经过的时间。直到现在我才意识到您正在使用固定的时间步长(我不推荐)。一个问题可能是您没有更新lastShot,并且在每一帧中都会创建一个弹丸。我建议你在第 83 行设置一个断点,然后注意向量是否有正确的数据。
      猜你喜欢
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多