nklbdev / godot-4-aseprite-importers

The addon for Godot 4 that adds several plugins for importing images and animations from Aseprite
https://godotengine.org/asset-library/asset/1880
MIT License
70 stars 3 forks source link

Questions from a Unity refugee #2

Open zomby138 opened 1 year ago

zomby138 commented 1 year ago

Hello. I'm transitioning from Unity to Godot. In Unity I've been using a Aseprite importer that I have had to extend to get the functionality I need out of it.

Because I'm so new to Godot, it's hard for me to know if something is a limitation of the aseprite plugin or Godot it's self, so I apologize if I'm wrong about anything.

Anyway. I would like to be able to import some animations as looping, and others as non-looping. Inside Aseprite there is no way to distinguish between these two, so what I did in Unity was add _1 to the end of each animation name that I want to be non-looping (ie play one time). Then in the importer I look at the animation name to see if I should set the looping flag.

I'm not even familier enough with Godot's animation system to know if this is needed. Is there some way I can play an animation once even if it's setup as a looping animation?

I guess right now I'm just looking for some advice.

nklbdev commented 1 year ago

I'm very glad that you decided to use my plugin!

I highly recommend that you use the Importality plugin instead of this plugin. It is a rethinking and continuation of the initiatives I made in this repository.

Please read the documentation for importing files from Aseprite. And I highly recommend using RAM Drive for intermediate temporary files during the import process.

I recommend that you first try the simplest and most successful import method: Aseprite -> AnimatedSprite2D. It will automatically create an AnimatedSprite2D node for you with an embedded SpriteFrames resource with the necessary animations, taking into account the specified cyclicity.

There are other ways to import animations, but they are more specific and are needed for special cases of using target resources. Also, if you want to modify the resulting resource at the end of the import, you can specify a post-import script that will make the changes you need to the resource before saving it.

Unfortunately, the spritesheet texture cannot be easily and compactly embedded into a saved resource. Therefore, it is saved separately in a neighboring file. I submitted a pull request to Godot to fix problems with the PortableCompressedTexture2D resource, but it has not yet been accepted.

Also, to import animations, you will need to specify the path to the Aseprite or LibreSprite (supports fewer features) executable file.

In Asepritе it is possible to specify the cyclicity of animations. To do this, select a number of frames on the timeline, call the context menu and create a tag. image

In the tag properties you can specify the direction of the animation and its cyclicity. image

Also in Importality the direction of the animation and the number of repetitions can be overriden using suffixes in the tag names:

<animation_name> [-d:<direction>] [-r:<repeat_count>]

Where:

For example:

Idle -r:0
Walk -r:0
Jump -r:1
Crouch -r:1
Hurt -r:1
Die -r:1
Special -d:pp -r:0

I'd be happy to answer any further questions you may have!

zomby138 commented 1 year ago

Thank you so much for the detailed reply. You have gone above and beyond. I will download importality next.

Right now I am really confused about the Asprite tag properties you have shown. Mine looks like this: image

I have the Steam version of Aseprite and I just uninstalled it and reinstalled to make sure it was totally up to date.

How come your version has the Repeat setting and mine does not?

nklbdev commented 1 year ago

Hmm, newer versions have been released for Aseprite. Perhaps for some reason they were not released on Steam, or are considered beta versions, although most artists around the world have been using them for a long time. I'm using version v1.3-rc4-x64.

image

Try to change the beta- settings for Aseprite in Steam.

image

New versions of Aseprite have many useful innovations: New tag properties Tile maps New export modes And much more

zomby138 commented 1 year ago

Yeah looks like you're on the beta. I've been able to get the -r:0 suffixes to work in importality, so I think I'm covered for animation flags.

I have another question. Once I have the AnimatedSprite3D object in Godot, and it has the imported list of animations, am I restricted to just use these particular animations on this AnimatedSprite3D, and/or can I use these animations on other AnimatedSprite3D objects? It looks to me like they do not go into a common pool. I can probably work around this though.

Earlier, you said something about "post-import script that will make the changes you need to the resource before saving it". This sounds very useful to me. In Unity, I had modified my import script to convert the PNG file to single channel grayscale based on a palette that I define in the first frame in Aseprite, this saves me 75% of the texture memory and lets me do lots of ticks with with the palette in the shader. Can I use a post-import script to do something similar in Godot?

Once again I want to thank you for being so helpful. I can't believe my luck. I was worried that it would be harder to get info on things in Godot compared to Unity because of the smaller community.

nklbdev commented 1 year ago

It seems I forgot to update the commit from which Importality was published in Godot Asset Library. I've done it now, but will have to wait a day or two for the update to be moderated.

You can download the latest version of Importality directly from the GitHub repository. Download the main branch of the repository as a zip archive and place the plugin files in place of the old files. There is already support for middle-import and post-import scripts. There is also an examples of simple scripts that you can take as a basis and make your own version.

Just inherit your script from one of these base scripts and write your code in the desired function.

You can import an Aseprite file as a Aseprite -> SpriteFrames resource, and then use that resource as you wish. For example, use it in your own created AnimatedSprite-nodes.

You can also import the Aseprite file as Aseprite -> Sprite Sheet (JSON) - you will receive the Godot resource JSON. This is a kind of container that contains data (dictionaries, arrays and so on). This resource may contain raw JSON text, but I don't use that (perhaps for good reason: it would help users better understand its structure).

You can examine this object by simply printing its "data" property to the console.

This data contains all the necessary information to independently, using your scripts, recreate any animation that is in the source file.

There is information about the location of sprites in the atlas. And there is information about animations, frames, duration and cycling.

Sorry, I'm going to bed now and won't be able to respond to any further messages until tomorrow.

I wish you successful experiments!

zomby138 commented 1 year ago

When you first mentioned post-import scripts I assumed it was a Godot feature. I see it's in fact just a feature of importality? Do you think I'll be able to use this feature to do what I want with the palette stuff? In my Unity version I would save out a seperate png that is just the first fame (the pallete), then make the actual sprite sheet grayscale based on that.

I have a question about best practices in Godot. What's the best way to have an animator switch back to an idle animation after finishing something like an attack or pain animation? Do I need to connect up a signal somehow?

I have other things I need to do today, but I'll be back on this tomorrow.

nklbdev commented 1 year ago

I see it's in fact just a feature of importality?

Yes it is. But this technique is not only used in this plugin.

Do you think I'll be able to use this feature to do what I want with the palette stuff?

You can do everything that can be done with the data that the middle-import script or post-import script operates on.

For example, the middle import script provides you a Сontext object that contains the spritesheet atlas (an instance of Godot's Image class, before it is saved to disk as a PNG file and automatically imported as Texture2D resource), spritesheet data, and animation data. You can change this data or perform some other external actions based on it.

In the post-import script, you can access a resource that was created by the plugin but not yet saved. You can modify it before saving. How exactly you change it - there are a lot of options.

For example:

What's the best way to have an animator switch back to an idle animation after finishing something like an attack or pain animation? Do I need to connect up a signal somehow?

In order to master working with animations (not necessarily with graphic animations), study the documentation pages:

You can control the progress of the animation from your script code, from signals emitted by various objects, or directly from AnimationPlayer keys on it's tracks (keys can contain not only new values for object properties, but also an arbitrary method calls with custom parameters).

For example, you can subscribe to a signal about the completion of playing an animation, and launch another one in the handler, or transfer your game object to another state.

It all depends on your ingenuity and ability to combine available tools.

zomby138 commented 1 year ago

Ok, it's time for me to get these mid/post import scripts working.

If I've made one of those scripts, where do I put it so that it will execute? The example ones in the folder don't see to execute, and I can't find any info in the readme or anywhere telling me what to do with the actual mid/post script.

nklbdev commented 1 year ago

You are free to place them in any place in your project filesystem and then specify paths to them in import options dock when you selected yout ".aseprite"-file.

You can copy example scripts from plugin folder and place them in your favorite place. Then modify scripts in your way.

image

zomby138 commented 1 year ago

Hi nklb. I've been able to make a mid import script that saves out the palette as a seperate texture, then turns the sprite sheet into a single channel image based on the palette, exactely like I had in Unity. I've also made a shader that turns it back into a full color sprite where I can change the palette on the fly.

So basically I am really happy. The only real difference is the sprite packing. Back in Unity I had to write my own code to pack the frames up nice and tight, but you have already done that for me here. The difference is your packing works better than mine did!

nklbdev commented 1 year ago

Thank you! Aseprite can pack sprites. You can use this out of the box. You could write a similar extension for Unity simply using the Aseprite command line interface. As a result, you will receive a packed atlas and a JSON spritesheet specification as separated file or command line output. But there is an error in his packaging algorithm, so I stopped using it ((((((

I took the packaging code from this repository from this file, and modified it a little so that it works well with the sizes typical for textures in Godot

I'm really happy that I could help you! I hope your colleagues will also find this plugin useful. Do you know how to spread information about it?

nklbdev commented 1 year ago

One more thing:

If you create and save another resource while importing one resource, add the path to this resource to the gen_files_to_add array, provided with Context-object. The engine needs this in order to establish dependencies between these resources, and so that your new resource is not accidentally erased.

If you need to immediately use your new resource during the import process, then it’s better to do as I did in the atlas_maker.gd file:

var my_new_texture_path: String = "res://my_new_texture.png"
var error: Error
error = my_new_image.save_png(my_new_texture_path)
if error:
    # handle the error
    return ... something :)

# oh, oh, oh!!! you can not do this! I forgot to provide EditorFileSystem-object with context for you! Sorry!
editor_file_system.update_file(my_new_texture_path)

error = editor_import_plugin.append_import_external_resource(my_new_texture_path)
if error:
    # handle the error
    return ... something :)

gen_files_to_add.push_back(my_new_texture_path)

var my_new_texture: Texture2D = ResourceLoader.load(my_new_texture_path, "Texture2D", ResourceLoader.CACHE_MODE_IGNORE)

# Now you can use your new texture resource in another resources without embedding
zomby138 commented 12 months ago

Ok. It's true that my new file doesn't appear in Godot right away. I have to tab out to the folder then back in again.

How do I get the editor_file_system object then?

nklbdev commented 12 months ago

I added the EditorFileSystem instance to the script parameters. Get the latest version from the GitHub repository

zomby138 commented 12 months ago

Very nice. I got it working. I'll be sure to tell anyone I can about your plugin. I'm honestly blown away by how helpfull you've been.

nklbdev commented 12 months ago

Thank you! It was just my dream to make the import process quick and easy. So that you can edit the source graphics file in your favorite application and immediately get the result in Godot.

zomby138 commented 12 months ago

I'm a big believer in the smoother the workflow, the better the end results.