Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Godot 4 exporter #3550

Merged
merged 19 commits into from
Feb 17, 2023
Merged

Godot 4 exporter #3550

merged 19 commits into from
Feb 17, 2023

Conversation

Skrapion
Copy link
Contributor

@Skrapion Skrapion commented Dec 25, 2022

Merry Christmas!

Godot 4 is currently in beta and expected to release before GDC 2023 in March. This version overhauled the tilemap system, so the old exporter (for Tiled) and the very old importer (for Godot) no longer work. This is a first-pass at adding first-class support for Godot 4 to Tiled.

I intend to complete the following before I submit this for merging:

  • collisions
  • non-equilateral grids
  • documentation

Potential projects for future pull requests include (by estimated order of difficulty):

  • non-orthographic maps
  • external tileset file option
  • tile flipping/rotating
  • animations
  • objects
  • collection-style tilesets

Godot 4 overhauled the tilemap system. The old exporter (for Tiled) and the old importer (for Godot) no longer work. This is a first-pass at adding support for Godot 4 to Tiled.

This first implementation currently lacks support for:
* collisions
* non-orthographic maps
* non-equilateral grids
* animations
* objects
@Skrapion Skrapion changed the title [WIP] Godot 4 exporter Godot 4 exporter Dec 26, 2022
@Skrapion
Copy link
Contributor Author

@bjorn Looks like there was a temporary internet issue with one of the checks, but otherwise this PR is good to go. Hope it meets your approval!

@bjorn
Copy link
Member

bjorn commented Dec 27, 2022

Looks like there was a temporary internet issue with one of the checks, but otherwise this PR is good to go. Hope it meets your approval!

@Skrapion I see the builds have succeeded now. :-)

Thanks for lot for working towards Godot 4 support in Tiled! Before merging this though, I'd like to know your opinion about including an exporter vs. adding an importer to Godot. A Godot 4 Importer for Tiled maps is being worked on as well. Are there merits for supporting both workflows, and if so, how could we help people decide between the two?

@Skrapion
Copy link
Contributor Author

Thanks for the heads up! I didn't know about the Godot importer. (I suppose that's not surprising when it's only a week old!)

I'm biased, but I think an exporter will result in a better user experience most of the time.

Pros of importer:

  • Tiled has no maintenance overhead for this code.
  • More Godot users know GDScript, compared to C++, so more people might contribute.
  • It's not tied to anyone's release schedule: people can use the latest version of the importer today, without waiting for an update to Tiled or learning how to compile code.

Pros of exporter:

  • It works out of the box; no installing scripts from a third party.
  • Faster iterations. The importer requires you to save your Tiled project, run the importer on your tilesets, then run the importer on your tilemaps. The exporter just requires you to click Export when editing your map, and Godot instantly offers to reload it, including the tilesets.
  • You can export without saving, which is good for experimentation.
  • The readme for the importer says the import may take a while. Using C++ instead of a scripting language, and working on data structures instead of XML, will always give the exporter a speed advantage.
  • The code is less likely to get abandoned when it's shipped with the software (Tiled has a history of merging this kind of exporter, but Godot doesn't have a history of merging this kind of importer, and the author doesn't seem to be pursuing that).
  • It's less brittle to upstream changes. Tiled is less likely to break exports with software updates, because we'll see problems at compile time instead of at import time.

There's not many instances I can think of where you would say "use the importer for this, and use the exporter for that". Here's the only one I can think of:

  • If you want a unified tilemap/tileset file (like the Godot IDE produces) use the exporter. If you want separate tilemap/tileset files (more space efficient for real games) use the importer.

However, this is mostly just the result of each of us taking the path of least resistance when writing our respective code. Both the importer and the exporter could add an option to produce separate or unified files.

@HeadClot
Copy link

Hey @Skrapion - Got a question about this exporter. I am building a game with Godot 4 at the moment and I am making use of the tiled world feature inside tiled. I am curious how this exporter would handle this particular Tiled feature. Could you elaborate on this?

Thank you for your time

  • Benjamin

@Skrapion
Copy link
Contributor Author

@HeadClot Worlds are just a collection of tilemap files, so you should be able to open any of them and export them individually.

This exporter won't do a big batch export of every map in the world (that's doable, but 99% of the time I think you'll want to export individual rooms anyway) and you'll still have to link all the maps together somehow in Godot, since how you do that is really game specific.

@HeadClot
Copy link

@HeadClot Worlds are just a collection of tilemap files, so you should be able to open any of them and export them individually.

This exporter won't do a big batch export of every map in the world (that's doable, but 99% of the time I think you'll want to export individual rooms anyway) and you'll still have to link all the maps together somehow in Godot, since how you do that is really game specific.

Cool. Thank you for the answer :)

@Skrapion
Copy link
Contributor Author

I've got a long travel day on New Years Day, so I might get some more features in. Looking to add:

  • Non-orthographic maps
  • External tileset option (for sharing one tileset file between multiple maps)
  • Tile rotations/flips
  • Animations

I hope I'll have enough time to implement at least a couple of those! @bjorn, if you see this message in the next 36 hours, please let me know if you think it's likely that this exporter has no future, so I can work on something else :)

@bjorn
Copy link
Member

bjorn commented Jan 2, 2023

I hope I'll have enough time to implement at least a couple of those! @bjorn, if you see this message in the next 36 hours, please let me know if you think it's likely that this exporter has no future, so I can work on something else :)

I missed this message since I was celebrating New Year with my family at my parents. Happy New Year! :-)

You've iterated quite well the advantages of this exporter and I'm glad to see you've been able to make further progress with it on your trip!

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left a number of small comments. I haven't tested the plugin yet, but I'm looking forward to do so when I have more time, hopefully later this week.

src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
@Skrapion
Copy link
Contributor Author

Skrapion commented Jan 2, 2023

Got all four features in that I wanted to get in. No more features on this PR, I promise :)

Thanks for the start on the review, @bjorn!

@dogboydog
Copy link
Contributor

Chiming in on one more factor in the importer vs. exporter question from a user perspective. In my experience, a useful feature of importers is that objects from tiled can be modified/replaced with in-engine assets, including with custom logic depending on custom properties/layer names, etc. Since an exporter doesn't know anything about your game project code/assets that's something i don't think you can achieve with an exporter.

@Skrapion
Copy link
Contributor Author

Chiming in on one more factor in the importer vs. exporter question from a user perspective. In my experience, a useful feature of importers is that objects from tiled can be modified/replaced with in-engine assets, including with custom logic depending on custom properties/layer names, etc. Since an exporter doesn't know anything about your game project code/assets that's something i don't think you can achieve with an exporter.

Actually, I think this would work quite well.

If I add a character to a scene in Godot, with some custom parameters, it outputs something like this:

[ext_resource type="PackedScene" uid="uid://bsp33usd3qwqq" path="res://Characters/PlayerCat.tscn" id="1_6eody"]
[node name="PlayerCat" parent="." instance=ExtResource("1_6eody")]
z_index = 2
y_sort_enabled = true
position = Vector2(104, 89)

There's no reason we couldn't make a Tiled exporter output all of that with some custom properties on the objects. And it has the added benefit of those properties being saved into the Tiled project file, so you don't need to re-specify them each time you import, or otherwise find a weird place to save those settings.

Making an interface in Godot that can do this would greatly inflate the complexity of the project, so I'm skeptical if anyone would ever do that. The only benefit is that, if someone did that, the user might be able to specify some of these properties by selecting an item from a list instead of typing it in.

@Skrapion
Copy link
Contributor Author

The importer I'm using in 3.5 exposes the ability to post-process the node generated from tmx files. I did something similar when I was using Unity as well. I can easily locate assets that way even based on partial names of assets and insert packed scenes into the map. I'm not sure if we're talking about two different things here as it hasn't increased the complexity of my project but rather reduced it. Maybe you thought there was a manual step or GUI involved.

Yes, I did assume you were talking about having a GUI to help you. And in that case, the increased complexity I was referring to was for the person writing the importer, not the end user.

I guess you're using this importer?

If the primary use case is replacing Tiled objects with packed scenes, and maybe adding some custom properties, then I think we can eliminate the need to write your own import script entirely.

In other words, instead of:

  • Create a new "type" property in Tiled and set it to "Lamp"
  • Write a custom script with a for loop and a bunch of if-else statements
  • Run the importer, being sure to check "custom properties", and browsing to find your custom import script

All you have to do is:

  • Create a new "type" property in Tiled and set it to "res://objects/Lamp.tscn"

And that's it. As soon as you click File->Export in Tiled, Godot would instantly reload your level and replace that object with the Lamp.tscn scene. We could even specify an object root and get rid of the "res://objects" part.

@dogboydog
Copy link
Contributor

dogboydog commented Jan 20, 2023

Yeah I'm using a modified / patched version of the vnen importer currently. I plan to move to 4 eventually when it is more stable but I've tried out the 4 beta a few times. Thanks for working on this

All you have to do is:

Create a new "type" property in Tiled and set it to "res://objects/Lamp.tscn"

And that's it. As soon as you click File->Export in Tiled, Godot would instantly reload your level and replace that object with the Lamp.tscn scene. We could even specify an object root and get rid of the "res://objects" part.

Well that sounds like it would fit my use case and I'd be interested to try it out. Just my opinion and not sure if 'type' was just an example, but I would suggest a different property besides "type" (AKA class in tiled 1.9) to store the optional resource path. This is because then I could still have a meaningful Type like Enemy or Pickup under type/class, and then I can build the res:// paths into the categories of objects using enums, making it easier to find the right ones. Here's a mockup of what I mean in Tiled

Enum of string values for resource paths where this type of entity are located in my game project
image
A class/type which uses this enum for whatever the resource path property is - here I used the example name resPath:
image
image

Anyway your exporter sounds interesting, sorry if I've misunderstood something or if I'm off topic

@Skrapion
Copy link
Contributor Author

You're right, a custom enum would be perfect for this. And yes, 'type' was just an example :)

@grusad
Copy link

grusad commented Jan 31, 2023

Hey yall! Just found this exporter and im really excited for it. Godot tilemap editor dont really work the way i want. Is this usabale yet or how long before i can start using it? :)

Have a good one!

@Skrapion
Copy link
Contributor Author

Skrapion commented Feb 1, 2023

Hey yall! Just found this exporter and im really excited for it. Godot tilemap editor dont really work the way i want. Is this usabale yet or how long before i can start using it? :)

Have a good one!

It hasn't been merged yet (what do you think, @bjorn?) but you can download it and use it right now.

Just click on the Details link for any "Build Packages" below, then click to "Summary" and scroll down to "Artifacts".

* Renamed some functions to start with lower case (coding style)

* Fixed translation issues (lupdate does not recognize source texts when
  not provided as direct parameter to known tr / translate functions) and
  use consistent translation context.
Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Skrapion I think this is great work and I'm in the process of trying to test this (have installed Godot 4 Beta, looking into setting up a project) and reviewing the code (pushed some small changes).

src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
src/plugins/tscn/tscnplugin.cpp Outdated Show resolved Hide resolved
* Pass QString by const& in a few places
* Don't use regular expression to replace " by \"
* Use range-based for loop for iteration in a few places
* Avoid double tilesetInfo lookup in addTileset
* Use TileLayer::localBounds when we're using it to iterate the layer's tiles
All layer types support the following custom properties:

* bool ``ySortEnabled`` (default: false)
* int ``zIndex`` (default: 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I tried exporting one of the examples, it did not look like in Tiled because the layers appeared to get rendered in a random order. Would it make sense to use an auto-incrementing z-index by default, instead of using 0 for each layer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you use ySortEnabled?

Are you recommending that reach Tiled later gets a new z-index? We can play with that, but I'm a little nervous about how magic that is, and how you might end up with layer numbers changing unexpectedly.

Right now it's just using the Godot defaults, but I'm happy to change them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not use ySortEnabled. I might have just been confused with what Godot was displaying, probably being in editing mode. When not in editing mode, it seems the layer order defines rendering order, so setting zIndex does not appear necessary.

@dogboydog
Copy link
Contributor

dogboydog commented Feb 9, 2023

Hi, I gave this a try too on one of my maps with the new Godot 4 RC1 from today.

First issue I hit was that objects are not supported, I see that's expected but i use them. I'm still not sure if I can replicate my object import workflow with an exporter or not since sometimes one object might end up having additional child objects when imported into the engine (for example I have a boolean object property interactZone that could be on any object, which instantiates a collider that lets the player examine/talk to an object/npc. ) This is nice because it means my importer logic can be modular - I can optionally create any number of child /sibling objects in-engine from one object in Tiled. It could be my workflow just doesn't match well with an exporter -- it's not a criticism but just a consideration.

Next I deleted all the objects from my map and was faced with this error when exporting:
image

To me tile flipping/rotation seems like something many maps would use, so I wonder why it needs a special option? I couldn't find a way to get around this error by adding a boolean property to my map (Edit: Sorry I just realized the error says the tileset needs this property, not the map. After adding the property to all my tilesets, the simple map I tried it with looks good in Godot 4)

Also a few more notes on the importer vs exporter question.

Faster iterations. The importer requires you to save your Tiled project, run the importer on your tilesets, then run the importer on your tilemaps. The exporter just requires you to click Export when editing your map, and Godot instantly offers to reload it, including the tilesets.

In both Unity and Godot, the importers I used didn't require any manual intervention, definitely not two manual steps every time. Just saving the map .tmx or .tsx file can trigger the reimport automatically (the editor detects the file contents have changed). I haven't tried the Godot 4 importer yet.

The other thing that comes to mind with importers vs exporters is that in Godot, there are breaking changes between versions of Godot even within a major release. You can see a lot of PRs and issues opened in the popular vnen importer repository for example trying to catch up with Godot editor updates within 3.x. saying it worked in 3.2 but not anymore. So, while you could check out a certain version of an importer repository to get compatibility with a certain version of the Godot editor, it seems like that might be more difficult when using an exporter that is bundled with Tiled, unless you were to provide some kind of compatibility level setting, or just require that people always use the latest version and keep it up to date.

I was able to try with the example 'desert' tileset that comes with Tiled though and it looks good
image

Overall thanks for making this, seems cool and was interesting to try!

@Skrapion
Copy link
Contributor Author

Glad you sorted it out, @dogboydog. Hopefully when the documentation is published it will be a little more obvious how those features work. But it sounds like until object experts are supported, that error message should be changed to a warning message. Unfortunately, I'm traveling for two weeks, so it won't happen just yet.

The main reason why exportAlternates isn't on by default is because Godot's handling of rotated and flipped tiles requires you to octuple the size of your tile set, so I thought it was more responsible to have the user opt into it.

@dogboydog
Copy link
Contributor

Got it, thanks for explaining. And nice work on the exporter.

@bjorn bjorn added this to the Tiled 1.10 milestone Feb 15, 2023
There was little reason to fail the export in these cases, which are now
reported as errors or warnings in the Console view instead:

* WARNING: Unsupported layer type encountered
* WARNING: Only rectangles or polygons supported for collissions
* ERROR: Tile animations have gaps
* ERROR: Tile used that is also part of an animation
* ERROR: Unsupported tile flipping (120 degree or missing exportAlternates)

The choice between error or warning is a little arbitrary, since none of
these cause the export to fail and all of them cause the export to only
partially work. I picked warnings for cases where I think some people
may want to just ignore them.

The errors and warnings also enable jumping to the respective location,
layer or tile, where applicable.
@bjorn
Copy link
Member

bjorn commented Feb 16, 2023

But it sounds like until object experts are supported, that error message should be changed to a warning message. Unfortunately, I'm traveling for two weeks, so it won't happen just yet.

I've changed a number of these hard errors into warnings / errors that now get reported to the status bar / Console view.

I think the plugin is in good shape, even if more features could be added, so I would propose to merge this for now. Further improvements and potential bugfixes can be made in future PRs. :-)

Regarding export plugin or Godot importer, it sounds to me like it'll be good to have both since there are pros / cons on both sides.

@bjorn bjorn merged commit e74ef2f into mapeditor:master Feb 17, 2023
@erniel
Copy link

erniel commented Feb 26, 2023

Hi all where can i download to test this feature? Kinda confused which link to access or where to find the build packages. I would like to test this in Godot RC5

@dogboydog
Copy link
Contributor

While logged in to GitHub, click on the green checkmark next to the latest commit in this PR
image

Then click one of the "Details" link next to one of the "Build Packages" jobs. Click summary on the top left of that page. Then scroll down to the list of downloads

@bjorn
Copy link
Member

bjorn commented Feb 27, 2023

The documentation for this new Godot 4 export plugin can be found at https://doc.mapeditor.org/en/latest/manual/export-tscn/. Any feedback is welcome. The most obviously missing feature is probably the support for object layers. If you're missing this, please also share with us your expectations for this feature.

@erniel
Copy link

erniel commented Mar 2, 2023

will there be new updates for this feature? it would be nice to have:

  • Import collision/occluder/navigation shapes (based on Tiled object type).
  • Support for one-way collision shapes.
  • Support for collision shapes layer.
  • Support for image layers.
  • Support for object layers, which are imported as StaticBody2D, Area2D or LightOccluder2D for shapes (depending on the type property) and as Sprite for tiles.
  • Support for group layers, which are imported as Node2Ds.
  • Custom materials for tilesets
  • Custom properties for maps, layers, tilesets, and objects are imported as metadata. Custom properties on tiles can be imported into the TileSet resource.
  • Create a new "type" property in Tiled and set it to "res://objects/Lamp.tscn"

and this would really be better to have this option

@bjorn
Copy link
Member

bjorn commented Mar 2, 2023

@erniel These are all good suggestions. I think the features of this exporter will generally be expanded on-demand and when there is a clear idea about how each of these should be implemented. Do you personally need all of these, or are some features more important than others? And can you help define exactly how each feature can be best mapped from Tiled to Godot 4, or even help implement them?

@feendrache
Copy link

Hey there,
i'm the developer of the Tiled importer mentioned above. I'm not sure if i will continue working on the importer, when tiled provides all functionality. I only started the importer because i wanted to use my tiled maps in my project...

@bjorn
Copy link
Member

bjorn commented Mar 8, 2023

@feendrache I think the discussion above showed that there are advantages to using an importer vs. an export plugin, but if this export covers your needs you of course don't need to maintain an importer.

Note that there is another importer in development in the meantime as well (not sure if they were aware of yours) at https://github.com/Kiamo2/YATI. It seems to already cover most of Tiled's features.

@feendrache
Copy link

@bjorn thx ... oh well... that's brilliant, so i will stop maintaining mine and redirect interested people to this one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Status: In Progress
Development

Successfully merging this pull request may close these issues.

7 participants