yiotro / Antiyoy

A source code of android game called 'antiyoy'.
422 stars 54 forks source link

Bigger maps #26

Open McAroni opened 6 years ago

McAroni commented 6 years ago

Hi, Is it possible to further increase the maximum size of the map? If yes, would it be possible to add more AIs, too?

yiotro commented 6 years ago

Yeah, it's possible, but there are few problems that have to be fixed before doing that:

For example: Level size is directly tied to screen ratio (due to frame buffer limitations). It wasn't a problem initially because all levels in campaign were just randomly created on every device. But since I started adding a lot of custom levels it became a problem. If you make level in editor on one device and then pass it to other device with different screen ratio you may notice some problems. This problem is more noticeable on larger maps, so adding even larger map size will make this problem even more obvious.

I have plans to fix it, but I can't tell when I will do that.

McAroni commented 6 years ago

Since this sounds really erroneous to me ... why is level size directly tied to screen ratio? I really cannot think of any good reason for this ...

OvermindDL1 commented 6 years ago

Yeah I'm curious, is the level drawn directly on the framebuffer instead of as a restricted polygon set?

yiotro commented 6 years ago

Here is why:

  1. Frame buffer size is restricted by screen resolution.

  2. It means that if I make level bounds dividable by screen bounds then:

  1. I didn't expect this game to be so popular, so I was making it just for myself. I didn't plan to support it for years. If I knew that then I wouldn't repeat this mistake. But at that time I just didn't think about it.

  2. It wasn't obvious to me that this decision can cause problems.

OvermindDL1 commented 6 years ago

Frame buffer size is restricted by screen resolution.

Indeed yep. ^.^

It means that if I make level bounds dividable by screen bounds then:

Hmm, that seems to be a very odd limitation? (I cannot actually play this game yet until I get my new phone (one week whoo) since all the text is still invisible on my current/old phone ^.^;)

I would need to use only 4 frame buffers for big maps (2 for normal and 1 for small)

Why not at least a gl displaylist that you could then render efficiently and move around and do stuff to instead (and it might even use less memory)?

Also less textures to draw.

TextureAtlas. :-)

Easier to program.

Eh, I need to look at the code, but wouldn't a spritebatch be easier?

I didn't expect this game to be so popular, so I was making it just for myself. I didn't plan to support it for years. If I knew that then I wouldn't repeat this mistake. But at that time I just didn't think about it.

We all do that kind of stuff. ^.^;

subchannel13 commented 6 years ago

Wait, are drawing whole map to texture and then that texture to screen? If so or anything resembling that, you can cut the middleman and draw directly and be free of screen size limitations.

yiotro commented 6 years ago

Why not at least a gl displaylist that you could then render efficiently and move around and do stuff to instead (and it might even use less memory)?

I am not very familiar with opengl stuff, that's why I am using libgdx in the first place :)

I don't know what is gl displaylist and I didn't knew that 3 years ago when I was making this game. I have to say that in my new game I'll also use frame buffers for same thing, but levels won't be tied to screen ratio,

TextureAtlas. :-)

I think you didn't understand me correctly. I render static pieces of level (all the land, trees and farms, but no units) to textures. Then I draw those textures instead of rendering all tiles every frame. Those textures change everytime someone captures land.

You can actually notice that if you zoom in and then try selecting and deselecting your province. You will see difference in quality of some sprites (most noticeable on trees).

Eh, I need to look at the code, but wouldn't a spritebatch be easier?

It would be even more easier, but it would give me 5-10 fps on my smartphone.

yiotro commented 6 years ago

Wait, are drawing whole map to texture and then that texture to screen? If so or anything resembling that, you can cut the middleman and draw directly and be free of screen size limitations.

I draw all solid objects to N separate textures. N is 4 for big maps for example. To render directly to texture I have to use frame buffer, and frame buffer size is limited. That's why I use list of textures and not one.

OvermindDL1 commented 6 years ago

Ah yep, you definitely want a displaylist then (a cached spritebatch in libGDX terms). You'd render the entire map in to it on level load (you could even update it later, or even add animations easily and efficiently then) then render it out with a single call on each frame. It can actually be a good bit faster than a single massive texture via a framebuffer render since the individual graphics are fairly simple (just keep them in an atlas). :-)

Technically for anything that looks even partially tile based though, libGDX's tilemap renderer will be even more efficient and should always be used as it will only render what is visible in chunks, allowing you to have fairly arbitrary and huge map sizes without issue (only limited by the ram of the device, so you can get utterly huge maps all rendered efficiently).

Plus using a cached spritebatch or a tilemap (which uses a cached spritebatch internally plus extra optimizations) will let you keep full quality regardless of zoom level. :-)

It would be even more easier, but it would give me 5-10 fps on my smartphone.

That absolutely should not ever be the case unless each graphic was an individual texture in memory as switching between each would cause a GL State Flush, which is costly.

If they are individual textures then you want to render all places of a single texture first, then all places of the next texture, and so forth, but even this will cause a number of state flushes equal to the number of textures (which if <100 or so is usually fine, <20 is best). If you instead load all the textures into a single TextureAtlas then they all share the same batched location in texture memory, thus you can then render the entire map without worrying about rendering one texture at a time, just render them all via a spritebatch and it will only perform one flush, you should get many hundreds of FPS even on the lowest end of devices, this is the purpose of a TextureAtlas and every-single-game in LibGDX should absolutely and only use a TextureAtlas or two for all their textures, never ever reference individual texture files.

I draw all solid objects to N separate textures. N is 4 for big maps for example. To render directly to texture I have to use frame buffer, and frame buffer size is limited. That's why I use list of textures and not one.

Which is why you should be using a TextureAtlas, then pointing into that single TextureAtlas via a spritebatch, then you can get significantly larger (and dang near infinitely large, memory limited, if you use a tilemap as well).

yiotro commented 6 years ago

Technically for anything that looks even partially tile based though, libGDX's tilemap renderer will be even more efficient and should always be used as it will only render what is visible in chunks, allowing you to have fairly arbitrary and huge map sizes without issue (only limited by the ram of the device, so you can get utterly huge maps all rendered efficiently).

Well, if I solve my problem with screen ratio then I will be also able to make giant maps. I prefer my own solutions for such things (it's more fun).

Plus using a cached spritebatch or a tilemap (which uses a cached spritebatch internally plus extra optimizations) will let you keep full quality regardless of zoom level. :-)

Hmm, that sounds interesting. I'll check it out, thanks for advice.

If they are individual textures then you want to render all places of a single texture first, then all places of the next texture, and so forth, but even this will cause a number of state flushes equal to the number of textures (which if <100 or so is usually fine, <20 is best). If you instead load all the textures into a single TextureAtlas then they all share the same batched location in texture memory, thus you can then render the entire map without worrying about rendering one texture at a time, just render them all via a spritebatch and it will only perform one flush, you should get many hundreds of FPS even on the lowest end of devices

Yeah, you are probably right. I actually use my own solution for texture atlas in my games and it works nice, but for some reason I didn't use it for drawing hexes. Check out this thing: https://github.com/yiotro/Antiyoy/blob/master/assets/field_elements/atlas_texture.png

As you can see, I use atlas only for things like units and buildings. In future I'll to put in there other textures (hexes, hex shadows etc.).

But I have to say I don't have any problems with performance in antiyoy, it runs smoothly even on that old smartphone of mine. I don't use gl displaylist, but I use my own solution for that :)