Trigonometry/Floating point issue - c++

The issue:
When using the math.h trigonometry functions with a simple SDL 2.0.4 application (top-down movement/rotation attempt), I discovered that there were some slight errors in the trigonometry calculations, resulting in the 'player' not moving exactly in the direction being faced, which bugged me a lot. I searched up why this could be, and the main reason seems to be that of floating point arithmetic.
I resorted to using a fixed-point maths library called libfixmath - and the problem was solved, but only to some extent. The cosine of 90 degrees returned in radians was 0.00775146, rather than 0; however, a cosine of 270 degrees did return 0 radians! I must admit this problem has got me stuck and I need a bit of help (my mathematics skills aren't great, which doesn't help).
The variables used in fixed-point arithmetic:
double direction = 0.0;
double sinRadians = 0.0;
double cosRadians = 1.0; // presuming player starts facing direction of 0 degrees!
And then the part of 'int main(int argc, char* argv[])' involving these variables:
if (keyDownW == true)
{
Player.setXPos(Player.getXPos() + (10 * sinRadians));
Player.setYPos(Player.getYPos() - (10 * cosRadians)); // +- = -
cout << "Cosine and Sine (in radians): " << cosRadians << ", " << sinRadians << endl;
cout << direction << " degrees \n" << endl;
}
else if (keyDownS == true)
{
Player.setXPos(Player.getXPos() - (6 * sinRadians));
Player.setYPos(Player.getYPos() + (6 * cosRadians)); // -- = +
}
if (keyDownA == true)
{
if (direction <= 0)
{
direction = 345;
}
else
{
direction -= 15;
}
direction = direction * (3.14159 / 180); // convert to radians
cosRadians = fix16_to_dbl(fix16_cos(fix16_from_dbl(direction)));
sinRadians = fix16_to_dbl(fix16_sin(fix16_from_dbl(direction)));
direction = direction * (180 / 3.14159); // convert back to degrees
}
else if (keyDownD == true)
{
if (direction >= 345)
{
direction = 0;
}
else
{
direction += 15;
}
direction = direction * (3.14159 / 180); // convert to radians
cosRadians = fix16_to_dbl(fix16_cos(fix16_from_dbl(direction)));
sinRadians = fix16_to_dbl(fix16_sin(fix16_from_dbl(direction)));
direction = direction * (180 / 3.14159); // convert back to degrees
}
When cosRadians and sinRadians are assigned, what's happening is that direction (which has been converted from degrees to radians) is converted to a fixed-point number, which is then used to calculate the cosine and sine individually, then converted from a fixed-point number back to a double for assignment, all with the use of the libfixmath library.
Here's the program currently (compiled as an .exe with the necessary .dll files; I statically linked the libfixmath library) so you can see the issue for yourself: https://mega.nz/#!iJggRbxY!ySbl-2X_oiJKFACyp_kLg9yuLcEsFM07lTRqLtKCsy4
Any ideas as to why this is happening?

One problem is that you are converting back and forth from degrees to radians and back every frame, and you will lose precision each time. Instead, do the conversion into a temporary variable, like this:
double direction_radians = direction * (3.14159 / 180); // convert to radians
cosRadians = fix16_to_dbl(fix16_cos(fix16_from_dbl(direction_radians)));
sinRadians = fix16_to_dbl(fix16_sin(fix16_from_dbl(direction_radians)));
This way the errors don't accumulate.
Also, is there any reason you can't just use the normal sin and cos functions from math.h instead of fixed point versions? If this is only being done for the player once per frame it shouldn't be a speed critical calculation.
One more thing: is the player x and y position stored as an integer or a double? If it's an integer then you won't be able to move in the precise direction you want because you have to move integral amounts each frame. To solve this you can maintain 2 double variables for the x, y position, and add your movement vector on to them each frame. Then set the x and y by converting to int. This will stop you losing the fractional part of your position each time.
e.g.
playerX += (10 * sinRadians);
playerY -= (10 * cosRadians);
Player.setXPos((int)playerX);
Player.setYPos((int)playerY);

Related

Using The Dot Product to determine whether an object is on the left hand side or right hand side of the direction of the object

so I currently am trying to create some method which when taking in a simulation vehicles position, direction, and an objects position, Will determine whether or not the object lies on the right and side or left hand side of that vehicles direction. This is what i have implemented so far (Note I am in a 2D co-ord system):
This is the code block that uses the method
void Class::leftOrRight()
{
// Clearing both _lhsCones and _rhsCones vectors
_rhsCones.clear();
_lhsCones.clear();
for (int i =0; i < _cones.size(); i++)
{
if (dotAngleFromYaw(_x, _y, _cones[i].x(), _cones[i].y(), _yaw) > 0)
{
_lhsCones.push_back(_cones[i]);
}
else
{
_rhsCones.push_back(_cones[i]);
}
}
return;
}
This is the code block which computes the angle
double Class::dotAngleFromYaw(double xCar, double yCar, double xCone, double yCone, double yawCar)
{
double iOne = cos(yawCar);
double jOne = sin(yawCar);
double iTwo = xCone - xCar;
double jTwo = yCone - yCar;
//ensure to normalise the vector two
double magTwo = std::sqrt(std::pow(iTwo, 2) + std::pow(jTwo, 2));
iTwo = iTwo / magTwo;
jTwo = jTwo / magTwo;
double theta = acos((iOne * iTwo) + (jOne * jTwo)); // in radians
return theta;
}
My issue with this is that dotAngleFromYaw(0,0,0,1,0) = +pi/2 and dotAngleFromYaw(0,0,0,-1,0) = +pi/2 hence the if statements fail to sort the cones.
Any help would be great
*Adjustments made from comment suggestions
I have change the sort method as follows
double Class::indicateSide(double xCar, double yCar, double xCone, double yCone, double yawCar)
{
// Compute the i and j compoents of the yaw measurment as a unit vector i.e Vector Mag = 1
double iOne = cos(yawCar);
double jOne = sin(yawCar);
// Create the Car to Cone Vector
double iTwo = xCone - xCar;
double jTwo = yCone - yCar;
//ensure to normalise the vCar to Cone Vector
double magTwo = std::sqrt(std::pow(iTwo, 2) + std::pow(jTwo, 2));
iTwo = iTwo / magTwo;
jTwo = jTwo / magTwo;
// // Using the transformation Matrix with Theta = yaw (angle in radians) transform the axis to the augmented 2D space
// double Ex = cos(yawCar)*iOne - sin(yawCar)*jOne;
// double Ey = sin(yawCar)*iOne + cos(yawCar)*jOne;
// Take the Cross Product of < Ex, 0 > x < x', y' > where x', y' have the same location in the simulation space.
double result = iOne*jTwo - jOne*iTwo;
return result;
}
However I still am having issues defining the left and right, note that I have also become aware that objects behind the vehicle are still passed to every instance of the array of objects to be evaluated and hence I have implemented a dot product check elsewhere that seems to work fine for now, which is why I have not included it here I can make another adjustment to the post to include said code. I did try to implement the co-ordinate system transformation however i did not see improvements compared to when the added lines are not commented out and implemented.
Any further feedback is greatly appreciated
If the angle does not matter and you only want to know whether "left or right" I'd go for another approach.
Set up a plane that has xCar and yCar on its surface. When setting it up it's up to you how to define the plane's normal i.e. the side its facing to.
After that you can apply the dot-product to determine the 'sign' indicating which side it's on.
Note that dot product does not provide information about left/right position.
Sign of dot product says whether position is ahead or backward.
To get left/right side, you need to check sign of cross product
cross = iOne * jTwo - jOne * iTwo
(note subtraction and i/j alternation)
To see the difference between dot and cross product info:
Quick test. Mathematical coordinate system (CCW) is used (left/right depends on CW/CCW)
BTW, in kinematics simulations it is worth to store components of direction vector rather than angle.
#define _USE_MATH_DEFINES // для C++
#include <cmath>
#include <iostream>
void check_target(float carx, float cary, float dirx, float diry, float tx, float ty) {
float cross = (tx - carx) * diry - (ty - cary) * dirx;
float dot = (tx - carx) * dirx + (ty - cary) * diry;
if (cross >= 0) {
if (dot >= 0)
std::cout << "ahead right\n";
else
std::cout << "behind right\n";
}
else {
if (dot >= 0)
std::cout << "ahead left\n";
else
std::cout << "behind left\n";
}
}
int main()
{
float carx, cary, car_dir_angle, dirx, diry;
float tx, ty;
carx = 1;
cary = 1;
car_dir_angle = M_PI / 4;
dirx = cos(car_dir_angle);
diry = sin(car_dir_angle);
check_target(carx, cary, dirx, diry, 2, 3);
check_target(carx, cary, dirx, diry, 2, 1);
check_target(carx, cary, dirx, diry, 1, 0);
check_target(carx, cary, dirx, diry, 0, 1);
}

Repulsion Vector

I am trying to implement a basic AI for a Turrets game in SFML and C++ and I have some problems.
This AI follows some waypoints stablished in a Bezier Courve.
In first place, this path was followed only by one enemy. For this purpose, the enemy has to calculate his distance between his actual position
to the next waypoint he has to pick.
If the distance is less than a specific value we stablish, then, we get to the next point. This will repeat until the final destination is reached. (in the submitting code, forget about the var m_go)
Okay, our problem gets when we spawn several enemies and all have to follow the same path, because it produces a bad visual effect (everyone gets upside another).
In order to solve this visual problem, we have decided to use a repulsion vector. The calculus gets like this: representation of what we want
As you can see, we calculate the repulsion vector with the inverse of the distance between the enemy and his nearest neighbor.
Then, we get it applying this to the "theorical" direction, by adding it, and we get a resultant, which is the direction that
our enemy has to follow to not "collide" with it's neighbors.
But, our issue comes here:
The enemys get sepparated in the middle of the curve and, as we spawn more enemys, the speed of all of them increases dramatically (including the enemies that don't calculate the repuslion vector).
1 - Is it usual that this sepparation occours in the middle of the trajectory?
2 - Is it there a way to control this direction without the speed getting affected?
3 - Is it there any alternative to this theory?
I submit the code below (There is a variable in Spanish [resultante] which it means resultant in English):
if (!m_pathCompleted) {
if (m_currentWP == 14 && m_cambio == true) {
m_currentWP = 0;
m_path = m_pathA;
m_cambio = false;
}
if (m_neighbors.size() > 1) {
for (int i = 0; i < m_neighbors.size(); i++) {
if (m_enemyId != m_neighbors[i]->GetId()) {
float l_nvx = m_neighbors[i]->GetSprite().getPosition().x - m_enemySprite.getPosition().x;
float l_nvy = m_neighbors[i]->GetSprite().getPosition().y - m_enemySprite.getPosition().y;
float distance = std::sqrt(l_nvx * l_nvx + l_nvy * l_nvy);
if (distance < MINIMUM_NEIGHBOR_DISTANCE) {
l_nvx *= -1;
l_nvy *= -1;
float l_vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
float l_vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;
float l_resultanteX = l_nvx + l_vx;
float l_resultanteY = l_nvy + l_vy;
float l_waypointDistance = std::sqrt(l_resultanteX * l_resultanteX + l_resultanteY * l_resultanteY);
if (l_waypointDistance < MINIMUM_WAYPOINT_DISTANCE) {
if (m_currentWP == m_path.size() - 1) {
std::cout << "\n";
std::cout << "[GAME OVER]" << std::endl;
m_go = false;
m_pathCompleted = true;
} else {
m_currentWP++;
}
}
if (l_waypointDistance > MINIMUM_WAYPOINT_DISTANCE) {
l_resultanteX = l_resultanteX / l_waypointDistance;
l_resultanteY = l_resultanteY / l_waypointDistance;
m_enemySprite.move(ENEMY_SPEED * l_resultanteX * dt, ENEMY_SPEED * l_resultanteY * dt);
}
} else {
float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;
float len = std::sqrt(vx * vx + vy * vy);
if (len < MINIMUM_WAYPOINT_DISTANCE) {
if (m_currentWP == m_path.size() - 1) {
std::cout << "\n";
std::cout << "[GAME OVER]" << std::endl;
m_go = false;
m_pathCompleted = true;
} else {
m_currentWP++;
}
}
if (len > MINIMUM_WAYPOINT_DISTANCE) {
vx = vx / len;
vy = vy / len;
m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt);
}
}
}
}
} else {
float vx = m_path[m_currentWP].x - m_enemySprite.getPosition().x;
float vy = m_path[m_currentWP].y - m_enemySprite.getPosition().y;
float len = std::sqrt(vx * vx + vy * vy);
if (len < MINIMUM_WAYPOINT_DISTANCE) {
if (m_currentWP == m_path.size() - 1) {
std::cout << "\n";
std::cout << "[GAME OVER]" << std::endl;
m_go = false;
m_pathCompleted = true;
} else {
m_currentWP++;
}
}
if (len > MINIMUM_WAYPOINT_DISTANCE) {
vx = vx / len;
vy = vy / len;
m_enemySprite.move(ENEMY_SPEED * vx * dt, ENEMY_SPEED * vy * dt);
}
}
}
I will try to answer your questions one by one, but first, I don't see anything terribly wrong in the code, so it could be simply a set of non contemplated situations.
1 - Is it usual that this sepparation occours in the middle of the
trajectory?
Well, you're applying repulsion forces to every enemy based on distance of near enough others. If something weird happens or if you're moving them more than necessary, could result on a considerable deviation from their original trajectory.
2 - Is it there a way to control this direction without the speed
getting affected?
In this line
m_enemySprite.move(ENEMY_SPEED * l_resultanteX * dt, ENEMY_SPEED * l_resultanteY * dt);
we see you're, in fact, applying that repulsion force based on l_resultante vector. That vector depends directly on l_nv (repulsion vector), which its module (or length) is proportional to the distance between this (enemy you are processing now) and other (the neighbor). As you're multiplying this vector by the speed of the enemy (a constant value), greater the distance, greater the force applied and more separation will be between them.
I suggest you to:
Normalize the vector l_nv (Easier): This is, force it to have module 1. With this solution every enemy will be pushed with the same force (basically ENEMY_SPEED) but in proper direction.
Inverse the vector l_nv (Little harder): If you apply this vector inversely proportional to the distance (module = 1/distance), they will behave the opposite and they will be pushed less if they are farther from each other.
Also consider that you are applying forces consecutively and you're making them effective by every neighbor processed. This implies something undesirable. If you push an enemy, this force could move it into a location where a future enemy (in the for loop) could push it maybe more than before. If this effect concatenates several times, could trigger a chain reaction where your enemy is pushed more and more. This effect will be amplified if you're applying the forces proportional to the distance.
3 - Is it there any alternative to this theory?
I actually run out of ideas, but I left this space here if someone want to edit the answer and suggest something

difficulty calculating angle of a point on a circle

I'm having a bit of trouble with the geometry for a function I'm writing. I have a class that contains various sprites. This container class needs to be able to move, rotate, and scale while keeping all the child sprite's relative position, rotation, and scale intact.
I'm running into issues when rotating the container. The angle calculated by atan2 seems to be random. I wrote a simple console application that does and outputs the math behind a function I'm using (it's hard to properly show the code, as it relies on various outside sources). I did this to make sure it wasn't another part of the code causing my error. But my results are the same with the console application. Here is the code (it's stand-alone. you can easily run it)
#include<math.h>
#include<iostream>
using namespace std;
int main()
{
float containerX = 0;
float containerY = 0;
float childX = 10;
float childY = 0;
for(int i = 0; i <= 360; i += 36)
{
float radius = sqrt(pow(containerX - childX, 2) + pow(containerY - childY, 2));
float angle = atan2 (containerY - childY, containerX - childX);
float newAngle = angle + (i / 180.0 * 3.14);
childX = containerX + radius * cos(newAngle);
childY = containerY + radius * sin(newAngle);
std::cout << "New angle: " << newAngle * 180.0 / 3.14 << " New Position: " << childX << ", " << childY << std::endl;
}
while(1!=2) {} // This line is so I can read the console output
return 0;
}
My output is as follows:
New angle: 180.091 New Position: -10, -8.74228e-007
New angle: 36 New Position: 8.09204, 5.87528
New angle: -72.0913 New Position: 3.08108, -9.51351
New angle: 216 New Position: -8.10139, -5.86238
New angle: 179.909 New Position: -9.99995, 0.0318542
New angle: 179.817 New Position: -9.99988, 0.0477804
New angle: 215.726 New Position: -8.12931, -5.8236
New angle: 287.635 New Position: 3.00522, -9.53775
New angle: 395.543 New Position: 8.15704, 5.78469
New angle: 179.27 New Position: -9.99897, 0.143339
New angle: 359.178 New Position: 9.99846, -0.175189
I know that the problem has something to do with me calculating the angle with atan2, since if I just convert i to radians (i is iterating through degrees 0 and 360 in increments of 36) and pass that to cos and sin, I get points in order around the circle. If I use my "newAngle" variable though, I get random points around the circumference of the circle (bottom left, rop right, near bottom left, left of circle, right of circle, etc)
Thanks for reading this. I really appreciate it. I'm totally stuck. Any help would be wonderful.
float angle = atan2 (containerY - childY, containerX - childX);
float newAngle = angle + (i / 180.0 * 3.14);
In the first line, you're getting the new angle. In the second line, you're not just adding 36 degrees, instead you're adding i degrees, so in every iteration the code is adding an increasing angle to the new angle which itself is already increasing, hence the sporadic behavior.
Two different solutions:
1) Replace the first line with
float angle = 3.14159; // allow the loop to add to it
or
2) Change the i to a 36 in the line
float newAngle = angle + (36 / 180.0 * 3.14);
Don't do both! Choose one.
float angle = atan2 (containerY - childY, containerX - childX);
Make it
float angle = atan2 (childY - containerY, childX - containerX);
As originally written, you are flipping the child coordinates around the center of rotation on every iteration (in other words, adding an extra 180 degrees offset). You could see this easily if you don't adjust the angle at all: float newAngle = angle;. Your coordinates would oscillate between -10 and 10.
I hinted at it in my comment, but this is how you could have broken down your issue to see the problem: http://ideone.com/nTGXuv
#include <cmath>
#include <iostream>
#include <utility>
std::pair<float, float> rotate(std::pair<float, float> origin, std::pair<float, float> start, unsigned int degrees)
{
std::pair<float, float> diff = std::make_pair(start.first - origin.first, start.second - origin.second);
float currentAngle = ::atan2(diff.second, std::abs(diff.first));
float newAngle = currentAngle + (degrees / 180.0 * 3.1415926539);
float radius = std::sqrt(diff.first * diff.first + diff.second * diff.second);
float cosAngle = ::cos(newAngle);
float sinAngle = ::sin(newAngle);
float x = origin.first + radius * cosAngle;
float y = origin.second + radius * sinAngle;
return std::make_pair(x, y);
}
int main()
{
std::pair<float, float> origin = std::make_pair(0.0, 0.0);
std::pair<float, float> start = std::make_pair(1.0, 0.0);
const unsigned int degrees = 45;
for (unsigned int i = 0; i < 360; i += degrees)
{
std::pair<float, float> newPos = rotate(origin, start, i);
std::cout << "Rotated to " << i << " degrees: (" << newPos.first << ", " << newPos.second << ")" << std::endl;
}
return 0;
}

C++ Logic Issue

I'm trying to write a simple c++ program that outputs an objects current height once it hits a specific point. The object I'm trying to accomplish is that you have an object that starts at a varied position a moves off under a random velocity with gravity attached. If the ball collides with a wall or another object, it should move backward, with no energy loss, but still continue to fall due to gravity. Once the ball has reached a specific height, output that value.
Now, all I'm trying to do right now is check to see if my ball has gone beyond my width bounds. But for the life of me I can't see why my last if statement at the bottom wont call.
Am I missing / doing something really stupid?
int _tmain(int argc, _TCHAR* argv[])
{
float velocity;
float height, targetHeight;
float gravity;
float time;
float angle;
float width;
float move;
float distance;
gravity = 9.80f;
time = 0;
distance = 0;
cout << "Set Height\n";
cin >> height;
cout << "Set target height\n";
cin >> targetHeight;
cout << "Set Angle ( 0 - 90 ): \n";
cin >> angle;
angle *= 3.14 * 180; // convert to radians
cout << "Set velocity (0 - 100): \n";
cin >> velocity;
cout << "Set Play field Width: \n";
cin >> width;
while( height >= target )
{
time++;
distance += velocity * cos(angle) * time;
height += (velocity * sin(angle) * time) - (gravity * pow(time, 2) ) / 2;
}
if( distance == width)
{
cout << "You've hit the wall\n";
}
return 0;
}
Your final if statement if( distance == width ) does not test if the distance has gone beyond the width. You probably want if( distance >= width ). There doesn't appear to be any testing of distance traveled within your movement loop so distance could easily be greater than the width and thus cause your if to not be true.
Move backwards at the same speed: velocity = -velocity;. Of course, if it's moving backwards, it may hit the other wall, so you probably want to check the distance == 0; as well. (Since it's floating point, I would also suggest you use >= and <= instead of exact comparisons, or you may find that the ball was one micrometer PAST the wall and then continues until it hits the sun, or you run out of math, or whatever else happens if you keep going forever).
I would further suggest that you would need the width and breadth of the "room" the ball is bouncing around in. So, in total you need X, Y, and Z coordinates of the ball.
Note: your time ever increases, which implies a direct formula for height and distance (one saying distance = f(time);), but you're accumulating.
So probably you want to assign instead of increment your distance and height variables:
distance = velocity * cos(angle) * time;
height = (velocity * sin(angle) * time) - (gravity * pow(time, 2) ) / 2;
Next to that, you probably want to check whether the travelled distance exceeds the distance to the wall (equality with floats is very improbable, plus inaccurate).
Some stylistic advice: put those equations in functions of their own.

Sporadic Collision Detection

I've been working on detecting collision between to object in my game. Right now everything tavels vertically, but would like to keep the option for other movement open. It's classic 2d vertical space shooter.
Right now I loop through every object, checking for collisions:
for(std::list<Object*>::iterator iter = mObjectList.begin(); iter != mObjectList.end();) {
Object *m = (*iter);
for(std::list<Object*>::iterator innerIter = ++iter; innerIter != mObjectList.end(); innerIter++ ) {
Object *s = (*innerIter);
if(m->getType() == s->getType()) {
break;
}
if(m->checkCollision(s)) {
m->onCollision(s);
s->onCollision(m);
}
}
}
Here is how I check for a collision:
bool checkCollision(Object *other) {
float radius = mDiameter / 2.f;
float theirRadius = other->getDiameter() / 2.f;
Vector<float> ourMidPoint = getAbsoluteMidPoint();
Vector<float> theirMidPoint = other->getAbsoluteMidPoint();
// If the other object is in between our path on the y axis
if(std::min(getAbsoluteMidPoint().y - radius, getPreviousAbsoluteMidPoint().y - radius) <= theirMidPoint.y &&
theirMidPoint.y <= std::max(getAbsoluteMidPoint().y + radius, getPreviousAbsoluteMidPoint().y + radius)) {
// Get the distance between the midpoints on the x axis
float xd = abs(ourMidPoint.x - theirMidPoint.x);
// If the distance between the two midpoints
// is greater than both of their radii together
// then they are too far away to collide
if(xd > radius+theirRadius) {
return false;
} else {
return true;
}
}
return false;
}
The problem is it will randomly detect collisions correctly, but other times does not detect it at all. It's not the if statement breaking away from the object loop because the objects do have different types. The closer the object is to the top of the screen, the better chance it has of collision getting detected correctly. Closer to the bottom of the screen, the less chance it has of getting detected correctly or even at all. However, these situations don't always occur. The diameter for the objects are massive (10 and 20) to see if that was the problem, but it doesn't help much at all.
EDIT - Updated Code
bool checkCollision(Object *other) {
float radius = mDiameter / 2.f;
float theirRadius = other->getDiameter() / 2.f;
Vector<float> ourMidPoint = getAbsoluteMidPoint();
Vector<float> theirMidPoint = other->getAbsoluteMidPoint();
// Find the distance between the two points from the center of the object
float a = theirMidPoint.x - ourMidPoint.x;
float b = theirMidPoint.y - ourMidPoint.y;
// Find the hypotenues
double c = (a*a)+(b*b);
double radii = pow(radius+theirRadius, 2.f);
// If the distance between the points is less than or equal to the radius
// then the circles intersect
if(c <= radii*radii) {
return true;
} else {
return false;
}
}
Two circular objects collide when the distance between their centers is small enough. You can use the following code to check this:
double distanceSquared =
pow(ourMidPoint.x - theirMidPoint.x, 2.0) +
pow(ourMidPoint.x - theirMidPoint.x, 2.0);
bool haveCollided = (distanceSquared <= pow(radius + theirRadius, 2.0));
In order to check whether there was a collision between two points in time, you can check for collision at the start of the time interval and at the end of it; however, if the objects move very fast, the collision detection can fail (i guess you have encountered this problem for falling objects that have the fastest speed at the bottom of the screen).
The following might make the collision detection more reliable (though still not perfect). Suppose the objects move with constant speed; then, their position is a linear function of time:
our_x(t) = our_x0 + our_vx * t;
our_y(t) = our_y0 + our_vy * t;
their_x(t) = their_x0 + their_vx * t;
their_y(t) = their_y0 + their_vy * t;
Now you can define the (squared) distance between them as a quadratic function of time. Find at which time it assumes its minimum value (i.e. its derivative is 0); if this time belongs to current time interval, calculate the minimum value and check it for collision.
This must be enough to detect collisions almost perfectly; if your application works heavily with free-falling objects, you might want to refine the movement functions to be quadratic:
our_x(t) = our_x0 + our_v0x * t;
our_y(t) = our_y0 + our_v0y * t + g/2 * t^2;
This logic is wrong:
if(std::min(getAbsoluteMidPoint().y - radius, getPreviousAbsoluteMidPoint().y - radius) <= theirMidPoint.y &&
theirMidPoint.y <= std::max(getAbsoluteMidPoint().y + radius, getPreviousAbsoluteMidPoint().y + radius))
{
// then a collision is possible, check x
}
(The logic inside the braces is wrong too, but that should produce false positives, not false negatives.) Checking whether a collision has occurred during a time interval can be tricky; I'd suggest checking for a collision at the present time, and getting that to work first. When you check for a collision (now) you can't check x and y independently, you must look at the distance between the object centers.
EDIT:
The edited code is still not quite right.
// Find the hypotenues
double c = (a*a)+(b*b); // actual hypotenuse squared
double radii = pow(radius+theirRadius, 2.f); // critical hypotenuse squared
if(c <= radii*radii) { // now you compare a distance^2 to a distance^4
return true; // collision
}
It should be either this:
double c2 = (a*a)+(b*b); // actual hypotenuse squared
double r2 = pow(radius+theirRadius, 2.f); // critical hypotenuse squared
if(c2 <= r2) {
return true; // collision
}
or this:
double c2 = (a*a)+(b*b); // actual hypotenuse squared
double c = pow(c2, 0.5); // actual hypotenuse
double r = radius + theirRadius; // critical hypotenuse
if(c <= r) {
return true; // collision
}
Your inner loop needs to start at mObjectList.begin() instead of iter.
The inner loop needs to iterate over the entire list otherwise you miss collision candidates the further you progress in the outer loop.