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

Author Topic: How to randomly generate sprites  (Read 19580 times)

0 Members and 1 Guest are viewing this topic.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
How to randomly generate sprites
« 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!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: How to randomly generate sprites
« Reply #1 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.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #2 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!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: How to randomly generate sprites
« Reply #3 on: July 29, 2013, 03:54:11 pm »
Again you can use a random number generator 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. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #4 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!  :)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: How to randomly generate sprites
« Reply #5 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:
  • Update the logic
  • Draw the scene

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. 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.
« Last Edit: July 29, 2013, 04:45:32 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #6 on: July 29, 2013, 05:00:45 pm »
Alright! Completely understood! I'm implementing it now. Thanks, eXpl0it3r!  ;D
« Last Edit: July 29, 2013, 05:45:56 pm by WDR »

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #7 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();
        }
}

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: How to randomly generate sprites
« Reply #8 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);
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #9 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.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: How to randomly generate sprites
« Reply #10 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. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Yemeni Cpluspluser

  • Newbie
  • *
  • Posts: 25
  • C/C++, Soon Java and SQL ^_^
    • View Profile
    • Email
Re: How to randomly generate sprites
« Reply #11 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;
}
sf::signature mySignature;
mySignature.setPosition(forum.x,forum.y);
window.draw(mySignature);

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #12 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!  :)

Yemeni Cpluspluser

  • Newbie
  • *
  • Posts: 25
  • C/C++, Soon Java and SQL ^_^
    • View Profile
    • Email
Re: How to randomly generate sprites
« Reply #13 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;
sf::signature mySignature;
mySignature.setPosition(forum.x,forum.y);
window.draw(mySignature);

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: How to randomly generate sprites
« Reply #14 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!