简体   繁体   English

SFML-尝试从矢量绘制精灵时程序崩溃

[英]SFML - program crashes when trying to draw sprite from vector

I am writing this relatively simple program to fire a small projectile from a moving character when the space bar is pressed. 我正在编写这个相对简单的程序,当按下空格键时,可以从移动的角色发射小弹丸。

The program compiles without any errors(in code blocks) and runs until the space bar is pressed. 程序编译无误(在代码块中),并运行到按下空格键为止。 Instead of launching the projectile, the program promptly crashes. 该程序没有启动弹丸,而是立即崩溃。

I think I have been able to isolate the crash to the line where I draw the projectiles to the screen(ln. 83). 我认为我已经能够将坠机事件隔离到将弹丸绘制到屏幕的那条线上(第83页)。 I just used cout statements on the lines before and after and the second statement didn't show. 我只是在前后的行上使用了cout语句,而第二条语句没有显示。

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

I believe that all of my code will be necessary to address this issue so I have posted all of it. 我认为解决此问题将需要我的所有代码,因此我已发布了所有代码。

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

Thanks so much for the help. 非常感谢帮忙。

EDIT: I tried using the debugger but couldn't figure anything out. 编辑:我尝试使用调试器,但什么都找不到。 A link to a good article on codeblocks debugging would be great. 链接到一篇有关代码块调试的好文章的链接将非常有用。

I was able to solve this myself. 我自己解决了。 I figured out that I had to reference the Bullet class by pointer, and make sure the texture was also public. 我发现必须通过指针引用Bullet类,并确保纹理也是公共的。 I was also using constructors wrong, and got rid of those. 我也错误地使用了构造函数,并且摆脱了这些构造函数。

My approximate solution was this... 我的大概解决方案是...

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

also had to change vector declaration in class 还必须在类中更改向量声明

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

and thanks again to the people who tried to answer. 再次感谢那些试图回答的人。

Well, you're coding the game quite wrong ! 好吧,您编写的游戏代码非常错误!

What I suggest: 我的建议:

  • You should create a player and a bullet classes, 您应该创建一个球员和一个子弹班,

  • each class as a render method and an update method - the update method has a dt (elapsed time till last frame) parameter, 每个类分别作为渲染方法和更新方法-更新方法具有dt(到最后一帧为止的经过时间)参数,

  • the player class has a "move" and a "fire" methods, 播放器类具有“移动”和“触发”方法,

  • in the game loop, you first read input (and call the move or fire method if needed), update all the objects (player and bullets position) and draw all, 在游戏循环中,您首先要读取输入(并在需要时调用move或fire方法),更新所有对象(玩家和项目符号的位置)并绘制所有内容,

  • the move method should give velocity to the player, move方法应使玩家具有速度,

  • the fire method should create bullets with velocity, 射击方法应以速度制造子弹,

  • the update method should compute the new position (with velocity and dt), 更新方法应计算新位置(具有速度和dt),

  • player and bullet could derivate from a basis game element class (witch compute position, collisions, etc...). 玩家和子弹可能来自基础游戏元素类(女巫计算位置,碰撞等)。

You have to reset the clock: 您必须重置时钟:

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

And you should load the texture of the projectile only once, and use it in all instances of the class Projectile. 而且,您应该只加载一次射弹的纹理,并在Projectile类的所有实例中使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM