user2315574
user2315574

Reputation: 11

SFML Game Slows Down When Shooting Bullets

I am making an asteroids game in C++ using SFML. I seem to have a problem though with shooting bullets. Although the class seems to work each time a bullet is shot the game significantly slows down. This is the code for the spaceship and the bullets. I just can't seem to find what's wrong with it! Thank you for your time.

This is the Code of the Ship:

#include "Spaceship.h"

Spaceship::Spaceship(void){}

Spaceship::~Spaceship(void){}

void Spaceship::LoadResources()
{

    if(!shipAnimImg.LoadFromFile("Resources/Images/SpaceshipAnimation.png"))
        std::cout <<"Could not locate the ship animation image" <<std::endl;

    if(!shipIdleImg.LoadFromFile("Resources/Images/SpaceshipIdle.png"))
        std::cout <<"Could not locate the ship idle image" <<std::endl;

    if(!bulletImg.LoadFromFile("Resources/Images/Bullet.png"))
        std::cout <<"Could not locate the bullet image" <<std::endl;

    shipSpr.SetImage(shipIdleImg);
    shipSpr.SetScale(0.5,0.5);
    shipSpr.SetCenter(shipIdleImg.GetWidth() / 2,shipIdleImg.GetHeight() / 2);

    x = DEFAULT_SCREENWIDTH / 2; 
    y = DEFAULT_SCREENHEIGHT / 2;

    shipSpr.SetPosition(x,y);
    shipSpr.SetRotation(90);

    std::cout<<shipSpr.GetCenter().x<<std::endl;
    std::cout<<shipSpr.GetCenter().y<<std::endl;

    vx = 0.2;
    vy = 0.2;

    isBulletOnScreen = false;
    isPressed = false;
}

void Spaceship::UnloadResources(){}

void Spaceship::Update(sf::RenderWindow &Window,sf::Event event)
{

    if (Window.GetInput().IsKeyDown(sf::Key::A))
    {
        shipSpr.Rotate(0.08);
    }

    if (Window.GetInput().IsKeyDown(sf::Key::D))
    {
        shipSpr.Rotate(-0.08);
    }

    if (Window.GetInput().IsKeyDown(sf::Key::W))
    {
        x += (cos(shipSpr.GetRotation() * (3.14159265/180.0)) *0.2);
        y -= (sin(shipSpr.GetRotation() * (3.14159265/180.0)) *0.2);
        shipSpr.SetPosition(x,y);
    }



    if (Window.GetInput().IsKeyDown(sf::Key::Space) && !isPressed)
    {   
    isBulletOnScreen = true;
    isPressed  = true;
    bullets.push_back(new Bullet(shipSpr.GetPosition().x,shipSpr.GetPosition().y,0.3,shipSpr.GetRotation(),bulletImg));
    }

    if (event.Type == sf::Event::KeyReleased)
    {
        isPressed  = false;
    }

    if(bullets.size() != 0)
    {
        for (int i=0; i<bullets.size(); i++)
        {
            bullets[i]->Update(Window,event);
            if ((bullets[i]->GetX() > DEFAULT_SCREENWIDTH + 40) || (bullets[i]->GetX() < 0 - 40) ||
                (bullets[i]->GetY() > DEFAULT_SCREENWIDTH + 40) || (bullets[i]->GetY() < 0 - 40))
                {
                    bullets.erase(bullets.begin() +i);
                }
        }
        std::cout<<bullets.size()<<std::endl;
    }
    std::cout<<bullets.size()<<std::endl;

}

void Spaceship::Draw(sf::RenderWindow &Window)
{
    if(isBulletOnScreen)
    for (int i=0; i<bullets.size(); i++)
    {
        Bullet *cur = bullets[i];
        bullets[i]->Draw(Window);
        std::cout<<bullets.size()<<std::endl;
    }

    Window.Draw(shipSpr);
}

And this is for the Bullet:

#include "Bullet.h"

Bullet::Bullet(void){}

Bullet::Bullet(float x,float y,float v,float r,sf::Image image)
{
    LoadResources(x,y,v,r,image);
}

Bullet::~Bullet(void){}

void Bullet::LoadResources(float x,float y,float v,float r , sf::Image image)
{
    this->x = x;
    this->y = y;
    this->v = v;

    bulletImg = image;
    bulletSpr.SetImage(bulletImg);
    bulletSpr.SetScale(0.5,0.5);
    bulletSpr.SetCenter(bulletImg.GetWidth() / 2,bulletImg.GetHeight() / 2);
    bulletSpr.SetPosition(x,y);
    bulletSpr.SetRotation(r);
}

void Bullet::UnloadResources(){}

void Bullet::Update(sf::RenderWindow &Window,sf::Event event)
{
    x += (cos(bulletSpr.GetRotation() * (3.14159265/180.0)) *v);
    y -= (sin(bulletSpr.GetRotation() * (3.14159265/180.0)) *v);

    bulletSpr.SetPosition(x,y);
}

void Bullet::SetX(float x)
{
    this->x = x;
}

void Bullet::SetY(float y)
{
    this->y = y;
}

void Bullet::SetRotation(float r)
{
    rotation = r;
}

float Bullet::GetX()
{
    return x;
}

float Bullet::GetY()
{
    return y;
}

void Bullet::Draw(sf::RenderWindow &Window)
{
    Window.Draw(bulletSpr);
}

EDIT: Changed the code so that it loads the image inside the Spaceship Class and passes it to the Bullet's Resources after it is created. The problem still remains the same though. The game becomes more and more slower each time a bullet is shot and it remains slow until it is erased.

Upvotes: 1

Views: 2348

Answers (2)

Victor Sand
Victor Sand

Reputation: 2340

1. You are loading the Bullet PNG image from disk every time you create a new object (often, if you like shooting). The loading from disk is probably going to be very slow. Try to reuse the same image several times instead!

You could probably pull the LoadFromFile function out of LoadResources and put it somewhere where it would last for the duration of the game. Then just have LoadResources refer to that place whenever a new bullet needs to be created. The same goes for any other images or resources that can be reused in your game.

2. I also saw that you have std::cout in your code. Try removing all of those that are in the rendering loop, as printing is slow.

for (int i=0; i<bullets.size(); i++)
{
    Bullet *cur = bullets[i];
    bullets[i]->Draw(Window);
    std::cout<<bullets.size()<<std::endl; // This is going to be slow
}

3. You might also want to look at the bullets vector. When adding bullets to it,push_back changes the size of the vector, and that takes some allocation and deallocation of memory each time. A better approach would be to make room for a maximum number of bullets to start with (using the resize function for example) so that the vector doesn't change size whenever a bullet is created.

if (Window.GetInput().IsKeyDown(sf::Key::Space) && !isPressed)
{   
    isBulletOnScreen = true;
    isPressed  = true;
    bullets.push_back(new Bullet(...); // avoid this
}

Upvotes: 3

user1944441
user1944441

Reputation:

Everytime you call a new Bullet

Bullet::Bullet(float x,float y,float v,float r)
{
    LoadResources(x,y,v,r);
}

You also call LoadResources(x,y,v,r) which calls

bulletImg.LoadFromFile("Resources/Images/Bullet.png")

and that call read a file from a disk, which is a very slow operation, in order of magnitudes slower than anything else, so your program stops for the duration of the load.

Upvotes: 1

Related Questions