Make Object Move Smoothly In C++-SFML - c++

Hey Guys I'm a Beginner in Game Development with C++ and Sfml I Wrote this code to make that purple Object move,but the problem is that it doesn't move smoothly, it's like the text input, How to fix That ?
Here Is My code :
#include <SFML/Graphics.hpp>
int main()
{
sf::ContextSettings settings;
settings.antialiasingLevel = 12;
sf::RenderWindow window(sf::VideoMode(640, 480), "Ala Eddine", sf::Style::Default, settings);
sf::CircleShape player(20, 5);
player.setFillColor(sf::Color(150, 70, 250));
player.setOutlineThickness(4);
player.setOutlineColor(sf::Color(100, 50, 250));
player.setPosition(200, 200);
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
window.close();
}
//MOOVING PLAYER////////////////////////////////////////
// moving our player to the right //
if(sf::Keyboard::isKeyPressed(sf::Keyboard::D)){ //
//
//
player.move(3, 0);
}
// moving our player to the left
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q)){
player.move(-3, 0);
}
// moving our player to the UP
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Z)){
player.move(0, -3);
}
// moving our player to DOWN
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S)){
player.move(0, 3);
}
}
window.clear();
window.draw(player);
window.display();
}
return 0;
}

I assume your player.move() method simply adds the offset to the player position. This means that your object will always move with the same constant velocity (assuming frame rate is constant). What you want instead is to have an acceleration which updates the velocity in every frame.
Here's the basic idea (for one direction; the y direction will work accordingly, although using vectors would be better):
Give your object both a velocity and an acceleration.
If a key is held down, set the acceleration to a constant term, otherwise set it to zero.
In every frame, add timestep * acceleration to the velocity.
In every frame, add timestep * velocity to the object position.
In every frame, multiply the velocity with some decay factor, say 0.99.
This is assuming you have a fixed timestep (say, 1/60 s for 60 fps). Timestepping is slightly more advanced, and I'll refer you to this article on the topic.

Related

SFML multiple objects with random values and their collisions

I'm pretty new with SMFL and C++ for the moment and I've got stuck while I was creating very simple physics simulator with balls.
Its my main.cpp:
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include "ball.hpp"
int main()
{
/*create window settings*/
sf::ContextSettings settings;
/*create window*/
sf::RenderWindow window;
window.create(sf::VideoMode(600, 600), "Simple Physics", sf::Style::Default, settings);
/*create ball(s)*/
Ball ball;
/*Main loop*/
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::Black);
// call ball.update(); and ball.draw();
balls.update();
balls.draw(window);
window.display();
}
}
And ball.hpp :
#include <SFML/Graphics/CircleShape.hpp>
class Ball
{
public:
int minXY = 0;
int maxXY = 600;
int ballRadius = rand() % 50 + 5;
int random = rand() % maxXY + 1; //random XY position
// vector for positions
//sf::Vector2f pos{random, random}; -> I Guess this should be included into loop
sf::Vector2f pos{100, 300};
// vector for velocity
sf::Vector2f vel{ 0.1, 0.1 };
void update()
{
// factors influence velocity
// update position based on velocity
pos.x += vel.x;
pos.y += vel.y;
if (pos.x + ballRadius*2 > maxXY || pos.x < minXY) vel.x = -vel.x; //boundary cond
if (pos.y + ballRadius*2 > maxXY || pos.y < minXY) vel.y = -vel.y; //boundary cond
}
void draw(sf::RenderWindow& window)
{
// draw ball to the window using position vector
sf::CircleShape circle(ballRadius);
circle.setPosition(pos.x, pos.y);
circle.setFillColor(sf::Color::White);
window.draw(circle);
}
};
Now, I want to draw multiple cirlcles, with random size, velocity and colors.
They should bounce on collision, i've got some ideas for that but can't really try them without multiple balls.
I've tried to make it with simple for loop, but it's not working.
After reading and watching many tutorials I'm still in this point so it would be great if somebody can help me up with ANY working example or some improvements to my code.
I will not give you working example but I think I can point you in the right direction:
You need some kind of Constructor for your Ball class, and given the example you should probably learn more about classes in general (for example here).
Then you should store balls you spawn from main loop in some kind of container. If you do know the number of balls you want to spawn std::array should be you choice, otherwise std::vector is the way to go.
You need some function to check collisions, static member function of Ball class should do the trick.

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.

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)

Centering Shapes/Objects in SFML for C++

So recently, I have begun using SFML to make games in Visual Studio.
After setting everything up, and writing some sample code, I devised this:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 600), "Move the Shape");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(shape);
window.display();
}
return 0;
}
The program produces the following result:
How do I place the circle in the center? I want to set up some code after that lets the user move the circle with the keyboard's arrow keys, so I need the circle in the center.
You need to set the position of shape with shape.setPosition(x, y). You know the width and height of the window (600px each way), and you know the radius of the circle (100px), so you can calculate the x and y that the circle needs to be moved to be centered. I'll leave that as an exercise for you.
You may also want to consider setting the origin of your circle so that you can position it by its center point (see setOrigin).
Actually, I've answered my own question. To set the position of an item, write:
shape.setPosition(x, y);
If you want to center a circle you can do something like this
circle.setPosition((window.getSize().x / 2.f) - circle.getRadius(), (window.getSize().y / 2.f) - circle.getRadius());
First, you should set the origin of the circle in the middle of it:
circle.setOrigin( circle.getRadius() / 2 , circle.getRadius() / 2 );
The, just move the center of the circle in the middle of the scree:
circle.setPosition( window.getSize().x / 2 , window.getSize().y / 2 );

How can I set gravity using this code? SFML/C++ [duplicate]

This question already has an answer here:
How can I set gravity using this code?
(1 answer)
Closed 8 years ago.
I am trying to make a game and am stuck on gravity..... In the following code a rectangle stands for a player and when I press up key it moves in y-axis but when I activate gravity on it (i.e resetting it's previous position) it does not animate (i.e. it does not jumps) instead it just stays in it's position.I know why it it happening. Because it is just staying in its position because when I press Up key it executes the code rectangle.setPosition(0, 350). Yeah I want it to do that but I also want to see my player in movement. I am using SFML library of C++. Please Help!
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Gravity");
sf::RectangleShape rectangle;
rectangle.setSize(sf::Vector2f(100, 100));
rectangle.setFillColor(sf::Color::Black);
rectangle.setPosition(sf::Vector2f(10, 350));
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
if(Event.type == sf::Event::Closed)
{
window.close();
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
rectangle.move(0, -1);
}
if(rectangle.getPosition().y >= 350-1)
{
rectangle.setPosition(0, 350);
}
window.display();
window.clear(sf::Color::Cyan);
window.draw(rectangle);
}
}
Gravity is an acceleration: that is, the double derivative of displacement. So you can't directly set the displacement (as you're currently doing) to get a nice representation of gravity.
An approach would be to create an entity class of your own, adding members for velocity, acceleration; alongside sf::RectangleShape's internal displacement; then have member functions operate on initialization/every frame - a quick & dirty example (untested):
class SomeEntity {
public:
SomeEntity( float x_pos, float y_pos ) : position(x_pos, y_pos) {
m_shape.setSize(sf::Vector2f(100, 100));
m_shape.setFillColor(sf::Color::Black);
m_shape.setPosition(sf::Vector2f(x, y));
// Constants at the moment (initial velocity up, then gravity pulls down)
velocity = sf::Vector2f(0, -30);
acceleration = sf::Vector2f(0, 9.81); //Earth's acceleration
}
void Step() { // TODO: use delta time
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
velocity.y -= 1;
}
velocity.x += acceleration.x;
velocity.y += acceleration.y;
x += velocity.x;
y += velocity.y;
m_shape.setPosition(x, y);
}
void Draw(sf::RenderWindow &window) {
window.draw(m_shape);
}
private:
sf::RectangleShape m_shape;
sf::Vector2f position, velocity, acceleration;
}
Which also means you can rewrite your application so it's a little cleaner:
SomeEntity ent(360, 0);
while(window.isOpen()) {
sf::Event Event;
while(window.pollEvent(Event)) {
if(Event.type == sf::Event::Closed) {
window.close();
}
}
ent.Step();
window.display();
window.clear(sf::Color::Cyan);
ent.Draw();
}
Seeing as you're setting your rectangle to x = 0, y = 350 repeatedly, I'll work under the assumption that that's your 'ground plane'. To achieve that, you just want to check whether the entity is under the ground plane, and reset it's position to the ground plane if it is - either in the entity's 'Step' function or directly in your main loop. In the long run, you might be better off using an entity manager/third party physics engine to do this sort of thing (a la box2D, for example)
You can do something like this instead :
if(rectangle.getPosition().y > 350)
{
rectangle.move(0, 0.01);
}