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

Tilemap editor feature #977

Open
22 of 42 tasks
dacap opened this issue Feb 24, 2016 · 101 comments
Open
22 of 42 tasks

Tilemap editor feature #977

dacap opened this issue Feb 24, 2016 · 101 comments
Labels
feature Feature request, or something should be improved high priority refactor complexity This issue needs some refactor / modifying several files / rethinking some part of the architecture tilemap
Milestone

Comments

@dacap
Copy link
Member

dacap commented Feb 24, 2016

UI design and main goals of the tilemap feature:

  • Everything related to tilemaps must be hidden until we create a new tilemap layer using a new Layer > New Tilemap Layer menu option (in this way we avoid bloating the UI with tilemap stuff)
  • As tilemaps will be a kind of layer, we'll be able to have several tilemaps in one sprite
  • One tilemap layer will have its own tileset, a tileset will have its own tile specs (grid size, etc.), but the tileset could be linked from an external file (with possibilities to embed the external tileset content inside the tilemap optionally)
  • Each cel in a tilemap layer will be a new kind of image where each pixels reference a tile:
    • Each pixel in the tilemap image will be a 32-bit value with some bits to reference the tile in the tileset and other bits to specify flip and rotation
  • When we create a new tilemap layer, it should behave almost exactly like a regular layer, and tiles should be handled transparently/automatically by default (so even if an user creates a new tilemap layer by mistake, she/he shouldn't see a different behavior from a default layer)
  • When the active layer is a tilemap layer, a new set of buttons should be displayed in the color bar, those buttons should allow:
    • Changing between the palette view <-> tiles view (keyboard shortcut: Shift+Tab)
    • Changing between the automatic mode of handling tiles
    • Do some special operations to tiles, which should match future operations with the palette too. E.g.
  • When a sprite contains tilemap layers, the sprite properties dialog should show a section of "tilesets" #3875
    • We should be able to reorder tilesets
    • We should be able to add new tilesets
  • Possibility to link external tilesets
    • Persistence (.aseprite information)
    • Auto-sync tileset from external file when the original is modified
    • UI to select external tilesets
    • Special import/external/linked tileset options, e.g. from grids, from frames, from layers, from "Import Sprite Sheet", etc.
  • Drawing tile pixels with three modes: Manual (modify the tiles, don't create new tiles), Auto (create/remove existent tiles automatically), Stack (add new tiles when they are modified, keep the existent tiles unmodified)
  • Drawing tools with tiles
    • Paint with tiles (still buggy)
    • Eyedropper for tiles
    • Selecting tools with tiles
    • Fill, Stroke, and Clear commands for tiles
    • Copy and paste tiles

Special Features

Possible advanced features:

  • Flip/Rotation per tile in tilemap layer Implement xflip/yflip/rotation flags in tilemap layers #3603
  • Overlapped tiles (isometric tiles etc., hexagonal tiles, etc.)
  • Palette shifting (e.g. some bits to shift the colors of a tile in the color palette)
  • Metatiles (hierarchy of tiles, where the tiles of one tileset is another tilemap with smaller tiles)

Persistence

  • Create a new chunk in .aseprite format to save tilesets
  • Each tileset should contain specs (tile width/height, type of tiles, etc.) and source of tiles (e.g. for linked tilesets between files).
  • Save/load layer tilemaps and their cels
  • Save only differences between cels in tilemap layers
  • Save (and load?) TMX files
  • Convert grid settings into tileset specs and save then in the .aseprite file if it's possible (Save grid parameters to .ase files #688), this might enable isometric grids too (Isometric object creation tools #720)

Integration

  • Check the integration with Tiled mode

Ideas, issues to review, and old ideas about the implementation

Review

UI Design

Here I'll be updating this issue to talk about the design of this feature. Some questions to solve:

  • How we create a new tilemap? (File > New > Advanced > a new tab for tilemaps appears? or we start creating the sprite sheet?)
  • Should be the tilemap a switcheable mode like "Tiled Mode"? I don't think so, we could be creating several tilemaps from the same tileset/sprite sheet. So it looks like a tilemap is just a way to say "we are going to create a map feeding tiles from these sprite sheets"

The general idea is this:

  • the color bar should be transformed into a tileset where we can pick tiles
  • the sprite editor is the tilemap editor where we can put/draw/pick(eyedropper) tiles

Internal tasks

Tasks to do (this list is not complete):

  • create a new kind of image that can reference different tiles/doc::Image on each area and with different rotation/flipping. (doc::TiledImage?)
  • create a generic iterator for any kind of image (current doc::Image, and this new tiled image)
  • different parts of code will use the doc::Image iterators (e.g. file format encoders/decoders) and other areas should use this generic iterator (e.g. sprite Editor widget).
  • get tileset from a tilemap (from this thread)

An alternative implementation would be to edit images as a regular image, and after each "tool loop", we update/sync the tilemap/tileset depending on these modifications. Pros: easier to implement (there is no new kind of image), Cons: it will use a lot more memory (and it couldn't be an option for big maps).

@dacap dacap added feature Feature request, or something should be improved tilemap labels Feb 24, 2016
@dacap dacap self-assigned this Feb 24, 2016
@not-surt
Copy link

All other image editors with tilemap editing that I know of are limited to non-overlaping rectangular tiles.
This is obviously useless for isometric, other axonometric tiles.
Ideally any solution would allow tiles to overlap on the tilemap canvas and be editable in place.
This should require an full tilemap implementation rather than just a hack on top of a regular image.

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

2not-surt: Full tilesets and tilemaps creation support is far out of animated layered image editing scope. Don't think Aseprite should be jack-of-all-trades here, because wishes will just grow and grow. There are lot of other things possibly required from such support: clipmasks/z-masks, 2D/3D tilemaps, animated voxel/point-cloud sources for isometric tiles/sprites, objects/locations placement with parameters and objects presets archetypes hierarchy, animated scenes timelines for sprites/objects/hints, different lighting/shadows support, advanced grids (hex-grids, walls-and-columns-around-cell grids, etc.). Just too many of them. But simple and clean Super Tiling support will be just OK. Better create another editor or mode for ATnT (Advanced Tiles & Tilemaps) =)

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

2not-surt: And you can create isometric tiles (not tilemaps) in Aseprite using hint guides layer. Frames will be different sprites (or sometimes "frames"). Layers will help create complex tiles with layered layouts. And then use this tileset in tilemap/level editors, not image editor. Simple tiles is special case specifically because they do not overlap.

@KasumiArai
Copy link

Block tile copy is an absolute must. (That is selecting multiple and pasting multiple tile indices. Pyxel Edit still lacks this, and it's my main problem with its workflow.)

It would be cool if this paired well with issue #974, or at least had a feature found in D-pixel. It allows you to work with tiles in a palettized way. Say you have a range size of say... 4 and draw a tile using indices 4, 5, 6 and 7. You place a duplicate of this tile to the right. You then draw on the left one using color 8. It remaps index 4 to 8, 5 to 9, 6 to 10 and 7 to 11, but only for the left tile. Meanwhile the stroke you made is still made on the identical right tile using color 4. So there's one tile in the tileset, but it can be displayed with two different palettes. Useful for retro stuff. A range equal to the current palette size would end up being "normal" painting behavior.

You can see a gif here, it's probably better than the text explanation:
d-pixel

What D-Pixel lacks that Pyxel Edit has is seeing the stroke you're making across all tiles the stroke has touched. D-Pixel lets you see the stroke, but if you make say... one continuous stroke across two of the same tile, both tiles will look different until you release click and it applies both sets of pixels that overlapped each tile in the map to the actual tile. You can see this above when a line is drawn on the white background. Ideally all of those white tiles would update during the stroke itself so it's never possible for two of the same tile to look different.

This is also a must. The palette stuff would be cool, but is not a must to me.

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

About blocks for Super Tiling I proposed at http://steamcommunity.com/app/431730/discussions/1/405692224243720164/

Copying blocks of tiles could be done by selecting tiles in Tileset window with Ctrl+click (they should be organized there for this, like 2x3 tiles for tree and etc.) or with Tiiling Pen on image layer with Ctrl+Alt+clicks, and then Ctrl+C to copy all selected tiles as image. Yes just an image. Then Ctrl+V to insert it. If current tool is Tiling Pen then Ctrl+V should insert it aligned to grid automatically and then movable with auto-aligning.

Also Ctrl+drag (Tileset window) and Ctrl+Alt+drag (image layer) could select/deselect tiles in rectangular block,yes.

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

2dacap: about "create a new kind of image that can reference different tiles/doc::Image on each area and with different rotation/flipping. (doc::TiledImage?)"

Just to clarify: for Super Tiling you don't need special kind of image. Only special kind of operations. It's perfectly possible to allow select existing files in Tileset window (and layer inside file for .ase files). And make combo list of such files with (+) and (X) buttons somewhere to add new and remove unwanted. And auto-select file and layer from this combo list then switching between layers of main image (restoring lastly selected file/layer for this layer).

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

For any tile WxH it's possible to calculate hash value using, for example, this function:

ub4 one_at_a_time(char *key, ub4 len)
{
ub4 hash, i;
for (hash=0, i=0; i < len; ++i)
{
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return (hash & mask);
}

From: http://www.burtleburtle.net/bob/hash/doobs.html

It's also possible to calculate hash values for flipped/rotated versions of same tile, because hash function is order-dependent.

These hash values could be used to create hashtable lookup of N lists, N = 2*max_tiles. Simply put tile index (and flip/rotate flags) into list with index = hash_value % N. Then when you need to find matching tile simply calculate hash value for your tile and lookup into same list and compare tile pixels only against those tiles in list (with flipped/rotated flags affecting comparison), not against all tiles of tileset.

max_tiles could be estimated as = ( tileset_width / tile_width + 1 ) * ( tileset_height / tile_height + 1 )

@EyeGem
Copy link

EyeGem commented Feb 27, 2016

One worst case scenario estimation:

  1. image 8192x8192 designed with tiles grid 16x16, thus 512x512 tiles, 256K tiles total
  2. tileset 128x1024 with same tile size 16x16, i.e. 8x64 tiles = 512 tiles
  3. all image tiles same (for example, black), thus same hash value
  4. all tileset tiles same (for example, black), thus same hash value
  5. hash function for 16x16 = 256 bytes ~ max. 3000 processor ticks (for Indexed mode)
  6. let us have CPU 1Ghz
  7. 512 * 3000 * 8 ~ 12M ticks to calculate hash values for tileset (4 rotates with flips) ~ around 10ms
  8. 256K * 3000 = 768M ticks to calculate hash values for whole image ~ less than 1 sec
  9. 512 tiles in list for same hash value, compare every tile 512 times, 256K * 512 * ~1000(memcmp) = ~128G ticks ~ 100 sec ... hmm, slow =)
  10. to optimize don't add to hashtable same tiles, extra 511 comparisons, 511 * ~1000 ~ 512K ~ 0.5ms
  11. thus only 1 tile in list, thus 256K * ~1000 = 256M ~ 200ms

And this 1.5 sec operation is rare operation only for special second click in Tileset window to select all tile instances in main image (including flipped/rotated) and edit them all. All other operations do not operate over full image. And this was really bad case scenario where hashtable failed because of all tiles were the same.

@AkashaRepo
Copy link

Right now I have a workflow where I make tiles in Aesprite and arrange them in Tiled. Being able to do all this in Aesprite would be <3

@astraldata
Copy link

+9000 to KasumiArai -- that sort of tilemap feature would be amazing in Asesprite! D:

@HawkenKing
Copy link

HawkenKing commented Jan 29, 2017

current workflow is aseprite / photoshop, then Tiled or TileTool2D, or NES ScreenTool (for colours)

Would be nice if NES style per 16x16 tile colouring was implemented but that might be asking for too much.

@dacap dacap added this to the v1.6 milestone Jun 9, 2017
@astraldata
Copy link

It's terrible -- this feature is due by 2021 ... and I've needed at least a preliminary version three years ago... :'(

@dacap
Copy link
Member Author

dacap commented Jan 4, 2018

Actually I'm planning to prioritize this one, it might be available sooner than you expect.

@oceanhahn
Copy link

Woah, that'd be three years ahead of schedule! ;)

@dacap dacap modified the milestones: v1.6, v1.3 Jan 4, 2018
@astraldata
Copy link

astraldata commented Jan 6, 2018

Indeed lol!

I currently don't have PyxelEdit, and, personally, I don't care for its pixel workflow in general, but the one feature it has on Aseprite is one I can't get away from -- and that's a tilemap editor.

I don't care about laying out a level in Aseprite -- I can do that in a game engine (or Tiled. )

Everything else I want to do with tiles needs a great pixel editor alongside it.

For that purpose -- I only want/need a few things:

  1. First, a list of editable tile indexes of a specific size that can be selected from and arranged like the color palette already can (in fact, a simple copy/paste of much of the palette arrangement code would do just fine)
  2. Second, a (potentially disposable) "swathe" space (similar to the "preview" window) where I can draw up a preview swathe of tiles (with chosen repetitions / mirrors / flips / rotations) of individual tile indexes
  3. Next, the swathe would respond, in realtime, to the strokes (and the color changes) you lay out in the main window. The main window itself would display a user-selected number of nearby swathe tiles in the X/Y direction and allow those tiles to be individually and simultaneously edited in the main window, right alongside the currently-selected tile from the swathe.

To clarify #3 and the imagined workflow in general -- just as the "Tiled x" and "Tiled y" settings allow repetitions to be displayed and edited in the main window area -- that's essentially what editing in the main window would do with a tile index selected, except with nearby tiles to the one that the user has chosen in the swathe. The swathe will always have 1 index at least, and if you select an index in the list of tiles, it can replace that index in the swathe automatically -- otherwise, selection would usually be done in the swathe palette window where both placement (and selection!) occurs. You would, of course, have a list of tile indexes that would, essentially, just act like the color picker for the most part. Only the first index is considered the origin tile (or perhaps the origin tile /group/) of course.

I do hope I've described everything here well enough to make it sensible.

From what I can tell from the editor -- the design outlined above will allow much of the code to be copy-pasted from the rest of the editor. -- Not all can be copy/pasted, but enough to have a preliminary display of tiles from a palette in a new preview window at least! -- Which is why this feature is so critical! It's the one thing Graphics Gale doesn't have and the one thing all other -lesser- (imo) pixel editors seem to have -- except with a poor implementation. Aseprite is up there with Gale in terms of user-friendliness, and I just wish it had this one feature to make it a Gale-killer for everything Gale lacks.

@haxpor
Copy link

haxpor commented Jan 6, 2018

Interesting feature. Although I'm natural on this but I do any pixel related stuff with aseprite so if this feature is there, it would be a plus.

Just want to chime in here as Tiled just released version 1.1 that included interesting concept of Wang Tiles. Their interesting discussion is here. In short, as from my understanding, it can generate tilesets from a few tiles with pre-defined color for each corner, or used to map a proper and correct tile within tilesets while user's drawing road, or terrain map. Sort of those areas. Might be an idea further. Just FYI guys. Anyway, cheers for tilemap feature.

@astraldata
Copy link

Thanks for sharing that, haxpor. -- In many cases (at least with pixel art), simple transparency overlays can handle the same problem Wang Tiles seeks to solve (using an uncecessarily-specialized algorithm).

@dacap 👍 :

If Aseprite did anything to help with what Wang Tiles tries to help with, it could be solved in a more useful and general-purpose way:

For example, it would be amazing if it would let you auto-merge individual layer-pair combinations sequentially. For example, you could specify that layers 1-4 would be the transparent overlays, and layers 5-22 would be the various combinations that 1-4 would overlay (i.e. 1 overlays 5, then 2 overlays 5, etc.., next 1 overlays 6, then 2 overlays 6... yada yada... you get the point.)

And for a slightly more complex (but infinitely more useful) alternative implementation, it would be nice to specify groups and sort orders of multiple overlays before executing the overlay+merge function. The idea came from when I was more recently playing with and it made me think of Aseprite ... It would be nice if the auto-combine feature I proposed above based on haxpor's suggestion could do more advanced transparent overlay combining. The idea behind Charas is to pull from a ton of layers of heads/hair/body-styles/accessories/etc. and letting a user combine them into a sprite atlas. I could see it being highly useful to do something like this for character animation too instead of a hard-coded thing like Charas has (perhaps by simply leveraging animation frames and layers simultaneously) to make it easier for an artist to generate automatic overlay + merges on a large variety of sprite combinations and animations. Even if we had to do this on a per-file basis, it would still be so much greater than the manual merging that is required in every other tool...

Just my two-cents! -- Maybe I'm onto something here though?

@dacap dacap added the refactor complexity This issue needs some refactor / modifying several files / rethinking some part of the architecture label Oct 23, 2018
@dacap
Copy link
Member Author

dacap commented Feb 6, 2019

Just in case I'm already working on this one:

https://twitter.com/aseprite/status/1092884555126763521

The basic idea is that we should be able to:

  1. Create a new "tilemap layer" using a new Layer > Add Tilemap Layer menu option
  2. When the active layer is a "tilemap layer", this will show some extra controls in the color bar ("Tiles" and "Auto" buttons at the moment, but that might change in the future)
  3. Then we can draw as in a regular layer, and tiles will be created automatically (when "Auto" button pressed)
  4. Shift+Tab will switch between color palette <-> tiles
  5. Clicking a tile will enable us to put tiles in the canvas (right-click might pick tiles from the canvas, or just act like the right-click default behavior, just like FG/BG colors, we could have a FG/BG tile, or FG/right-click behavior)
  6. When the "Auto" mode is unpressed, we can edit tiles manually (no new tiles are generated automatically)
  7. We should be able to reference different tilesets from each tilemap layer, anyway each tilemap layer will have one layer-specific tileset to create those automatic tiles when the "Auto" mode is enabled.

In general terms, this new tilemap layer should work as the regular layer by default. And the special modes should start giving us more options (like putting tiles, modifying all instances of the same tiles, etc.).

@EyeGem
Copy link

EyeGem commented Feb 6, 2019

... anyway each tilemap layer will have one layer-specific tileset to create those automatic tiles when the "Auto" mode is enabled

Do you mean old tiles not removed from this layer-specific tileset when they entirely removed from Tilemap Layer itself? And editor will keep order of tileset tiles until moved/edited by user just like colors of palette? Hmm... and we can load tiles to tileset from external tileset file (auto split by tiles size) once and then use them to draw map and later export tilemaps with exact tiles order saved? Sounds interesting. Hope tile width and height are Tilemap Layer properties then and could be any, for example 20x25 --- there're cases where art like this looks best. And image right and bottom not-full-tile-size edges should be ignored maybe. And we could mix different tiled layers, like 8x8 for physics, 16x16 for platforms and 32x32 for backgrounds. Also if add exporting of animated tilemaps (tiles indices) and maybe even with encode-only-changes-different-from-prev-frame mode it will be something like animated cutscene packing and partial image animations used in good old games.

@dacap
Copy link
Member Author

dacap commented Feb 6, 2019

Hi @EyeGem!

Do you mean old tiles not removed from this layer-specific tileset when they entirely removed from Tilemap Layer itself?

There should be two possibilities: 1) Keep tiles intact and just add new tiles (+ offer a button to clear unused tiles automatically), 2) Clear unused tiles automatically too.

And editor will keep order of tileset tiles until moved/edited by user just like colors of palette?

The user will be able to disable the "Auto" mode for the layer tileset (a tilemap layer will have only one "auto" tileset that can be enabled/disabled, any other referenced tileset will not be automatically handled = be in this "auto" mode).

we can load tiles to tileset from external tileset file (auto split by tiles size) once and then use them to draw map and later export tilemaps with exact tiles order saved?

Yes, the final version of the tilemap editor should give us the chance to reference several tilesets (from external .aseprite files too) and use tiles from those tilesets in one or several layer tilemaps.

Hope tile width and height are Tilemap Layer properties then and could be any

Yes, the only limitation will be that the "tileset specs" (tile width/height) should match with the layer tilemap specs. Anyway you will be able to have several layer tilemaps in the same files with different specs.

About animated tilemaps: each frame in a layer tilemap will be a different tilemaps (so you could reference the same tilesets/tiles on each frame or vary only one tile, etc.). I still have to think about the persistence details and memory usage implications for huge tilemaps, but we should save tilemaps differences only for animations.

If I find something really complicated in the process, I'll try to push things forward for future versions and have a more basic version in the first v1.3-beta.

@EyeGem
Copy link

EyeGem commented Feb 6, 2019

the final version of the tilemap editor should give us the chance to reference several tilesets (from external .aseprite files too) and use tiles from those tilesets in one or several layer tilemaps.

To keep things simple it could be really preferable to just have one single tileset inside each Tilemap Layer data and give user tools to copy images from external tilesets into this single tileset, so that exporting tilemap may produce simple indexes of tiles and those indices not broken even by "Auto clear unused tiles" option or "Now clear unused tiles" button, so tileset should really have used/not used bit flag for each tile and allow free moving of tiles inside tileset, it's often really useful to arrange tiles in tileset in specific manner, so those unused-flagged tiles around arranged tiles will be helpful.

@stickynoteme
Copy link

Another basic feature to consider is being able to merge layers down into tilemaps. As of right now it's kind of convoluted process if you want to say take a hard/soft light layer and merge it into a tilemap layer.

@awesomez
Copy link

awesomez commented Jun 9, 2022

Another basic feature to consider is being able to merge layers down into tilemaps. As of right now it's kind of convoluted process if you want to say take a hard/soft light layer and merge it into a tilemap layer.

Although having two tilesets separated is great for modularity, I can agree with this. I can imagine a grassland tileset with a village on it and a snow version of that, and wanting to merge this down into a single tileset for some game engines. This is often for performance reasons, as drawing both grass and snow overlay tiles can be expensive (unless needing to transform them at runtime for example).

That being said, being able to edit mutliple tilesets to create a snow "layer" on top of the grass tile (without merging it) is useful too. Getting these out of Aseprite intact in the way you ultimately want them does matter though.

@joemicmc
Copy link

With the new export tileset it would be cool if the 'ignore empty' option applied to tiles too. I have compiled latest code (was extending the extrusion) so could take a look at some point.

image

@dacap dacap removed their assignment Sep 15, 2022
dacap added a commit that referenced this issue Nov 13, 2023
Implemented a specific item of tilemap feature (#977) to allow flipped
tiles in X/Y/Diagonal axes.
@dacap dacap unpinned this issue Nov 24, 2023
@dacap dacap modified the milestones: v1.3.1, 1.3.2 Nov 28, 2023
@dacap dacap modified the milestones: v1.3.2, v1.3.3 Dec 1, 2023
@Saturnine-Softworks
Copy link

Saturnine-Softworks commented Jan 29, 2024

I've read through and seen some of the opinions and assertions about isometric tilemap feature additions, and just want to give my 2¢.

Obviously, flat, square tiles that you would use in a platformer or topdown game are the most common use for a tilemap. But they certainly are not the only use. A lot of the opinions that have been written so far act like there's this slippery slope of feature requests that would occur if isometric tilemap support was added. I think this is a limited viewpoint. Games that use isometric tiles/tilemaps are not exactly rare. I think it's a little unfair to act like it's a niche use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request, or something should be improved high priority refactor complexity This issue needs some refactor / modifying several files / rethinking some part of the architecture tilemap
Projects
None yet
Development

No branches or pull requests