Page 1 of 2

How to program action game in a wrapping world? (2D torus)

Posted: Sat Jan 01, 2022 12:51 pm
by nadomodan
Imagine simple top-down arena shooter, bump.lua for collision, tile map made in Tiled or proceduraly generated, standard stuff except the edges of the map are connected, kind of like in Asteroids.
This game seems to have implemented it pretty well https://benjamin-soul.itch.io/voidrun, look at the second .gif, notice that singular ground tile sticking out of water in one of the pools, you can see it at the bottom first, then when player goes north you can see it at the top, the world loops seamlessly. How would you implement this in game? I've searched through reddit posts, forums and articles but couldn't find any solution, everyone suggest the same naive implementation that only works in something very simple like Asteroids, as in: when object goes out of map bounds, teleport it to the other side, they also suggest drawing everything 4 or even 9 times to make it visible through the "loop" when near the edge of the map, also checking collisions extra 4 times to account for all the wrapping directions, well, you can probably see how it's not going to work well, all the edge cases you have to individually code for etc etc.
Here's one example, illustrated
Image
Green is floor, light blue is impassable water, grey is mountains (obstructs enemy vision). Yellow is player with their camera viewport selected, since the map wraps around they should be able to see the white square. Red and orange don't have a clear line of sight for each other if you compute it normally since the mountain blocks it but they should be able to see each other, looking the other way through the edge of the map. Red and orange also see the player, they can't pathfind to player if it was a normal map with impassable edges but since it loops they should be able to reach player by going south.

I feel like there is some way to program a system that elegantly and automatically handles all this but I just can't figure out how to do it, I have played Voidrun, kept running in one direction, looping around the world and the enemies perfectly follow and shoot at me, there are no obvious gaps or connected edges while playing, it's seamless.
https://twitter.com/benjamin_soule_/sta ... 0998666241
https://twitter.com/benjamin_soule_/sta ... 5538442240
https://twitter.com/benjamin_soule_/sta ... 9649017861
Even those segmented worm enemies work perfectly, no way you could get it to work cleanly with the hacky "drawing everything multiple times and checking collisions multiple times in all directions" method since that doesn't cover pathfinding, line of sight, aiming and shooting etc. How?

Re: How to program action game in a wrapping world? (2D torus)

Posted: Sat Jan 01, 2022 1:49 pm
by ReFreezed
My suggestion would be exactly like the suggestions you've already gotten: do everything 4 or 9 or however many times necessary. There's no magical solution. From each individual character or object's perspective, it looks like there are more other objects than there technically are, so you have to treat everything like that in the code - like there are more objects than there actually are.

You'll just have to adapt the code (e.g. there might be an array of 5 actual objects) so that the idea of what's happening in the game world looks true (e.g. it looks like there's an infinite number of objects, no matter what the reality is or any code actually says). Obviously it's not feasible to collision check or render an infinite number of objects, but with limitations (maybe characters can only "see" things one "world length" away in any direction) and optimizations (e.g. only check collisions with "wrapped" objects when you're close to a border) you can get away with doing things only a few times.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Sat Jan 01, 2022 3:01 pm
by pgimeno
I wanted to add a few things to what ReFreezed has said. You may not have considered worlds smaller than the screen, but if you did, they would indeed look infinite, as he noted, like this toroidal Sokoban clone: https://tic80.com/play?cart=1441 . That's how objects in the world see the rest of the world, rather than through the tiny window that you let people see.

I wrote Thrust II Reloaded with wrapping in mind, like the original did. Indeed I drew everything twice in my case, because the T2R world's topology is a cylinder rather than a torus (top and bottom are bounded and don't wrap around) and big enough to not have to worry about more than two copies. That's simpler, but still there were some challenges and I had to fix several wrapping-related bugs (especially the disappearance of some objects during the crossing of the wrapping line). You face bigger challenges.

In your case, the biggest challenge is going to be the libraries. The graphics, not so much. I'm not sure if there's a pathfinding library that supports toroidal graphs; maybe Jumper supports different topologies, but not built-in. As for collisions, I'm afraid you need to have all objects 9 times in the Bump world, and keep them up-to-date somehow (probably via query and repositioning). That, or modify Bump (or make your own) to add support for wrapping.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Sun Jan 02, 2022 9:11 am
by BrotSagtMist
Wrap everything into modulo.
Like Tile[X%Screensize]
Consider that the real position of objects doesnt matter at all that way.
A block being at 1500 will collide with a block at 500 as long as the collision math includes a modulo 1000.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Sun Jan 02, 2022 11:09 am
by pgimeno
@BrotSagMist Can you give a very simple example of what you just said? Something like the typical rectangle-rectangle intersecting test, using modulo everywhere. Because I'm having trouble understanding how e.g. comparisons would work on coordinates with the modulo applied.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Sun Jan 02, 2022 11:53 am
by BrotSagtMist
I only used this for tiles and point objects, rectangles will make this complicated again.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Wed Jan 12, 2022 8:03 pm
by JimOfLeisure
You could alternately allow the player and enemies to have infinite coordinates and relocate parts of the map. The map would always have to be bigger than the viewport, of course.

If you need e.g. long-tailed enemies to wrap around, their tails could be drawn with a modulus function, but if you need to check collisions you'd need to modulus the potential colliding wrapping entities, too.

For my bumpy road simulation/game I'm procedurally generating a rolling surface. There are just a handful of ground objects, and their coordinates are destroyed when offscreen to the left and recreated to exist on the right.

If I had a repeating terrain I could just translate the coordinates instead of regenerating.

Not the best code ever, but if you want to see it: https://github.com/JimOfLeisure/bumpy-r ... ground.lua . Ground:load() creates the ground sections, and new_ground_section() generates the polygon and physics object for the new ground. In this case it's procedurally generated based on the X coordinate, but again this could just move an existing shape to new coordinates, too. The Grount:update() function checks to see if a section is far enough to the left to be 'moved' to the right.

Re: How to program action game in a wrapping world? (2D torus)

Posted: Wed Jan 12, 2022 9:28 pm
by darkfrei
ReFreezed wrote: Sat Jan 01, 2022 1:49 pm There's no magical solution.
Maybe some shader for it?

Re: How to program action game in a wrapping world? (2D torus)

Posted: Wed Jan 12, 2022 9:56 pm
by grump
darkfrei wrote: Wed Jan 12, 2022 9:28 pm
ReFreezed wrote: Sat Jan 01, 2022 1:49 pm There's no magical solution.
Maybe some shader for it?
Hah, you fools! There is a magical solution, and it was SHADERS all along!

Re: How to program action game in a wrapping world? (2D torus)

Posted: Wed Jan 12, 2022 10:34 pm
by pgimeno
I hope darkfrei was being sarcastic, but with Poe's law, you never know :)