Do all 2D games do this?

Started by
16 comments, last by frob 9 years, 10 months ago

The reason I ask is because I only want to drawn the tiles if their coordinates are "within" the screen. I figure this would improve performance of the game and be efficient code. I don't think I am optimizing...just making sure unnecessary things don't get drawn when the player is not going to see it.

I hear draw calls are expensive...so this is why I do this. I figure if I do not do this, the game might slow to a crawl when draw calls are being called even though the objects are not on the screen.

The game is a 2D platformer with a camera system.

My Java code example:

update block:


if(getX() - camera.getX() < Screen.WIDTH)
{
draw = true;
}
else
{
draw = false;
}

draw block:

if(draw)
{
blockAnim.draw(g2D,camera);
}
Advertisement
All games all humans or aliens in any civilization on any planet past or future have eliminated unnecessary tiles from being drawn, no exceptions.

However they tend to use grids or quadtrees.
Instead of checking each tile, for a regular tile grid, you can’t get any faster than calculating the left, right, top, and bottom rows of tiles that need to be drawn and simply draw them.

Then your tile-drawing loop would look like:
for ( int y = top; y <= bottom; ++y ) {/*left/right - top/bottom fixed. */
	for ( int x = left; x <= right; ++x ) {
		// Just draw the tile; it is on-screen.
	}
}
In any case, you don’t run over the tiles and set a “draw” flag. Just draw it when you discover it should be drawn. Setting a flag and then going back over to draw is a waste of cycles.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid


Setting a flag and then going back over to draw is a waste of cycles.

What do you mean by waste of cycles? Does my game run slightly slower then?

Apparently your flow involves making one pass to set a flag and then another pass to check the flag and draw or skip.

Unless you need to know which tiles are going to be drawn for any part of your game other than drawing (and you don’t; there are other ways to handle that kind of situation, such as by pre-calculating the left, right, top, and bottom rows and deriving that information from those metrics), make a single pass at the time of rendering to simply go over the tiles once and draw or not draw them.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

I have many questions now.

1) Why is y first instead of x? And why are you using the pre-increment?

2) How do I know how many tiles my computer is capable of rendering?

Suppose my screen is 760 * 1080 in width and height respectively. My block tile is 20 * 20. So that is 38 blocks going in each row and 54 blocks going in each column. So that is 2052 blocks being drawn given my screen dimensions.

I hear draw calls are expensive...so this is why I do this


They are. Culling unnecessary tiles is one way of solving this. Batching your calls together or instancing solves this another way without culling. They work wonders when combined.

On most hardware in most games, anyway. Yours may be different. Measure and quantify your inefficiencies before optimizing and afterward for comparison purposes.

1) Why is y first instead of x? And why are you using the pre-increment?


The code Spiro posted may just have a typo since he mixed Y with left/right and X with top/bottom, which is against usual convention. Y first is convention based on how images and arrays are laid out in memory. There are various mathematical and performance reasons this is "correct." It's not especially critical.

Pre-increment is a convention mostly used by C++ programmers. In a non-optimizing build, post-increment is a teeny tiny bit slower. For some C++ iterator types (not simple ints), it's measurably slower. Post-increment has to make a copy of the value before incrementing and then return the copy. An optimizing compiler will generally output identical machine code for both pre- and post-increment in cases like this even for complicated iterators, and certainly for any ints.

2) How do I know how many tiles my computer is capable of rendering?


It can render a lot. Do you mean per hour? Per second? Per frame at 60hz? Try drawing a few million. Measure the time it takes. Adjust as necessary until you drill into the number of tiles matching your target draw rate. Remember that this number is specifically for your computer and not any other.

Then remember that that is a best-case maximum and assumes you're doing no AI, physics, multitasking with a music player, etc., which will all slow down the device and reduce its draw rate.

Sean Middleditch – Game Systems Engineer – Join my team!

2) How do I know how many tiles my computer is capable of rendering?

You might as well be asking us how far you can throw a baseball. Even if we knew specific details about you it is very hard to quantify such a thing, there are too many variables involved. Nobody really "knows" how much fps you'll get in different situations, thats why performance is often guaged off of benchmarking on a few different hardware setups.

A better line of thinking is to draw as many as you want, and if you run into performance problems then look at your options(cutting down on rendering, improving performance through profiling, etc.)

2) How do I know how many tiles my computer is capable of rendering?

  • “warnexus, what does the computer say about his draw count?”
    It’s over 9,000!!!!
  • This many:
    |------------------|
    I hope that answers that.

    As SeanMiddleditch mentioned, find out for yourself by benchmarking. But it’s a silly thing to know anyway. Reduce your draws as much as possible.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Furthermore, if you are concerned about drawcalls I would like to see how this function is implemented.


blockAnim.draw(g2D,camera);

Just from looking at that line I suspect there is much room for improvement.

I hear draw calls are expensive...

What graphics API is being used to draw your tiles?

The "draw calls are expensive" primarily relates to DirectX/OpenGL. If you are using an intermediary API, it's quite possible it is batching up draws already, and thus may have completely different performance characteristics.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement