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

Workaround for loss of Trim feature? #119

Open
Kylemcarthur opened this issue Jan 24, 2024 · 10 comments
Open

Workaround for loss of Trim feature? #119

Kylemcarthur opened this issue Jan 24, 2024 · 10 comments

Comments

@Kylemcarthur
Copy link

First off, thanks for making this plugin! People can be so awesome.

I saw that the Trim feature was removed in the past due to issues with it. I'm looking for a workaround because that feature is currently necessary for how I animate.

Player Character Animations

My workflow has all directions for a character side-by-side. This ensures that the action stays consistent across the different directions for a given animation. When it comes time to export, I would typically just hide the layers not in use and have the exported image trimmed. Prior to trimming, this would be the result:

image

While I can get this imported just fine using the plugin, it's still a ton of alpha that needs to be trimmed. Normally that step would be handled in the native Aseprite export. Is there a viable workaround for this using the plugin?

@viniciusgerevini
Copy link
Owner

Hello @Kylemcarthur . Thank you :). And thanks for sharing your use-case. Most of the times when people bring trimming, they refer to file size gains, which are negligible. I think yours is the first scenario that justify bringing trimming back.

Unfortunately, I can't think on any workaround at the moment. A lot has changed in both Godot and Aseprite since I removed the feature, so maybe I can make it work properly this time. I'll give it a try and let you know how it goes.

Good luck with your project. Your sprite looks pretty good.

@viniciusgerevini
Copy link
Owner

By the way, what are you using for your animations? AnimationPlayers or AnimatedSprites?

@Kylemcarthur
Copy link
Author

Unfortunate to hear that there isn't a workaround, but I'd be very eager to see if one ends up becoming implemented. I've been a game designer / pixel artist for the past 10 or so years. Only recently getting into the programming side of things. So I have a pretty well-defined art and animation workflow pipeline at this point. For animations with multiple facing directions where things need to be consistent, this is the best workflow I've found - if there's a better alternative, I've never seen it. Layers and layer groups are your friends :) Happy to lend my experience if that can be at all useful for the plugin.

Thanks! The sprite is actually just a placeholder from a previous project I drew art for.

I'm currently learning about the use cases for Sprite2D, AnimatedSprite2D, and AnimationPlayer with AnimationTree. I found a plugin that seems to do a good job of converting an AnimatedSprite2D to AnimationPlayer (much easier to do a quick setup than keying every single frame...), so most likely that will be what I end up using, but that's subject to change as I learn more.

@viniciusgerevini
Copy link
Owner

Hello @Kylemcarthur . I put some thought on the trimming issue and I believe the feature you are looking for is Slices and not trimming. (https://www.aseprite.org/docs/slices/)

All explain the current issue and why I think slices is a better fit.

You might already know this, but Aseprite has 3 trimming options (trim, trim sprite and trim by grid).

Trim sprite does the trimming across frames. This would be the one to go if it respected layer visibility, but it doesn't. So this means it also includes hidden layers and the resulting sprite sheet still has the empty space.

Trim and Trim by grid are very similar, and both result on the same issue, that was the reason I removed it in the first place. Frames are trimmed individually, which result on the sprite moving around:

crop_issue

One way I can solve the issue above is by going through all the frames checking for the position and dimensions to identify the bounding box and calculate the crop manually, preventing the offset from the example above.

But even if I do this. there is still the issue of growing frames. If you set a frame bigger than the existing ones this would also expand your sprite node, potentially changing it's position a bit, so you would have to re-adjust it in Godot to be at the right place again.

I think slices is a better fit for this because you can define multiple regions in your file and the size won't change (unless you change it in Aseprite). Currently, the Aseprite CLI does not support slicing spritesheets, but it does include the metadata in the export so I'm able to set the right region. Technically, the spriteesheet png will still contain the empty space, however in the engine you would be seeing just the region from the slice you selected. I might be able to pair this with trimming to get rid of the extra space in the sheet, but I haven't tested if it works.

What this means for the plugin is that besides being able to select which layer to import you will also be able to select a Slice from the list, and just the slice area you selected will be visible.

Do you think this approach would fit your workflow?

@Kylemcarthur
Copy link
Author

I may be misunderstanding something, but I don't have the issue with trimming that you describe. I'm on Aseprite v1.3.2, if that helps. The trim feature respects what layers I have visible. I'll show you with the same file as before. Here is absolutely every layer in the file visible.

image

Trimming this would lead to just trimming to the border, as seen here. (Despite the pixels on the background layer, I guess Aseprite can detect it's a single solid color background and trims it regardless, though I couldn't explain why. Nice feature though.)

image

Now, if I hide all the layers other than a direction I want to use (let's go with right-facing for this example, with helmet and some SFX turned off), it'll look like this.

image

And then trimming it results in this.

image

The trim is respecting only the visible layers with consideration to every frame that I have. So in this case, this frame here is the reason for this trim's size.

image

This also works the same when exporting a sprite sheet. Here is the same file, setting up the export, before the trim.

image

And here is what the trim looks like.

image

No issue, so this has been my workflow. Now, could slices do this better? That's an interesting question. I'm admittedly not well versed in the slice tool since I've only really needed it for the rare times I'm doing a 9-slice for something like a button. Beyond that, I haven't needed it. If after seeing that I don't have the trim issue you're describing (I'm not sure why you are having that issue, hmmm), you believe that slices are still the way to go, I can try to familiarize myself with it a bit more and report back.

What do you think?

@viniciusgerevini
Copy link
Owner

viniciusgerevini commented Feb 9, 2024

Thanks for the screenshots. They are very helpful. I found where the issue is. The problem is that exporting a specific layer still considers the other layers for trimming.

When exporting via the CLI, instead of hiding all other layers like you are doing via the interface, the command is equivalent to this screen:

Screenshot from 2024-02-09 08-49-16

I can see the issue even in the UI. If I enable "trim sprite" and select one layer only the result is this:

Screenshot from 2024-02-09 08-49-39

This might be by design, but I found an open issue related to that. aseprite/aseprite#1634 . I can add a comment to that, but not sure when this is going to be tackled.

For the slice solution, I'll be implementing it anyway as I can see myself using it in another project. I also didn't pay much attention to that feature before, but I think it's a nice fit for this case. I think in earlier versions the tool was a little clanky, so maybe that's why I didn't use it before. I know they made some improvements to it and there are few others in their issue tracking.

The slice tool also does not work as intended for spritesheets (aseprite/aseprite#2469), but this one I'm able to workaround in the plugin. I can't think on any workaround for the trimming issue though.

This was referenced Feb 13, 2024
@Kylemcarthur
Copy link
Author

Thanks for the update! I'll give this a look when it's ready (or if it needs testing). Maybe slices are the future? My current project will definitely be able to make use of the feature, so it'll be a great testing ground for feedback if needed. Feel free to ping me when that's possible (I'm new to this whole Github thing), and direct me where you'd like feedback to go if relevant.

@viniciusgerevini
Copy link
Owner

Thanks. The current version in the asset lib already has the slice feature. For feedback, you can always post issues in this repo for bug reports, feature requests or even usage questions. All the best for your project. Cheers.

@Kylemcarthur
Copy link
Author

Kylemcarthur commented May 23, 2024

Hello! I've finally been able to dive into the slice solution and report back. I've put together a quick example animation to show a case where the trim method has a major flaw and the slice method actually seems to be superior, but I'm definitely hitting some snags.

Here's the example animation: a simple 3 frame attack for a character facing in 3 directions (3 separate animations in total, onion skinning is on).
image

As you might expect, when exporting the animations using the trimming method I described previously, you'll end up with spritesheets where the character is off-center and inconsistent from sheet to sheet, requiring setting offsets for each animation., such as these:

haunted_armor_attack_up
haunted_armor_attack_right
haunted_armor_attack_down

Personally, I find that pretty tedious and error prone. So, making use of the slices method as you suggested, I produced 3 identical slices like this, though centering and sizing them requires manual adjustment which isn't ideal, but ultimately doable if no other option exists.
image

Using your plugin to import these slices to Godot works pretty well! I'm able to set the layer groups "Up", "Right", and "Down" in the Layer import, as well as the corresponding slice, and this works as you'd expect, which makes the overlapping slices not have an issue. This is fairly close to ideal, but has a few major snags and some more minor ones.

Let's start with the major ones. This may very well be user error, so please let me know if there's a better way to do this. So, when I go to import a slice, it produces the correct result.
image

However, when I go to import the next slice, this will overwrite the previous import entirely rather than allowing me to add it to a new animation or something similar. Notice how the "test_animation" from the previous image is gone and "default" has been overwritten.
image
In posting this, I see that "default" has turned into the "Attack" tag I added to the .ase file, and testing with additional tags shows they get added as separate animations - neat! That actually solves the other snag I had of not seeing a field to tell the importer which animation to do.

The problem here is that this overwriting is preventing me from including all of the slices in the animation list for the node. This image shows the desired end goal with the animation list including all of the character directions.
image

If there's a way to do that with the importer, I haven't been able to figure it out yet. If not, that does pose a pretty major roadblock to being able to make use of the plugin unfortunately. The solution I think I'd want to see would either be the ability to tell the importer to include all slices, or multiple designated slices for more control, with each slice following the current import rules - each slice within each tag as a separate animation. Or alternatively, import each slice separately as it is currently setup, but be able to include those into the current SpriteFrames, adding the new imported animations to the same list, as opposed to overwriting the previous import.

EDIT: I should also mention that trying to create the animations manually by using the imported textures directly does not solve this because, while I can then produce multiple animations on the same node's list as needed, they retain all of the alpha from the original .ase canvas as described next, rather than using the slice area.
image

On the more minor side of things, there's a few issues. First is the amount of alpha present in the imports. I noticed that the imported file has all of the original alpha from the .ase canvas, though the slice shown in the animation does not and only has the slice area. Since I don't fully understand what's going on in that distinction, I don't know if this causes any impact on the game's performance or not.
image

Along those same lines, a disadvantage of the slice method is that there is inherently a lot of alpha space within the slice by necessity - trimming that would result in the same problem as before where the character is no longer centered. In an ideal world, I think the solution would be some way to trim the alpha down in a way that doesn't change where the art is aligned relative to its canvas edges, resulting in it remaining centered (that is, the character centered correctly, and not centering based on the entirety of the sprite - important distinction) without unnecessary alpha. If this is even possible, I have no idea, but it would solve the issue. I noticed that in Aseprite, the slice properties has the ability to set a pivot point, which perhaps could be used in some way to achieve this goal?
image

Perhaps in the end, the best solution ultimately is to just trim spritesheets and set offsets on every animation, but that's pretty... gag.

The other (very) minor issue is the naming of file outputs. I noticed that the output includes either the layer or slice name at the end of the output name. So for example, I end up with "haunted_armor_attack_" becoming "haunted_armor_attack_Down" whereas my convention would prefer it to be "haunted_armor_attack_down". This is simple enough to work around, such as making my layer / slice names lower case within Aseprite, but since I'm writing up this post anyway, I figured might as well mention it too in case an option to overwrite that behavior is simple to do. Naming the output manually such as "haunted_armor_attack_down" lead to "haunted_armor_attack_downDown".

To wrap this up, I fully recognize that this is a free plugin that I'm benefiting from, so I don't in anyway feel entitled to any of these changes, but it would certainly be awesome, because the art workflow natively into Godot is... kind of stupifyingly awful. Either way, I really appreciate the work you've done on this to help out your fellow game devs. You best believe I'll be finding a way to contribute when I'm not as broke as a record. Stay awesome.

@Kylemcarthur
Copy link
Author

I should also note that I looked through the other potential workflows for the plugin: Importers, Sprites and TextureRect -> AnimationPlayer (I'm currently using an AnimationPlayer + AnimationTree, so this workflow would ultimately make the most sense), Imports Manager, and Wizard Dock, but none of those seemed to provide the necessary solutions (or were missing the previous functionality of dealing with slices altogether).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants