Setting a sprite interval for sprite generation

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Aug 08, 2013 at 16:10

So, I’ve been developing this 2D space shooter game in SFML 2.0 in C++ in MS Visual Studio 10. Everything was going perfect until I hit a snag where the enemy sprites are generated off-screen and move vertically down. The enemy sprites are generated from a std::list. The problem is all the enemies move down all at once. I am unable to set a time interval so that the enemies move one after the other. I checked the SFML documentation, but there was nothing there on the subject, so I figured this might be a C++ problem. I checked C++ reference on the related subject, got two functions: Sleep() and delay(). Both of these stop the whole program from executing, so they are not correct for this job. Yes, I have checked Google and so far nothing.

Here’s the code for drawing and moving the sprite across the screen:

for(std::list<sf::Sprite>::iterator enemyit = enemy.begin(); enemyit != enemy.end(); enemyit++)
  {
   enemyit->move(0.f, enemyspeed * time);
   window.draw(*enemyit);
  }

Please help me on this. :(

6 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Aug 08, 2013 at 16:54

How about just generating them with a vertical offset in their offscreen position? The ones that should appear a bit later should have an initial position a bit higher.

Either that or you need to control when you’re generating them, so that you don’t create all of them in one frame, but spaced out over several consecutive frames.

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Aug 08, 2013 at 18:20

Either that or you need to control when you’re generating them, so that you don’t create all of them in one frame, but spaced out over several consecutive frames.

Exactly… Now, I tried out several solutions using the time function in the SFML modules. That either gave errors or undesired output. Now, there ARE some solutions available on the internet for similar problems, but they are too complex for a beginner like me. At least for now, anyway. And I’m supposed to explain this code to my examiners. And I don’t think it’s wise for me to explain code that I don’t understand well myself. So, I am trying to opt for a simpler method to achieve the desired output. And THAT, I’m having trouble with.

How about just generating them with a vertical offset in their offscreen position? The ones that should appear a bit later should have an initial position a bit higher.

This might work for me, but does it have any drawbacks? Does it affect the code or the memory by any chance?

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Aug 08, 2013 at 19:52

Well obviously it affects the code since you have to write the code to do it. :) The impact is very localized though; it only affects the code that creates new sprites.

It shouldn’t have any effect on memory or performance. You’ll have the same number of sprites as before; they’re just positioned differently.

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Aug 08, 2013 at 21:27

Haha… :D What I meant was does it affect the code negatively or undesirably… As I see, there’s no change in performance. But, in order to generate large number of sprites for a long time (you know, to keep them coming), I used a large list. This affected performance quite a bit. So, instead I opted to push_back() elements into the sprite list every time an element is erased in order to keep the list from growing in size and also to keep on generating. But… (there’s always a but)… Using a push_back() is setting the position of the newly created sprite to (0,0), rather than a randomly generated co-ordinate off-screen. So, I added the same RNG function I used to initialize the position at the start of the program. This generated new sprites as required, but the whole list is being erased instead of a single element, and a whole new list is being generated again. I’ve tried to pinpoint my error, but I’m clueless. Here’s my code:

std::list<sf::Sprite>::iterator enemyit = enemy.begin(), next;
  while(enemyit != enemy.end())
  {
   next = enemyit;
   next++;
   if(enemyit->getGlobalBounds().intersects(player.getGlobalBounds()))
   {
    enemy.erase(enemyit);
    enemy.push_back(sf::Sprite(enemytex));
    srand(time(NULL));
    float y = -200;
    for(std::list<sf::Sprite>::iterator enemyit = enemy.begin(); enemyit != enemy.end(); enemyit++)
    {
     float x = rand() % dist + wastage;
     enemyit->setPosition(x, y);
     y = y - enemyit->getGlobalBounds().height * 2;
    }
   }
   enemyit = next;
  }

Can you tell me where I went wrong? Thanks! :)

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Aug 08, 2013 at 23:27

Well you’re iterating over the entire list and overwriting every enemy’s position, inside the code for handling a single enemy’s collision with the player. So of course it’s blowing away all the enemies.

If you just want to generate one new enemy when the player touches one, then just do that. Don’t touch the rest of the list. In fact, you don’t even need to erase the current enemy and then push_back a new one. Just re-use the current enemy (the one the player touched) and generate a new starting position for it.

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Aug 09, 2013 at 04:55

Ohhh… I suspected it would be somewhere in the for loop. I’ll change it now. Thanks, Reedbeta. Your help has been very invaluable. :)