godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add more types of TileMapLayers to hold different data types #10572

Open groud opened 2 months ago

groud commented 2 months ago

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

I was thinking about how to implement https://github.com/godotengine/godot-proposals/issues/10567. But in general, we have tons of demand to add a system to paint values (integer, enums, etc.) directly on the tile map.

The main problem with the current implementation, is that the TileMap storage format relies on storing, per-cell, the following data: coordinates, souce_id, atlas_coords, alternative_id. It is not flexible, and is kind of a problem when you want to store arbitrary data inside. That also leads to some confusion, as with TileSetScenesCollectionSource for example, the atals_coords value should always be set to (0,0), and the alternative_tile identifier is used as the index in the source.

In general, the API as designed for TileSetAtlasSource, which makes adding new data types complicated and confusing.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Now that tile map layers are individual nodes. We could maybe implement several subtypes of TileMapLayers.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

We would split tile map layers into several classes. Probably something like this:

Each of those subclasses would have dedicated API to set data in the layer. So on a TileMapSceneLayer, set_cell(coords, source_id, atlas_coords, alternative_tile) would become set_cell(coords, scene_id)

This has a main consequence though: TileSet/TileSetSource should likely be split into several new parts too:

Some random thoughts:

If this enhancement will not be used often, can it be worked around with a few lines of script?

It's core

Is there a reason why this should be core and not an add-on in the asset library?

It's core.

dugramen commented 2 months ago

This sounds great but I notice a few potential problems

Ysorting across multiple tile maps would be required. Otherwise if you have 2 atlas layers, for example, the second will always appear on top

There's also an inconvenience to consider. Across 2 atlas layers, setting a tile would no longer overwrite that spot, but rather set it on that layer. If you're editing a lower layer, you might not even see a change, since it could be covered by a tile in a higher layer, and that higher tile would remain

There should be a way to group/link layers together, so they can overwrite each others tiles. Maybe a TileGroup node, or a TileGroup resource similar to the ButtonGroup resource

groud commented 2 months ago

Ysorting across multiple tile maps would be required. Otherwise if you have 2 atlas layers, for example, the second will always appear on top

This is already the case, if the parent node of both layers has Y-sort enabled too.

There's also an inconvenience to consider. Across 2 atlas layers, setting a tile would no longer overwrite that spot, but rather set it on that layer. If you're editing a lower layer, you might not even see a change, since it could be covered by a tile in a higher layer, and that higher tile would remain

I mean, that's already the case in 4.3 with several TileMapLayers. Llayer highlighting solves that by making upper layers transparent.

There should be a way to group/link layers together, so they can overwrite each others tiles. Maybe a TileGroup node, or a TileGroup resource similar to the ButtonGroup resource

I think this is a bit too complex, and it's a small drawback to have. I would not implement it unless there's high demand for it I think.

dugramen commented 2 months ago

I understand. But I still think it could be a really big drawback. Here's another example with just an atlas layer and a terrain layer.

You can draw bunch of grass on the atlas layer with a couple of rocks with collision sprinkled around, as the "floor". If you then want to add a lake with the terrain layer, you first have to delete all the tiles you might need in the atlas layer, then paint it all again in the terrain layer. Do this every time you want to change the lake a little bit. If not, you'll have random invisible walls in your lake because there are still rocks there in the atlas layer

I can see this becoming very inconvenient for people

Maybe it doesn't even have to be a separate TileGroup node, but just a toggle on a layer, to let child layers overwrite each others tiles

groud commented 2 months ago

You can draw bunch of grass on the atlas layer with a couple of rocks with collision sprinkled around, as the "floor". If you then want to add a lake with the terrain layer, you first have to delete all the tiles you might need in the atlas layer, then paint it all again in the terrain layer. Do this every time you want to change the lake a little bit. If not, you'll have random invisible walls in your lake because there are still rocks there in the atlas layer

I assume the other layer would be procedurally generated from the first one then, so it should not be a problem. But to be clear, this is something that already exists in the current state and nobody complained that they sometimes have tiles from a given layer hidden by another. The layer highlighting feature already helps with that. This is a bit unrelated to this proposal, and might require its own proposal.

dugramen commented 2 months ago

I assume the other layer would be procedurally generated from the first one then, so it should not be a problem.

I don't think we should assume the mechanics of the game. I used lake as an example, but even something as simple as a path would be in the terrain layer, and it'd have the same problems

But to be clear, this is something that already exists in the current state and nobody complained that they sometimes have tiles from a given layer hidden by another. The layer highlighting feature already helps with that. This is a bit unrelated to this proposal, and might require its own proposal.

It's different because people currently use layers for independent "sections" or depth / elevation. You don't expect different layers to be mixed

But if terrains also have to be separate layers, then they're no longer just a helpful auto tiling system. If you just want a convenient auto tile alongside your other tiles, they'd now be a lot more tedious to work with. Even features like floodfill would stop working as well, because the bounds would be different

I agree though that this should probably be a different proposal. I just think this new tile layer system shouldn't release without it

groud commented 2 months ago

But if terrains also have to be separate layers, then they're no longer just a helpful auto tiling system. If you just want a convenient auto tile alongside your other tiles, they'd now be a lot more tedious to work with. Even features like floodfill would stop working as well, because the bounds would be different

Right I see what you mean. I still think it's a minor annoyance. "grouping layers" together is a bit of a complex thing to do as I don't want to bloat the node structure. In any case, I don't think it's a priority, but I think it might end up worth implementing if people end up complaining.

MatthiasBae commented 2 months ago

What exactly do you mean with

This could allow more custom algorithm.

Is the user possible to "override" the algorithm or will the core algorithm be more flexible for new algorithms like the dual grid system you mentioned?

groud commented 2 months ago

Is the user possible to "override" the algorithm or will the core algorithm be more flexible for new algorithms like the dual grid system you mentioned?

Id say both. It could allow other kind of algorithms (that are likely more robust) as built-in, but also custom ones. It's a bit hard to define right now, but painting arbitrary values / ID on map allows a ton of possibilities.

KoBeWi commented 2 months ago

Will TileMapAtlasLayer still allow custom data for tiles? Would TileMapSceneLayer allow customizing placed instances (e.g. changing exported properties)?

groud commented 2 months ago

Will TileMapAtlasLayer still allow custom data for tiles?

Yes. This will not change.

Would TileMapSceneLayer allow customizing placed instances (e.g. changing exported properties)?

It's out of the scope of this proposal, but I would not be against a mode that would instantiate scenes as children of the currently selected TileMapLayer (or TileMapSceneLayer). So that you would be able to select them and edit them in the scene tree. But that has a set of challenges (what if you modify a scene's position ?), and is probably work for another day.

monkeez commented 2 months ago

You mentioned LDtk in the proposal, are you saying that this would allow functionality like in LDtk where you paint a collision layer and then be able to have the tiles be generated from that? It's something I really like in LDtk and would love to have it in Godot.

Being able to set exported properties on the scene layer would be great too, it's one of the missing features that has made me skip using scenes in tile maps at all.

groud commented 2 months ago

You mentioned LDtk in the proposal, are you saying that this would allow functionality like in LDtk where you paint a collision layer and then be able to have the tiles be generated from that? It's something I really like in LDtk and would love to have it in Godot.

I mean, probably not out of the box, but with a simple script, I guess so.

IntangibleMatter commented 2 months ago

I would like to add that #10439 feels related to this proposal in terms of modifying tilemap functionality.

Additionally, on the subject of allowing more complex things like in LDtk, I think one of the features of LDtk which would be most beneficial in Godot's Tilemaps would be the more complex Autotile Rule system (e.g. matching against tiles x distance away, negative matching, matching against any terrain of a set, etc), as it enables much more diverse and powerful autotiles,like having a "fade" away from the surface that lasts a few tiles, instead of only being able to have edges/centers as autotiles currently do.

Portponky commented 2 months ago

This sounds like a good idea in general, and the right direction to take the TileMap in. The naming is contentious to me, as 'Tile' is associated with the graphics (part of an atlas).

Perhaps something like MapLayer, with TileMapLayer, SceneMapLayer, etc.

I am unsure that every different layer would need a corresponding data source for that layer type.

SceneLayer

The scene source in the tile map currently works fine but lacks utility. The two main issues that are frequently raised about it are:

  1. Can't set exported properties of placed scenes. This is vital for functionality similar to LDtk and Tiled.
  2. It always instances all nodes immediately. This makes it fine for level-based games, but poor for larger worlds where instantiation can be controlled discretely by the developer. If it had a function like spawn(rect, filter_func) and a property to auto-spawn everything (defaulting to true) that would be incredible.

In terms of a data source (e.g. TileSceneSet), I'd rather have a resource called something like SceneList which is a list of scenes. This could then be used in other places where a list of scenes is needed, for example MultiplayerSpawner. That would be really convenient.

TerrainLayer

This sounds unnecessary to me. Terrains are a tool for automatic placement of tiles - it's usually called autotiling. Devs don't want to separate out normal tile placement and terrain placement, they want autotile to accelerate and simplify placement of normal tiles. Making terrains a separate layer/node is going against how people want to use autotiling in practice.

An argument could be made for a separate dual-grid layer, especially if all tiles are offset by (-0.5, -0.5), though I still feel it's better handled by a generic autotiling system.

DataLayer

This sounds fantastic. Again, not sure if TileDataSet is needed. If it just held one type and out-performed a Dictionary of Vector2i -> Variant, and had editor capabilities, that'd be fabulous. I think I'd prefer it mapping one type of variable, and that multiple types were just done via multiple layers.

groud commented 2 months ago

This sounds like a good idea in general, and the right direction to take the TileMap in. The naming is contentious to me, as 'Tile' is associated with the graphics (part of an atlas).

I don't know. I guess this can be discussed.

I am unsure that every different layer would need a corresponding data source for that layer type.

I don't think it would be possible to share data between the different types, at least the built-in ones. If everything goes well we should be able to allow more custom data storage though.

Can't set exported properties of placed scenes. This is vital for functionality similar to LDtk and Tiled.

I believe it makes sense, but I don't want the tile map editor to expose those properties. If we go that way, those scene-layers will instantiate the scene as a child node of the layer instead, insider the editor. That raises a concern when users move a subscene manually though (how would you detect which cell the scene corresponds to). Maybe we could prevent moving subscenes, but that's not an easy task I believe.

In terms of a data source (e.g. TileSceneSet), I'd rather have a resource called something like SceneList which is a list of scenes. This could then be used in other places where a list of scenes is needed, for example MultiplayerSpawner. That would be really convenient.

Well, if there's a way to make it usable elsewhere I don't mind, but I don't think it's a high priority.

This sounds unnecessary to me. Terrains are a tool for automatic placement of tiles - it's usually called autotiling. Devs don't want to separate out normal tile placement and terrain placement, they want autotile to accelerate and simplify placement of normal tiles. Making terrains a separate layer/node is going against how people want to use autotiling in practice.

I am not sure about that. LDtk has a very powerful rule system that kind of relies on such a possibility. I kind of agree we could do without it but it brings a ton of possible improvements. By separating layers into different subclasses, I think we could expose a lot more of the internal and allow users to implement their own algorithms if they wish so.

Maybe a middle-ground solution might be to keep a simple autotiling feature for atlases (no "terrain" support)? I am thinking about bringing back the 3.x algorithm for atlas layers (as an editor helper, with some runtime update maybe), as it's a lot simpler and reliable algorithm. And then we could move complex algorithms to a new TerrainLayer ? Or RuleLayers, if we want something more customizable?

This sounds fantastic. Again, not sure if TileDataSet is needed. If it just held one type and out-performed a Dictionary of Vector2i -> Variant, and had editor capabilities, that'd be fabulous. I think I'd prefer it mapping one type of variable, and that multiple types were just done via multiple layers.

That's kind of an issue. The problem is that, if you have many tiles, storing a huge list of variant as text (in the tscn) would take hundreds of thousands of lines, which means tanking the performance in the editor. As a consequence, data must be instead serialized efficiently in a byte array, which is possible a lot easier if we use a integer -> Variant map. Maybe we could store the data directly inside the map though, that could be a possibility. That's likely TBD if we rework thing.

Sharaf5 commented 3 weeks ago

why separation if someone need them to be at the same layer ? I really find the deprecated TileMap more user friendly and handling layer data via TileSet but as you try to separate concepts, the separation of concept should be at the collections inside TileSet so it's more reusable by user accross multible TileMapLayers and separated in the way they behave with each data type