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/AppGameKit Studio Showcase / [WIP] Tiled importer v.3

Author
Message
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 23rd Feb 2024 16:58 Edited at: 26th Feb 2024 20:09
Yesterday, I began working on a new importer. Tiled has deprecated the XML format and with AGK2's json loading ability I wanted to see if I could take advantage of that. I'm happy to say that so far the json loading is working very well, and since I don't have to do the parsing in Tier1 it is MUCH quicker. A 500x500 map with 2 layers loads instantly, at least as far as reading the map file. It will still need to generate the sprites and load images. The sprites shouldn't slow it down, the image loading will obviously depend on the size of the tileset image and how many. But honestly, half the project before was the parser. There are a few caveats though; Your file must be saved as TMJ/JSON format and the layer format as uncompressed CSV. While this will increase the size of the files, by using the built-in json loader I would not be able to decode the base64 without first loading into a temp array then parsing it. This would more than likely be a lot slower. The other important note is you'll need to make one minor change to the file before agk can read it. While agk can load json object from a string, loading from a file only works on an array. The Tiled format saves a json object so it must be wrapped with square brackets [ ] so it's seen as an array of map objects and not just a single object. That's it. Not a big deal but can be frustrating as I keep forgetting to do this and wonder why my maps suddenly refuse to load. Failure to load the json will not produce an error, you'll just end up with an empty array.
I'll post some photos once I have some map rendering done, but as I said the loading/parsing was always a big chunk of the work and it looks promising so far.

Going over my old code, a sprite was created for every tile in the map. While this simplified several things, it's obviously inefficient when it comes to very large maps. Happy to say this is now being addressed.


Command Set:
  • tmx_LoadMap()
  • tmx_SetMapPosition()
  • tmx_SetMapOffset()
  • tmx_SetMapScissor()
  • tmx_SetLayerAlpha()
  • tmx_SetLayerVisible()
  • tmx_PickTile()
  • tmx_GetTileProperty()



Features:
JSON/csv format only (uncompressed)
Layer alpha and visibility
External tilesets (tsx) in xml and embedded tilesets done.
Only orthogonal maps are implemented, isometric to come soon.


For example, with 32x32 tile size on a 640x480 screen, you will have at most 336 tile sprites (21 * 16) per layer. As these are cloned sprites, the number of truly unique sprites (image data) is only equal to the number of tilesets loaded. As the map scrolls around and the sprites are updated with proper tile images, there are chances of it having to delete a sprite and reclone another because of images existing within different tilesets. While this should not have any noticable impact, for efficiency it'd be recommended not using more than a single tileset per layer. Until I do more testing I can't say how much this really matters or not. An option I'd have is loading all the tilesets and combining them into a single image in AGK. As far as I can tell, Tiled breaks image tilesets into tiles sizes equal to that of the map's tile size, so I should theoretically never have tilesets with different tile sizes.


Current largest map size tested is 528x512, that's 12x the size of the legend of zelda overworld map. It slowed down a little bit compared to a small map, but nothing major. And loading is still instananeous. I'm still tweaking the code to get more speed but the biggest slow down seems to come from simply positioning the sprites. If I have 2000 fps, it drops to 500 when moving the sprites. Stripping everything out but the positioning yields about the same result, so there may not be anything I can do about it. For reference, hat was with 825 sprites being moved at a time.

Older v.2
https://forum.thegamecreators.com/thread/219035


Loading the tilset (tmx) files requires my xml parser, you can find it here: https://github.com/phaelax/agkxml/blob/master/xmlparser.agc

Example:


tmxloader.agc
Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 24th Feb 2024 05:04
While this is a WIP thread, a dev blog really, I know people like pictures and videos so here we go. I opted to show it like this so that folks can see how quickly the loading happens. Even though this is a small map, 20x60 with 2 layers. Screen resolution was 1024,768 but cropped to only show the visible part of the map. The entire map with both layers would have been 2400 sprites with my old importer. This one only displays at most 1000, even if I grew the map to 20x5000. (gonna work on a topdown vertical-scrolling shooter for a demo)

Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 25th Feb 2024 20:28
If anyone has any Tiled maps already built and don't mind sending them to me for testing I'd appreciate it. More than likely someone out there will use a feature in Tiled I'm not familiar with or overlooked.
Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

adambiser
AGK Developer
9
Years of Service
User Offline
Joined: 16th Sep 2015
Location: US
Posted: 27th Feb 2024 06:45
From what I remember, Tiled's tile rotation/flipping flags require unsigned 32-bit integer support, which AppGameKit doesn't have and again, if I remember correctly, AppGameKit truncates larger values at the largest signed 32-bit integer, so anything above 0x7fffffff stays as 0x7fffffff.
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 29th Feb 2024 05:14
I'll try to look at that, but I know I had tile flipping in my old version. Tiles have a global ID that include flip flags in them.

horizontal = gid && 0x80000000
vertical = gid && 0x40000000

I didn't give me any trouble in the past. Reading in the initial GID might show negative because of the flags, but once the flags are cleared (required to get the true tile ID) then the remaining bits should remain positive values if that makes sense. The flags are in the upper 4 bits.
Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

Awower
User Offline
Joined: 22nd Jan 2024
Location:
Posted: 1st Mar 2024 20:43
Hello! Thank you for continuing to develop your importer! It's a good news! I'll start making a map for my project and upload it for testing. So far 500x500, ideally 1000x1000. But this is just my personal whim for a single project, in particular, such large maps are not needed, but sometimes they are needed I'll be waiting for advanced functionality, and optimization. Thank you for being with us
APG Studio
Awower
User Offline
Joined: 22nd Jan 2024
Location:
Posted: 1st Mar 2024 20:45
Oh, and I forgot to add one more thing. What will be the implementation of the collision?
APG Studio
adambiser
AGK Developer
9
Years of Service
User Offline
Joined: 16th Sep 2015
Location: US
Posted: 3rd Mar 2024 03:44 Edited at: 3rd Mar 2024 03:54
Try this:

prints 2147483647 instead. The fromjson parser clamps the value to 2147483647 max.
fromjson doesn't read hex values, so
sets jt.x to 0.

EDIT:
message(str(val("80000000", 16))) also reports 2147483647 instead. So does message(str(val(hex(-1), 16)))
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 9th Mar 2024 15:58
Are you seeing numbers that high when exporting from Tiled? The documentation on flipping is a bit lacking. It says it stores that info under tileset->transformations but I sure don't see it. Heck I can't even find documentation on how my old version handled it, but it appears it hasn't changed.
For instance, I just flipped a random tile horizontally. The gid for that tile unchanged is 89, flipped it's 2147483737.

To clear the flip flags:
gid = gid && 0x1FFFFFFF

which results in the base ID of 89. Or at least it should. Ok, yea I see what you mean. So while I can implement the flags for tile flipping, looks like it won't actually work. I could've sworn this worked in my old version as I would've tested it. Even with a gid of 1, flipping will make it 2147483649 which is still beyond the range.

Ok so simply put, maps cannot use flipped tiles with my importer or it'll result in errors because there's no way to maintain the true value and clear the flags to obtain the proper GID. This is a bummer and a limitation of AppGameKit using signed INTs.

Is there a possible workaround? Technically, yes. Will I do it, no. It's not worth the trouble to be honest and would kill the main performance advantage of using the json loader. If I parsed everything manually, reading each line of the file as string data, I could technically write functions to do the math on large numbers by keeping them strings or by building a memblock. Parsing the file is way slower than using json load. And with AppGameKit clamping the value as it's read, I really see no other way around it.


Quote: "What will be the implementation of the collision?"

Collision is really up to the user to implement. But that's not to say you can't add it to your map. Using my zelda map as a test (256x88) I added in collision. You can add custom properties to each tile within a tileset (not individual map tiles). For instance, you cannot walk on water, so I selected the water tile and added a property called 'collision' = 1. Then in your game, you can retrieve the property of the tile your character is moving to.

I don't have all the functions written yet, but this example will get the property of the tile under the mouse coordinates. There's still enhancements to make to hopefully reduce having to search each tileset, which for most I imagine isn't going to be more than 1 or 2. And while tilesets generally increment IDs sequentially, it's not guaranteed. I forget how exactly, but I do know there could be breaks in the ID numbers. So like you can have 1,2,3,7,8,9.... Which is why I can't simply reference them from an array and must search each time. If AppGameKit had associative arrays it'd be nice.


Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

adambiser
AGK Developer
9
Years of Service
User Offline
Joined: 16th Sep 2015
Location: US
Posted: 10th Mar 2024 01:52 Edited at: 10th Mar 2024 01:54
I found no easy way around AGK's 32-bit signed limit.
For my tmx importer, I think I had to require base64 when flipped tiles were used, then write my own 2's complement function to convert string representations of the numbers. Slow, but functional. I haven't been up on Tiled's changes lately, so I don't even know whether it would still do that.

EDIT: I take that back, looks like I ended up expanding the base64 tile string into a memblock and then use GetMemblockInt to get the signed representation.
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 10th Mar 2024 16:42
I'm not using the base64 encoding anymore, it just doesn't even compare to the speed increase of using json load. That may have been why it worked before in my old version, because it was base64 string and was all read into a memblock.
Tiled TMX Importer V.2
XML Parser V.2
Base64 Encoder/Decoder
Purple Token - Free online hi-score database
Legend of Zelda
Pixel-Perfect Collision

"I like offending people, because I think people who get offended should be offended." - Linus Torvalds

adambiser
AGK Developer
9
Years of Service
User Offline
Joined: 16th Sep 2015
Location: US
Posted: 11th Mar 2024 18:08
My loader used the xml format since json had that limitation. And the json can't have the same field defined as a string and as an integer array. What I ended up with was pretty fast, but yeah, I imagine that a simple json load is faster. Just something I was toying around with at the time.
If you used the base64 string, that is likely why the flip flags worked before, like you said.

Login to post a reply

Server time is: 2024-11-21 10:02:11
Your offset time is: 2024-11-21 10:02:11