Tileson - A Tiled json parser for Modern C++

Hi,

I am really a noob with c++ game development. I have to do this for school so…

How do I run your project? I passed my path to a tiled json file in the main.cpp.
tson::Map map = parser.parse(fs::path("./src/level/level1.json"));
I have already added a tiled json file in the project and the path is correct.
But keeps saying file not found. It seems to be ignoring the main.cpp

How can I run this project?

Hopefully this is not a stupid question.

Thanks in advance!

How did you make sure the path is correct? Note that you are passing a relative path, which the program will resolve as relative to its working directory. This may not be where you think it is (you can check using std::filesystem::current_path() to be sure).

Good luck with your assignment, sounds like fun!

Thank you for your reply :).
How can I run the main.cpp? The main.cpp is not being called. It only calls the tileson_tests.exe

Hmm, that depends on how the project is set up and your development environment. Maybe @SSBMTonberry can help with that. If this is a Visual Studio usage question, you may just need to activate a different project in the solution view.

But do you know how to install this in my project with cmake? I don’t find a guide for this.

@ffbodie: Sorry for the late reply. I have been very busy lately…
First of all I think @bjorn is right when he says that your path probably isn’t pointing to a file. “./” means the folder relative to the running executable, and unless you actually have created the folder “./src/level/” exactly where the .exe runs, it will not be valid. You can easily check if you have a valid path, by doing something like this:

fs::path path = fs::path("./src/level/level1.json");
bool pathExists = fs::exists(path);

Keep in mind that fs is an alias for std::filesystem that is used by Tileson.
If pathExists has the value true, then you are right, if not: then the path is not valid.
Since Tileson uses this functionality itself, I am fairly certain that the path you specified is not valid from where your .exe is running.

Sounds like you have recently started programming in C++. If this is the case, I would suggest you try making a regular C++ program using Visual Studio. Tileson uses CMake because it is designed to be cross-platform, but I would not recommend you to start there. Sounds like you have been able to build Tileson with its examples, which is a good start! When you built the project there is a Tileson.lib(default) or Tileson.dll file created (depending on how you configured CMake). You will need to use this when linking with your new Visual Studio project. You will also need all the header-files (*.h) related to Tileson for your project to recognize Tileson’s functions. You will need to read up on how you link libraries with Visual Studio, but it’s easy to find on the internet. Good luck! :slight_smile:

Additional note: .lib is libraries used for static linking (they will be built into your .exe), while .dll files are not built into your .exe, and will be required inside the same folder as where your .exe is for your program to work.

@ffbodie: Also: Check out SFML if you want to make a 2D game (handles drawing, input, sound, networking etc.). If you go to their home page they have very good tutorials how you use their library, and how you link SFML using Visual Studio.

I cloned this for my own attempt at using Tiled with C++ since this one supports the newest C++ standard (which I’m trying to learn). I did run into a slight issue, however, with the cmake system. I was trying to convert my CMakeLists.txt to be something like this: https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/

He makes a compelling case but Tileson doesn’t really support this style. Now, I’m not going to argue about CMake since this is the first project I’m doing with it (I’ve never liked gmake and decided to give this a try) but what are your thoughts? Could Tileson support this?

@Makis: I’m not completely certain what you tried to do. Were you trying to rewrite the CMakeLists.txt of Tileson, or of your own? If you could compile the project using a unmodified CMakeLists.txt of Tileson, then have issues compiling because you rewrite it to fit what that guy wrote in the article, you are kinda on your own. If you however have issues using the original CMakeLists.txt for builing, I will gladly help you solve your issue.

Please keep in mind that this library is made to work cross-platform, which is the reason why CMake is used. I also have Continuous Integration for every platform, making sure everything compiles and unit tests are okay with each build for every system, with several compiler version that supports C++17. For the demo using SFML, I made something quick to showcase how to use the library, as there were several questions on how it should be used with a Tiled map.

As for the CMakeLists.txt for Tileson itself, I really see no value changing it, unless there is a bug with it. I’m sure many people have different opinions on how things should be done, but there is really nothing complicated with the linking of the library, and the way I see it, there is really no value added in rewriting it to do it like the guy in the article, when the options that are provided works.

You are of course free to do whatever you want with your own CMakeLists.txt in your project. If you have issues compiling your application using Tileson, I gladly help. That is, if you have not modified the original CMakeLists.txt.

If there is a bug with anything, please give me some more detailed information on what your issue is, so I can solve it. I do, of course, want the library to be as stable as possible :slight_smile:

So what is the correct way of adding the library and include path? Just target_link_libraries and target_include_directories?

If I understand that article correctly one potential issue is if you move Tileson.h or add another interface header or rename the target. My build system breaks because I’m fixing those to current values.

There are several ways of doing it, but you will need to use the target_link_libraries() eventually, to link the library.

Why would you want to move Tileson.h or even rename it? Since it uses relative paths to files below the level it’s at, the result will be that you get errors if you move it. If you rename it, you would also need to rename it in the CMakeFiles.txt. I honestly still don’t see the issue, because you are not supposed to those things.

"My build system breaks because I’m fixing those to current values."
What is broken, and what are you fixing? I’ve used the library myself for personal projects, and I have never really had any issues linking it, so I am wondering what you are doing. Still don’t know if you are tampering with the CMakeLists.txt of the project or your own. If you want any help at all, I would need some details.

With that said, CMake can be quite a mess. I am in no way an expert myself, but there are a hundred ways you can do things. If there are any direct errors, I am of course interested in fixing them, but I have not experienced any such errors by using the library myself, or by the CI building the project on OSX, Linux and Windows. I will need some kind of information to have any idea of what is going on.

If you just want help linking Tileson, I can show you some alternatives, but I will need to see your CMakeLists.txt file. This is of course considering that you have not tampered with Tileson itself, which you of course are free to do, but then it’s your responsibility (and I strongly discourage it) :wink:

I don’t want to move it but you might. I did the linking like this in my own engine (will creates a library):

include_directories(rev_engine
PUBLIC
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/gfx/inc>
PRIVATE
    ${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS}
    ${CMAKE_CURRENT_SOURCE_DIR}/tileson/src
    ${CMAKE_CURRENT_SOURCE_DIR}/tileson/external_libs
)

And then in the main makefile that creates the executable I added tileson to target_link_libraries but I also need

add_library(tileson STATIC IMPORTED)
set_target_properties(tileson PROPERTIES
IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/engine/tileson/libtileson.a")

I think that if a library is properly defined I would only need find_package and target_link_libraries?

This seems to compile and I can include Tileson.h but as you can see I had to actually include two directories. If you rename those or add a third one my app wouldn’t compile. This is not a big issue in this single instance and I was basically just asking if you are aware of this thing.

I don’t intend to touch Tileson unless I find a bug or find I need something. In this case I’ll submit a pull request.

The point this blog post seems to make is mostly that by doing a bit more work to use some modern CMake features, we can keep the stuff that needs to be written in CMake files downstream to an absolute minimum. This has both the benefit of simplifying things for the users of a library as well as being able to change certain things (like include paths, dependencies, etc.) without breaking builds downstream.

To me, those features remind me a lot about how Qbs works, the build system I’m using for Tiled. It just calls things a little different, but there are products (targets in CMake) with properties and they can export stuff (like include paths, which library to link, etc.) to products depending on them. Personally I wish Qbs would become more popular, but I’m glad to see such concepts have been added to CMake (even though I find their syntax incredibly verbose and repetitive).

Anyway, as it often is with free software, if you want to improve something, you may just have do to it yourself. I’m sure @SSBMTonberry would gladly review a pull request to improve the CMake files. :slight_smile:

I would love to do something like that but my experience with CMake so far is in the single digit hours. If I get around learning enough I might do that. I think I already know about as much about it as I have learned about gmake’s syntax in the past 15 or so years.

But your comments are exactly how I understood the idea behind that blog post.

Thanks! Now it got more clear to me what you were talking about :slight_smile:

There is definitely room for improvement for the CMake file by adding support for find_package() and related properties. As for now there sadly isn’t. That you have to add “external_libs” as an additional include_directory is not ideal either, and it shouldn’t be like that. I may implement a proper find_package() support at a later time, but I may find a way to prevent you from needing to add that extra include dir soon.

What I usually do, personally, is to add things as subdirectories. When they are not subdirectories, they still can work as such by adding a full relative path to the library folder and where it is built. For instance, if debug:
add_subdirectory(${PROJECT_SOURCE_DIR}/external_libs/source/tileson ${PROJECT_SOURCE_DIR}/external_libs/source/tileson/cmake-build-debug)

Then I can just simply do:
target_link_libraries(my_app tileson)

Not saying this is the best way of doing things, but I have found it simple to do it that way :slight_smile: Which may also be the reason why I haven’t thought of the issues you describe. I do like the fact that you are trying to do CMake in a proper and modern way, as there are many things that can be quite a mess otherwise, and I am not afraid to admit that I have done quite a mess with CMake myself over the years, and still am.

1 Like

I have to say I’m not quite sure how I’m supposed to use this. I want to use SDL2 to draw the graphics so what I’d like to do is to get the tileset image name so I can open it as I can’t figure out how I’m supposed to use the data in the layer with SDL2. I’d also like to get the order of the layers somehow but this doesn’t seem to work for me either.

I’m using the desert scene from Tiled for testing. It has a layer, Ground, and I added another, Roof. I made a simple helper function:

void TiledMap::print_layers()
{
    for (const auto& layer : map.getLayers()) {
        std::cout << layer.getDrawOrder() << " : " << layer.getImage() << " : " << layer.getName() << std::endl;
    }
}

But this is all I get:

 :  : Ground
 :  : Roof

What gives? Is the order of the layers returned by getLayers() guaranteed to be correct? Where is the file name and what does getImage() return then (it has a return value of std::string after all)?

The image of a layer is probably only set when the layer is an image layer, which is a simple kind of layer in Tiled that can be used to display an image. For the tileset image, you’d need to look at the tilesets referenced by the map. See map.getTileset and tileset->getImagePath.

Hm, I thought every layer can have a different tileset in Tiled?

That ordering thing is obviously necessary so maybe it really is already ordered. How else to draw them in the correct order?

Hm, still not getting anything. Trying to print stuff from the tileset produces empty strings and zeros. Must have an issue parsing the file but it’s funny I can print the layer names.

If you download the latest master branch (not latest release), there is a demo showcasing how to draw stuff with SFML, using a demo map. Maybe that will help you :slight_smile:
The idea should be the same with SDL. Please note: It only shows how to draw stuff, and is inefficient, but should give you an idea how to use the data.

1 Like

I must have an issue saving the json files. Code reads the map file ok except for the tileset part (ok, I’m not quite sure about some of the fields). I saved that as a json file as well (I’m using the rpg example from Tiled). I created these json files by simply opening the island map and then saving the map and tileset as json.

Or could there be some sort of version issue between the examples in Tiled and Tileson? The example json for the SFML demo looks quite different from the files I generated.

E. Yep, something odd with the files I saved. Tried with your test map (ultimate_test.json) and things work.