Want to talk about my level format for a minute, which is otherwise completely undocumented. I use a set of layers, with fixed names for each. Changing that or adding more isn't hard, you would just need to update the Level class and Level::load() and Level::unload(). For collision, I ended up going with float-coordinate AABBs drawn with the polygon tool in Tiled, then adding a custom property "aabb_type" to them to indicate normal level geometry, damage volume, death volume, etc. Copy-pasting those helps block out a level fast, using grid snap, or pixel snap to match to something not grid-aligned, like the thinner platforms in level 2. Not the most elegant solution, however. When I get around to refactoring that whole thing, level geometry colliders will be their own class, while other volumes will go with the other level objects - coins, health pick-ups, items, moving platforms, goal, save points, whatever. The code to convert from Tiled polygon objects is nasty, but that can't be helped. Tiled has their coordinate system starting in the upper-left, the coordinates are in pixels, whereas I use floats with 1 tile being 1.0x1.0, plus the fucking polygon points are given relative to the object origin, which also happens to be where you started drawing from, not a set corner. I currently support 1 tileset per level, it can be any size though. I would like to change that to support multiple tilesets, so that a level can mix and match tilesets of different "themes" without them needed to be on the same sheet, eliminating duplication.
There are a few custom properties set on a per-level basis: map background music file name, player start x and y, and completion time limit. That's all pretty self-explanatory. You can set all sorts of parameters here if you want, like flags for which way the level scrolls, whether it auto-scrolls or not, if it's an underwater level, whatever. Coins were created using a 'tile object' with the 'name' parameter filled in to distinguish it from other objects. Tile objects though, have the drawback of being dependent on a tile graphic out of one of your tilesets for display, which fucked me up briefly when I tried to copy-paste a coin object from level 1 to level 2. I should really change those to 'point objects', which I find to be a lot more flexible, if not as visually pleasing in the editor. Speaking of which, coins and spikes are placed in Tiled, but currently I have MOBs being placed via a separate XML file. Even though MOBs could be handled with point objects in Tiled, using custom properties to fill in all the data I need for instantiation - position, jump speed, gravity direction and strength, phase, etc.etc. I couldn't find an elegant solution to list up all of the graphic and sound assets that needs to be imported for them, so I just whipped up a second XML doc for MOBs. Currently, in order to read it in on level load, the file name needs to be in the format (level name)_mobs.xml. Inflexible, but it works. Like a ghetto database of sorts.