-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Going forward with the TileMap editor #6415
Comments
Another needed feature is collider merging. Right now every tile adds a separate polygon (!) to the physics layer, which results in performance issues with very big TileMaps. It's also surprisingly easy to hit the seams between tiles, which may result in unexpected bouncing or colliding of some objects. The collider merging would basically try to merge all shapes into one big polygon. A single polygon, even if it has hundreds of vertices, is vastly more performant.
Only if switching with the shortcut will still be possible. |
This will also help reduce collision issues with seams between shapes. That said, a single large polygon may take a while to be created (and that approach may not do well with a chunked/procedurally generated TileMap). Should we create a single shape per row/column/quadrant instead? |
What are the advantages of this option? I saw this idea, but I do not understand what problem it should solve. Especially if we artificially block many properties of layers as nodes. Also, one user noticed that you cannot use different cell sizes for different layers of the same TileMap. But this does not depend on whether the layers are nodes or not. |
In the NavigationMeshGenerator pr godotengine/godot#70724 the NavigationRegion2D receives a navigation polygon baking feature. The baking feature merges the entire TileMap navigation polygons into one optimized polygon by parsing all the TileMap used collision shapes or navigation polygons. This works more or less the same as NavigationRegion3D and GridMap. The same behind the scene feature could be retrofitted to be used for physics collision merging either by quadrant or for the entire TileMap. From tests it is pretty performant even for large and complex TileMaps and also can be split into steps with a WorkerThreadPool to not block framerate when doing runtime changes to the TileMap tiles. I would not remove the TileMap quadrants. You need some in-the-middle update unit between cells and the entire TileMap. |
Note these 3 bools are complete as they do allow all rotations etc. but I don't think they're user friendly. Like it's not obvious what should be passed to get 90 degrees rotation, etc. Maybe a better solution would be to add a flags enum for it instead. This way it would be a single parameter, and also many common operations could be exposed as combinations of the basic ones. E.g. something like:
I guess with such approach the question would be what should be the exact naming for each of 8 combinations, and whether maybe some combinations should be exposed as few different namings (like e.g. if there would be |
@kleonc this ties into another open proposal about bitmasking being more user friendly |
Added it to the list, and mentioned navigation too, as smix8 suggested to.
As we exposed a lot of properties of the internal canvas item, a layer now shares a lot of properties with a basic Node2D (modulation, visible, name, etc...). And it would make sense to add the possibility to set a shader on a layer, or things like that. Eventually, it would also make the API a bit simpler (as you would do Initially I did not plan to use nodes for layers, but people kept asking for per-layer features, so in the end I feel it might deserve a custom node. On a side note, I am more leaning towards implementing a TileMapGroup node, that would have a TileSet property. TileMap would have only one layer, with an optional TileSet. If a TileMap is a child of a TileMapGroup node, it would use the parents TileMapGroup's tileset and would see it's position locked. Also, the TileMapGroup node would handle the data for dimming not-edited layers.
I was mostly discussing the internals. Exposing an enum makes sense, but it's likely that implementing rotation/flip functions would be even simpler. |
I think the TileMap layers are fine as they are, just the naming and gui could be better, looking at you layers_layers_of_layers function. Maybe allow some more drag&drop with layers but still contained inside the same TileMap node.
Users ask for a lot of things, not always aware of all the issues they invite with them. By adding dependency on subnodes you are opening a giant can-of-worms, basically begging for trouble. If we learned one thing from all the nodepaths and debug visual nodes troubles in the past it is that everything that can not be an extra subnode should not be an extra subnode. |
I also think layers should remain inside the same node. If layers are kept inside the node, the users always has the option of not using them and use several nodes if he wants to. But if layers are moved outside the node, there will be no alternative. BUT, if there are good enough reason to separate them, like a performance or usability gain, or making the architecture/implementation simpler, then it is justifiable to use separate nodes. |
Oh, that's for long term anyway, not a soon-to-be-released version anyway.
This would be the exact same with my last comment's proposal. The TileMap node would be used as a layer only if used as a child of a TileMapGroup. Otherwise, it would provide a single layer with an associated TileSet. No feature is lost here. |
I have a few small things that I think would help for UX For collision: I'm not seeing any 'close curve' tool in the layer painter - there's just add polygon, delete point, and move point. It would be really nice to have one, because when trying to close the curve I keep missing the end node somehow, and Godot just adds more points in a little cluster to my polygon. This tool already exists on the path2d node, so this would make it consistent with the existing UI. Second: Finally: If no physics or navigation layer exists in a tileset, Godot currently displays a gray bar for "physics" or "navigation" that can't be interacted with, which doesn't have a submenu. It would be nice if there were a submenu option for 'create physics layer' or 'create navigation layer' there, so you can just create it and immediately use it seamlessly. |
100%. Absolutely. I was literally thinking about this for soooo much time, but I was afraid that you, groud himself, would take issue with this, because the API had been pretty much finalized. With that said, I do not think multiple "TileMap layers" should be sub-nodes. Coupling them this way doesn't solve much of the confusion behind them. Rather, just normal TileMaps that would be able to "cooperate" with one another in the editor. |
Regarding this, the solution doesn't look nearly as difficult as it is made to be. As kleonc stated, an enum would suffice for this purpose. However, this also exacerbate how much more complex the TileMap API has gotten. Favouriting nodes for layers would definitely help a tad, but this singular function call would still be quite the mouthful: var pos = Vector2i(1, 4)
var tile_id = 1
var atlas_coords = Vector2i(-1, -1)
var alt_tile = 0
set_cell(0, pos, tile_id, atlas_coords, alt_tile, FLIP_H | TRANSPOSE) Where to even put the additional flip/transpose arguments? |
Oh, perfect! That does just what I want, maybe needs a rephrasing of the tooltip, but that's a pretty trivial documentation tweak. (I was misled by the tooltip, and assumed that if if the collision boxes didn't appear when visible collision was already set on in the editor, that the property wasn't what I was looking for.) One other thing that I probably am just having trouble finding - when using the physics painter is there a way to grab the collision set for an existing tile? If not, can I suggest that right-clicking a tile should load its collision data into the physics window? That would make it easy to tweak collision from this tab (instead of going back to the 'select' pane), and would also make it possible to copy a collision polygon across multiple tiles in only a few clicks. |
Use the picker tool (P). |
Hey, I don't know if I'm right here, but I used the new Tilemap now quite a while so maybe I'm missing some stuff or this would push the Tilemap forward: Currently you can add scenes, but you can't edit properties of a Scene, right? The use case would be a teleporter scene which will take place as a door for a house. But I need to set which scene he needs to load, so I need properties access for each placed scene. I think this would be really nice but not really necessary right now. |
Indeed, that would be really nice. You currently cannot change any property of instanced scenes in a TileSetScenesCollectionSource (like, for example, if the root of the scene is an audio player, changing the audio stream or the root node). But this would be more useful if it where associated with the tilemap instead of the tileset. |
If you just need a few variations of a scene, you can use inherited scenes as a workaround. |
Here are a few UX suggestions:
|
Well, you can't really "delete" data, only reset it to the default value. Maybe using right-click for that would be nice (but it conflicts with panning). |
Panning should be done only with the middle mouse button, like the main window. |
Another thing I am missing currently is the option to create custom tile placement logic for terrain. |
In general, the terrain system of the v3.x and v4 tilemap systems is very limiting. I think that the target of providing an autotiling logic that is easy to use and prototype has been considered more important than the use of truly flexible rule-based autotiling schemes seen in tilemap softwares such as tiled, ldtk and others. I think that this is one of the best features of the current autotiler. However, for the sake of more advanced autotiling, I would suggest the implementation of a rule-based autotiling system (see LDtk) or, even better (and probably easier), a script-based autotiling system. In Godot 3.x, it was possible to gdscript the tileset resource to define rules by overriding the _forward methods though there is some limited documentation on it. In v4, this is unclear. |
Along with people wanting to rotate and flip tiles on the fly, I frequently see users wanting to modulate the color of individual tiles. That is, not just a few colours here and there, but using a lot of colors across a lot of tiles. The alternate tile system is very useful, but it gets frustrating for users to have to take what is essentially transient data and make it fixed into the tileset. It bloats out the tileset and is unwieldy. I'd suggest moving all of these properties into the tilemap cells, rather than the alternate tiles, though that is probably too severe a change for a stable API. Removing terrain tilesets was a move I proposed a good while back, and I still strongly support. I've implemented a plugin for fully featured autotiling (here) and have had a substantial amount of positive feedback. One of the key features is that any terrain type can interact with other terrains in any desired way, regardless of type/grouping. I hope that Godot's built in terrain system can improve to the point where my plugin is obsolete. |
Laptop trackpads rarely have a middle mouse button, which is why you can use the right mouse button for panning as an alternative to the middle mouse button. It's a feature many people rely upon, so we can't remove it like that. |
But I think it's probably best to add the ability to edit this via the Paint Property in the TileSet editor, since each animation frame is a tile. |
Just a simple question, but why are you doing this ?!?
the tile node, is already convoluted, with stuff ( colliers, slope colliders... now its all collider into one..etc.. ) For me this is the same thing that putting a 500 hp engine on a car, that only has 3 wheels... its funny... |
I can't say I for sure understand how tiles work in 4.0 at the level of architecture, so I'm just going to ask for clarification. Near as I understand, the design has been that tiles are considered discreet resources defined in Tilesets. They can be extremely complex resources with many varied parameters - even customizable ones. They can even have variants. But to Tilemaps, a tile is just a glorified table index pointing to this incredibly complex resource in its Tileset. In 4.0, Tilemaps are just integers, and that's made something as rudimentary as flips and rotations hard, because those are parameters, and thus aren't indexable without some decoding. If all this is as I understand it, I think it's likely to result in greater headaches in the future. It's simply not true in modern games that a Tileset can depend on there being a discreet, countable list of every possible object that can appear inside the environment that it makes possible. Procgen and player customization are things now. It is not possible to know every possible combination of parameters we might want to assign to a tile. Tiles do a lot - flips, rotation, color, depth, collision, transparency... and that's not even getting into terrain and custom data. I agree it simplifies things immensely to think of, on the one hand, a master list of possible tiles that's already dealt with our parameter hell for us, and a grid that references into that list. But imagine, on the other hand, if we treated Tilesets as a set of defaults, and Tilemaps as a choice between default settings and overrides. That'd be a lot of power. I'm aware that duplicating the Tileset interface in Tilemaps would cause everything to explode. However, I think we should at least consider expanding what Tilemaps hold as data structures. We could expand Tilemaps to encode a couple of key paraments such as modulation, depth, or collision, for instance. I couldn't say what a "just right" size for such an object would be, so I don't think that's the best way. What I might actually recommend is, by default, keeping everything exactly as it is, but allow users to select a parameter overrides feature. While a parameter override is active, a data structure is created which allows users to override parameters as they they appear in the Tileset, using more or less the Tileset interface for that single parameter, but on individual tiles, and see realtime updates. Under the hood, the data is stored as a simple array of the relevant data, but calling a getter for a Tilemap tile with an override will return the override data instead of its Tileset data. The override data defaults to the tileset data when it is first created, or when it is erased. This way, we still have the relatively trim and efficient indexing structure we have now most of the time, with only a small incremental penalty as we demand more parametric customization directly into the Tilemaps system. It seems like a fair tradeoff. |
Hey, this is probably another thing where I just can't figure out the UI or find the hotkey, but is there any way to copy and paste an entire stack of tiles (across multiple layers)? If you need to add something to the middle of a map and already have large chunks built, it'd be nice to be able to move big pieces as a whole instead of layer by layer. On the topic of tile stacks, a feature that was very useful in other engines I've worked with was having an option for tiles to override physics for tiles on lower layers. For instance, if you put a bridge (marked as having no collision) on a layer above nonwalkable water tiles which do have collision, characters could walk over the bridge. Would this be at all possible, or would it require a fairly deep rework of how the physics of the tilemap is assembled? Alternatively, if we could toggle 'physics enabled' on a tile layer, to make tiles on that layer ignore collision, that would achieve a similar effect. EDIT:
This would also offer an additional UI improvement: being able to move normal tiles within the TileSet grid without breaking the links to that tile in a TileMap. As is, it appears that the Tilemap is pointing to the specific x/y coordinates of a tile rather than to a specific tile object, so if you change where a tile is located on your PNG tile sheet, you can't just move the corresponding tile in the tileset and expect the tilemap to grab the tile from the new location. |
Great idea, currently the performance of tilemap is worrying me, do not define any layer and other properties (such as collision, navigation), as long as the scene paint 6000*6000 (cell size:16x16, eq: 375x375 cell), the editor freezes, delays, almost does not work. Even crashes (vulkan error: many too objects), although improved by better GPU/CPU, are currently almost impossible to paint large maps through the editor. |
This is the changing levels using PNG images instead of tiles Using png images instead of tiles the change is instantaneous, it doesnt take any milisecond... //----------------------//---------//------------------------------- This is the changing levels using tileMaps made in Tiled exported to godot has *.tcsn In here it takes about 1 sec to change between levels, it feels like its processing something.... //-------------------------//------//---------------- the tilesets are no longer has they used to be in the 90's Now tiles are used has objects with lots of properties, that get instantiated/spawned on screen with the intent of doing completely diferent things, . |
You know, when I think about it, the Tilemap editor could probably use more like an entire dev team working on it. Tilemap Editors are complicated enough that they're usually stand-alone applications. Depending on the type of game you're doing, you could end up treating the Tilemap Editor more like an entire level editor and end up wanting to do 90% of your entire game inside it rather than all the rest of Godot, which I think is part of what's making these issues so complicated. That, and the very data-centric procedural generation stuff. Either way I think it's a higher priority area than the resources dedicated to it would suggest. |
The Tiled exporter generates a lot of alternate tiles if you enable the option to do so. Most of these alternative tiles will remain unused, which is hardly ideal in terms of hardware utilization. Also, you should test performance in a project exported in release mode as a debug build has significant overhead with all CPU-bound operations (i.e. everything that isn't GPU-bound or I/O-bound). |
Make sure your TileSets are not embedded in the scene. |
It also exports transparent tiles that get into conflict with the godot tileSet Has i was expecting the flip/rotate triggered a chain of problems, that dragged on top of other things... Also now you ll have to use 3 applications ( tiled/photoshop/godot ), to get a simple castlevania circle of the moon level... Making it very difficult to add, edit or remove levels later on...
I dont think making a tile editor is very dificult... All it would take would be a simple drawing program using brushes instead of tiles, godot already has a build grid, theres also a viewport texture... |
Even if we go back to like, NES Mario, tilesets were always designed in order to include physics and other interactions, rather than being purely graphical. EDIT: to give an example, here's the tile data array in RAM for the start of the first level, overlaid on the displayed tiles (with 00 values omitted for clarity). Both physics and graphics are based on looking up the values in this data array (using what the disassembly calls "GetMTileAttrib"). |
that is such a lie
but there are no physics in there only graphics |
Back in 3.x, tilemaps had the option to use the tilemap colliders as part of a parent body or area: This was really useful for creating tilemap nodes as child of area2ds and use that area for whatever. For example, you could have a "Damager" script attached to the area2d and paint hazards like spikes in the tilemap. Besides, it was easier to setup a collision parent, like an area2d or any body2d and have all the colliders in the tilemap act as was set up in the parent. And even more useful was setting collision_use_parent to true but not using a body or area as parent to ensure that that tilemap was going to be just decoration, guaranteed to be colision free. In 4.x these things became less convenient. Since we are discussing these things, we could consider restoring the collision_use_parent functionality or at least somehow make it easier to use tilemaps with area2ds. |
Yes, extremelly difficult, with 90% of the entire game inside. It took me about 1 week to do this, a few hours a day godot-4-TileDraw Its still not finished, but the basic stuff its there. The very ( data-centric procedural generation stuff ). collisions, access to tiles in game, i wont be adding this one will be mainly for drawing... change tile color...etc.. |
That's just super, @jonSP12. Here's a gold star. You get an A+ on the assignment. But I'm afraid making something competitive with the other free Tile Editor software out there's going to be a little more work than that. Users of Tile Editors have a lot of bespoke needs, you see. But keep on trying, I'm sure you'll get there. Or maybe you can join one of the existing Tile Editor projects so that the time you spend is will be better appreciated by other people interested in the same things. Tiled is a great project I'm sure would be glad for you to lend a hand. Or Godot. Godot's tile editor could really use some love from an ambitious, talented developer like you. Gold star's are great and all, but they're not everything. |
Iam not intrested in gold stars, hey i know the admins will jump in here and say we cant post this stuff, it will be my final message. Its the way of how you and some other people, sometimes express things in an exaggerated way or a philosophical way... |
I have to remind you both that we have a Code of Conduct which you have to follow when writing in Godot communities, including GitHub. Please stay respectful of each other and constructive in the technical discussions. |
Of course. I got carried away, and I apologize, both for undervaluing the contribution made by @jonSP12, and for wasting the time of my fellow subscribers. Nothing would please me more than getting back on topic. I note that the tile flipping/rotating issue has been recently closed: #3967 |
Tiles are stored as 64-bit integers. 16 bits for source ID, 16 for x coordinate in the atlas, 16 for y and last 16 for alternate tile ID. The transforms reserved the last 4 bits of alternate tile, which means there is now 12 bits for alternate tile ID and last 4 are for transform. |
Are there any plans to make the navigation include all layers and not only the first? It seems like the tilemap editor already supports this (there are checkboxes for "navigation_enabled" for each layer) but apparenlty e.g. navigationRegion2d only uses the first layer of the tilemap and so does navigationAgend2d. See e.g. this image with the same tile form the same tileset being excluded in layer0 but ignored in layer1. |
@HSven1611 Don't spam in unrelated issues when there are dedicated ones for navigation in other layers |
Sorry for the inconvenience. I wasn't aware this is not tilemap editor related. Sorry for not knowing the exact internals of Godot.
I would posting one single question not consider "spamming" though.
Would you consider pointing to the better matching issue or discussion as I wasn't able to find one.
|
@HSven1611 see: godotengine/godot#85856 It's already merged, so it should be working in 4.3. |
@chryan That's already supported (showcase below in v4.2.2.stable.official [15073afe3]): |
Describe the project you are working on
Godot
Describe the problem or limitation you are having in your project
The 4.0 TileMap, despite a lot of improvements, has still lot of issues that leads to a frustrating UX in some cases and has an API more complex than in 3.x. I think there are still some big improvements that could be done, that are either compatibility-breaking or not.
I want to use this proposal as a tracker of things that could be improved and how they could be implemented.
Compared to 3.x, creating flipped / rotated tiles is a bit more complex in 4.0. You need to create alternative tiles for each tile. To solve this issue, I suggest using 3 bits from the
alternative_tile
to store the filp_h/flip_v/transpose status, which is a 32 bit integer. It's theoretically compat breaking, but I doubt anyone reached enough alternative tiles to need the 32 bits count. When rotating tiles on the map, those bits should only be set for tiles using aTileSetAtlasSource
, otherwise it would lead to invalid tiles forTileSetScenesCollectionSource
.Regarding the API, I see two solutions to the problem:
transform_alternative_tile(alternative_id : int, flip_h : bool, flip_v: bool, transpose: bool) -> int
function that would set the higher bits of alternative_id.Would implement #3967.
TileMap quadrants are required for rendering, but they cause significant performance issues for anything else. Indeed, when a quadrant is modified, the whole quadrant needs to update, including the physics, navigation, scenes, etc... systems. The internals should be reworked so that quadrants are only used for rendering, where they are needed. This likely means compat breakage if we rename the property or change the behavior of the
quadrant_size
property a bit. It should not be that big of a deal.Implemented by godotengine/godot#74603
To improve performance, merging polygons for navigation and collision polygons would be helpful. For collision, it would also help to avoid characters being stopped while running a flat surface and issues like that. For navigation, it would allow creating less regions, and thus create straighter navigation paths.
To avoid triggering again a full merge of the TileMap, the collisions shapes and navigation polygons could be merged inside quadrants. Those quadrants could have different sizes than the rendering one if the previous point is implemented.
The main purpose of terrain set is to group a set of terrains under a same "terrain matching mode". It however bloats both the UI and make the API more complex. Instead, someone (sorry I don't remember who) suggested to simply assign a matching mode to each terrain. Only terrains with the same mode would interact with each other. That should simplify the API and the UI a lot, but it would definitely break compatibility on the API side (the tile data should be easy to keep though)
To respect the common Godot workflow to add things to the tree, it would be great to move layers to nodes. After all, layers are basically CanvasItems. That, however, causes some challenges:
Technically, this should not be super complex to implement, but of course, this is compatibility-breaking.
Also, that would require every TileMap user to add a TileMapLayer node to be able to use a given TileMap. Also, the TileSet would be on another node than the Layer, which might be a bit annoying to work with.
More solutions could be imagined here, like a TileMapGroup node that would use several child TileMap as layer, and impose them a TileSet. Other solutions could be find I guess.
The way alternative tiles is made makes things difficult to work with, especially if we now want to move the flip/transpose stuff to the TileMap. To help users with that, the idea would be to be able to lay alternative tiles anywhere on a grid, so that people would organize it however they want. That brings some challenges to the table, as users would like to get an alternative ID out of it's coordinates on the grid. This would require a mapping function from coords to (altlas_coords, alternative_id), and update the API to allow moving those alternatives tiles on the grid.
This leads to another possible improvement, that is for super long term (likely 5.0, not before, if it ever happend). If we consider moving alternative tiles to a grid, we could move everything in a TileSet to a single grid too, and thus lay out all TileSet sources (atlas and scenes) to a single grid. The TileSet would then provide you with a unique ID for each tile, so that moving TileSet sources on the atlas would not lead to a breakage of all your TileSet. A function would be provided to give you an ID for a given coords. This would simplify all TileMap and TileSets APIs which currently use 3 IDs
source ID
,atlas_coords
andalternative_tile
. All functions would then now use a single ID instead. To set a cell you could do something like:instead of:
This would also allow to remove the source list of TileSet's editor UI and would thus make things a lot simpler: just drag your texture on the grid and it works. TileSetter hacs a bit of this UI and it might be a good example about how it could work for us.
I'll try to add more things to the list when I remember ideas.
The text was updated successfully, but these errors were encountered: