Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / Tile Based Map Scrolling - The most efficient way?

Author
Message
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 9th Jan 2014 21:05
Hi,

I'm making a tile map editor. I've not concentrated on performance as I'm new to AppGameKit basic and wanted to get something going rather than get bogged down too early. So, so far I create a sprite for each tile placed and write values to an array [map_x, map_y, Sprite_ID]. Then for the display I look up the sprite IDs in the array for the screen co-ordinates that I'm at (taking into account the offsets for x and y) then draw cloned sprites on the screen. Each loop I set the position of the sprites used in the map to be off screen to clear the map (I guess I should be setting them to be inactive and invisible too?) and then reposition the ones that are needed according to the map array. It seems to work, though I'm sure it could be more efficient? But the real part I want to get to grips with is how I'll use the map in my games. I want to start by building a framework that will do scrolling and that does need to be efficient so I thought I'd come and ask for some help. I've read as many threads as I can and here are a few methods I figure I could do...

1. Place all the tiles (sprites) that make up the whole map and use the viewoffset command for scrolling. My understanding is that AppGameKit is efficient in not actually trying to draw sprites that are off screen but I've also read that having large number of sprites isn't efficient...so onto 2...

2. I've also read about methods where you use only enough sprites to fill the screen (plus a border of one tile) and then re-use the sprites somehow. I can see that you only therefore need to have as many sprites as fill the screen (plus the border) thus increasing the performance. I'm guessing I'd need to re-assign the image associated with each sprite just before it comes onto screen based on the direction of scrolling? But then I can see that animated sprites will cause difficulties as I can't just re-assign the image associated with them... Is this a more efficient way?

3. I've read about a hybrid where the whole map's worth of tiles are placed down at the start and viewoffset is used but that only the portion on screen is made active/visible so as to increase performance.

4. I guess I could mimic the system I'm currently using in the editor...so create all sprites up front but then have them all turned off and only make them active and visible when they are actually drawn on the screen? This would avoid issues with animated sprites that I highlighted in number 2...

I'm wondering what the best method is?

And whilst I'm here...
One last titbit that I picked up, so thanks to whoever write about it, (sorry don't remember the name and I can't re-find the thread) is that you can use the map array (map_x, map_y, Sprite_ID) to ascertain which tile the character is on rather than checking for collisions. That seems to be a real performance boost so any other tips for maps/platform games that you can think of woule be welcome!
Ched80
13
Years of Service
User Offline
Joined: 18th Sep 2010
Location: Peterborough, UK
Posted: 10th Jan 2014 06:57
Hi David,

I used a tile-based map in my game shown here:



I used a similar method to 2 in your list.

I used 3 sets of arrays to create the effect.

The first array was simply a list of all the different image IDs that were to be used in my map.

The second was an array of the entire map. But this array did not have any sprite IDs. This array only listed the ID of the sprite to copy from the first list.

The third array was a small array of sprite IDs that contained the sprites shown on screen + the boarder. I also used ViewOffset to move across the map.

So the method went something like this:

1 - Move ViewOffset position and determine where in array-2, the player actually is.

2 - If the player have moved across to a different tile, re-assign the images associated with the sprites in array-3 and shift the small array of sprites based on the player's position. The new images were assigned by copying the appropriate image ID from array-1.

The player position was simply calculated using:

TileX = trunc(playerposx#/tilewidth#)
TileY = trunc(playerposy#/tileheight#)

DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 10th Jan 2014 08:50
How did you get around animated sprites where you can't just assign a new image? I was thinking about this last night and thought that I could have all animated tiles as animated sprites over the top of the base layer of static map tiles...but this started sounding complicated and means unnecessary layering of sprites which again I've heard isn't ideal.
Van B
Moderator
21
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 10th Jan 2014 11:10
Thinking outside the box for a moment, there are always options.

How about, using text? - if you set a tile sheet as a text font, with a fixed size - you could make the map using text objects. This would limit the number of different tiles you can have, as you'd need to stick to the text objects limits, but consider how efficient text is at rendering. It's all 1 image, so that whole text object is more like a mesh, with several sprites all rendering at once. A text object would render much much quicker than it's equivalent sprites, because it's a single draw call. Even if the limit is 100 tiles on a 16x16 grid, if it can display those 100 tiles quicker than 256 sprites, then isn't it worth considering. Maybe it would be nice to have parallax layers with this idea. Also - you'd have to do your own sprite collision for the map, as you can't collide with text - but that's no big deal really. Maybe it would be best to have a text backdrop tile map, with sprite based platforms in front.
This method also has the added benefit of easy file loading, like your map could be a text file you load as a string and apply to a text object.

Another option would be to use 3D, like make a model from your map data, kinda like a matrix in DB. That would be fairly quick and efficient as well. I think the only way to avoid the issues with sprites in tile based maps is to not use them, at least not use them for the whole thing - just the parts that need it.

I am the one who knocks...
Funnell7
12
Years of Service
User Offline
Joined: 8th Sep 2011
Location: UK, England
Posted: 10th Jan 2014 12:11
I'm gonna go against the grain here and tell you that for my platform game (Happy Chick), I load the entire level (as per option 1) up front which includes all animations, all sprites. I then simply use the ViewOffset to follow my character.

I'm sure there are more efficient ways (as per a few previous posts) but I have found that the biggest issue in terms of performance is the fill rate (how much you are drawing at any one time). And as you have already mentioned, AppGameKit does not draw any sprites outside of the view (for 2D at least) so from a fill rate perspective, this isn't really an issue.
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 10th Jan 2014 13:41
The font idea sounds whacky! I'm not keen on the inherently imposed tile number limit that you identify though. I thought sprites were the most efficient way of drawing to the screen? Regarding the number of draw calls, if you use an atlas image and assign sprites images from that then from my understanding it draws all the sprites that use the atlas image in one call (there's a great video explaining this somewhere!)

Funnell7 - interesting, I can see you got good performance with your method from reading the thread about Happy Chick. So I guess you just positioned all the static tiles at the start of a level, then forgot about them in the main loop and just re-drew the moving sprites (baddies etc). The the viewoffset did all your scrolling as it were?

I guess I could do a couple of tests, using two methods and see what the unclampled FPS is? I wonder if turning sprites on and off etc and moving them about as in my option 2 will be slower than letting AppGameKit decide what to draw via ViewOffset?

Cheers Ched80 for your input too. I'll read through that again when I do my tests.

Any more ideas on efficient tile/map scrolling?
Funnell7
12
Years of Service
User Offline
Joined: 8th Sep 2011
Location: UK, England
Posted: 10th Jan 2014 14:21
That's right, just load everything (sprites, baddies, the lot) and just forget about them... AppGameKit then handles what to draw based on the ViewOffset...

You know what, I don't even do anything fancy with collisions, animation or physics, it's all running even though you can't even see most of the level. If I were to zoom right out, you would see my entire level with all the anmimations/collision detections happening...

Bad? Probably! Does it work? Indeed it does
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 10th Jan 2014 14:39
It's a tempting method for eases sake! I wonder if setting the off screen sprite attributes to non active and invisible etc would speed things up or actually slow them down? I'm guessing that turning physics off for them would be worth it...the rest I'm not sure about. My guess is that AppGameKit will handle turning sprites off that are off screen faster than I can via code....

Has anyone done tests on the various methods?
Funnell7
12
Years of Service
User Offline
Joined: 8th Sep 2011
Location: UK, England
Posted: 10th Jan 2014 14:56 Edited at: 10th Jan 2014 14:57
What I had tried before was checking the sprite postition, and only performing collision checks/animation when the sprites were on screen. What I found was that this added little to no benefit at all. The reason being (I assume) is that in order for me to do this I had to call GetSpriteX and GetSpriteY on every sprite, to see if they were on screen. This resulted in 2 additional calls per loop per sprite. Where as without this, I was only making 1 call per loop per sprite (the collision check). Now you would assume that a collision check is more labour intensive than the GetSpriteX/Y check, but seeing as I had to do two (one for the X and one for the Y) I didn't see any real benefit... Additionally, I would imagine the collision check is already doing some form of position check, so this was duplicating the effort...

My app is by no means perfect and performance is something I would love to improve. This is just my experiences thus far...
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 10th Jan 2014 16:25
Not sure when you talk about collisions you're referring to just the baddies or you're including the static platform sprites too. One neat thing I read about was using the mapx and mapy coordinates (in tiles) and then looking at the map array [mapx, mapy, tile attribute]to see if you were 'colliding' with a tile or not. I'm guessing (lack of knowledge means I really am guessing!) that reading values out of an array is way faster than checking for collisions. So I'm toying with the idea of actually performing four of these array checks (up down left and right) on the map tiles but then relying on traditional collisions for baddies etc.

There's no doubt that the way you're doing it keeps things simple which I like. So, if it offers good performance it's definitely the way to go. I'm just keen to make sure the framework I develop will be robust and perform well.
Funnell7
12
Years of Service
User Offline
Joined: 8th Sep 2011
Location: UK, England
Posted: 10th Jan 2014 17:09
Sorry, yeah I am talking about collisions with enemies, coins, collectables etc, not the static platform tiles...
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 10th Jan 2014 17:35
So you use the array method for the tiles?

So, just been thinking, if you use view offset and still want parallax scrolling, are you having to move the background to compensate? The background layer shouldn't move the same as the foreground layer or you loose parallax but viewoffset will 'move' them together (or rather move over the layers at the same speed). So do you move the view but then move the background to compensate for a reduced movement relative to the foregound?

...if that makes any sense whatsoever!
Van B
Moderator
21
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 10th Jan 2014 17:51
That's where the ghetto text map would come in - easier to reposition a text object than an array of sprites

I am the one who knocks...
Funnell7
12
Years of Service
User Offline
Joined: 8th Sep 2011
Location: UK, England
Posted: 11th Jan 2014 10:18
Not sure what you mean by 'array method' for the tiles... I place my tiles using a text document, for example;

-----
-----
A--A-
BBBBB

- being a blank space, A being a small platform and B being the ground. Once the tiles have been placed, I do not do any thing with them as they are set up as static, so am not sure why you would need to keep track of the tiles?
Van B
Moderator
21
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 11th Jan 2014 11:55
The array would hold the raw map data, maybe just a single byte designating the tile number.

Like map[5,4]

Then rather than reading the data from a text file, you'd make a map editor and save and load the array - which is much nicer than using a text file usually, you can see the level exactly how it will be in game, you can test jumps while you edit if you like. Gives more control, and provides the tile data in case you need it - I'd bet that you'd find a use for having the data in an array.

For example, in a Mario game, tiles might have different properties - they might be slidey for example, or bouncy, or deadly, and being able to cross reference the tile number directly with a 'properties' array is a neat way to work. It actually cuts down the amount of coding you have to do, and makes the game easier to add to.

I am the one who knocks...
The Daddy
15
Years of Service
User Offline
Joined: 13th Jan 2009
Location: Essex
Posted: 12th Jan 2014 20:03
The most efficient way IMHO:

Lets say you have a virtual screen res of 640 x 480 (anything can go here)
And your 'tiles' are 32pix x 32pix...20 tiles wide x 15 tiles hide to cover the screen

Create sprites starting at -32, -32 (change for tile size) and have 22 sprites wide, by 17 tiles high so you have a row of sprites that are off screen...in each direction (top, bottom ,left and right).

Then have an atlas of textures (tile images) and an array of tile types/numbers. Each number in the array is an index into the atlas...so at arraypos[0,0] is the number 5...atlas image 5 is a wall etc...

Then just make the relevant sprite image set to 5 from the atlas texture. To scroll you simply only have to move 32 pixels (in increments) in any direction....each time you have move 32 pixels (all sprites) update the sprites image from the array....


This way you have one atlas texture for all tiles and only use/move 374 sprites for one layer of your map....far more efficient than (lets say your map is 100 tiles x 100 tiles) 10000 sprites.

Using this efficient system, firstly your map can be HUGE (whilst still only needing 374 sprites per layer) and can even have animated tiles (nice).

This is the most memory efficient way i think!

www.bitmanip.com
All the juicy you could ever dream of!
The Daddy
15
Years of Service
User Offline
Joined: 13th Jan 2009
Location: Essex
Posted: 12th Jan 2014 20:11
Thinking about my method...even though in your app you need to loop through 374 sprites each frame which speed wise is not a problem....(used it with no speed issues)..this may sound a lot but setting up 10000 sprites for you map and forgetting about them is not that efficient as AGK's internal engine (even though very fast) still needs to loop through all created sprites to check if visible, active, depth etc.

My way (assuming only the map sprites have been created thus far) your app loops through (to scroll, animate, check collisions etc) 374 sprites and AppGameKit engine loops through 374 sprites....748 sprites for a MASSIVE and possible animated scrolling map...compared to 10000....!

www.bitmanip.com
All the juicy you could ever dream of!
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 13th Jan 2014 16:26
The Daddy...So would you handle the animated tiles/sprites yourself via the array (eg the array holds which images from the atlas to use etc) or would you turn those tiles/sprites into animated sprites somehow? I can see how the method works with static tiles but not with animated ones.

When I thought about this screen plus rim method I figured I might create a sprite of each tile and animated tile place them off-screen and then clone them based on an array as needed. So, for example, the map array says you need a copy of tile(sprite) number 17 (because it's just about to come on screen) and so you just clone a version of tile/sprite 17..which of course could be static or already set up as an animated sprite. The you just delete the sprite as it goes off screen or in the case of a static one just change its image? I can see that the downside is that you have one of each tile on the map sitting off-screen not being used but it feels like an easy system to set up and I hear that cloning is pretty fast?

Yes Van B - the array I have in mind would be Map [x,y, attributes] where the attributes part holds info about the tile. Alternatively you have a Map [x,y,ID] which references a TileAttributes[ID, Attributes] to separate the two.

With the ViewOffset method, I reckon a lot of things become a lot easier and I'm guessing that with cloned sprites, they're just markers and when off screen are handled very fast by AGK...but again, I guess only a test will tell.
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 14th Jan 2014 08:55
Using view offset is absolutely fine, I have used it for huge levels with no slow down at all. If you are worried you could load chunks of the level and delete chunks as you go, I did this in an endless runner game and it worked fine.

Test if you like but with AppGameKit generally the code always runs fast, it tends to be gfx that slow agk down... she's quick as a fox under the sheets but when she needs to look good she's as slow as any other girl [/sexist analogy]

oct(31) = dec(25)
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 14th Jan 2014 10:04
Cheers Baxslash. I think I'll do a single test tonight with a large level and see how it performs with ViewOffset. If it works well, then that's what I'll do. Only issue is that my PC is probably faster than most..but hey, the game is probably only ever going to be played in my home!

I like the idea of the ViewOffset way - feels way simpler all around! Just felt too good to be true from a performance way but...you sound confident, backed with experience so that sounds good to me.
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 14th Jan 2014 10:16
I felt the same way at first but I found that pretty much no matter what I did my games ran really well unless I was careless with the kind of assets I used. Of course I generally try to be lean with my code anyway but other than gfx there are only a few issues that have a noticeable impact on performance.

In my latest WIP I am using my own 2D animation system, my own 2D lighting system (which does hundreds of exact distance calcs per loop) and uses any size map loaded fully at the start and it runs just the same with a huge map as with a small one. The only real difference is the loading time.

oct(31) = dec(25)
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 14th Jan 2014 13:38
Sounds perfect. Did you use parallax scrolling in any of your games? With ViewOffset I'm guessing you have to move the background tiles to partially compensate for the ViewOffset so that it does move independently from the foreground....if that makes sense. Ie get it to either move exactly the same as the view offset if you want a static background or move it but only at half the ViewOffset speed if you want some movement but not the same movement as the foreground.
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 14th Jan 2014 16:01
For parallax I have found that the best method is to calculate the distance from the object to the distance from the centre of the screen (in world co-ordinates). Then I apply an opposite offset of a fraction of that distance depending on the depth I want for that object. It works pretty well in my latest WIP and is a new method I just came up with. I could share the code but it would take a while to extract it into a useful bit of code.

Hope that helps!

oct(31) = dec(25)
The Daddy
15
Years of Service
User Offline
Joined: 13th Jan 2009
Location: Essex
Posted: 14th Jan 2014 18:05
I would not suggest cloning/creating/deleting sprites in your main loop....this will slow your app down exponentially.

My method, create all the 374 sprites in the initialisation and move them each loop. Have an array of your total map based on a UDT something like...
Type tMap
TileType As integer (is it solid/lift/rock...whatever you like)
TileStartFrame as integer
TileNumFrames as integer (if 1 then no animation)
TileAnimationType as integer (loop, play once, ping pong etc)
.....any other stiff your map needs
EndType

Then simply use an atlas texture to use TileStartFrame as an image index....animation is simple from there.....

This way you could have tiles that animate always, when walked on/hit, collide with sprite x animate tile y etc etc....

www.bitmanip.com
All the juicy you could ever dream of!
The Daddy
15
Years of Service
User Offline
Joined: 13th Jan 2009
Location: Essex
Posted: 14th Jan 2014 18:07
In AppGameKit even offscreen sprites must be checked in the AppGameKit Engine Loop....even if all it does is see if its on screen...still 10000 sprites over 374!

www.bitmanip.com
All the juicy you could ever dream of!
Van B
Moderator
21
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 14th Jan 2014 18:37
I think that would be best for parallax layers as well, the problem with using a full offset is the sheer number of sprites required.

Still though, parallax is still a concern I think - there's a lot to be said for just having big images for parallax layers I think, makes scrolling much more straightforward, especially if it's a big sprite fixed to the screen, then it can be repeated and UV shifted to suit the scrolling.

It's a shame there isn't a way to control the view for different sprite groups, as soon as view offsetting comes into play, parallax becomes a bit of a pill. I am determinned to try my text idea though, if just to satisfy my own curiosity.

I am the one who knocks...
Van B
Moderator
21
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 14th Jan 2014 19:48 Edited at: 14th Jan 2014 19:58
Text tile map demo attached, 8 parallax layers... pretty interesting, I think it has potential

Like, this is all the code that it needs to handle displaying the tilemap layers:



Maybe someone can come at it with sprites, see if they can display the same any quicker.
It can support up to 224 tiles per text object, like a tile sheet of 15x15 - which is really not too bad of a limitation. Of course, the tiles could be adjusted just like with text, rotated, coloured etc etc - maybe properly animated things would be better as sprites though, might be slow to change a tile unfortunately.

I am the one who knocks...

Attachments

Login to view attachments
DavidAGK
AGK Developer
10
Years of Service
User Offline
Joined: 1st Jan 2014
Location:
Posted: 16th Jan 2014 09:17
Love the curve ball feel about this!

Login to post a reply

Server time is: 2024-02-25 16:02:41
Your offset time is: 2024-02-25 16:02:41