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

Author Topic: Presentation and question (initialise sf::Texture)  (Read 2165 times)

0 Members and 1 Guest are viewing this topic.

Gaaza

  • Newbie
  • *
  • Posts: 6
    • View Profile
Presentation and question (initialise sf::Texture)
« on: July 22, 2018, 11:45:54 am »
Hi!

My name is Gaaza. Nice to meet all of you. I have done my presentation here because I didn't see any presentations topic.
I am not a english speaker, so I have to apologise for my english.
Also, I am a completely beginner in C++, learning through reference books and SFML.

Next, the question. I did a little program to see how textures are working before programming a class for sprite animation. The program is changing a texture (so, the drawing) every second.
What I found is that if I comment the line in red (texture.loadFromFile("0.png");) the screen turns completely black and it doesn't work, but if I uncomment that line works fine.

Do I need to initialise a texture before to assign it to a sprite?

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>

class Ejemplo{

public:
    void setTexture(sf::Texture& tex);
    sf::Sprite getSprite();

private:
    sf::Sprite sprite;

};

void Ejemplo::setTexture(sf::Texture& tex){
    sprite.setTexture(tex);
    std::cout << "Direccion tex: " << &tex << std::endl;
}
sf::Sprite Ejemplo::getSprite(){
    return sprite;
}


int main()
{
    sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");

    Ejemplo ejemplo;
    sf::Texture texture;
    sf::Sprite sprite;

    sprite.setPosition(0, 0);

    texture.loadFromFile("0.png"); //this is the strange line to comment or uncomment
    ejemplo.setTexture(texture);

    sf::Clock clk_temp;
    sf::Time timer_temp;;

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

        timer_temp = clk_temp.getElapsedTime();
        float delay = timer_temp.asSeconds();

        if(delay < 1) texture.loadFromFile("0.png");
        if(delay > 1) texture.loadFromFile("1.png");
        if(delay > 2) clk_temp.restart();

        sprite = ejemplo.getSprite();

        window.clear();
        window.draw(sprite);
        window.display();
    }

    std::cout << "Direccion texture: " << &texture << std::endl;

    return 0;
}
 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Presentation and question (initialise sf::Texture)
« Reply #1 on: July 22, 2018, 01:09:08 pm »
When you set the texture of a sprite, it also sets the sprite's size based on the size of the texture and its texture rectangle (part of the texture to use). When you comment out that line, the texture is zero in size when you set the sprite so the sprite stays 0x0 size until changed, which you don't do.

You'll find that if you set the texture after loading each time, this should fix your strangeness. Basically, the sprite needs setting to the texture when it has a size so needs to be loaded.

Actually, this is not strictly true because you can set the texture rectangle at any time and that can be used to size the sprite. So, a simple
sprite.setTextureRectangle(sf::IntRect(0, 0, width, height));
would set the size of the sprite in advance (it could replace the original loading of the texture, for example).

So, that's why.


However, there are some things you should really considering changing in this code, especially linked to your texture usage.
The big one is that you load texture from files every frame/cycle of the main loop. Loading from file is not only significant enough to slow down the program but also not necessary more than one: simply load before the main loop any textures you will need and then switch amongst them in the program.

Load them in before the loop:
sf::Texture texture0;
sf::Texture texture1;
if (!texture0.loadFromFile("0.png")) ||
    !texture1.loadFromFile("1.png")))
    return EXIT_FAILURE;

Switch between them in the program:
if (delay < 1) sprite.setTexture(texture0);
if (delay > 1) sprite.setTexture(texture1);
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Gaaza

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Presentation and question (initialise sf::Texture)
« Reply #2 on: July 23, 2018, 09:51:12 am »
When you set the texture of a sprite, it also sets the sprite's size based on the size of the texture and its texture rectangle (part of the texture to use). When you comment out that line, the texture is zero in size when you set the sprite so the sprite stays 0x0 size until changed, which you don't do.

You'll find that if you set the texture after loading each time, this should fix your strangeness. Basically, the sprite needs setting to the texture when it has a size so needs to be loaded.

Actually, this is not strictly true because you can set the texture rectangle at any time and that can be used to size the sprite. So, a simple
sprite.setTextureRectangle(sf::IntRect(0, 0, width, height));
would set the size of the sprite in advance (it could replace the original loading of the texture, for example).

So, that's why.

Thank you for your help! It makes sense! As I am not using the rectangle attached to the sprite class I didn't think about it.

However, there are some things you should really considering changing in this code, especially linked to your texture usage.
The big one is that you load texture from files every frame/cycle of the main loop. Loading from file is not only significant enough to slow down the program but also not necessary more than one: simply load before the main loop any textures you will need and then switch amongst them in the program.

Load them in before the loop:
sf::Texture texture0;
sf::Texture texture1;
if (!texture0.loadFromFile("0.png")) ||
    !texture1.loadFromFile("1.png")))
    return EXIT_FAILURE;

Switch between them in the program:
if (delay < 1) sprite.setTexture(texture0);
if (delay > 1) sprite.setTexture(texture1);

Thank you for your advices! By now I am doing the "loadingFromFile" in the constructor of the objects and inserting them into a map with a string (the path) as key value and the sf::Texture as the mapped value.
Until now I was drawing by moving the same sprite and setting the texture, but now I am going to create a vector of sprites to avoid move them, in order to simplify collision detection.


Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Presentation and question (initialise sf::Texture)
« Reply #3 on: July 23, 2018, 11:05:08 am »
For sprite animation, it is common to put the different frames of the animation into the same image (often known as a sprite sheet or similar), load it into a single texture and then set the texture rectangle to animate instead of constantly setting the sprite's texture.
You can also include frames from other animation into the same sheet/image and re-use the same texture for multiple objects and animations!
It can be pretty simple to use an image editor to put multiple small images into one large image. There are also programs available that can do this automatically...

You don't have to do all this texture rectangle manipulation yourself manually, of course. Selba Ward's Gallery Sprite stores the texture rectangles internally and allows you to just choose a 'frame' and it will adjust itself automatically. It also includes alignment of frames so you can have frames that are different shapes and sizes and still have them match how they should!
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Gaaza

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Presentation and question (initialise sf::Texture)
« Reply #4 on: July 23, 2018, 10:12:46 pm »
Thank you again for your response!

At the very first time, when I was looking for sprites I found a lot of "Atlas sprite", which I thought it was a awkward way to organise images to load them into a game. Then, I found individual sprites, which I am using in my project.
With your answers it makes sense to put the atlas sprite into a texture and move the rectangle to show what I need each moment, but I will consider this in the futur. By now, although I know there are some libraries like Thor, 2DBox, and now, Selba Ward's Gallery Sprite, I want to do most of the things on my own with SFML as starting point. I know it is like trying to invent the wheel, as these libraries are much better than the one I could program, but I think it is a good way to learn how to program and how the API, C++ and the game animation works.

But when I get tired of programming that part, or mucho more interested in another parts of the project, I am pretty sure I will use them.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Presentation and question (initialise sf::Texture)
« Reply #5 on: July 23, 2018, 11:47:35 pm »
If you want to do stuff yourself for learning purposed, I totally understand. Gallery Sprite is simple a prepared version that can be used instantly but you can roll your own basic thing pretty easily, something like:
sf::Texture texture;
std::vector<sf::IntRect> textureRectangles;
sf::Sprite sprite(texture);
Then, add the textureRectangles (one for each frame in the texture).
To use a frame, just set the texture rectangle from the vector:
sprite.setTextureRect(textureRectangles[3]); // use the fourth frame
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Gaaza

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Presentation and question (initialise sf::Texture)
« Reply #6 on: July 25, 2018, 04:20:48 pm »
Very useful!! Thanks fo all!  ;D ;D ;D ;D