C++: Unsure if code is multithreadable - c++

I'm working on a small piece of code which takes a very large amount of time to complete, so I was thinking of multithreading it either with pthread (which I hardly understand but think I can master a lot quicker) or with some GPGPU implementation (probably OpenCL as I have an AMD card at home and the PCs I use at my office have various NVIDIA cards)
while(sDead < (unsigned long) nrPoints*nrPoints) {
pPoint1 = distrib(*rng);
pPoint2 = distrib(*rng);
outAxel = -1;
if(pPoint1 != pPoint2) {
point1 = space->getPointRef(pPoint1);
point2 = space->getPointRef(pPoint2);
outAxel = point1->influencedBy(point2, distThres);
if(outAxel == 0 || outAxel == 1)
sDead++;
else
sDead = 0;
}
i++;
}
Where distrib is a uniform_int_distribution with a = 0 and b = nrPoints-1.
For clarity, here is the structure I'm working with:
class Space{
vector<Point> points
(more stuff)
}
class Point {
vector<Coords> coordinates
(more stuff)
}
struct Coords{
char Range
bool TypeOfCoord
char Coord
}
The length of coordinates is the same for all Points and Point[x].Coord[y].Range == Point[z].Coord[y].Range for all x, y and z. The same goes for TypeOfCoord.
Some background: during each run of the while loop, two randomly drawn Points from space are tested for interaction. influencedBy() checks whether or not point1 and point2 are close enough to eachother (distance is dependent on some metric but it boils down to similarity in Coord. If the distance is smaller than distThres, interaction is possible) to interact. Interaction means that one of the Coord variables which doesn't equal the corresponding Coord in the other object is flipped to equal it. This decreases the distance between the Points but also changes the distance of the changed point to every other point in Space, hence my question of whether or not this is multithreadable. As I said, I'm a complete newbie to multithreading and I'm not sure if I can safely implement a function that chops this up, so I was looking for your input. Suggestions are also very welcome.
E: The influencedby() function (and the functions it in turn calls) can be found here. Functions that I did not include, such as getFeature() and getNrFeatures() are tiny and cannot possibly contribute much. Take note that I used generalised names for objects in this question but I might mess up or make it more confusing if I replace them in the other code, so I've left the original names there. For the record:
Space = CultSpace
Point = CultVec
Points = Points
Coordinates = Feats
Coords = Feature
TypeOfCoord = Nomin
Coord = Trait

(Choosing "Answer" because the format permits better presentation. Not quite what your're asking for, but let's clarify this first.)
Later
How often is the loop executed until this condition becomes true?
while(sDead < (unsigned long) nrPoints*nrPoints) {
Probably not a big gain, but:
pPoint1 = distrib(*rng);
do {
pPoint2 = distrib(*rng);
while( pPoint1 == pPoint2 );
outAxel = -1;
How costly is getPointRef? Linear search in Space?
point1 = space->getPointRef(pPoint1);
point2 = space->getPointRef(pPoint2);
outAxel = point1->influencedBy(point2, distThres);
Is it really necessary to recompute the "distance of the changed point to every other point in Space" immediately after a "flip"?

Related

C++ Function not working as expected

So I know this is a very broad topic, but I'm not sure how to describe it and I'm not sure where the bug is. So I'm making a game in the console window, a roguelike-rpg, (I haven't done the random dungeon yet, but I've done it in other languages.) and I'm having problems dealing with walls.
I have a function called placeMeeting(REAL X, REAL Y) that I use to check for collisions, but it appears to be returning bad values and I couldn't tell you why. I have couple of macros defined: #define AND && and #define REAL double.
Here is the function:
bool GlobalClass::placeMeeting(REAL X, REAL Y)
{
//The return value -- False until proven otherwise
bool collision = false;
//Loop through all walls to check for a collision
for(int i = 0; i < wallCount; i++)
{
//If there was a collision, 'say' so
if (X == wallX[ i ] AND Y == wallY[ i ])
{
//Set 'collision' to true
collision = true;
}
}
return collision;
}
But the strange catch is that it only doesn't work when displaying the screen. The player collides with them all the same even though there not displayed. Even stranger, only the first wall is being displayed.
Here is where the walls are defined:
int wallCount;
//Array of walls
REAL wallX[ 1 ];
REAL wallY[ 1 ];
and
wallCount = 1;
//Basic wall stuff; basically just a placeholder
wallX[ 0 ] = 10;
wallY[ 0 ] = 10;
So I have a function used to render the screen (In the console window of course.) and it looks like this:
for (int y = oGlobal.viewY; y < oGlobal.viewY + oGlobal.viewHeight; y++)
{
//The inner 'x' loop of the view
for(int x = oGlobal.viewX; x < oGlobal.viewX + oGlobal.viewWidth; x++)
{
//Call the function to check this spot and print what it returns
screen += oGlobal.checkSpot(x, y);
}
}
That's not the whole function, just the actual screen refreshing. After 'screen' is printed to the screen, to reduce buffer time. And of course, checkSpot:
STRING GlobalClass::checkSpot(REAL x, REAL y)
{
STRING spriteAtSpot;
//First check for the player
if (x == oPlayer.x AND y == oPlayer.y)
{
spriteAtSpot = oPlayer.sprite;
}
else if (placeMeeting(x, y)) //ITS TEH WALL SUCKAS
{
spriteAtSpot = WALL_SPRITE;
}
else //Nothing here, return a space
{
spriteAtSpot = EMPTY_SPRITE;
}
//Return the sprite
return spriteAtSpot;
}
I know it's a lot of code, but I really don't know where I screwed up.
I really appreciate any help!
P.S. Here is an image to help understand
http://i.imgur.com/8XnaHIt.png
I'm not sure if I'm missing something, but since rogue-like games are tile-based, is it necessary to make the X and Y values doubles? I remember being told that doubles are finicky to compare, since even if you assume they should be equal, they could be very slightly off, causing comparison to return false when you'd think it would return true.
I'm not sure we have enough of your code to debug it, but I have developed a Rogue-like console game, and here is my $.02...
Start over. You seem to be doing this in a very non-OO way (GlobalClass?). Consider objects such as Level (aggregates entire level), DungeonObject (essentially each space on the level; it's a base class that can be inherited from into Wall, Player, etc.). Doing this will make the programming much easier.
Embrace the suck. C++ syntax may suck, but the more you fight against it, the harder it will be to learn. Use && and the built-in datatypes. It won't take long to get used to.
Rouge-like locations are essentially integer-based. Use integer for x, y locations, not doubles (the biggest built-in data-type). Not only is it more efficient, you'll find debugging much easier.
Start in the small. Start with a 5 x 5 dungeon level to get the basics down. Then, if you've designed it correctly, scaling up to a 10x10 or 25x25 will be much easier.
That's how I developed my game; I hope it helps.
Apart from the use of double instead of int, I see something strange in your definition of walls:
int wallCount;
//Array of walls
REAL wallX[ 1 ];
REAL wallY[ 1 ];
and
wallCount = 1;
//Basic wall stuff; basically just a placeholder
wallX[ 0 ] = 10;
wallY[ 0 ] = 10;
You are defining a variable called wallCount, which you later use to go through the elements of your array in your placeMeeting function:
//Loop through all walls to check for a collision
for(int i = 0; i < wallCount; i++)
Then why don't you use wallCount to define the size of your arrays? Of course you can't use that syntax, because the size of a static array must be known at compile time, so you should either use new or std::vector, but still you shouldn't have a variable that defines the length of the array and then use another value when you actually create the array, it is a source of bugs if you fail to keep them aligned. So for example you could do this:
const int wallCount = 1;
int* wallX = new int[wallCount];
int* wallY = new int[wallCount];
But there's a bigger problem: why are you creating arrays of size 1? You are having only one wall! It doesn't really make sense to have arrays of size 1, unless you intend to use another value but you have reduced it to 1 for debugging purposes. But, you wrote this:
Even stranger, only the first wall is being displayed.
That's because you only have 1 wall!
By the way, the way you have designed your data isn't the one I would use. From your checkSpot I understand this: oPlayer.x and oPlayer.y are the coordinates of your player, and x and y are the coordinates of the tile you have to draw (and for which you need to choose the appropriate sprite). If in your map you have 3 walls, you have to put 3 values in wallX and 3 in wallY, and you must make sure that you keep the 2 arrays "aligned" (if the coordinates of your second wall are for example x=10 and y=20, you could get confused, or have buggy code, and instead of saving it as
wallX[1] = 10;
wallY[1] = 20;
you might write
wallX[1] = 10;
wallY[2] = 20; // wrong index!
so it's one more source of bugs), and worse, you must check that they are consistent with other arrays of other objects: you could have, for example, doors, and then following your approach you'd have doorX[] and doorY[], and how can you be sure that you don't have a wall and a door at the same place? Like, if you had
doorX[0] = 10;
doorY[0] = 20;
it would be at the same place as the wall, and the error isn't obvious, because you'd have to cross-check all your arrays to find it. So I would suggest to have a level[height][width] instead, and to have a wall at x=10 and y=20 you could use level[10][20] = 'w';. This would ensure that you only have ONE object per tile. Besides, checking for collisions would be faster: with your approach, if you have 50 walls you need 50 checks; with mine, you always only need one. Ok, performance is certainly not an issue in these games, but still I think you should consider my approach (unless there are other reasons to prefer yours, of course).

C++ plotting Mandlebrot set, bad performance

I'm not sure if there is an actual performance increase to achieve, or if my computer is just old and slow, but I'll ask anyway.
So I've tried making a program to plot the Mandelbrot set using the cairo library.
The loop that draws the pixels looks as follows:
vector<point_t*>::iterator it;
for(unsigned int i = 0; i < iterations; i++){
it = points->begin();
//cout << points->size() << endl;
double r,g,b;
r = (double)i+1 / (double)iterations;
g = 0;
b = 0;
while(it != points->end()){
point_t *p = *it;
p->Z = (p->Z * p->Z) + p->C;
if(abs(p->Z) > 2.0){
cairo_set_source_rgba(cr, r, g, b, 1);
cairo_rectangle (cr, p->x, p->y, 1, 1);
cairo_fill (cr);
it = points->erase(it);
} else {
it++;
}
}
}
The idea is to color all points that just escaped the set, and then remove them from list to avoid evaluating them again.
It does render the set correctly, but it seems that the rendering takes a lot longer than needed.
Can someone spot any performance issues with the loop? or is it as good as it gets?
Thanks in advance :)
SOLUTION
Very nice answers, thanks :) - I ended up with a kind of hybrid of the answers. Thinking of what was suggested, i realized that calculating each point, putting them in a vector and then extract them was a huge waste CPU time and memory. So instead, the program now just calculate the Z value of each point witout even using the point_t or vector. It now runs A LOT faster!
Edit: I think the suggestion in the answer of kuroi neko is also a very good idea if you do not care about "incremental" computation, but have a fixed number of iterations.
You should use vector<point_t> instead of vector<point_t*>.
A vector<point_t*> is a list of pointers to point_t. Each point is stored at some random location in the memory. If you iterate over the points, the pattern in which memory is accessed looks completely random. You will get a lot of cache misses.
On the opposite vector<point_t> uses continuous memory to store the points. Thus the next point is stored directly after the current point. This allows efficient caching.
You should not call erase(it); in your inner loop.
Each call to erase has to move all elements after the one you remove. This has O(n) runtime. For example, you could add a flag to point_t to indicate that it should not be processed any longer. It may be even faster to remove all the "inactive" points after each iteration.
It is probably not a good idea to draw individual pixels using cairo_rectangle. I would suggest you create an image and store the color for each pixel. Then draw the whole image with one draw call.
Your code could look like this:
for(unsigned int i = 0; i < iterations; i++){
double r,g,b;
r = (double)i+1 / (double)iterations;
g = 0;
b = 0;
for(vector<point_t>::iterator it=points->begin(); it!=points->end(); ++it) {
point_t& p = *it;
if(!p.active) {
continue;
}
p.Z = (p.Z * p.Z) + p.C;
if(abs(p.Z) > 2.0) {
cairo_set_source_rgba(cr, r, g, b, 1);
cairo_rectangle (cr, p.x, p.y, 1, 1);
cairo_fill (cr);
p.active = false;
}
}
// perhaps remove all points where p.active = false
}
If you can not change point_t, you can use an additional vector<char> to store if a point has become "inactive".
The Zn divergence computation is what makes the algorithm slow (depending on the area you're working on, of course). In comparison, pixel drawing is mere background noise.
Your loop is flawed because it makes the Zn computation slow.
The way to go is to compute divergence for each point in a tight, optimized loop, and then take care of the display.
Besides, it's useless and wasteful to store Z permanently.
You just need C as an input and the number of iterations as an output.
Assuming your points array only holds C values (basically you don't need all this vector crap, but it won't hurt performances either), you could do something like that :
for(vector<point_t>::iterator it=points->begin(); it!=points->end(); ++it)
{
point_t Z = 0;
point_t C = *it;
for(unsigned int i = 0; i < iterations; i++) // <-- this is the CPU burner
{
Z = Z * Z + C;
if(abs(Z) > 2.0) break;
}
cairo_set_source_rgba(cr, (double)i+1 / (double)iterations, g, b, 1);
cairo_rectangle (cr, p->x, p->y, 1, 1);
cairo_fill (cr);
}
Try to run this with and without the cairo thing and you should see no noticeable difference in execution time (unless you're looking at an empty spot of the set).
Now if you want to go faster, try to break down the Z = Z * Z + C computation in real and imaginary parts and optimize it. You could even use mmx or whatever to do parallel computations.
And of course the way to go to gain another significant speed factor is to parallelize your algorithm over the available CPU cores (i.e. split your display area is subsets and have different worker threads compute these parts in parallel).
This is not as obvious at it might seem, though, since each sub-picture will have a different computation time (black areas are very slow to compute while white areas are computed almost instantly).
One way to do it is to split the area is a large number of rectangles, and have all worker threads pick a random rectangle from a common pool until all rectangles have been processed.
This simple load balancing scheme that makes sure no CPU core will be left idle while its buddies are busy on other parts of the display.
The first step to optimizing performance is to find out what is slow. Your code mixes three tasks- iterating to calculate whether a point escapes, manipulating a vector of points to test, and plotting the point.
Separate these three operations and measure their contribution. You can optimise the escape calculation by parallelising it using simd operations. You can optimise the vector operations by not erasing from the vector if you want to remove it but adding it to another vector if you want to keep it ( since erase is O(N) and addition O(1) ) and improve locality by having a vector of points rather than pointers to points, and if the plotting is slow then use an off-screen bitmap and set points by manipulating the backing memory rather than using cairo functions.
(I was going to post this but #Werner Henze already made the same point in a comment, hence community wiki)

How do I most efficiently perform collision detection on a group of spheres

Suppose I have a CPU with several cores, on which I want to find which spheres are touching. Any set of spheres where each sphere is connected (ie. they're all touching at least one of the spheres in the set) is called a "group" and is to be organized into a vector called, in the example below, "group_members". To achieve this I am currently using a rather expensive operation that looks conceptually like this:
vector<Sphere*> unallocated_spheres = all_spheres; // start with a copy of all spheres
vector<vector<Sphere*>> group_sequence; // groups will be collected here
while (unallocated_spheres.size() > 0U) // each iteration of this will represent the creation of a new group
{
std::vector<Sphere*> group_members; // this will store all members of the current group
group_members.push_back(unallocated_spheres.back()); // start with the last sphere (pop_back requires less resources than erase)
unallocated_spheres.pop_back(); // it has been allocated to a group so remove it from the unallocated list
// compare each sphere in the new group to every other sphere, and continue to do so until no more spheres are added to the current group
for (size_t i = 0U; i != group_members.size(); ++i) // iterators would be unsuitable in this case
{
Sphere const * const sphere = group_members[i]; // the sphere to which all others will be compared to to check if they should be added to the group
auto it = unallocated_spheres.begin();
while (it != unallocated_spheres.end())
{
// check if the iterator sphere belongs to the same group
if ((*it)->IsTouching(sphere))
{
// it does belong to the same group; add it and remove it from the unallocated_spheres vector and repair iterators
group_members.push_back(*it);
it = unallocated_spheres.erase(it); // repair the iterator
}
else ++it; // if no others were found, increment iterator manually
}
}
group_sequence.push_back(group_members);
}
Does anyone have any suggestions for improving the efficiency of this code in terms of wall time? My program spends a significant fraction of the time running through these loops, and any advice on how to structurally change it to make it more efficient would be appreciated.
Note that as these are spheres, "IsTouching()" is a very quick floating point operation (comparing position and radii of the two spheres). It looks like this (note that x,y and z are the position of the sphere in that euclidean dimension):
// input whether this cell is touching the input cell (or if they are the same cell; both return true)
bool const Sphere::IsTouching(Sphere const * const that) const
{
// Apply pythagoras' theorem in 3 dimensions
double const dx = this->x - that->x;
double const dy = this->y - that->y;
double const dz = this->z - that->z;
// get the sum of the radii of the two cells
double const rad_sum = this->radius + that->radius;
// to avoid taking the square root to get actual distances, we instead compare
// the square of the pythagorean distance with the square of the radii sum
return dx*dx + dy*dy + dz*dz < rad_sum*rad_sum;
}
Does anyone have any suggestions for improving the efficiency of this code in terms of wall time?
Change the algorithm. Low-level optimization won't help you. (although you'll achieve very small speedup if you move group_members outside of the while loop)
You need to use space partitioning (bsp-tree, oct-tree) or sweep and prune algorithm.
Sweep and prune (wikipedia has links to original article, plus you can google it) can easily handle 100000 moving and potentially colliding spheres on single-core machine (well, as long as you don't put them all at the same coordinates) and is a bit easier to implement than space partitioning. If you know maximum possible size of colliding object, sweep and prune will be more suitable/simpler to implement.
If you're going to use sweep and prune algorithm, you should learn insertion sort algorithm. This sorting algorithm is faster than pretty much any other algorithm when you work on "almost" sorted data, which is the case with sweep-and-prune. Of course, you'll also need some implementation of quicksort or heapsort, but standard library provides that.

Brute force collision detection for two objects too slow

I have a project to see if two objects (made of about 10,000 triangles each) collide using the brute force collision algorithm, rendered in OpenGL. The two objects are not moving. I will have to translate them to some positions and find e.g. 100 triangle collisions etc.
So far I have written a code that actually checks for line-plane intersection between these two models. If I got everything straight I need to check every edge of every triangle of the first model with the each plane of each triangle of the other model. This actually means 3 'for' loops that take hours to end. I suppose I must have something wrong or got the whole concept misunderstood.
for (int i=0; i<model1_faces.num; i++) {
for (int j=0; j<3; j++) {
x1[j] = model1_vertices[model1_faces[i].v[j]-1].x;
y1[j] = model1_vertices[model1_faces[i].v[j]-1].y;
z1[j] = model1_vertices[model1_faces[i].v[j]-1].z;
}
A.x = x1[0];
A.y = y1[0];
A.z = z1[0];
B.x = x1[1];
B.y = y1[1];
B.z = z1[1];
C.x = x1[2];
C.y = y1[2];
C.z = z1[2];
TriangleNormal = findNormalVector((B-A)*(C-A));
RayDirection = B-A;
for (int j=0; j<model2_faces.num; j++) {
PointOnPlane = model2_vertices[model2_faces[j].v[0]-1]; // Any point of the triangle
system("PAUSE");
float D1 = (A-PointOnPlane)^(TriangleNormal); // Distance from A to the plane of j triangle
float D2 = (B-PointOnPlane)^(TriangleNormal);
if ((D1*D2) >= 0) continue; // Line AB doesn't cross the triangle
if (D1==D2) continue; // Line parallel to the plane
CollisionVect = A + (RayDirection) * (-D1/(D2-D1));
Vector temp;
temp = TriangleNormal*(RayDirection);
if (temp^(CollisionVect-A) < 0) continue;
temp = TriangleNormal*(C-B);
if (temp^(CollisionVect-B) < 0) continue;
temp = TriangleNormal*(A-C);
if (temp^(CollisionVect-A) < 0) continue;
// If I reach this point I had a collision //
cout << "Had collision!!" << endl;
Also I do not know exactly where exactly should this function above be called. In my render function so that it runs continuously while rendering or just once, given the fact that I only need to check for a non-moving objects collision?
I would appreciate some explanation and if you're too busy or bored to see my code, just help me with understanding a bit more this whole concept.
As suggested already, you can use bounding volumes. To make best use of these, you can arrange your bounding volumes in an Octree, in which case the volumes are boxes.
At the outermost level, each bounding volume contains the entire object. So you can test whether the two objects might intersect by comparing their zero-level bounding volumes. Testing for intersection of two boxes where all the faces are axis-aligned is trivial.
The octree will index which faces belong to which subdivisions of the bounding volume. So some faces will of course belong to more than one volume and may be tested multiple times.
The benefit is you can prune away many of the brute-force tests that are guaranteed to fail by the fact that only a handful of your subvolumes will actually intersect. The actual intersection testing is of still brute-force, but is on a small subset of faces.
Brute force collision detection often does not scale, as you have noticed. :) The usual approach is to define a bounding volume that contains your models/shapes and simplifies the intersection calculations. Bounding volumes come in all shapes and sizes depending on your models. They can be spheres, boxes, etc.
In addition to defining bounding volumes, you'll want to detect collision in your update section of code, where you are most likely passing in some delta time. That delta time is often needed to determine how far objects need to move and if a collision occurred in that timeframe.

2D Platformer Collision Handling

I am trying to create a 2D platformer (Mario-type) game and I am some having some issues with handling collisions properly. I am writing this game in C++, using SDL for input, image loading, font loading, etcetera. I am also using OpenGL via the FreeGLUT library in conjunction with SDL to display graphics.
My method of collision detection is AABB (Axis-Aligned Bounding Box), which is really all I need to start with. What I need is an easy way to both detect which side the collision occurred on and handle the collisions properly. So, basically, if the player collides with the top of the platform, reposition him to the top; if there is a collision to the sides, reposition the player back to the side of the object; if there is a collision to the bottom, reposition the player under the platform.
I have tried many different ways of doing this, such as trying to find the penetration depth and repositioning the player backwards by the penetration depth. Sadly, nothing I've tried seems to work correctly. Player movement ends up being very glitchy and repositions the player when I don't want it to. Part of the reason is probably because I feel like this is something so simple but I'm over-thinking it.
If anyone thinks they can help, please take a look at the code below and help me try to improve on this if you can. I would like to refrain from using a library to handle this (as I want to learn on my own) or the something like the SAT (Separating Axis Theorem) if at all possible. Thank you in advance for your help!
void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;
int up = 0;
int left = 0;
int right = 0;
int down = 0;
if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}
if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ballPrev.coords[1] < block[i].coords[3] && block[i].coords[3] < ballPrev.coords[3])
{
down = 1;
}
cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;
if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
To explain what some of this code means:
The blocks variable is basically an integer that is storing the amount of blocks, or platforms. I am checking all of the blocks using a for loop, and the number that the loop is currently on is represented by integer i.
The coordinate system might seem a little weird, so that's worth explaining.
coords[0] represents the x position (left) of the object (where it starts on the x axis).
coords[1] represents the y position (top) of the object (where it starts on the y axis).
coords[2] represents the width of the object plus coords[0] (right).
coords[3] represents the height of the object plus coords[1] (bottom).
de2dCheckCollision performs an AABB collision detection.
Up is negative y and down is positive y, as it is in most games.
Hopefully I have provided enough information for someone to help me successfully. If there is something I left out that might be crucial, let me know and I'll provide the necessary information. Finally, for anyone who can help, providing code would be very helpful and much appreciated.
Thank you again for your help!
Edit 2: I have updated my code with a new algorithm that checks where the ball was previously before collision. Corner cases work on that single platform correctly now, and when I have a wall of objects, I can slide against it correctly now. The only remaining problem is that there is a small jittering effect that happens when I am on the ground, where the ball is constantly going up and down as if it is being pulled by gravity and then the ball falls back into the object again.
Edit: Here is a URL to an image trying to show the kinds of problems I am having:
http://img8.imageshack.us/img8/4603/collisionproblem.png
In case the explanation in the picture doesn't make too much sense, the ball cannot move left past the corner of an object unless I jump over it. However, the ball can move right, but it gets repositioned to the right of the object while moving, which is not needed. This creates a skipping movement essentially, where it appears as the the ball is skipping over half of the object or so when I move right. If this doesn't make sense, please ask me and I'll try to clarify more.
One problem with your code is that you only detect situations like this:
If the circle happens to be fully inside the block, you don't reposition at all. And that's a problem.
You're trying to think about your simulation as if it were continuous, but keep in mind it's discrete. In general, if you only look at the current state of the ball, you really cannot know which side it collided with. Look at these two possibilities:
The first solution that comes to mind is to look at the last position of the ball as well; more precisely, look at the delta vector. See if the delta vector intersects a wall. If it does, reposition in an axis-aligned direction towards the wall intersected by the delta vector.
Edit: When I said "delta vector", I forgot that you're moving a square and not a single point. So, if you just look at the delta vector of the top-left corner, that's not going to be enough because it may not detect that part of the ball entered a block. Instead, you can look at the delta vectors of all 4 corners.