Related Discussions
...

I was looking forward to it! This is great Q.Q
I'm already having fun with Godot Spine :fiesta:

Just in time, we were intending to check out Godot after our current project ends.

I think it will be profitable, maybe not immediately, but with time. Thanks!

spine-godot sits on top of spine-cpp, our C++ runtime. Since we wanted to integrate tightly with the Godot editor to provide a best in class experience, we had to implement spine-godot as a custom C++ engine module. We had to take this route, as GDNative and its successor GDExtensions do not surface all of the editor APIs we need, such as the animation player and editor APIs.

Thank you for writing a custom C++ module.

We've started work on the spine-godot runtime in November 2021, based on a generous source contribution by rayxuln.

Also thanks to rayxuln on github for providing a starting point.

Hi! Very excited about this however, I am having issues with the examples. After getting the Git, when I try to load "spine-runtimes/spine-godot/example/project.godot" I get an error box with "Error loading: helloworld.tscn Load failed due to missing dependencies: [url=res://assets/spineboy/spineboy-data-res.tres]res://assets/spineboy/spineboy-data-res.tres[/url]".

I can see that file in the FileSystem folders and if I choose "Fix Dependencies", I get the 'Dependencies For: helloworld.tscn" pop-up box with 2 entries: spineboy-helloworld.gd and spineboy-data-res.tres in the Resource section and [url=res://examples/01-helloworld/spineboy-helloworld.gd]res://examples/01-helloworld/spineboy-helloworld.gd[/url] and [url=res://assets/spineboy/spineboy-data-res.tres]res://assets/spineboy/spineboy-data-res.tres[/url] in the Path section.

Not sure what to do next as the "Fix Broken" button remains grayed out.

If I ignore the dependencies and press "Open Anyways", I get a "Load Errors" pop-up box with "Scene'res://assets/spineboy-data-res.tres has broken dependencies: [url=res://assets/spineboy/spineboy-pro.json::SpineSkeletonFileResource]res://assets/spineboy/spineboy-pro.json::SpineSkeletonFileResource[/url] [url=res://assets/spineboy/spineboy.atlas::SpineAtlasResource]res://assets/spineboy/spineboy.atlas::SpineAtlasResource[/url]"

I'm probably missing something simple, but if anyone has an idea, I am open to suggestions! Thanks - ChzBoi

EDIT - Found it...I was logged into the wrong machine with the old Godot build! Easy fix!

that's amazing! Thanks for creating this spine-godot Runtime!

how can I import the SpineSkeletonFileResource for the .skel or .json skeleton file and the SpineAtlasAssetResource ? because when I click import no resource is created.



maranpis a écrit

that's amazing! Thanks for creating this spine-godot Runtime!

how can I import the SpineSkeletonFileResource for the .skel or .json skeleton file and the SpineAtlasAssetResource ? because when I click import no resource is created.


I figured it out! I have made a video to everybody explaining how to import from spine to godot 😉



Also I have made a video of how to load the spine examples:

8 jours plus tard

Hey everyone!
I'm new to the forum and I didn't find a Godot section to post this. I'm having problems on replicating the sample 08-animation-player.

I've done the following:

  • Start an empty 2D Scene
  • Create a child node of type SpineSprite
  • Fill the skeleton_data_res on editor with res://assets/spineboy/spineboy-data-res.tres
  • Create a grandchild node of type SpriteAnimationTrack

In the documentation at http://esotericsoftware.com/spine-godot#SpineAnimationTrack :

When creating a SpineAnimationTrack, an AnimationPlayer node is created and attached as a child.

That's not happening.

I made sure to check every variable of the original scene's nodes and put it on my test scene, mainly setting the Debug variable on the SpineAnimationTrack to true. Still, no automatic creation of the node AnimationPlayer.

I tried creating the AnimationPlayer node manually. The problem is that the automatic created node would allegedly be filled with animations from the skeleton_data_res. I tried making it the animations manually but I can't seem to find the properties animation_name and loop on SpineAnimationTrack.

I can force any property to create the track, then rename it. Still, I can't seem to be able to change the value.

What am I missing? I'm sure I must doing something wrong, but I still can't figure out what.
Thank you for your time!

Hello! How do I get the current animation playing and not display the same animation again if it is already shown? Been having trouble just implementing simple topdown movement because of that...

What is the bigger context?
You could set the looping off for example as explained here, so that the animation you set only plays once:
spine-godot Runtime Documentation: Animating a
(disclaimer: I am but a humble animator attempting to code in Godot for the first time)

Erika a écrit

What is the bigger context?
You could set the looping off for example as explained here, so that the animation you set only plays once:
http://esotericsoftware.com/spine-godot#Animating-a-
(disclaimer: I am but a humble animator attempting to code in Godot for the first time)

I might need to play around with it some more xD (anyway Spine is great! I could make animations that would usually take me ages to make in like a day).

Btw, Godot 3.5 was just released, will the Spine runtime be updated to support that version?

8 jours plus tard
Mario a écrit

Already up-to-date 🙂 You can find the download links for the new binaries here:
spine-godot Runtime Documentation

Nice thank you 😃
Amazing software with amazing support!


It seems using the custom build Godot Spine version clashes with some plugins that also use JSON for data... Keeps saying error parsing JSON at line 0, which doesn't happen if I use the official build of Godot 3.5 (I use a bare new project with only that plugin for tests)

The big one I'm using is Dialogic, which is kinda essensial plugin if you want to have dialogs in the game. Any way to fix this or am I doing something wrong?

Animating my character in Godot is working great.

As far as setting up the character controller, I know I can do something like:

if Input.is_action_just_pressed("ui_left"):
get_animation_state().set_animation("Run", true, 0)
velocity.x -= speed

...this moves the character, but since I'm not extending KinematicBody2D I don't have access to 'move_and_slide()' & 'is_on_floor()' like most controller examples use.

So what I'm doing is setting the 'SpineSprite' node as a child of 'KinematicBody2D' node.

Then I can apply the animation Spine code to the SprineSprite node & have a separate script on the KinematicBody2D node to process anything I want with is_on_floor() & move_and_slide().

But I'm not sure if this is the best way to do this, or if it's better I just build out all the custom control physics all in the 'SpineSprite' script. Curious what anyone else is doing...

jdowdy6 a écrit

But I'm not sure if this is the best way to do this, or if it's better I just build out all the custom control physics all in the 'SpineSprite' script. Curious what anyone else is doing...

I mean, you'd do this for a regular KinematicBody2D + Sprite setup, wouldn't you?

That's a reasonable setup imho.

Okay cool thanks Ryusui & Mario.

13 jours plus tard

Hello guys, 🙂 I have a question:

What is the best way to detect when a specific animation has finished that has been playback twice in a queued animation?

Let me explain:

I'm doing a boxing game where the enemy do a combo punch: left punch, right punch, and again same animation left punch.

First I tried to use the signal completed animation to go back to idle(if the animation name is "left punch" go back to idle animation) but obviously because the first animation and the last are the same after playback the first animation it will go back to idle skipping the rest of the combo(right punch and left punch again).

The idea I've come up with is making two idle animations that are the same but with different names, one when the scene starts another one (that has been duplicated in Spine) with different name when the combo finish to go back to idle animation.

I tried using when animation is completed signal and using SpineTrackEntry get_current(track_id: int) something like this:

But it seems it doesn't work. Is there a way to detect when all the added animations has finished? Or detect when a specific animation has finished that has been playback twice in a queued animation?

I feel like you're leaning too heavily on the animation itself to time the mechanics.

Like...what I'd do is, I'd queue up the left jab, wait till it finishes, queue up the right jab, wait until that finishes, queue up the left jab again, wait for that to finish, and then set the idle animation. You could, alternately, use signals to determine which animations have finished, and detect whether all three animations have played that way, but I think my suggested method would be more straightforward to implement.

@maranpis AnimationState.get_current() will not return null if you loop the animation, as the track entry will remain on the track indefinitely until you queue a new animation or clear the track entry.

I have a todo list item that will allow setting a signal callback on individual track entries as returned by add_animation or set_animation. That way, you can add a signal callback to the track entry and know exactly when it has started/completed (a loop)/ended, and do whatever you need to do. You can already do this by setting a signal callback on the animation state itself, then checking the track entry that your signal callback is passed, e.g.
https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-godot/example/examples/02-animation-state-listeners/animation-state-listeners.gd#L15

You can simply query the animation name of the animation represented by the track entry:

func _animation_completed(sprite: SpineSprite, animation_state: SpineAnimationState, track_entry: SpineTrackEntry):
   print("Animation completed: " + track_entry.get_animation().get_name())
Ryusui a écrit

I feel like you're leaning too heavily on the animation itself to time the mechanics.

Like...what I'd do is, I'd queue up the left jab, wait till it finishes, queue up the right jab, wait until that finishes, queue up the left jab again, wait for that to finish, and then set the idle animation. You could, alternately, use signals to determine which animations have finished, and detect whether all three animations have played that way, but I think my suggested method would be more straightforward to implement.

Hello Ryusui, thanks for your answer 🙂 . Considering that the animation goes like this (left_jab, right_jab_left_jab) I don't get how with signals I can differentiate the first left jab animation playback from the second jab animation playback. Could you explain it a little bit more, please?


Mario a écrit

@[supprimé] AnimationState.get_current() will not return null if you loop the animation, as the track entry will remain on the track indefinitely until you queue a new animation or clear the track entry.

Hello Mario and thanks for your answer. The final animation "idle" is the solution I have found to finish the combo and go back to idle animation. But before I just have the piece of code without the last animation:

Ebrius_Spine_animation.set_animation("ebrius_left_jab",false,0)
   Ebrius_Spine_animation.add_animation("ebrius_right_jab",fixed_delay,false,0)
   Ebrius_Spine_animation.add_animation("ebrius_left_jab",fixed_delay, false,0)

So I thought that when the last animation finishes, the AnimationState.get_current() in the func _animation_completed will give me null. Apparently, when the left jab animation finishes, it stays in the last frame of the animation, so I guess the track still has the animation and won't give null.

I might be misunderstanding how your game works but it feels like you're stuck on the idea of "the final left jab has to reset the animation." What's wrong with setting a count for the number of queued animations, decrementing it by one each time an animation in the sequence ends, and when it hits 0, returning to the idle state? You could configure this for any sequence of animations, without having to worry about which specific ones are queued. (And if anything interrupts the sequence - like the character getting hit mid-combo - you could set the count to 0 then!)

But yeah, to explain my original idea better, you could also set it so the animation_complete callback sets each subsequent animation in the sequence in turn, instead of queueing them all at once.

7 jours plus tard
Ryusui a écrit

I might be misunderstanding how your game works but it feels like you're stuck on the idea of "the final left jab has to reset the animation." What's wrong with setting a count for the number of queued animations, decrementing it by one each time an animation in the sequence ends, and when it hits 0, returning to the idle state? You could configure this for any sequence of animations, without having to worry about which specific ones are queued. (And if anything interrupts the sequence - like the character getting hit mid-combo - you could set the count to 0 then!).

That's a great idea! thanks for the suggestion 🙂

If you want the track to clear when it reaches the animation duration, you need to set TrackEntry trackEnd. However, you probably want to use an empty animation to transition to the setup pose rather than clearing the track.

You could use a listener on the TrackEntry for the last queued animation (eg the second left jab) to set to idle. I'm not sure spine-godot supports that yet, but it will.

Using the animation system for your game state isn't great. It would be much better to track what state your game is in separately, then set animations based on that. Separating animating from game state simplifies things and will help if you ever need to serialize the game state. You can Google for the "MVC design pattern". Super Spineboy uses it:
https://github.com/EsotericSoftware/spine-superspineboy/tree/master/src/com/esotericsoftware/spine/superspineboy

You can see how it works here:
https://github.com/EsotericSoftware/spine-superspineboy/blob/master/src/com/esotericsoftware/spine/superspineboy/CharacterView.java
The game state keeps track of what the player is doing, then this code checks if the corresponding animation is playing. If not, it plays it.

Nate a écrit

If you want the track to clear when it reaches the animation duration, you need to set TrackEntry trackEnd. However, you probably want to use an empty animation to transition to the setup pose rather than clearing the track.

You could use a listener on the TrackEntry for the last queued animation (eg the second left jab) to set to idle. I'm not sure spine-godot supports that yet, but it will.

Using the animation system for your game state isn't great. It would be much better to track what state your game is in separately, then set animations based on that. Separating animating from game state simplifies things and will help if you ever need to serialize the game state. You can Google for the "MVC design pattern". Super Spineboy uses it:
https://github.com/EsotericSoftware/spine-superspineboy/tree/master/src/com/esotericsoftware/spine/superspineboy

You can see how it works here:
https://github.com/EsotericSoftware/spine-superspineboy/blob/master/src/com/esotericsoftware/spine/superspineboy/CharacterView.java
The game state keeps track of what the player is doing, then this code checks if the corresponding animation is playing. If not, it plays it.

Thanks, Nate! I'll keep that in mind for the animations. Now, I have a problem with the enemy's hook: I want the player to be able to dodge the hook by going under the glove like this:


I have no idea how I can change just the drawing order of the left arm because as you see if I change the entire skeleton's draw order the enemy torso overlaps the player's right glove. I've come up with 3 possible solutions:

1) Put the left arm on a different skeleton and copy the animations.

2) Maybe use the tracks, put the arm on track 1, and maybe you can change only the drawing order.

3) The easiest solution when the glove passes over the head is to make the player's head disappear, making the illusion that it has passed under it, and play then with the mesh tool to progressively make the face appear at the edge of the glove and the face.

Any ideas?

Have you considered adjusting the composition of the player and enemy sprites so you don't have to adjust the drawing order? Perhaps make the player dodge backwards instead of crouching, or crouch low enough that the punch looks like it's sailing over their head without overlapping. Alternately, move the sprites further apart so that the fist doesn't reach beyond the player's body, so that it makes sense that the fist never overlaps the player.

Ryusui a écrit

Have you considered adjusting the composition of the player and enemy sprites so you don't have to adjust the drawing order? Perhaps make the player dodge backwards instead of crouching, or crouch low enough that the punch looks like it's sailing over their head without overlapping. Alternately, move the sprites further apart so that the fist doesn't reach beyond the player's body, so that it makes sense that the fist never overlaps the player.

Hi Ryusui, yes, I have tried it, I have to keep in mind that the player can either dodge the hit or then take damage and for that there will be a taking damage animation. I have tried different positions and this is the only one that works for all actions.

Would it be possible to get pre-built versions of the runtime with Godot 4 that line up with the alphas (or beta, which is due very soon)? I know neither Godot 4 nor Esoteric's support for it is stable yet, but a lot of folks are trying to get a jump on Godot 4 for various reasons (myself included) and would love to be able to use Spine without having to custom build everything all the time.

Really appreciate you all!

You can count out alpha builds, since they're still finalizing APIs and whatnot. Beta is possible, but still doubtful unless there's some huge demand for it.

You can fork the spine-runtimes repository on GitHub, enable Actions on your fork, then modify this file in your fork:

https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/.github/workflows/spine-godot.yml#L16

Change the GODOT_TAG value from 3.5-stable to master and the GODOT_VERSION to whatever you like, e.g. 4.0.alpha. You can then manually trigger the Build and Publish Godot editor and templates workflow on GitHub. If the build succeeds, you can download the binaries from GitHub, like for this run:
https://github.com/EsotericSoftware/spine-runtimes/actions/runs/3043534000

We currently simply do not have the resources to support both pre-built 3.5 and 4.0 binaries. 4.0 is still in flux, even if the API is frozen, and has quite a few bugs. Before there's a stable release, we won't be able to suppor it I'm afraid.

Understood. I appreciate the suggestion of running it myself. I had been building locally but running in to errors, I'll give GH Actions a try.

Godot 4 won't be stable for the next 6 months at least. And while most things are locked in, there will still be some API changes so officially supporting early beta versions seems counter productive.

I'd rather see current Godot 3.5 issues resolved like this one: https://github.com/EsotericSoftware/spine-runtimes/issues/2119 and stuff like the .json conflict with Dialogic and similar plugins.

EDIT: And now that https://w4games.com/, a corporate entity founded by lead developers of Godot, exists, there should be no issues with representing interests of Spine in a commercial context. They're not FOSS purists and no one will get lynched by interacting with them via regular bug reporting and feature proposal channels.

8 jours plus tard
Mario a écrit

I've now "fixed" the .json issue. More infor here: https://github.com/EsotericSoftware/spine-runtimes/issues/2134

Blog post will also be up this week. TL;DR: backup your project, use the convert.py script to rewrite files, open project with Godot editor containing the latest spine-godot.

thanks a lot 🙂

un mois plus tard

Hi, I don't know why but when I run the convert.py script to rename the skeleton.json file it shows several errors. I also tried to use .skel file export with no success. Can somebody explain me what i'm doing wrong?

It looks like your skeleton.json is in use by another process. Maybe try closing Godot, then run the script.