Good Evening!
I'm back with another question that hopefully someone can help me out with. This week I was required to create a ball that would be launched from the bottom left corner of the screen, and continuously bounce off the surfaces of the screen. The longer I hold Spacebar, the faster the ball would get. I managed to complete my assignment a lot quicker than I thought I would, so I thought I would contact my teacher and see if I can't do something extra. He told me to add Gravity to my code. This is all he gave me.
Implement gravity into your ball movement:
- This will apply acceleration to your physics now.
- Remember, Velocity is the change in position per second, while acceleration is the change in Velocity per second.
- Gravity in our "Game" should be between 500 - 1500 Pixels/s^2
I have been trying to do this for a couple of days now, however I have been unable to implement it into my code. I know their are multiple ways of doing everything in coding, but from everything I have seen online and on tutorial videos, none of the methods have been working. So, I was hoping someone here has run into the same problems as me, and will be able to help me out.
Thank you all in advance for taking the time to look at my code, and helping me out!
// Engine.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
void applyGravity(float, float);
float yVelocity;
int main()
{
float Power = 0.0f;
bool toMove = false;
float Time;
sf::RenderWindow window(sf::VideoMode(1024, 512), "Welcome to SDVA 203!");
sf::CircleShape shape(25);
shape.setPosition(0, 486);
shape.setOrigin(shape.getRadius(), shape.getRadius());
shape.setFillColor(sf::Color::White);
sf::Clock clock;
float angleInDegrees = 225;
float angleInRadians = angleInDegrees * 2 * 3.1415 / 360;
float xVelocity = cos(angleInRadians) * 100;
yVelocity = sin(angleInRadians) * 100;
while (window.isOpen())
{
sf::Time dt = clock.restart();
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyReleased)
{
if (event.key.code == sf::Keyboard::Space)
{
toMove = true;
}
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Num1)
{
xVelocity = cos(angleInRadians) * 100;
yVelocity = sin(angleInRadians) * 100;
}
if (event.key.code == sf::Keyboard::Num2)
{
xVelocity = cos(angleInRadians) * 300;
yVelocity = sin(angleInRadians) * 300;
}
if (event.key.code == sf::Keyboard::Num3)
{
xVelocity = cos(angleInRadians) * 600;
yVelocity = sin(angleInRadians) * 600;
}
if (event.key.code == sf::Keyboard::Num4)
{
xVelocity = cos(angleInRadians) * 1200;
yVelocity = sin(angleInRadians) * 1200;
}
if (event.key.code == sf::Keyboard::Space)
{
toMove = false;
}
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
{
Power += dt.asSeconds();
if (Power > 2.0f)
{
xVelocity = cos(angleInRadians) * 100;
yVelocity = sin(angleInRadians) * 100;
std::cout << "Power Level is at 100!" << std::endl;
}
if (Power > 4.0f)
{
xVelocity = cos(angleInRadians) * 300;
yVelocity = sin(angleInRadians) * 300;
std::cout << "Power Level is at 300!" << std::endl;
}
if (Power > 6.0f)
{
xVelocity = cos(angleInRadians) * 600;
yVelocity = sin(angleInRadians) * 600;
std::cout << "Power Level is at 600!" << std::endl;
}
if (Power > 8.0f)
{
xVelocity = cos(angleInRadians) * 1200;
yVelocity = sin(angleInRadians) * 1200;
std::cout << "Power Level is at 1200!" << std::endl;
}
if (Power > 10.0f)
{
xVelocity = cos(angleInRadians) * 9001;
yVelocity = sin(angleInRadians) * 9001;
std::cout << "Power Level Over 9000!" << std::endl;
}
}
if (toMove == true)
{
shape.move(xVelocity * dt.asSeconds(), yVelocity * dt.asSeconds());
cout << xVelocity << yVelocity << endl;
applyGravity(500.0, 500.0);
}
sf::Vector2f position = shape.getPosition();
if (position.y <= shape.getRadius())
{
yVelocity *= -1;
shape.setPosition(position.x, shape.getRadius());
}
if (shape.getRadius() + position.y >= 512)
{
yVelocity *= -1;
shape.setPosition(position.x, 512 - shape.getRadius());
}
if (position.x <= shape.getRadius())
{
xVelocity *= -1;
shape.setPosition(shape.getRadius(), position.y);
}
if (shape.getRadius() + position.x >= 1024)
{
xVelocity *= -1;
shape.setPosition(1024 - shape.getRadius(), position.y);
}
if (shape.getRadius() + position.y >= 512)
{
yVelocity = yVelocity / 2.0f;
}
//std::cout << "Ball position is " << position.x <<","<<position.y << std::endl;
window.clear();
window.draw(shape);
window.display();
}
return 0;
}
void applyGravity(float gravity, float time)
{
yVelocity = yVelocity + (gravity * time);
if (yVelocity < .01)
{
yVelocity = 0;
}
}
O_o
Is that what my applyGravity is doing?! I'm only supposed to add 500 pixels per second squared.....What would be the correct input for that?
yes, as Hapax said you passed 500 as gravity and 500 as time that means you adding 500 * 500 = 250,000 to y velocity which is huge number.
in your applyGravity() should not take time, time will be evaluated later with move() function. also, you need to apply the gravity before call move(). like so,
if (toMove)
{
applyGravity(gravity);
shape.move(xVelocity * dt.asSeconds(), yVelocity * dt.asSeconds());
}
Thank you both for the replies! This is helping me out a lot!
So, at this point, when I launch the ball it shoots up properly, and then the gravity shoots it back down quickly. So, it is kind of working. It's like it is bouncing but just shooting back down about a second into it being in the air. I feel like I am getting close, but I am either missing something or my formula is incorrect. Here is what I added/edited
void applyGravity(float Gravity);
float yVelocity;
// The function and yVelocity are outside of my main loop
// yVelocity is fully declared inside of the main loop
yVelocity = sin(angleInRadians) * 100;
// I made an if statement to help keep elapsedTime to just about a second
if (elapsedTime > 2.0)
{
elapsedTime = 0.0;
}
// I put the function in an if statement so it only fires about every second, otherwise it caused my ball to just zoom back and forth on the ground.
if (toMove == true)
{
if (elapsedTime < 2.0 && elapsedTime >= 1.0)
{
applyGravity(Gravity);
}
shape.move(xVelocity * dt.asSeconds(), yVelocity * dt.asSeconds());
cout << xVelocity << yVelocity << endl;
}
// And this is my function. I have a set amount for the time because the "per second" part of his instructions, I was assuming that meant Time should only be about 1 second?
void applyGravity(float Gravity)
{
yVelocity = (Gravity * (1.0 * 1.0)) + yVelocity;
}
Edit:
P.S. Should anything be done to xVelocity during all of this? I noticed that when I bumped up the power of launching the ball up to make it bounce around more, all that ends up happening is it starts bouncing off the sides of the window and barely skimming the "ground"
@Hapax, you are correct. my attempt solution was came from frustration when i was calculating the math in piece of paper i always end up with undesired results doe to time in velocity formula. so, i just treated the gravity as velocity instead of acceleration which is wrong mathematically but it some how works for me by making the initial velocity much higher with negative value as direction to up and then for every frame i added initial velocity to "gravity velocity" before call move() function. this works fine in my game be cause i have free choices to determine the values of gravity and initial velocity. here the game that i was working on: https://github.com/MORTAL2000/Simple-Super-Mario-
here a few suggestions:
1) it's always recommended to use fixed timestep when the game applies physic.
2) remove the "timer", i don't think this is a proper way to handle the physic in your game. better to let physic flow regularly, this is what should be the game or real world physic behaved.
3) the possible implementation will be
if (toMove)
{
yVelocity += gravity * dt.asSeconds(); // gravity could be negative value here: -500
shape.move(xVelocity * dt.asSeconds(), yVelocity * dt.asSeconds());
}
NOTE: i haven't tested it but you may try it.