Applying gravity to objects - c++

I'm having trouble with implementing gravity on objects.
I have a bunch of circle objects that I'm drawing using OpenGL. I'm using delta-x and delta-y to move the circles (balls). I'm trying to add a gravitational constant to the y coordinate each frame so it simulates being pulled downward, but I'm not sure exactly how to do that.
Here's the relevant code:
class Ball
{
public:
double x;
double y;
double radius;
double deltaX;
double deltaY;
};
std::vector<Ball> gAllBalls; // a vector of balls with random positions and delta-values
double gGravity = ?; // gravitational constant - I know it's 92 m/s^s, but I don't know how to apply that to deltaX and deltaY
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
for (auto &thisBall : gAllBalls)
{
// draw
glColor3d(thisBall.red, thisBall.green, thisBall.blue);
DrawCircle(thisBall.x, thisBall.y, thisBall.radius);
// gravity - not working
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.y += gGravity;
}
// wall bouncing
if (thisBall.y + thisBall.radius + thisBall.deltaY >= gScreenHeight) // up
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.y + thisBall.deltaY - thisBall.radius < 0) // down
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.x + thisBall.deltaX - thisBall.radius < 0) // left
{
thisBall.deltaX = -thisBall.deltaX;
}
if (thisBall.x + thisBall.radius + thisBall.deltaX >= gScreenWidth) // right
{
thisBall.deltaX = -thisBall.deltaX;
}
// move
thisBall.x += thisBall.deltaX;
thisBall.y += thisBall.deltaY;
}
glutSwapBuffers();
glutPostRedisplay();
}
A big problem I'm having is that I don't know how to calculate the gravity, since I'm using deltaX and deltaY instead of having separate speed and distance variables to calculate 92 m/s^2. However, no matter what I set the gravity to, the balls don't behave like they should - regardless of gravity strength, so there has to be something else wrong, but I don't know what.

I think the problem here is the physics, rather than the programming technique.
In your case, I would change the 'delta' members of your Ball class to 'speed', since they are a unit of distance that change the position of your object per cycle (time), however this is just a suggestion to make it easier to visualize...
class Ball
{
public:
double x;
double y;
double radius;
double speedX;
double speedY;
};
In second place, I in your code, you are changing the 'y' member, rather than the speed, and since gravity changes speed, hence the problem.
Try doing that, and for debugging purposes, I would try with punctual objects (no radius, just plain (x,y) coordinates).
So, to conclude, I would simply change your gravity code to the following:
// gravity - 'fixed'
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.speedY -= gGravity; //notice the '-'
}
The value of gravity should be absolute and positive, so as to keep things as simple as posible. If you try this, you should have an ideal simple physics simulator, with a ball of constant speedX (only changing its direction, not magnitude).
Please try this, and let me know how it went, good luck, keep it up =)

Related

Rotation Angle of Sprite towards Mouse is only calculated but Sprite does not rotate. But, it works well in Debugger

I am a beginner in C++ and know SFML. I have read a lot of articles about Sprite rotation towards Mouse and have been able to calculate proper angle of rotation of Sprite using this code:
void Player::changeAngle(double Mx, double My) { // This is for making Player point towards Mouse
double dX = x - Mx; // x and y are global Varibales declared outside
double dY = y - My;
double magnitude = sqrt((dX*dX) + (dY*dY));
double normalizedX = dX / magnitude;
double normalizedY = dY / magnitude;
// This part is for Making Player move to Mouse
Xvelocity = normalizedX * speed; // Xvelocity, Yvelocity and speed are global variables
Yvelocity = normalizedY * speed;
// Rotate towards the Mouse
double angle = ( atan2(dY, dX) ) * 180 / M_PI;
entity.setRotation(angle); // entity is a sf::RectangleShape
}
And, this bit actually worked and the Sprite was rotating properly only before a few days. Now the Sprite is just frozen on the screen, nothing happens. I had not made any changes in that code but I had added a View from the main.cpp.
So here is how I call changeAngle() from the main.cpp :
case Event::MouseMoved : {
Vector2f worldPos = window.mapPixelToCoords(Mouse::getPosition(window), view);
double x = worldPos.x;
double y = worldPos.y;
player.changeAngle(x, y);
break;
}
I tried running the debugger and stepped through the code. I found that the angle is properly calculated and my mouse coordinates are also right. And, to my surprise, the sprite was Rotating now !
I could not understand why, but every time its in debugging mode, the Sprite will rotate. But, it won't rotate while running normally.
Can anyone tell me why and how to fix it so it rotates every time ? Tell me if there is any problem with my code.
Thanks !

How to rotate an object so it faces another?

I am making a game in opengl, and i can't figure out how to make my enemy characters turn to face my player. I only need the enemy to rotate on the y axis towards the player. Then I want them to move towards him.I have tried a bunch of different methods but haven't been able to get anything to work.
There are a few things you need to decide on yourself at the beginning of the project to be used throughout the project, like the representation of positions and the orientation (as well as the setup of the screen/clip planes etc.) However, you haven't mentioned any of this. So you may have to adapt the code below to suit your game, but it should be easily adaptable and applicable.
For the following example, I'll assume that -y axis is the top of your screen.
#include <math.h> // atan2
// you need to way to represent position and directions
struct vector2{
float x;
float y;
} playerPosition, enemyPosition;
float playerRotation;
// setup the instances and values
void setup() {
// Set some default values for the positions
playerPosition.x = 100;
playerPosition.y = 100;
enemyPosition.x = 200;
enemyPosition.y = 300;
}
// called every frame
void update(float delta){
// get the direction vector between the player and the enemy. We can then use this to both calculate the rotation angle between the two as well as move the player towards the enemy.
vector2 dirToEnemy;
dirToEnemy.x = playerPosition.x - enemyPosition.x;
dirToEnemy.y = playerPosition.y - enemyPosition.y;
// move the player towards the enemy
playerPosition.x += dirToEnemy.x * delta * MOVEMENT_SPEED;
playerPosition.y += dirToEnemy.y * delta * MOVEMENT_SPEED;
// get the player angle on the y axis
playerRotation = atan2(-dirToEnemy.y, dirToEnemy.x);
}
void draw(){
// use the playerPosition and playerAngle to render the player
}
Using the above code, you should be able to move your player object around and set the angle of rotation (you need to watch out for radians/degrees of the returned and expected angle values).

How to make a ball bounce off a paddle at a certain angle depending on where it hit the paddle?

So I have two separate detections for collision for both the player paddle and the enemy paddle and in the player paddle I have commented out what seems to be the math calculation needed to bounce a ball based on where it hit. The code that isn't commented simply bounces the ball around the screen as you would expect when you reverse the velocity (it's velocity is a float value) on each bounce. So for starters, is the commented out formula actually the correct formula, and if so does it need to be applied to both xSpeed and ySpeed when it collides with a paddle?
When I saw this formula it took BallAngle or PaddleAngle as an argument (I can't remember to be honest). Now if this IS the correct formula, how do I even get that angle in the first place? I'm just using integer's in there (for testing) because I don't know how to get the angle.
if (ball.getPosition().x < (player.getPosition().x) //PLAYER COLLISION DETECTION
&& (ball.getPosition().y + (ball.getRadius() * 2)) >= player.getPosition().y
&& ball.getPosition().y <= (player.getPosition().y + player.getSize().y))
{
xSpeed = -xSpeed;
//xSpeed = xSpeed*cos(91);
//ySpeed = ySpeed*sin(90);
ball.move(xSpeed, ySpeed);
}
if (ball.getPosition().x > enemy.getPosition().x - 30 //ENEMY COLLISION DETECTION
&& (ball.getPosition().y + (ball.getRadius() * 2)) >= enemy.getPosition().y
&& ball.getPosition().y <= (enemy.getPosition().y + enemy.getSize().y))
{
xSpeed = -xSpeed;
ball.move(xSpeed, ySpeed);
}
cos(91) is just under -1, presumably it is meant to reverse the X direction and slow it down due to the impact. sin(90) is almost one so again is presumably meant to slow it down a bit.
Of course these functions are actually quite expensive to calculate so you may as well just hard code the values.
const float xBounce = -0.99436746092
const float yBounce = 0.8939966636
...
xSpeed *= xBounce;
ySpeed *= yBounce;
ball.move(xSpeed, ySpeed);

How to define a path of motion for the camera in OpenGL?

EDIT: I CHANGED THE QUESTION WHEN I REALIZED THAT I ACTUALLY NEEDED TO MOVE THE CAMERA AND NOT THE POLYGON. MY BAD, EVERYONE.
So I'm taking a class on OpenGL and need to define a path that the camera can automatically traverse.
How can I make my camera move around my world by hitting the F1 key?
Just to clarify,
I know how to use keyboard functions that use constants such as GLUT_KEY_F1.
I'm trying something new and am clueless.
Is this as simple as incrementing (with a loop) the values in the parameters of gluLookAt() ?
Here is the code that I have now:
if(key == GLUT_KEY_F1)
{
float x;
collisionKey = GLUT_KEY_F1;
for(x = 0.0; x < 3600.0;)
{
x += .01;
gluLookAt(200 + x, cameraY, 400 + cameraZ, 200 + studentX, 250 + studentY, studentZ, 0, 1, 0);
}
}
glutPostRedisplay();
Let me know if you have any questions!

Circular collision rebound not working properly

I'm writing a little physics simulation in C++ that basically moves circles across the screen and when two circles collide, they should ricochet in the same manner as billiard balls would. When the circles do collide with each other, most of the time they will practically slow down infinitely/they appear to stick to each other and become static. Sometimes only one ball will rebound in the collision and the other will retain it's trajectory. This is just a simple 2D simulation.
So here's what I have for the detection/ricochet logic:
bool Ball::BallCollision(Ball &b2)
{
if (sqrt(pow(b2.x - x, 2) + pow(b2.y - y, 2)) <= b2.radius + radius) // Test for collision
{
normal[0] = (x - (x + b2.x) / 2) / radius; // Finds normal vector from point of collision to radius
normal[1] = (y - (y + b2.y) / 2) / radius;
xvel = xvel - 2 * (xvel * normal[0]) * normal[0]; // Sets the velocity vector to the reflection vector
yvel = yvel - 2 * (yvel * normal[1]) * normal[1];
////x = xprev; // These just move the circle back a 'frame' so the collision
////y = yprev; // detection doesn't detect collision more than once.
// Not sure if working?
}
}
I can't figure out what is wrong with my function. Thanks for any help in advance!
Edit:
Every variable is declared as a float
The functions:
void Ball::Move()
{
xprev = x;
yprev = y;
x += xvel;
y += yvel;
}
void Ball::DrawCircle()
{
glColor3ub(100, 230, 150);
glBegin(GL_POLYGON);
for (int i = 0; i < 10; i++)
{
angle = i * (2*3.1415/10);
newx = x + r*cos(angle);
newy = y + r*sin(angle);
glVertex2f(newx, newy);
}
glEnd();
}
The loop:
run_prev.clear(); // A vector, cleared every loop, that holds the Ball objects that collided
for (int i = 0; i < num_balls; i++)
{
b[i].Move();
}
for (int i = 0; i < num_balls; i++)
{
b[i].WallCollision(); // Just wall collision detecting, that is working just fine
}
//The loop that checks for collisions... Am I executing this properly?
for (int i = 0; i < num_balls; i++)
{
for (int j = 0; j < num_balls; j++)
{
if (i == j) continue;
if (b[i].BallCollision(b[j]) == true)
{
run_prev.push_back(b[i]);
}
}
}
for (int i = 0; i < num_balls; i++)
{
b[i].DrawCircle();
}
//xprev and yprev are the x and y values of the frame before for each circle
for (int i = 0; i < run_prev.size(); i++)
{
run_prev[i].x = run_prev[i].xprev;
run_prev[i].y = run_prev[i].yprev;
}
Makes balls collide (reflect movement vector) only if they're moving towards each other. Do not process collision if they're moving away from each other. Break this rule, and they'll be glued together.
When processing collision, update both balls at once. Do not update one ball at a time.
Your move vector adjustment is incorrect. Balls don't reflect against each other, because they can be moving at different speeds.
Correct movement adjustment (assuming balls have equal mass) should look something like that:
pos1 and pos2 = positions;
v1 and v2 are movement vector (speed);
n is collision normal == normalize(pos1 - pos2);
collisionSpeed = dot((v2-v1), n);
collisionSpeed *= elasticy; (0.0..1.0);
v1 = v1 - dot(v1, n);
v2 = v2 - dot(v2, n);
v1 -= scale(n, collisionSpeed * 0.5);
v2 += scale(n, collisionSpeed * 0.5);
To understand the formula, check newtons law (impulses in particular). Or check Chris Hecker's papers on game physics.
It's not clear how you're calling this function, but I think I see the problem.
Say you have Ball ballA and Ball ballB, which are colliding in the current frame, and then you run ballA.BallCollision(ballB).
This will update the member variables of ballA, and move it back a frame. But it doesn't update the position or trajectory of ballB.
Even if you call the converse as well (ballB.BallCollision(ballA)), it won't detect the collision because when you called ballA.BallCollision(ballB), it moved ballA back a frame.
I haven't looked at your code in detail, but it doesn't take into consideration that this type of collision can only work in center of momentum frames. Now, I assume your balls are of equal masses. What you do is take the average of the two momentums (or velocities since they have the same masses) and subtract that average from the velocities. Perform your calculations, and add the average back. Here is the question I asked that may relate to this.
I know this question is quite old, but it's still relevant, especially to students. Something that wasn't mentioned in the answers made me want to contribute.
One thing that I ran into when solving a similar problem was overlap. That is, if the moving balls overlap by any amount at all, the collision detection will trigger continuously, giving the sticking behavior the OP referred to.
There was an attempt here to prevent this by moving the balls to the previous frame, but that can occasionally fail if the movement was enough that the balls enmeshed more than a single frame can account for, or if the movement velocity is just right so that the frame before doesn't trigger collision but the frame after is too far overlapped.
Since the original check was for center distance less than or equal to the sum of the radii, the detection triggers on both collision AND overlap.
One way to fix this is to separate the test into checking for collision (equals only) or overlap (less than only). For the collision, proceed as normal. But for the overlap condition, you can physically move one ball or the other (or both by half) the amount of overlap. This positions them at correct "collision" position, which allows for the correct behavior of the bounce function.
An overlap function that only moves one ball at a time might look something like this(not real code):
if (distanceBetweenBallCenters < sumOfRadii){
currentPosition = oldPosition - (distanceBetweenBallCenters - sumOfRadii) * (unitVectorFromSecondBallToFirstBall);
}
One could easily move both balls by half, but I found that moving one at a time gave satisfactory results for my uses, and allowed me to keep the parameter as a const.
I hope this helps future students! (I am also a student, and new to this, so take my advice with the proverbial grain of salt)
Your way of calculating the normal is wrong. (x + b2.x)/2 doesn't have to be the point of collision, if the radii of the balls aren't equal.