SFML community forums

Help => Graphics => Topic started by: WDR on July 29, 2013, 01:02:45 pm

Title: How to randomly generate sprites
Post by: WDR on July 29, 2013, 01:02:45 pm
How do I randomly generate multiple instances of a single sprite at random positions off-screen and make them move into view? So far I am able to a generate a single sprite from a single fixed position off-screen and make it move into view. Here's my code:

//enemy is the sprite

enemy.setPosition(512, -50); //the window is 1024x768
enemy.move(0.f, speed * time);
window.draw(enemy);

Please help me with this! Thanks!
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on July 29, 2013, 01:13:21 pm
How do I randomly generate multiple instances of a single sprite
Use a loop and a std::vector to create multiple sprites.

at random positions off-screen
Use a random number generator and add/subtract it from the max/min of the current view/size.

and make them move into view?
Get the direction vector from each sprite to the center/random point within the view and move the sprite in that direction.
Title: Re: How to randomly generate sprites
Post by: WDR on July 29, 2013, 01:39:45 pm
I'm sorry if I didn't elaborate on my question but could you please elaborate on your answer. I really didn't understand the second and third parts of your answer. All sprites are supposed to move in a single direction i.e. downwards. Only their original positions off-screen should be randomly generated. Can you please tell me how that is done. Sorry for taking up your time. Thanks!
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on July 29, 2013, 03:54:11 pm
Again you can use a random number generator (http://en.cppreference.com/w/cpp/numeric/random) to generate x and y positions. Just make sure they are outside of the window view.

All sprites are supposed to move in a single direction i.e. downwards.
In one direction or towards one point?

If it's towards one point, you simply get the direction vector to that point and then you can move the sprite in that direction.
E.g. (pos_sprite - pos_point)/length(pos_sprite - pos_point) * speed_vector
It's basic vector math, so if you don't understand it, maybe you should read at bit about it, it's essential for programming a game. ;)
Title: Re: How to randomly generate sprites
Post by: WDR on July 29, 2013, 04:14:24 pm
OK, now I get it! I use an RNG for the x and y coordinates of the sprite and draw the sprite in a loop to randomly spawn the objects on screen, right? I understood. One last thing... And correct me if I'm wrong, the loop condition should also include a constant time interval condition, right? Or, would it be better to use an RNG for the time too? Also, where do I write the sprite.move() function for the sprite? Because writing it inside the loop previously caused the sprite to flicker in the same spot. Please clear these for me... Thank you!  :)
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on July 29, 2013, 04:34:46 pm
Well the time should steadily increase, otherwise you'll get some strange movements, but you can decide to use random speeds, but I'd make sure that the same sprites get the same speed, otherwise they'll be stuttering all over the place.

Now for the game loop. A normal game loop is defined as:

So the first thing you do, is generate the different sprites + their position. So you might want to use a for loop and iterate over the amount of sprites you want. In the loop you create a new sprite in a std::vector and set its position randomly. If you want to have random speeds you could use a std::pair to "pair" a random speed number with the sprite, if not you can simply use the same speed for all objects.
Now you'd have a vector of sprites, thus we can start game loop.
You'll need a sf::Clock to keep track of the frametime and/or use a fixed time step (http://gafferongames.com/game-physics/fix-your-timestep/). Then you'll generate the direction vector on the fly and multiply it with the normalized speed, either from the pair or the one that applies for all (see formula above) and then multiply it with the frametime.
After you've now updated all sprites, you can draw all of them.
Title: Re: How to randomly generate sprites
Post by: WDR on July 29, 2013, 05:00:45 pm
Alright! Completely understood! I'm implementing it now. Thanks, eXpl0it3r!  ;D
Title: Re: How to randomly generate sprites
Post by: WDR on July 29, 2013, 05:53:18 pm
OK... I apologize for the double post, but editing the previous one won't show as a new post in the forums. So... I understood what you said from a theoretical point of view. But, when I implement it, it doesn't show the required output. The sprite is flickering at a single point. Where did I go wrong? I have no idea where I went wrong, so I'm posting the whole code. Please help. Thank you for your patience.

#include "headers.h"

int main()
{
        sf::RenderWindow window(sf::VideoMode(1024, 768), "Game");
        sf::Texture backgroundtex, playertex, enemytex;
        sf::Sprite background, player;
       
        if(!backgroundtex.loadFromFile("images/space.jpg"))
        {
                return EXIT_FAILURE;
        }
        background.setTexture(backgroundtex);
       
        if(!playertex.loadFromFile("images/ship.png"))
        {
                return EXIT_FAILURE;
        }
        player.setTexture(playertex);
        player.setScale(0.125, 0.125);
        player.setPosition(473, 630);

        if(!enemytex.loadFromFile("images/enemy.png"))
        {
                return EXIT_FAILURE;
        }
        std::vector<sf::Sprite> enemy(5, sf::Sprite(enemytex));

        float x = rand() % 915 + 1;
        float speed = 400.f;
        sf::Clock clock;
       
        while(window.isOpen())
        {
                float time = clock.restart().asSeconds();
                sf::Event event;
               
                while(window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                                window.close();
                       
                        if(event.key.code == sf::Keyboard::Escape)
                                window.close();
                }
               
                sf::FloatRect border = background.getGlobalBounds();
                sf::FloatRect playerbounds = player.getGlobalBounds();
               
                if((sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) || (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) && (playerbounds.top + playerbounds.height) < (border.top + border.height))
                        player.move(0.f, speed * time);
               
                if((sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) || (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) && playerbounds.top > border.top)
                        player.move(0.f, -speed * time);
               
                if((sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) || (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) && (playerbounds.left + playerbounds.width) < (border.left + border.width))
                        player.move(speed * time, 0.f);
               
                if((sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) || (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) && playerbounds.left > border.left)
                        player.move(-speed * time, 0.f);

                window.draw(background);
                window.draw(player);
               
                for(int i=0; i<5; i++)
                        enemy[i].setPosition(x, 180);
                for(int i=0; i<5; i++)
                        enemy[i].move(0.f, speed * time);
                for(int i=0; i<5; i++)
                        window.draw(enemy[i]);

                window.display();
        }
}
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on July 29, 2013, 06:08:33 pm
It flickers because you don't call window.clear(), which is required!
It doesn't move, because you reset the position every time to (x, 180), where x is a randomly generated coordinate:
        for(int i=0; i<5; i++)
            enemy[i].setPosition(x, 180);
Title: Re: How to randomly generate sprites
Post by: WDR on July 29, 2013, 06:29:52 pm
OK... window.clear(), got it! But RNG, still confused! Do I declare it inside the game loop or outside it? Declaring outside is not generating multiple random numbers. Only a single one. And how do I get it to move? Please tell me this.
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on July 29, 2013, 06:34:38 pm
Please read my comments above, especially the detailed description. It's all there you'll just have to understand it. ;)
Title: Re: How to randomly generate sprites
Post by: Yemeni Cpluspluser on July 29, 2013, 06:40:35 pm
for me I will go with the rand(); and srand(); functions and make 5 sprites and rand numbers from 0 - 4 ;
is this what you want ?

example how to use rand from cplusplus.com

/* rand example: guess the number */
#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

int main ()
{
  int iSecret, iGuess;

  /* initialize random seed: */
  srand (time(NULL));

  /* generate secret number between 1 and 10: */
  iSecret = rand() % 10 + 1;

  do {
    printf ("Guess the number (1 to 10): ");
    scanf ("%d",&iGuess);
    if (iSecret<iGuess) puts ("The secret number is lower");
    else if (iSecret>iGuess) puts ("The secret number is higher");
  } while (iSecret!=iGuess);

  puts ("Congratulations!");
  return 0;
}
Title: Re: How to randomly generate sprites
Post by: WDR on July 31, 2013, 05:57:12 pm
OK... So far, I've been able to draw the sprites from the vector array using a for loop and I've been able to move them. So far, so good. But I've hit a snag again and for the love of the remaining hair on my head, I'm not able to figure out how to solve them. I've tried all the possible solutions to the best of my knowledge and ended up with more problems. So, please help me with these problems and how to solve them:-

1) All sprites are generated randomly but they all appear at once. They should appear one after the other with a fixed time interval. How do I set that condition?

2) The maximum number of sprites generated is the maximum size of the array. Is there any other method where indefinite number of enemies are generated until the player dies or the game is stopped?

3) I've set bounding box collisions and collision conditions for the enemy sprites in a similar fashion using vector arrays, but I'm pretty sure that's wrong because it doesn't work. They overlap each other, and do nothing when they collide with the player. How do I randomly generate them such that they don't overlap each other and they collide with the player?

Here's my code:

        if(!enemytex.loadFromFile("images/enemy.png"))
                return EXIT_FAILURE;

        std::vector<sf::Sprite> enemy(100, sf::Sprite(enemytex));

        std::vector<sf::FloatRect> enemybounds(100);
        for(int i=0; i<10; i++)
                enemybounds[i] = enemy[i].getGlobalBounds();

        srand(time(NULL));
        for(int i=0; i<10; i++)
        {
                float x = rand() % dist + 1; // dist is the visible width of the screen
                enemy[i].setPosition(x, 180);
        }

        float playerspeed = 400.f;
        float enemyspeed = 200.f;
        sf::Clock clock;

        while(window.isOpen())
        {
                float time = clock.restart().asSeconds();
                window.clear();
                for(int i=0; i<10; i++)
                        enemy[i].move(0.f, enemyspeed * time);
                for(int i=0; i<10; i++)
                        window.draw(enemy[i]);

                window.display();
        }

Please clear these three queries for me. I shall be ever grateful. Thank you!  :)
Title: Re: How to randomly generate sprites
Post by: Yemeni Cpluspluser on July 31, 2013, 10:59:52 pm
I am working on my game, trying to do cool stuff lol, here is what I came out with, random color generator

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <random>
#include <cstdlib>

int  main()
{
    srand( time(0));
    size_t R, G, B;
    std::cout << "This is the brain of the game, don't think of closing it\nPlease wait the game is loading . . . " << std::endl;
    // declare mainWindow
    sf::RenderWindow mainWindow( sf::VideoMode( 800, 600, 32) , "Hello title" , sf::Style::Close ); // Declare of mainWindow
    mainWindow.setFramerateLimit( 60 );
    std::cout << "Game resolution is : " << mainWindow.getSize().x  << " X " << mainWindow.getSize().y
              << " bits : " << mainWindow.getSettings().depthBits + mainWindow.getSettings().stencilBits << std::endl
              << "Frame per second : 60" << std::endl;
    // declared mainWidow

    // load images into ram
    sf::Image img_SpaceShip;
    if( !img_SpaceShip.loadFromFile( "Resource/img_ship.png" ) )
       std::cout << "Error LFF : Failed to load Resource/img_ship.png" << std::endl;
    else std::cout << "Resource/img_ship.png successfully loaded" << std::endl;

    sf::Texture img_button;
    if ( !img_button.loadFromFile( "Resource/img_button.png" ) )
        std::cout << "Error LFF : Failed to load  Resource/img_button.png" << std::endl;
    else std::cout << "Resource/img_button.png successfully loaded" << std::endl;

    // load sound and music into ram
    sf::Music msnd_intro;
    if( !msnd_intro.openFromFile( "Resource/msnd_intro.ogg") )
        std::cout << "Error OFF : Failed to load Resource/msnd_intro.ogg" << std::endl;
    else std::cout << "Resource/msnd_intro.ogg successfully loaded" << std::endl;
    msnd_intro.setLoop( true );
    msnd_intro.play();

    // loads fonts
    sf::Font font_English;
    if (!font_English.loadFromFile( "Resource/font_English.ttf" ) )
        std::cout << "Error LFF : Failed to load Resource/font_English.ttf" << std::endl;
    else std::cout << "Resource/font_English.ttf successfully loaded" << std::endl;

    // every thing should be loaded

    // declarations

    sf::Text text_MainWindowText ( "SpaceShips 0.01 Alfa", font_English);
    text_MainWindowText.setCharacterSize( 40 );
    text_MainWindowText.setColor( sf::Color::Blue );
    text_MainWindowText.setPosition( 200 , 30 );

    sf::Text text_MainWindowNewGame ( "New Game", font_English);
    text_MainWindowNewGame.setCharacterSize( 30 );
    text_MainWindowNewGame.setColor( sf::Color::Green );
    text_MainWindowNewGame.setPosition( 60 , 150 );

    sf::Text text_MainWindowExit ( "Exit Game", font_English );
    text_MainWindowExit.setCharacterSize( 30 );
    text_MainWindowExit.setColor( sf::Color::Red );
    text_MainWindowExit.setPosition( 60, 200 );

    sf::Sprite spr_ButtonNewGame;
    spr_ButtonNewGame.setTexture( img_button );
    spr_ButtonNewGame.setPosition( 0 , 150 );
    spr_ButtonNewGame.setScale( 1.8 , 1 );

    sf::Sprite spr_ButtonExitGame;
    spr_ButtonExitGame.setTexture( img_button );
    spr_ButtonExitGame.setPosition( 0 , 200 );
    spr_ButtonExitGame.setScale( 1.8 , 1 );

    sf::Sprite spr_SpaceShip;



    // the main game loop
    while ( mainWindow.isOpen() ) // main game loop
    {
        sf::Event mainEvents; // declare of main events checker
        while ( mainWindow.pollEvent( mainEvents ) ); // checking
        {
            switch ( mainEvents.type ) // what event type
            {
            case sf::Event::EventType::Closed: // users clicks X or press Alt-F4
                mainWindow.close(); // close the window
                break;
            }
        }
    // main loop :
    mainWindow.clear( sf::Color( 11,11,11) );
    mainWindow.draw( spr_ButtonNewGame );
    mainWindow.draw( spr_ButtonExitGame );
    mainWindow.draw( text_MainWindowText );

    R = rand() % 255;
    G = rand() % 255;
    B = rand() % 255;

    text_MainWindowText.setColor( sf::Color ( R, G, B ) );
    mainWindow.draw( text_MainWindowNewGame );
    mainWindow.draw( text_MainWindowExit );
    mainWindow.display();
    }
    return EXIT_SUCCESS; // returns 0;
}
 

Quote
1) All sprites are generated randomly but they all appear at once. They should appear one after the other with a fixed time interval. How do I set that condition?

I would recommend using different variables for each different object for random sprite, as you can see I used 3 sprites, R,G and B;
Title: Re: How to randomly generate sprites
Post by: WDR on August 01, 2013, 06:08:34 am
Your code is good... But I'm not sure how it helps me solve my three problems. Can anybody please help me solve those three problems? Please help! Thanks!
Title: Re: How to randomly generate sprites
Post by: WDR on August 01, 2013, 08:59:25 pm
Come on, guys... Nothing? Please Help!!!  :(
Title: Re: How to randomly generate sprites
Post by: eXpl0it3r on August 01, 2013, 09:06:17 pm
Sorry, we're not here to program your game.
I've explained everything in detail and some have given you code pieces, if that's not enough, then made you're not ready for that kind of programming?
Title: Re: How to randomly generate sprites
Post by: WDR on August 01, 2013, 09:49:48 pm
I didn't ask for code. I asked for theoretical solutions. But no one responded to that either.
Title: Re: How to randomly generate sprites
Post by: zsbzsb on August 02, 2013, 12:16:42 am
I didn't ask for code. I asked for theoretical solutions. But no one responded to that either.

I will respond to your questions without code, but before I do you need to understand what you are asking is basic C++ knowledge. That is why I highly recommend you pickup a good C++ book and get the bases down before you try game programming. Trying to learn C++ and game programming at the same time will cause you to learn questionable coding habits.

1) All sprites are generated randomly but they all appear at once. They should appear one after the other with a fixed time interval. How do I set that condition?

There is no "condition" you can just set, this is where knowledge about computer programming comes in. What you must do is track the total elapsed time from every frame and when it exceeds your time interval subtract your time interval from the total elapsed time and spawn a new sprite.


Quote
2) The maximum number of sprites generated is the maximum size of the array. Is there any other method where indefinite number of enemies are generated until the player dies or the game is stopped?

To start off std::vector<t> is not a fixed array. You can put as many elements into it as you want (until you run out of memory). So just keep spawning (as I explained above) until you wish to stop.


Quote
3) I've set bounding box collisions and collision conditions for the enemy sprites in a similar fashion using vector arrays, but I'm pretty sure that's wrong because it doesn't work. They overlap each other, and do nothing when they collide with the player. How do I randomly generate them such that they don't overlap each other and they collide with the player?

Do not use another vector for bounding boxes. There is nothing magical that will update your second vector bounding boxes with what you applied to your sprite. Just your existing vector of of enemies and call sf::Sprite.getGlobalBounds() to get the bounding box of the sprite. As for collisions use sf::Rect.intersects(xxx) to determine if bounding boxes intersect.