Garmaine Staff asked 2 years ago

I'm trying to learn C++, and I'm making this little space-invader-like game to get better at it. Currently everything works just fine but for some reason the performance of the game is kind of terrible considering how simple the graphics are (the game runs smoothly for a while and then stops for like half a second, constantly). I'm pretty sure the lag is due to the amount of bullets I'm removing and creating from the vector containing them (I'm removing the bullets that go outside the screen because there's no point in updating them or rendering them). So how could I fix this? I checked the game loop and the problem isn't there.

Code below

player.h:

#pragma once
#include <vector>
#include <iostream>
#include "entity.h"
#include "SFML/Graphics.hpp"
#include "vector.h"

class Player : public Entity {
private:
    int f_lastshot = 0;
    const double shoot_delay = 0.5;
    const float bullet_speed = 1, speed = 0.75;
    std::vector<Entity> bullets;
    sf::Clock *c;
    sf::Sprite bullet_sprite;
public:
    Player(Vector &pos, int w, int h, sf::Sprite &spr);
    ~Player();
    void init();
    void update();
    void render(Window &win);
    void shoot();
};

player.cpp:

#include "player.h"

Player::Player(Vector &pos, int w, int h, sf::Sprite &spr) : Entity() {
    this->pos = pos;
    this->sprite = spr;
    this->width = w;
    this->height = h;
    float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
    float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
    sprite.setScale(scale_x, scale_y);
}

void Player::update() {
    if (sf::Mouse::isButtonPressed(sf::Mouse::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
        if ((double)(f_lastshot / 60) > shoot_delay) // shoot only if enough time has passed
            shoot();
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) dir.setX(-speed); // move left
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) dir.setX(speed); // move right
    else dir.setX(0); // stop if no button is being pressed
    f_lastshot++; 
    pos = pos + dir; // add the direction to the position

    for (Entity &e : bullets) {
        e.update(); // update each bullet
        if (e.getPos().getY() < 0) // if the bullet is outside the screen delete it
            bullets.erase(bullets.begin()); 
    }
}

void Player::render(Window &win) {
    sprite.setPosition(pos.getX(), pos.getY()); // update the position of the sprite
    win.render(sprite);
    for (Entity &bullet : bullets) 
        bullet.render(win);
}

void Player::shoot() {
    f_lastshot = 0;
    bullets.push_back(Entity::Entity(Vector::Vector(pos.getX() + width / 2 - 8, pos.getY()), 16, 32, bullet_sprite, Vector::Vector(0,-bullet_speed)));
}

void Player::init() {
    if (c == nullptr) c = new sf::Clock();
    else c->restart();
    dir.setX(0); dir.setY(0);

    sf::Texture *bullet_texture = new sf::Texture();
    if (!bullet_texture->loadFromFile("bullet.png"))
        std::cerr << "Could not load bullet image" << std::endl;

    bullet_sprite.setTexture(*bullet_texture);
}


Player::~Player() {
    delete bullet_sprite.getTexture();
    delete c;
}

entity.h:

#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include "vector.h"
#include "window.h"

class Entity {
protected:
    Vector pos;
    sf::Sprite sprite;
    int width, height;
    Vector dir; // the direction
public:
    Entity();
    Entity(Vector &pos, int w, int h, sf::Sprite &spr);
    Entity(Vector pos, int w, int h, sf::Sprite &spr);
    Entity(Vector pos, int w, int h, sf::Sprite &spr, Vector dir);

    void update();
    void render(Window &win);
    bool collides(Entity &other) const;
public:
    Vector getPos() const;
    Vector getDirection() const;
    sf::Sprite getSprite() const;
    int getWidth() const;
    int getHeight() const;
    void setPos(Vector &pos);
    void setWidth(int width);
    void setHeight(int height);
    void setSize(int width, int height);
    void setSprite(sf::Sprite &sprite);
    void setDirection(Vector dir);
};

entity.cpp:

#include "entity.h"

Entity::Entity() {}

Entity::Entity(Vector &pos, int w, int h, sf::Sprite &spr)
    :  pos(pos), width(w), height(h) {
    this->sprite = spr;
    float scale_x = (float)w/(float)spr.getTexture()->getSize().x;
    float scale_y = (float)h/(float)spr.getTexture()->getSize().y;
    sprite.setPosition(pos.getX(), pos.getY());
    sprite.setScale(scale_x, scale_y);
}

Entity::Entity(Vector pos, int w, int h, sf::Sprite &spr)
    : pos(pos), width(w), height(h) {
    this->sprite = spr;
    float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
    float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
    sprite.setPosition(pos.getX(), pos.getY());
}

Entity::Entity(Vector pos, int w, int h, sf::Sprite &spr, Vector dir)
    : pos(pos), width(w), height(h) {
    this->sprite = spr;
    this->dir = dir;
    float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
    float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
    sprite.setPosition(pos.getX(), pos.getY());
}

bool Entity::collides(Entity &other) const {
    bool x_coll = (pos.getX() + width> other.getPos().getX() && pos.getX()< other.getPos().getX())||(pos.getX() < other.getPos().getX() + other.getWidth() && pos.getX() > other.getPos().getX());
    bool y_coll = (pos.getY() + height > other.getPos().getY() && pos.getY() < other.getPos().getY()||(pos.getY() < other.getPos().getY() + other.getHeight() && pos.getY() > other.getPos().getY()));
    return (x_coll && y_coll);
}

void Entity::render(Window &win) {
    sprite.setPosition(pos.getX(), pos.getY());
    win.render(sprite);
}

void Entity::update() {
    pos = pos + dir;
}

Vector Entity::getPos() const { return pos; }
int Entity::getWidth() const { return width; }
int Entity::getHeight() const { return height; }
sf::Sprite Entity::getSprite() const { return sprite; }
Vector Entity::getDirection() const { return dir; }
void Entity::setPos(Vector &pos) { this->pos = pos; }
void Entity::setWidth(int width) { this->width = width; }
void Entity::setHeight(int height) { this->height = height; }
void Entity::setSprite(sf::Sprite &sprite) { this->sprite = sprite; }
void Entity::setDirection(Vector dir) { this->dir = dir; }
void Entity::setSize(int width, int height) {
    this->width = width;
    this->height = height;
}