0
\$\begingroup\$

I'm building a 2D game engine that uses tilesets to build levels. I recently added functionality to handle wraparounds (ie. where the right edge of the map connects to the left edge.) The engine scrolls the map to follow the character around, remaining centered on the player whenever possible.

I implemented wraparound as follows:

The map engine has a Viewport object, which has a bounding rect and can test each tile to see if the tile is contained within the viewport. When the screen coordinates are such that wraparound is needed, the viewport can set up sub-viewport objects that display different parts of the coordinate space, and place them side by side.

Each frame, I test the tiles on the map against the viewport to see if they can render. Each tile object has a viewport property designating which viewport it's rendering into. In the case of a composite viewport, this will delegate the test to each sub-view in turn, and on the first match, set the tile's viewport object and break the loop.

This works just fine in practice, until I hit one specific edge case: When the map is the minimum size, which is exactly the size of the screen, while trying to scroll, the tiles along the edge will be in the area of both viewports at once until the scroll completes the full width of that tile, which causes it to render on one edge and the other edge to show blank space for a moment.

I could resolve this by giving each tile a list of viewports instead of a single one, but that would significantly increase the complexity of my rendering, which I want to keep as fast and simple as possible, just to deal with a minor edge case.

Does anyone know of an elegant way to resolve this issue?

\$\endgroup\$
  • \$\begingroup\$ You shouldn't test every tile against every viewport because that will become exceedingly slow on a big map. Instead you should get all the tiles that are within each viewport. \$\endgroup\$ – user253751 Dec 3 '17 at 22:10
1
\$\begingroup\$

It sounds like what you have is this: (pseudocode)

for each tile:
  find viewport that tile is in
  if viewport != null:
    render tile according to viewport

Instead consider doing this:

for each viewport:
  for each tile in the viewport:
    render tile according to viewport

Not only will this fix your problem, it should give you a speed improvement on big maps because you only need to check the tiles that are on-screen (using the viewport's coordinates), instead of every tile in the map.

\$\endgroup\$
  • \$\begingroup\$ Testing each tile is actually very fast. (I implemented it as an optimization, and it gave me a massive speedup on large maps over trying to render everything whether or not it's on-screen.) And the way the engine is set up, with multiple Z-layers that need to be rendered in order, including the player and other sprites that aren't part of the tile map, it's not simple to correctly answer the question "what are all the sprites located at this coordinate pair?" in all cases. \$\endgroup\$ – Mason Wheeler Dec 3 '17 at 22:30
  • \$\begingroup\$ @MasonWheeler When you have a hundred million tiles (which is a 10000x10000 map) it won't be so fast to test them all. \$\endgroup\$ – user253751 Dec 3 '17 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.