Advertisement

AABB collision

Started by March 29, 2024 09:20 PM
50 comments, last by JoeJ 6 months ago

Ok, for such a small number of bricks a tile map is not needed.

ok sounds good

Advertisement

should I use an array or vector to store the bricks values?

pbivens67 said:
should I use an array or vector to store the bricks values?

I would use a vector, because makes it easy to remove bricks after they were hit.

good I like vectors

is this good code for my vector?

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector <float> bricks;
	
	for (int y = 0; y < 6; y++)
	{
		for (int x = 0; x < 3; x++)
		{
			bricks.push_back(x * 40 + 260);
			bricks.push_back(y * 80);
			bricks.push_back(40);
			bricks.push_back(80);
		}
	}
	vector<float>::iterator iter;

	for (iter = bricks.begin(); iter != bricks.end(); iter++)
	{
		cout << *iter << " " << endl;
	}
		
	return 0;
}
Advertisement

pbivens67 said:
is this good code for my vector?

Nothing wrong with the code itself, but you forgot about data structures, and the advantage you can expect from that.

This:

vector <float> bricks;

must become this:

vector <Rect> bricks;

That's the whole point!
That's what will make it easy to work with many bricks.
You want many bricks, then make a vector of the data structure you want to use to represent your bricks, which is the Rect you have worked out before.

You got it right last time, when using an array for the bricks.
The same thing works with std::vector.

how is my code so far? I am using vectors and dynamic memory using the new operator. Here is my stubbed-out code.

#include <iostream>
#include <vector>

using namespace std;

class Rect
{
public:
	int x;
	int y;
	int w;
	int h;
};

int main()
{
	vector <Rect> bricks;
	
	for (int y = 0; y < 6; y++)
	{
		for (int x = 0; x < 3; x++)
		{
			Rect *r1 = new Rect;
			r1->x = x * 40 + 260;
			r1->y = y * 80;
			r1->w = 40;
			r1->h = 80;
			bricks.push_back(*r1);
		}
	}
	
	vector<Rect>::iterator iter;

	for (iter = bricks.begin(); iter != bricks.end(); iter++)
	{
		cout << iter->x << " " << iter->y << " " << iter->w << " " << iter->h << endl;
	}
		
	return 0;
}

pbivens67 said:
how is my code so far?

To figure that out, the first thing to do is compiling it.
Do this now and try to make sense of the error message.
So next time you do such mistake, you know instantly what's wrong.
(Do it now, before you fix the issue! And ideally before you read on….)

pbivens67 said:
I am using vectors and dynamic memory using the new operator.

My primary reason to use std::vector is to avoid a need to manage memory myself.
Using vector, i usually never need a new operator, nor a malloc(), or other forms of memory allocation.
It also can not happen i forget to free the memory. The vector automatically deallocates the memory when it goes out of scope.
This makes using C++ as easy as a (slower) language with a garbage collector.

The second reason to use std::vector is: We do not need to know how much memory we need in advance.
We just push elements one after another as they appear and as needed.
The vector cares about memory allocating internally and automatically for us.
Technically it works like this:
When pushing the 1st element, the vector allocates memory for 2 elements first, then places the element.
When we push the 2nd, memory to store it is already there.
When we push the 3rd, the vector allocates memory for 4 elements, copies the old elements to the new memory and adds the new 4th element as well, then it releases the old memory.
When we push the 4th, memory to store it is already there.
Pushing the 5th, the vector allocates new memory for 8 elements, copies the stuff and releases old memory.
Pushing 6,7,8th elements is easy.
For the next it will allocate memory for 16 elements.
Then 32, 64, 128, 256, and so far.

This means: The amount of allocations (which cost a lot of time) and copy operations (another hidden cost) decreases as we push more elements.
But still, there is a lot of stuff going on under the hood, which has a cost. And that's usually the reason to NOT use a vector. Because this automatic memory management is convenient to use, but slow.
To avoid the costs, and knowing roughly how much memory we need, we can minimize the cost:

vector <Rect> bricks;
bricks.reserve(3 * 6);

This way the vector allocates memory only once once, which solves the cost problem, and the rest of the code remains the same.

If we would reserve to (3 * 5), the vector would at some point need to reallocate one more time while we push too much elements, and it may end up at space for (3 * 5 * 2) elements, which is a waste.

If we would reserve to (3 * 7), we allocate more memory than needed, but it's not as much too much, so the waste is actually smaller.

But the cool thing is: No matter what we do (nor reserving at all, reserving not enough, reserving too much), it just works anyway. It's an opportunity to optimize, but it is not a requirement.

That's the things you should know about vectors, and that's the reason why you like them.

Obviously you did not yet know why you like them.
You decided to manage memory on your own using new, so you loose all advantages the vector would give you!
And worse: Because you allocate each single element on its own, the elements will scatter randomly across memory, leading to worst case performance. Iterating over all your elements will become very slow, because your CPU caches won't help read memory quickly.
On my C64, random memory access was no problem at all. It did not matter what's the order of my elements in memory.
But on any modern hardware, random memory access is simply our biggest performance problem! So we want to avoid it if we can.

Thus, instead of using pointers to Rects as your vector elements, use Rects directly as elements, as your declaration requires to compile the code anyway.
Use rects, not pointers. Then your stuff has linear memory order and is fast to iterate, which is the whole point to use std::vector.

You're not trolling, do you???

Otherwise you're on good track. It's just a bit suspicious you always find a way to do something wrong.
How the hell can you even come up with such things?

Next time i want to see those 3 * 6 bricks rendered each frame on screen, plus a paddle you can move with keyboard. >: )

is this code good enough for storing values in a vector for collision detection in breakout bricks?

#include <iostream>
#include <vector>

using namespace std;

class Brick
{
public:
	float x;
	float y;
	float brick_x = 0.0f;
	float brick_y = 0.0f;
	float brickWidth = 40.0f;
	float brickHeight = 80.0f;
	bool TestCollision(float x, float y)
	{
		if (x > brick_x && x<brick_x + brickWidth && y > brick_y && y < brick_y + brickHeight)
		{
			return true;
		}
		return false;
	}
};

class BrickLayer
{
public:
	vector<Brick> bricks{ (40.0f,40.0f) };
	bool TestCollision(float x, float y) {
		for (auto& brick : bricks) if (brick.TestCollision(x, y)) return true;
		return false;
	}
};

int main()
{
	BrickLayer brick;
	cout << brick.TestCollision(40.0f,40.0f) << endl;

	system("pause");
	return 0;
}

This topic is closed to new replies.

Advertisement