🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

breakout in opengl and c++

Started by
55 comments, last by pbivens67 2 years, 11 months ago

so should I use an vector or array?

Advertisement

pbivens67 said:

so should I use an vector or array?

In C++, you should prefer a vector over a C-style array all the time.
Whether you end up finding valid exceptions to this eventually, is a different matter.

Vector is your go-to collection for handling of stuff in a sequence. It has its drawbacks, as its not specialised to any particular use.
It's just a solid all-rounder. Here, Stroustrup explains some of the benefits of using a std::vector compared to a C-style array.

If you're up and running with the array example from @joej already, just keep using it. It's still an implementation detail, and if it's static, its even less important which one you're using.

pbivens67 said:
so should I use an vector or array?

You can use what you prefer. Does not really matter.

Some years ago, using STL was considered a no-go for games because performance. Maybe you remember this time and have doubts.
std::vector has dynamic size, and adding elements can cause a reallocation of more memory. Such reallocation takes a very long time and can ruin performance of realtime applications. Thus i prefer to use arrays (or std::array) if i do not need dynamic size.

In our case, using std::vector to represent the breakout board, reallocation only happens at the beginning of a new level, not during gameplay. So no problem and you can use it. Advantage is there is no need to allocate and free up memory. Which is very good to have because it's easy to forget freeing up memory otherwise, leading to memory leaks.

My advise previously made ‘use array over vector’ was made under a different assumption:
Many people would represent their breakout level like this:

struct Brick
{
	int x, y, color;
};
std::vector<Brick> bricks;

//...
bricks.push_back( Brick({3,5,7}) ); // add brick at position (3,5) with color 7

This is bad. It seems convenient to push bricks into the board vector, setting position for each, not caring about empty space.
But we get performance problems at runtime:

To find a brick at a certain position we need to iterate ALL bricks each time. So our collision test become O(N).
Deleting (or adding) a brick during gameplay changes the size of the vector, and may cause reallocations.

Both is terribly slow and should be avoided. And we do that by representing the whole level with a ‘regular grid’:

constexpr int width = 16;
constexpr int height = 10;

std::vector<int> board(width * height, 0); // set whole grid to zero

//...
board[3 + 5 * width] = 7; // set brick at position (3,5) to color 7

This is good. We can lookup which brick is at a certain position without a need of iterating all bricks. Cost is O(1) and ideal.
Adding / removing bricks does not change size of our board, so no reallocation ever happens.

To index our grid, we use simple indexing math known from arrays (index = x + y * width), and that's why i said ‘use array over vector’.

Following this, there is no difference then between using vector or array during runtime.
Vector uses an array (pointer to allocated memory of board size) internally too, so both methods give us the same performance.

If there are any questions left, ask for it. But also explain WHY you ask!
So we can make proper assumptions on what you already understood or what maybe not, to optimize both your learning and our teaching.

SuperVGA said:
In C++, you should prefer a vector over a C-style array all the time.

I can't second this advise, even if targeted at beginners.

I have seen people implementing their vec3 or matrix4x4 classes using std::vector<float> pretty often. Terrible! Would you hire somebody doing this?

So, i think it's better to tell the whole truth to beginners. Even if they don't get it all at the moment, they memorize ‘there is a catch, need to keep that in mind, coming back to it later…’. Likely this helps to prevent such bad practices from coming up.

I would rephrase your advise to ‘In C++, you should prefer std::array over a C-style array all the time.’, which is fine to me : )

JoeJ said:

SuperVGA said:
In C++, you should prefer a vector over a C-style array all the time.

I can't second this advise, even if targeted at beginners.

You have realistic scenarios where you'll recommend a beginner to use a C-style array over a std::vector, when they're trying to learn C++?

JoeJ said:

I have seen people implementing their vec3 or matrix4x4 classes using std::vector<float> pretty often. Terrible! Would you hire somebody doing this?

My advice to beginners implementing their vec3 or matrix4x4 classes would obviously be to not use array or vector at all.
You can try to argue against any tool by coming up with an example where it's used in an inefficient way, it's just not much of an argument.
So no, I probably wouldn't hire someone like that. I wouldn't hire anyone constructing a vague argument like that, either.

JoeJ said:

So, i think it's better to tell the whole truth to beginners.

It's tough with truth. They're given an arsenal of ways to shoot themselves in the foot, the first thing they should do is to at least let go of the C way to do that.

JoeJ said:

I would rephrase your advise to ‘In C++, you should prefer std::array over a C-style array all the time.’, which is fine to me : )

The overhead of using a vector in a typical beginner scenario is so little, and they have all the stuff available to them, that they'll be needing a few lessons in. Sure a std::array works for this case, and you can give that advise. Mine is and will be different, though.

SuperVGA said:
My advice to beginners implementing their vec3 or matrix4x4 classes would obviously be to not use array or vector at all. You can try to argue against any tool by coming up with an example where it's used in an inefficient way, it's just not much of an argument. So no, I probably wouldn't hire someone like that. I wouldn't hire anyone constructing a vague argument like that, either.

But there are no vague argument here at all:

struct vec3 { float v[3]; } is fast, and allows to index by dimension

struct vec3 { float x,y,z; } is fast, semantically meaningful, but lacks option to index. So i don't see why it is the obvious solution for you? (assuming that's what you mean with neither using array nor vector)

We can make a union to combine advantages without compromising anything. (discussions about unions aside)

struct vec3 { std::vector<float> v; } requires allocation and wastes memory for pointers and counters which are not needed.

Those my arguments are totally solid and relevant in any practical context. It's not a matter of personal opinion or preferences. It's just unfair to assert i would construct ‘vague’ arguments, honestly.

SuperVGA said:
It's tough with truth. They're given an arsenal of ways to shoot themselves in the foot, the first thing they should do is to at least let go of the C way to do that.

This is a matter of personal opinion. I accept yours, and i'm no teacher anyways.

JoeJ said:

SuperVGA said:
My advice to beginners implementing their vec3 or matrix4x4 classes would obviously be to not use array or vector at all. You can try to argue against any tool by coming up with an example where it's used in an inefficient way, it's just not much of an argument. So no, I probably wouldn't hire someone like that. I wouldn't hire anyone constructing a vague argument like that, either.

But there are no vague argument here at all:

struct vec3 { float v[3]; } is fast, and allows to index by dimension

struct vec3 { float x,y,z; } is fast, semantically meaningful, but lacks option to index. So i don't see why it is the obvious solution for you? (assuming that's what you mean with neither using array nor vector)

We can make a union to combine advantages without compromising anything. (discussions about unions aside)

struct vec3 { std::vector<float> v; } requires allocation and wastes memory for pointers and counters which are not needed.

Those my arguments are totally solid and relevant in any practical context. It's not a matter of personal opinion or preferences. It's just unfair to assert i would construct ‘vague’ arguments, honestly.

I think it is vague, not in general, but in this context. You can whip out any advanced scenario that doesn't apply to pbviens, or any other newcomer to the language, and have them using advanced features from the get-go. That's not what we're trying to do here, I think.

Aside from that, your point is entirely valid, and while I might fiddle with some [] overloads first, I'm not disputing that it has merit to use char[] for some other thought scenario.

I'm just saying it's very far-fetched in deed to use it as an argument that a beginner should use C-style arrays. I worded that wrongly, and of course your argument wasn't absolutely vague in entirety.

We're good - let's not pollute this thread with our discussion any longer.

SuperVGA said:
I think it is vague, not in general, but in this context. You can whip out any advanced scenario that doesn't apply to pbviens, or any other newcomer to the language, and have them using advanced features from the get-go. That's not what we're trying to do here, I think.

I assume a different context than you do. AFAIK, Phil hangs out here for a very long time. Too long to be treated as a total beginner, maybe even long enough to assume his background was C first, then adopt some C++ slowly (like i did). I don't think his primary goals are to learn the programming language, but to learn good solutions for given problems.

However, that's all assumptions, causing pollution as we got here. It's on Phil to provide better context by asking more specifically. Though, that's not as easy for everybody.

well I am going to use a vector

I have a tip for anyone who wants to make breakout games and needs a simple algorithm for randomly generating levels that are symmetrical:

  • Split your X-Tiles so you have a left side and a right side
  • For each line:
    • Dice out a number using half of the maximum number of X-Tiles for a line (works better when it's even a number)
    • Dice out a starting offset in the same range, but minus one → Ensure that your starting offset + number of tiles does not exceed the maximum available tiles
    • Generate the tiles from the offset to the number of tiles you want (For left increment, for right decrement) → Or better, use a unit scalar as a 1D direction
  • Done

Of course, this algorithm can be improved slightly:

  • Different max X-tiles for each line
  • Introduce a similar concept for Y
  • Have three parts instead of left/right side (center)

A simple code example (can translate to C if needed):

function setRandomLevel() {
	var lvl = level;
	var halfWidth = (brickCols - 1) / 2;
	var x, y;
	for (y = brickRows - 1; y > 0; y--) {
		var randomHalfWidth = Math.random() * halfWidth;
		for (x = 0; x < brickCols; x++) {
			lvl[y * brickCols + x] = 0;
		}
		var xstart = Math.random() > 0.5 ? Math.min(halfWidth, Math.round(halfWidth - randomHalfWidth)) : 0;
		for (x = xstart; x < randomHalfWidth; x++) {
			lvl[y * brickCols + x] = 1;
			lvl[(y + 1) * brickCols + (-x - 1)] = lvl[y * brickCols + x];
		}
		if (Math.random() > 0.5) {
			lvl[y * brickCols + halfWidth] = 1;
		}
	}
}

This produces very interesting results (Yes this is automatically generated and not placed by hand!)

Nice! Looks like an iconic Space Invaders sprite : )

At 0:36 this video shows a ball - corner collision, result is physically correct but unpredictable for the player and he misses the ball. (Just to illustrate what i meant with that.)

This topic is closed to new replies.

Advertisement