Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: SFML Draw() won't draw sprite on Window [SOLVED]  (Read 8949 times)

0 Members and 1 Guest are viewing this topic.

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
SFML Draw() won't draw sprite on Window [SOLVED]
« on: October 14, 2020, 10:03:30 am »
I'm creating a clone of space invaders, which actually is an old project that I'm attempting once more. The Draw function can draw everything like the Enemy Space Ship, the Bullets they shoot, but not the Player Ship that he uses to play the game. The most frustrating thing is that there is no error while compiling or executing the program.

Here's the code

Draw
        // Draw
        window.clear();

            // Draw Enemy
        for (unsigned int i = 0; i < e.size(); i++) {
            window.draw(e[i].sprite);
        }

            // Draw Enemy Bullet
        for (unsigned int i = 0; i < e.size(); i++) {
            if (e[i].b.bExist == true) {
                window.draw(e[i].b.sprite);
            }
        }

            // Draw Ship
        window.draw(ship.sprite);

        window.display();
 

Entities
#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include <stdlib.h>
#include <time.h>  

extern short WIDTH, HEIGHT;

struct Bullet {
        sf::Sprite sprite;
        bool bExist = false;
        float speed = 5;
        bool amEnemy;

        Bullet(bool amAnEnemy) : amEnemy(amAnEnemy) {
                sprite.setTexture(tbullet);
                sprite.setScale(0.05f,0.05f);
                if (amEnemy == true) {
                        sprite.rotate(90);
                }
                else sprite.rotate(270);
        }

        void handler() {

                // Should I Exist? & Move By Gravity
                        switch (amEnemy)
                        {
                        case true:
                                if (sprite.getPosition().y > HEIGHT) {
                                        bExist = false;
                                        break;
                                }
                                if (bExist == true) {
                                        sprite.move(0, speed);
                                }
                                break;
                        case false:
                                if (sprite.getPosition().y < 0) {
                                        bExist = false;
                                        break;
                                }
                                if (bExist == true) {
                                        sprite.move(0, -speed);
                                }
                                break;
                        }
        }

       

};

struct Enemy {
        sf::Sprite sprite;
        Bullet b = (Bullet)true;
       

        Enemy(int nIter) {
                sprite.setTexture(tenemy);
                sprite.setScale(0.1f, 0.1f);
                sprite.setPosition(WIDTH * nIter / 5.0f, 0.0f);
        }

        void Shoot() {
                b.bExist = true;
                b.sprite.setPosition(sprite.getPosition());
        }

        void handler() {
                if(b.bExist == false){
                        int possNum = rand() % 500 + 1;
                        if (possNum == 1) {
                                Shoot();
                        }
                }
        }


}enemy = (Enemy)1;

struct Ship {
        sf::Sprite sprite;
        Bullet b = (Bullet)false;

        Ship() {
                sprite.setTexture(tship);
                sprite.setScale(0.5,0.5);
                sprite.setPosition(WIDTH / 2 - sprite.getGlobalBounds().width / 2, HEIGHT * 5 / 6);
                std::cout << "Ship Builded\n";
        }
};
 

Thanks in advance
« Last Edit: October 16, 2020, 11:10:57 am by Ago19 »

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #1 on: October 14, 2020, 11:04:30 am »
Are you sure it's not drawn at the top of the screen?
Because 5 / 6 is equal to 0

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #2 on: October 14, 2020, 11:43:12 am »
Yes, I've also outputed the position and it says that is at y = 666.
However 5 / 6 != 0
The setPosition(WIDTH / 2, HEIGHT * 5 / 6) means to put the sprite at the 5 / 6 of the screen height, so in the lower part

Kvaz1r

  • Newbie
  • *
  • Posts: 39
    • View Profile
    • Email
Re: SFML Draw() won't draw sprite on Window
« Reply #3 on: October 14, 2020, 04:31:24 pm »
Yes, I've also outputed the position and it says that is at y = 666.
However 5 / 6 != 0
The setPosition(WIDTH / 2, HEIGHT * 5 / 6) means to put the sprite at the 5 / 6 of the screen height, so in the lower part

It probably expected to be so, but because both operands are integer C++ will use integer operations.
#include <iostream>

int main() {
        std::cout<<5 / 6<<'\n';
}
Output: 0

Of course in your code HEIGHT * 5 part is evaluate first, so it won't be 0.

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #4 on: October 14, 2020, 09:30:39 pm »
I've changed the code converting all integers in floats but the problem is the same

        Ship() {
                sprite.setTexture(tship);
                sprite.setScale(0.5f,0.5);
                sprite.setPosition((float)WIDTH / 2.0f - (float)sprite.getGlobalBounds().width / 2.0f, HEIGHT * 5.0f / 6.0f);
                std::cout << "Ship Builded\n";
        }
 

Kvaz1r

  • Newbie
  • *
  • Posts: 39
    • View Profile
    • Email
Re: SFML Draw() won't draw sprite on Window
« Reply #5 on: October 14, 2020, 09:41:16 pm »
In that case can you provide complete (minimal if possible) code for reproducing the behaviour?
Or maybe your project is on Github, Gitlab or something like that?

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #6 on: October 14, 2020, 10:33:46 pm »

main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <thread>
#include <vector>
#include <stdlib.h>
#include "Collision.hpp"
#include "TextureLoad.h"
#include "Entity.h"
#include "Threads.h"

short WIDTH = 600, HEIGHT = 800;
std::vector<Enemy> e;
Ship ship;

int main()
{
    srand(time(NULL));

    // Setup Game Window
    sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "Space Invaders");
    window.setFramerateLimit(60);

    // Load Textures
    textureLoad();

    // SetUp Level
    for (int i = 0; i < 5; i++) {
        e.push_back(enemy = (Enemy)i);
    }

    // Threads
        // Enemy
    std::thread th_enemy(EnemyThread);

    // Game Loop
    while (window.isOpen())
    {
        // Event Handler
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // Bullet Handler
        for (unsigned int i = 0; i < e.size(); i++) {
            if (e[i].b.bExist == true) {
                e[i].b.handler();
            }
        }

        // Draw
        window.clear();

            // Draw Enemy
        for (unsigned int i = 0; i < e.size(); i++) {
            window.draw(e[i].sprite);
        }

            // Draw Enemy Bullet
        for (unsigned int i = 0; i < e.size(); i++) {
            if (e[i].b.bExist == true) {
                window.draw(e[i].b.sprite);
            }
        }

            // Draw Ship
        window.draw(ship.sprite);

        window.display();
    }

    th_enemy.join();
    return 0;
}
 

TextureLoad.h
#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>



sf::Texture tship, tenemy, tbullet;

bool textureLoad() {
        if (tship.loadFromFile("../Textures/ship.png")) {
                std::cout << "Ship Texture Succesfully Loaded\n";
                if (tenemy.loadFromFile("../Textures/enemy.png")) {
                        std::cout << "Enemy Texture Succesfully Loaded\n";
                        if (tbullet.loadFromFile("../textures/bullet.png")) {
                                std::cout << "Bullet Texture Succesfully Loaded\n";
                                return true;
                        }
                        else return false;
                }
                else return false;
        }
        else return false;
}

 

Threads.h
#pragma once
#include <chrono>


extern std::vector<Enemy> e;
void EnemyThread() {
        auto startTimer = std::chrono::steady_clock::now();
        while (1) {
                auto endTimer = std::chrono::steady_clock::now();
        if (std::chrono::duration_cast<std::chrono::milliseconds>(endTimer - startTimer).count() >= 16.67) {
                    for (unsigned int i = 0; i < e.size(); i++) {
                            e[i].handler();
                    }
                                startTimer = std::chrono::steady_clock::now();
        }
        }
}

 

Entity.h
#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include <stdlib.h>
#include <time.h>  

extern short WIDTH, HEIGHT;

struct Bullet {
        sf::Sprite sprite;
        bool bExist = false;
        float speed = 5;
        bool amEnemy;

        Bullet(bool amAnEnemy) : amEnemy(amAnEnemy) {
                sprite.setTexture(tbullet);
                sprite.setScale(0.05f,0.05f);
                if (amEnemy == true) {
                        sprite.rotate(90);
                }
                else sprite.rotate(270);
        }

        void handler() {

                // Should I Exist? & Move By Gravity
                        switch (amEnemy)
                        {
                        case true:
                                if (sprite.getPosition().y > HEIGHT) {
                                        bExist = false;
                                        break;
                                }
                                if (bExist == true) {
                                        sprite.move(0, speed);
                                }
                                break;
                        case false:
                                if (sprite.getPosition().y < 0) {
                                        bExist = false;
                                        break;
                                }
                                if (bExist == true) {
                                        sprite.move(0, -speed);
                                }
                                break;
                        }
        }

       

};

struct Enemy {
        sf::Sprite sprite;
        Bullet b = (Bullet)true;
       

        Enemy(int nIter) {
                sprite.setTexture(tenemy);
                sprite.setScale(0.1f, 0.1f);
                sprite.setPosition(WIDTH * nIter / 5.0f, 0.0f);
        }

        void Shoot() {
                b.bExist = true;
                b.sprite.setPosition(sprite.getPosition().x / 2 + b.sprite.getPosition().x / 2, sprite.getPosition().y);
        }

        void handler() {
                if(b.bExist == false){
                        int possNum = rand() % 500 + 1;
                        if (possNum == 1) {
                                Shoot();
                        }
                }
        }


}enemy = (Enemy)1;

struct Ship {
        sf::Sprite sprite;
        Bullet b = (Bullet)false;

        Ship() {
                sprite.setTexture(tship);
                sprite.setScale(0.5f,0.5);
                sprite.setPosition((float)WIDTH / 2.0f - (float)sprite.getGlobalBounds().width / 2.0f, HEIGHT * 5.0f / 6.0f);
                std::cout << "Ship Builded\n";
        }
};
 

This is the whole code

Kvaz1r

  • Newbie
  • *
  • Posts: 39
    • View Profile
    • Email
Re: SFML Draw() won't draw sprite on Window
« Reply #7 on: October 14, 2020, 11:37:13 pm »
Well now it's obvious - (btw, code still doesn't compile), your texture load after initialization of global variable.
For quick fix add right after loading e.g:
    textureLoad();
    ship = Ship();

But I strongly recommend refactor all code.
« Last Edit: October 14, 2020, 11:38:46 pm by Kvaz1r »

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #8 on: October 15, 2020, 04:24:15 pm »
Thanks now it works but it's now creating 2 instances of Ship  :(
I've fixed it removing the constructor and writing all the code in a method called setUp, but it's not how I want to do it. I want to only write once Ship ship like I did with the Enemy instances.
I'm wondering why I had to add that line (ship = Ship() Is it the same as ship.Ship() ?). I'm pretty new to c++ so I still have a lot to learn.
I can't explain why it didn't compile on your computer, while on mine goes flawlessly. I have visual studio community
« Last Edit: October 15, 2020, 04:59:51 pm by Ago19 »

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #9 on: October 15, 2020, 07:52:33 pm »
I think I'm getting nuts. Maybe I just need a break  :o
Before optimizing the code I wanted to implement some more features, like making the ship shoot. But when I press the button to trigger the Shoot() function the Bullet's sprite isn't drawn on the screen, even if the function is called. Here's some code:

Ship Class:
struct Ship {
        sf::Sprite sprite;
        Bullet b = (Bullet)false;
        int speed = 5;
        enum Side {LEFT, RIGHT};

        // Keys
        bool isLeftPressed = false;
        bool isRightPressed = false;


        void setUp() {
                sprite.setTexture(tship);
                sprite.setScale(0.5f,0.5);
                sprite.setPosition((float)WIDTH / 2.0f - (float)sprite.getGlobalBounds().width / 2.0f, HEIGHT * 5.0f / 6.0f);
                std::cout << "Ship Builded\n";
        }

        void move(Side side) {
                switch (side)
                {
                case Ship::LEFT:
                        sprite.move(-speed, 0);
                        break;
                case Ship::RIGHT:
                        sprite.move(speed, 0);
                        break;
                default:
                        break;
                }
        }

        bool keepShipInScreen() {
                if (sprite.getPosition().x < 0) {
                        sprite.setPosition(0, sprite.getPosition().y);
                        return true;
                }
                else if (sprite.getPosition().x > WIDTH - sprite.getGlobalBounds().width) {
                        sprite.setPosition(WIDTH - sprite.getGlobalBounds().width, sprite.getPosition().y);
                        return true;
                }
                else return false;
        }

        void Shoot() {
                b.bExist = true;
                b.sprite.setPosition(sprite.getPosition().x + sprite.getGlobalBounds().width / 2 - b.sprite.getGlobalBounds().height / 2, sprite.getPosition().y);
        }

        void handler() {

                if (keepShipInScreen() == false) {
                        if (isLeftPressed == true) {
                                move(LEFT);
                        }
                        if (isRightPressed == true) {
                                move(RIGHT);
                        }
                }


                b.handler();

        }

}ship;
 

Player's Thread:
void ShipThread() {
        // Thread Settings
        auto ssTimer = std::chrono::steady_clock::now();
        while (1) {
                auto seTimer = std::chrono::steady_clock::now();
                if (std::chrono::duration_cast<std::chrono::milliseconds>(seTimer - ssTimer).count() >= 16.67) { // Set Looprate to 60
                        // Thread
                                // Player Input
                                        // Move Left
                        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                        {
                                ship.isLeftPressed = true;
                        }
                        else ship.isLeftPressed = false;
                                        // Move Right
                        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                        {
                                ship.isRightPressed = true;
                        }
                        else ship.isRightPressed = false;
                                        // Shoot
                        if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
                                ship.Shoot();
                        }
                                // Player Handler
                        ship.handler();

                        ssTimer = std::chrono::steady_clock::now(); // Restart Timer
                }
        }
}
 

Texture Loading Function:
sf::Texture tship, tenemy, tbullet;

bool textureLoad() {
        if (tship.loadFromFile("../Textures/ship.png")) {
                std::cout << "Ship Texture Succesfully Loaded\n";
                if (tenemy.loadFromFile("../Textures/enemy.png")) {
                        std::cout << "Enemy Texture Succesfully Loaded\n";
                        if (tbullet.loadFromFile("../textures/bullet.png")) {
                                std::cout << "Bullet Texture Succesfully Loaded\n";
                                return true;
                        }
                        else return false;
                }
                else return false;
        }
        else return false;
}
 

main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <thread>
#include <vector>
#include <stdlib.h>
#include "TextureLoad.h"
#include "Entity.h"
#include "Threads.h"

short WIDTH = 600, HEIGHT = 800;
sf::RenderWindow window;
std::vector<Enemy> e;


int main()
{
    srand(time(NULL));

    // Setup Game Window
    window.create(sf::VideoMode(WIDTH, HEIGHT), "Space Invaders");
    window.setFramerateLimit(60);

    // Load Textures
    textureLoad();
    ship.setUp();
    // SetUp Level
    for (int i = 0; i < 5; i++) {
        e.push_back(enemy = (Enemy)i);
    }

    // Threads
        // Enemy
    std::thread th_enemy(EnemyThread);
        // Ship
    std::thread th_ship(ShipThread);


    // Game Loop
    while (window.isOpen())
    {
        // Event Handler
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // Bullet Handler
        for (unsigned int i = 0; i < e.size(); i++) {
            if (e[i].b.bExist == true) {
                e[i].b.handler();
            }
        }

        // Draw
        window.clear();

            // Draw Enemy
        for (unsigned int i = 0; i < e.size(); i++) {
            window.draw(e[i].sprite);
        }

            // Draw Enemy Bullet
        for (unsigned int i = 0; i < e.size(); i++) {
            if (e[i].b.bExist == true) {
                window.draw(e[i].b.sprite);
            }
        }

            // Draw Ship
        window.draw(ship.sprite);
           
            // Draw Ship Bullets
        if (ship.b.bExist == true) {
            window.draw(ship.b.sprite);
        }

        window.display();
    }

    th_enemy.join();
    th_ship.join();
    return 0;
}
 

I looked if the sprite was drawn out of the windows but it wans't. I checked if the texture was loaded correctly and it was, also because the bullets of the enemies work fine. I have no idea
PLS HELP ME!! :P

Kvaz1r

  • Newbie
  • *
  • Posts: 39
    • View Profile
    • Email
Re: SFML Draw() won't draw sprite on Window
« Reply #10 on: October 15, 2020, 11:26:56 pm »
I'm wondering why I had to add that line (ship = Ship() Is it the same as ship.Ship() ?). I'm pretty new to c++ so I still have a lot to learn.

Because at the moment when global variable get values (i.e. constructor is called) your texture is not yet loaded (it's loading from file inside main function). No, it's not the same (I'm not even sure that ship.Ship() compiled)

About your bullet sprite problem...
Did you try to add setUp method also for bullet?  ;)

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window
« Reply #11 on: October 16, 2020, 08:43:59 am »
Quote
Because at the moment when global variable get values (i.e. constructor is called) your texture is not yet loaded (it's loading from file inside main function)
You're right, thanks for the explenation
Quote
No, it's not the same (I'm not even sure that ship.Ship() compiled)
You're right 2.0. As much as I've understood ship = Ship(); is like calling the constructor. But I was wondering why Ship ship doesn't do the same.

Quote
About your bullet sprite problem...
Did you try to add setUp method also for bullet?  ;)
You're right 3.0. I thought that the reason why the sprite didn't load was different from the previous one, while in truth was the exact same
;)

Kvaz1r

  • Newbie
  • *
  • Posts: 39
    • View Profile
    • Email
Re: SFML Draw() won't draw sprite on Window
« Reply #12 on: October 16, 2020, 10:52:57 am »
As much as I've understood ship = Ship(); is like calling the constructor. But I was wondering why Ship ship doesn't do the same.
ship = Ship();
it's assign to variable ship of new object with type Ship.
Ship ship
it's creation of new variable ship with type Ship. Different scopes can have different variables with same name i.e. hidding.

Ago19

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: SFML Draw() won't draw sprite on Window [SOLVED]
« Reply #13 on: October 16, 2020, 11:12:46 am »
Thank you  ;D