VertexArray of circles - c++

I am wondering if it is possible to create a VertexArray of circles in SFML. I have looked for answers but I didn't find anything that could help. Moreover, I don't understand the part on the SFML documentation where it is written that I can create my own entities, I think this is maybe what I want to do in fact.
EDIT : I want to do that because I have to draw a lot of circles.
Thanks for helping me

While #nvoigt answer is correct, I found it useful in my implementations to work with vectors (see http://en.cppreference.com/w/cpp/container/vector for more details, look up "c++ containers", there are several types of containers to optimize read/write times).
You probably do not need it for the above described use case, but you could need it in future implementations and consider this for a good coding practice.
#include <SFML/Graphics.hpp>
#include <vector>
int main()
{
// create the window
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// initialize myvector
std::vector<sf::CircleShape> myvector;
// add 10 circles
for (int i = 0; i < 10; i++)
{
sf::CircleShape shape(50);
// draw a circle every 100 pixels
shape.setPosition(i * 100, 25);
shape.setFillColor(sf::Color(100, 250, 50));
// copy shape to vector
myvector.push_back(shape);
}
// iterate through vector
for (std::vector<sf::CircleShape>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
{
// draw all circles
window.draw(*it);
}
window.display();
}
return 0;
}

sf::CircleShape is already using a vertex array (thanks to being inherited from sf::Shape). There is nothing extra you need to do.
If you have a lot of circles, try using sf::CircleShape first and only optimize when you have a real use-case that you can measure your solution against.

In addition two previous answers I will try to explain why there is no default VertexArray of circles.
By ideology of computer graphics (and SFML in our case) vertex is a smallest drawing primitive with least necessary functionality. Classical example of vertices are point, line, triange, guad, and polygone. The first four are really simple for your videocard to store and to draw. Polygon can be any geometrical figure, but it will be heavier to process, that's why e.g in 3D grapichs polygons are triangles.
Circle is a bit more complicated. For example videocard doesn't know how much points she need to draw your circle smooth enough. So, as #nvoigt answered there exists a sf::CircleShape that is being built from more primitive verticies.

Related

How is SFML so fast?

I need to draw some graphics in c++, pixel by pixel on a window. In order to do this I create a SFML window, sprite and texture. I draw my desired graphics to a uint8_t array and then update the texture and sprite with it. This process takes about 2500 us. Drawing two triangles which fill the entire window takes only 10 us. How is this massive difference possible? I've tried multithreading the pixel-by-pixel drawing, but the difference of two orders of magnitude remains. I've also tried drawing the pixels using a point-map, with no improvement. I understand that SFML uses some GPU-acceleration in the background, but simply looping and assigning the values to the pixel array already takes hundreds of microseconds.
Does anyone know of a more effective way to assign the values of pixels in a window?
Here is an example of the code I'm using to compare the speed of triangle and pixel-by-pixel drawing:
#include <SFML/Graphics.hpp>
#include <chrono>
using namespace std::chrono;
#include <iostream>
#include<cmath>
uint8_t* pixels;
int main(int, char const**)
{
const unsigned int width=1200;
const unsigned int height=1200;
sf::RenderWindow window(sf::VideoMode(width, height), "MA: Rasterization Test");
pixels = new uint8_t[width*height*4];
sf::Texture pixels_texture;
pixels_texture.create(width, height);
sf::Sprite pixels_sprite(pixels_texture);
sf::Clock clock;
sf::VertexArray triangle(sf::Triangles, 3);
triangle[0].position = sf::Vector2f(0, height);
triangle[1].position = sf::Vector2f(width, height);
triangle[2].position = sf::Vector2f(width/2, height-std::sqrt(std::pow(width,2)-std::pow(width/2,2)));
triangle[0].color = sf::Color::Red;
triangle[1].color = sf::Color::Blue;
triangle[2].color = sf::Color::Green;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
window.close();
}
}
window.clear(sf::Color(255,255,255,255));
// Pixel-by-pixel
int us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
for(int i=0;i!=width*height*4;++i){
pixels[i]=255;
}
pixels_texture.update(pixels);
window.draw(pixels_sprite);
int duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
std::cout<<"Background: "<<duration<<" us\n";
// Triangle
us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
window.draw(triangle);
duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
std::cout<<"Triangle: "<<duration<<" us\n";
window.display();
}
return EXIT_SUCCESS;
}
Graphics drawing in modern devices using Graphic cards, and the speed of drawing depends on how many triangles in the data you sent to the Graphic memory. That's why just drawing two triangles is fast.
As you mentioned about multithreading, if you using OpenGL (I don't remember what SFML use, but should be the same), what you thinking you are drawing is basically send commands and data to graphic cards, so multithreading here is not very useful, the graphic card has it's own thread to do this.
If you are curious about how graphic card works, this tutorial is the
book you should read.
P.S. As you edit you question, I guess the duration 2500us vs 10us is because you for loop create a texture(even if the texture is a pure white background)(and the for loop, you probably need to start counting after the for loop), and send texture to graphic card need time, while draw triangle only send several points. Still, I suggest to read the tutorial, create a texture pixel by pixel potentially prove the miss understanding of how GPU works.

Moving Sprite (SFML) in c++ using Loops

I am new to c++ and as well as SFML. I am trying to make my sprite object move down in position relative to its last position using a loop. I am looking for the animation of it sprite object falling when the program starts.
I thought implementing a the sleep function in my for loop would help solve the issue i was having where the program would just display the object at the last iteration of the loop. However my program just freezes and crashes.
Looking for some direction. Maybe the sleep function isn't the right thing to call here?
#include <SFML/Graphics.hpp>
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
// Create the window here. Calling out the dimensions
sf::RenderWindow window(sf::VideoMode(800, 600), "Example Window");
// run the program as long as the window is open
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
//close window we requested
if (event.type == sf::Event::Closed)
{
window.close();
}
}
window.clear(sf::Color::Black);
sf::Texture texture;
if (!texture.loadFromFile("c:\\abstract.png"))
{
cout<<"Failed to load image...";
}
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setTextureRect(sf::IntRect(20,20,30,30));
for (float i = 0; i < 30.; i++)
{
sprite.move(sf::Vector2f(5.f, i));
window.draw(sprite);
Sleep(50);
}
window.display();
}
return 0;
}
What you are doing in your for is : Processing, drawing, processing, drawing... And finally displaying what you've drawn using window.display().
Meaning that what will be displayed on your window every frames, is the result of your "Processing, drawing" thing, in other word, 30 times your sprite at different positions.
What you want is to move your sprite a bit every frames. Thus, you have to finish your current while (window.isOpen()) iteration to move your sprite, draw it, and display it, and this over and over.
What you should do is declaring your sprite outside of your game loop (Which is while (window.isOpen())), and move it in this loop.
Step by step, your program should look like:
[Start]
Initialize your context
Create a sprite
Start looping
Clear the screen
Collect inputs
Move your sprite
Draw your sprite
Display your drawing on the window
End looping
[Exit]
The last thing you will need to handle is deltaTime (The timestep). Because if you move your sprite from (x,y) every frames, it means that the faster your computer is (Able to render a lot of frames quickly), the faster your sprite will move. In order to fix this problem, you'll have to move your sprite considering the time elapsed between the current frame and the previous frame (The slower is your PC, the more your sprite will move in one frame, the faster is your PC, the less your sprite will move in one frame). Timestep will cause your sprite to move (x,y) per second instead of (x,y) per frame, which is what you want in most graphic applications.

Most efficient way to Spawn and destroy objects for endless runner game? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm currently very new to SFML and i was wonder what the most efficient way to spawn and destroy objects in a vector based on the camera position ? Currently I'm instantiating a vector of wall "points" which will be linked together after debugging. Should i be Creating and destroying them based on the the cam position or moving the already existing ones to the correct position ?
I also wouldn't mind some feedback on my code for this.
Cave Chaos.cpp
int main()
{
//get classes from CaveChaos.h
CaveChaos::Wall objWall;
CaveChaos::Player objPlayer;
//set render window size and name
sf::RenderWindow window(sf::VideoMode(800, 600), "CaveChaos");
//set the view
sf::View view1(sf::Vector2f(0.f, 0.f), sf::Vector2f(window.getSize().x, window.getSize().y));
//create the player object as a triangle
sf::CircleShape Player(20, 3);
//initialise random
srand(time(0));
//sets the player position to a good position based on camera size
objPlayer.posx = window.getSize().x / 2;
objPlayer.posy = window.getSize().y / 1.1;
Player.setPosition(objPlayer.posx, objPlayer.posy);
//used to instantiate wall points
int locationsX[numofpoints];
//add random x values to locations
for (int i = 0; i < numofpoints; i++)
{
locationsX[i] = (rand() % 50) + 1;
}
while (window.isOpen())
{
sf::Event event;
//clear the window with black color
window.clear(sf::Color::Black);
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
//calls wallspawn in Walls.cpp which creates the wall points
WallSpawn(window, locationsX );
//calls playermove in Player.cpp which move the player
PlayerMove(window, Player);
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
//set the player as the cam follow point
view1.setCenter(Player.getPosition().x, Player.getPosition().y - objPlayer.posy / 3);
//set the view to the player
window.setView(view1);
window.display();
}
return 0;
}
Currently when i call WallSpawn() it loops through 10 objects and spawns them, would there be a way to spawn an infinite amount of objects instead ?
Walls.cpp
void WallSpawn(sf::RenderWindow& window, int locationsX[] )
{
//initiate random
srand(time(0));
//class objects
CaveChaos::Wall objWall;
CaveChaos::Player objPlayer;
//creates a vector of circleshapes
std::vector<sf::CircleShape> points;
//defines and circle of size 5
sf::CircleShape shape(5);
//loop through all of the points
for (int i = 0; i < numofpoints; i++)
{
//set the shape position to the random variable from CaveChaos.cpp
shape.setPosition(locationsX[i], objPlayer.posy + i * 55);
//set shape color to green
shape.setFillColor(sf::Color(100, 250, 50));
// copy shape to vector
points.push_back(shape);
}
// iterate through vector
for (std::vector<sf::CircleShape>::iterator it = points.begin(); it != points.end(); ++it)
{
//draw wall points on screen
window.draw(*it);
}
}
What would be the best way to move or destroy these objects after they have been spawned ?
I want this last point to either get destroy or moved to the front when i go forward:
and when i move forward something like this to happen:
If this method is completely wrong or i shouldn't be using this method at all please let me know.
thanks for the help.
Code Review
So first of all stackoverflow is not the right site for code review. If you seek for a complete review ask on codereview. However, here are some things I noticed:
Don't use rand or srand. If you want RNG use <random> (usually uniform_int_distribution or uniform_real_distribution).
Why are you using a native array for locationsX? std::vector seems much more reasonable.
Avoid frequent allocations inside performance critical loops (ex. you call WallSpawn each game loop iteration and WallSpawn itself creates a new vector sf::CircleShape each time which canbe avoided). More on that later.
Preallocate space for std::vector using vector.reserve() if you have an estimate of the final vector size.
Why do you do you have two event loops inside the window loop instead of just one?
Using auto instead of std::vector<sf::CircleShape>::iterator improves readability.
Design
Usually a game loop looks like this:
polling window events and handling user input,
updating game state (reacting to input, applying physics, character movement, ...), and
drawing the new game state.
Your WallSpawn function, for example, shows how it shouldn't be done. You're generating new game entities (wall points) and then you draw them straight away in the same function.
I have limited expirience with SFML but I know that there is a sf::Drawable base class which can be used for everything that needs to be drawn on the window. You don't have to use it but it's designed for easier OOP development. For example, you could create a type for your wall points or for the entire wall (depending on what you actually want to do with those points):
class WallPoint : public sf::Drawable
{
public:
WallPoint(int x, int y) :
position(x, y), circle(x, y, 5)
{
}
/*
* Getter and setter for position
*/
void draw(RenderTarget& target, RenderStates states) const override
{
target.draw(circle);
}
private:
sf::Point position;
sf::CircleShape circle;
};
And then keep a collection of those points in a variable outside of your game loop.
Entity Management
Large games with thousands or millions of game entities (vehicles, trees, rocks, walls, weapons, ammo, projectiles, crowds, NPCs, ...) have the problem that they have to be very efficient when it comes to managing them. However, in your case with a few simple circle shapes, efficient management is not really a concern. Don't optimize if you don't have to.
You gave too little information about the game behavior to make a profund recommendation, so here is some guessing.
How does the game progress affect your entities? Your case (a runner game) suggests that the environment is constantly moving along one axis (left <> right, or up <> down). If this is true, this means that your wall points always spawn and despawn at the edges of the current environment. In such a case std::deque is an ideal container to store your data.
Usually std::vector is a solid allrounder when it comes to container.
Always destroy your entities when you don't need them anymore. For example, if your wall points leave the view port (and you are sure they won't enter it again) remove them for the container.
Putting Things Together
Considering everything I wrote above, your game loop could now like this:
int main()
{
// Create window and init everything you need
std::deque<WallPoint> wallPoints;
// create some initial points
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
// event handling
}
// update game state
// add new wall points
// remove old points
// move the player
// draw the new game state
window.Clear();
for (const auto& point : wallPoints)
window.draw(point);
window.draw(player);
}
}

C++ SFML, orbiting

I recently started to learn SFML, and I have a question, how to make what would be the second body moving in an orbit, help please.
#include <SFML/Graphics.hpp>
using namespace sf;
int main()
{
RenderWindow window(VideoMode(800, 600), "Hello, world!");
CircleShape shape(50.f);
shape.setFillColor(Color::Black);
shape.setPosition(400,300);
shape.setOrigin(50,50);
CircleShape shape2(10.f);
shape2.setFillColor(Color::Black);
shape2.setPosition(700,500);
shape2.setOrigin(10,10);
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(Color::White);
window.draw(shape);
window.draw(shape2);
window.display();
}
return 0;
}
Well... I will not post full solution. It would not be educational to give you complete code. But I will give you some hints :) .
Your world update should happen in the loop. In the while loop. You have two there. Which one do you think is the one which updates your world?
Circle equation in Cartesian coordinate system is: (x-a)^2 + (y-b)^2 = r^2
In the loop from 1 you should use equation from 2 to update coordinates of second object (shape2).
To perform action from point 3 you have two possibilities: function setPosition and function move, both members of class CircleShape.
If you have further questions ask them in the comments.
For your future questions on stack: give us proof that you put some effort in resolving problem. If question looks like the one I'm answering now we have the idea that you did not think about it just posted it here and you are waiting for someone to write your code for you.
The easiest and i think most precise way would be to use two perpendicular sine waves with the origin being your well origin and the amplitude being the distance for which you want to orbit.
#include <cmath> -- sin(), cos functions
As you probably know sin goes from 0 to 1 then -1 and it repeats. cos is identical but shifted. If you use both for the position then you're left with the sine and cosine values of a given number. If you use one for 'x' and the other for 'y' you're left with circular motion (perpendicular waves). Try out the code below:
int main()
{
CircleShape shape(50.f);
shape.setFillColor(Color::Black);
shape.setPosition(400,300);
shape.setOrigin(50,50);
CircleShape shape2(10.f);
shape2.setFillColor(Color::Black);
shape2.setPosition(700,500);
shape2.setOrigin(10,10);
CircleShape shape3(10.f);
shape3.setFillColor(Color::Black);
shape3.setPosition(700,500);
shape3.setOrigin(10,10);
CircleShape shape4(10.f);
shape4.setFillColor(Color::Black);
shape4.setPosition(700,500);
shape4.setOrigin(10,10);
float speed = 0.01;
float distance = 100;
// create the window
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
window.setFramerateLimit(60);
float counter = 0;
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
counter += speed;
// clear the window with black color
window.clear(Color::White);
shape2.setPosition(shape.getPosition().x+distance*sin(counter),shape.getPosition().y+distance*cos(counter));
shape3.setPosition(shape.getPosition().x+distance*sin(counter),shape.getPosition().y+distance*sin(counter));
shape4.setPosition(shape.getPosition().x+2*distance*sin(counter),shape.getPosition().y+distance*cos(counter));
// draw everything here...
// window.draw(...);
window.draw(shape);
window.draw(shape2);
window.draw(shape3);
window.draw(shape4);
// end the current frame
window.display();
}
return 0;
}
As you can see shape2 is oribitng shape1. Shape2 and shape3's position is dependant on the position of shape1 (our origin) as well as the sine and cosine values generated. I marked distinct places in the code with variables to show you the possibilities you can have with this setup. Let's go through the setposition function:
For both x and y we need a base position from which the shape will orbit. we use shape1's position. The sine and cos need some type of number input from which to generate a value. I just used a normal iterator that grows every frame by 'speed' amount. the more it is the faster the sine will repeat thus faster orbiting around the shape1. The next part is the addition of the sine and cos values to the origin. this is where things get fun. we're essentially adding the sine value to the position to move it by that much in any direction. 'Distance' is how much we multiply the sine cos values. Thus bigger distance = further away.
Note:
using sine for x and cos for y you get a normal circular orbit.
using sine for both x and y you get a 3D-looking orbit to and from the screen (shape3)
multiplying sine and cos value additions by a non identical number will result in eliptical rotations (shape4)

Handling Vectors of Textures/Sprites # SMFL

This is basically the White Square Problem when vectors of textures and sprites are used in SMFL. After fighting with it for sometime, I have come up with a code with some pointers inside but still could not get what I want.
Here is what I have in the int main()
vector<sf::Sprite> sprites;
vector<sf::Texture> textures;
// Load sprites
for(int i=0;i<3;i++){
sf::Texture texture;
texture.loadFromFile(resourcePath() + "pink_sq.png");
textures.push_back(texture);
vector <sf::Texture>::iterator it = textures.begin() + i;
sf::Sprite sprite(*it);
sprite.setPosition(i*100,i*100);
sprites.push_back(sprite);
}
// Start the game loop
while (window.isOpen())
{
window.clear();
// Draw the sprite
for(int i=0;i<sprites.size();i++)
window.draw(sprites[i]);
window.display();
}
What I am getting is only third square at (200,200) is pink. The other two are white. Somehow textures are not copied to first two sprites.
I know for this simple code, I can avoid vectors, but this code is just for demonstration. I will be using possibly 100s of sprites in the future. Let me know if you guys have an idea on how to fix this.
Have you considered using a map for your textures? It seems to not work no matter what i try with a vector, the functionality dosn't change much with a map. I usually use maps when dealing with sprites, because you can have a string as your index if you so choose, which can make your code easier to follow.
#include <map>
.
.
.
vector<sf::Sprite> sprites;
sf::Sprite sprite;
map<int, sf::Texture> textures;
// Load sprites
for(int i=0;i<3;i++){
textures[i].loadFromFile(resourcePath() + "pink_sq.png");
sprites.push_back(sprite);// loads a dummy sprite for a pushback
sprites[i].setTexture(textures[i]);
sprites[i].setPosition(i*100,i*100);
}
// Start the game loop
while (window.isOpen())
{
window.clear();
// Draw the sprite
for(int i=0;i<sprites.size();i++){
window.draw(sprites[i]);
window.display();
sf::sleep(sf::milliseconds(30)); // so the loop dosn't crash the program randomly
}
}
this way produces 3 pink boxes
hope this helps
p.s. still tinkering with the vector, will add to the post if i can find a way.