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

Author Topic: Vector elements keep changing textures. [SOLVED]  (Read 1829 times)

0 Members and 1 Guest are viewing this topic.

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Vector elements keep changing textures. [SOLVED]
« on: June 07, 2020, 12:50:56 pm »
Hello,I'm trying to create a simple Shoot 'em Up game in SFML,and I created an entity class called "enemy" currently containing two members,a texture and a shape:

class enemy {
public:
        sf::Texture t;
        sf::RectangleShape s;

};
 

I created two objects from this class,one called "basic_enemy",and the other a vector called "enemies":

enemy basic_enemy;
std::vector<enemy> enemies;
 

I then wrote a function that randomly chooses between two sets of parameters to assign to the "basic_enemy" object,effectively choosing what type of enemy it will be (So far there are only two):

void enemy_spawner() {

        std::string texture_path;
        sf::Vector2f enemy_size;
        sf::Vector2f enemy_origin;


        switch (int r1 = rand() % 2) {
        case 0:
                texture_path = "res/images/enemy1.png";
                enemy_size.x = 70;
                enemy_size.y = 70;
                enemy_origin.x = 35;
                enemy_origin.y = 35; break;
        case 1:
                texture_path = "res/images/enemy2.png";
                enemy_size.x = 100;
                enemy_size.y = 100;
                enemy_origin.x = 50;
                enemy_origin.y = 50; break;

        }


        basic_enemy.t.loadFromFile(texture_path);
        basic_enemy.s.setSize(enemy_size);
        basic_enemy.s.setOrigin(enemy_origin);
        basic_enemy.s.setTexture(&basic_enemy.t);

        int spawn = rand() % 640 + enemy_origin.y;
        basic_enemy.s.setPosition(sf::Vector2f(spawn, -(enemy_origin.y)));

}
 

(I'm aware the name "enemy_spawner" is not an accurate description so I'll change it later)

Then I tried to set it up so that a new enemy type is chosen every two seconds,assigned to the "basic_enemy" object which will have it's content copied to the new element added to the "enemies" vector:

sf::Time elapsed_time;
        sf::Clock clock;
       

        while (w.isOpen()) {
                sf::Event e;
                while (w.pollEvent(e)) {
                }

               

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

                elapsed_time += delta_time;
                if (elapsed_time > sf::seconds(2)) {
                        for (int i = 0; i < 1; i++) {
                                enemy_spawner();
                                enemies.push_back(basic_enemy);
                                elapsed_time = clock.restart();
                                ii++;

                        }
                }
...
}
 

The issue here is that for some reason,everytime a new enemy type is chosen,the texture corresponding to that enemy is then re-assigned to all other existing enemies...
Here's an example of an enemy of the second type(with the "enemy2.png" texture):

And here's the same enemy roughly two seconds later,after an enemy of the first type(with the "enemy1.png" texture) was spawned:

At first I thought all of the elements of the vector were being rewritten every two seconds,but now I'm fairly certain that's not the case,because every enemy retains it's the size and x coordinates initially assigned to it for example,but still change textures for some reason...

Any idea what's causing this?
« Last Edit: June 16, 2020, 10:20:13 pm by Riser »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
Re: Vector elements keep changing textures
« Reply #1 on: June 07, 2020, 10:12:28 pm »
I might be wrong, but I think the issue is, that because you haven't implemented a custom copy-constructor the rectangle shape of your enemy class will always keep referencing the texture of the originally created enemy class.

When you push_back an object into a vector, you're creating a copy (unless it's movable). Copying a texture will create a new OpenGL reference, but when you copy the rectangle shape, it won't reassign it's reference to the copied texture, but will keep referencing the texture it was copied from.

There are at least three take aways here:

1. Don't store the texture with your sprite/shape, but use something like a resource holder. Copying textures is an expensive task and almost always not what you want to do. Instead you want to load images once from disk and then keep referencing the already loaded texture.
2. If you move around referenced objects in memory, you have to ensure that the objects that reference it, are informed and properly updated. Note that std::vector doesn't just copy on push_back, but it can move all the objects to a new memory location if the reserved memory space isn't large enough anymore.
3. You probably want to use one big texture atlas with your sprites on it and simply adjust the texture rect, instead of having many small images loaded. It makes it easier to work with resources and can be more performant.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Vector elements keep changing textures
« Reply #2 on: June 08, 2020, 05:10:04 pm »
1.Alright,I'm still very inexperienced,so I don't know what a resource holder is or how to use it,but you did give me another idea,I simply replaced the "basic_enemy" object with two new objects "basic_enemy1" and "basic_enemy2",gave them the parameters of each enemy type respectively (Outside the window loop,as opposed to inside the "enemy_spawner" function where they previously were,since you specified that I should only load the textures once) and modified the "enemy_spawner" function to return one randomly everytime it's called,then had it 'push_back'ed into the "enemies" vector,and that solved the problem.

2.I'm still new to working with vectors so I've yet to fully understand how they work,but I'll get use to them over time.

3.Understood,the reason each texture is it's own image is because I randomly downloaded them off of Google,but I'll start editing them into a single image starting from my next project.

That was very helpful,thank you!

EDIT: I...just remembered constructors are a thing,yeah those definitely make things a lot easier...
« Last Edit: June 09, 2020, 12:00:15 pm by Riser »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Vector elements keep changing textures [SOLVED]
« Reply #3 on: June 15, 2020, 09:20:32 pm »
A resource holder is basically just the storage of all resources in one place (separate from all of the things that use them). They can they be passed around by reference or pointer.

A simple vector of textures that is almost global is a basic resource holder. Notice that I say "almost". Global resources, especially SFML ones, is a bad idea. Almost global here could be within main but not inside anything else and then passed around as needed.
« Last Edit: June 15, 2020, 09:23:20 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Vector elements keep changing textures [SOLVED]
« Reply #4 on: June 16, 2020, 10:08:01 pm »
I see,the book I'm learning from (SFML Essentials) talks about an asset manager class,that to me appears to have the same purpose as resource holder ("...will load, hold, and destroy all assets in our program" according to the book) but appears to be much simpler,I would post the code but I'm not sure if I'm allowed to (It's page 42 of the "SFML Essentials" book if you own it)

Would this work one in place of the resource holder? It's is explained in more detail and the code seems simpler so I have somewhat of a grasp on how to use it.

 

anything