• Runtimes
  • [UE4] Animation Event

Related Discussions
...

I recently made Spine Runtime compatible with UE4's GamePlay Ability system, making it easier to perform animation combos and the like, but encountered some problems with Delegate.

I did some small tests in UE4, first broadcast A animation, then broadcast B animation. B animation will only trigger the interrupt of A animation after the end of the animation... This is very unreasonable. It should be played before B Triggered to be right.

Here is an example:

After testing, I found that there is a problem with the implementation of disableQueue and enableQueue here. When enableQueue, it seems that the call to “drain” is missing.


second question:Because the characters are more complicated, we split the animation into different SkeletonData files. Switching the Skeleton Data file will cause the state machine to be deleted, but the callback of the corresponding animation is not triggered before the deletion. I think this is an error.


I have another question. I intend to do the "afterimage" effect when I move. Do I have any way to get the Skeleton Transform of any frame of animation and then set it to a StaticMesh Actor? I don't want any animation content because the overhead will be larger.


The last question, is there any better way to play animations, such as: play and stop instead of setempty.

Thanks for the repro, I've created an issue for the first problem here: [ue4] Widget does not drain queue in SetAnimation and consorts · #1341

Regarding your second question, there's currently no way to retain the AnimationState after switching out the skeleton data. The reason is that the AnimationState is stateful, meaning it retains data that applies to the Skeleton instance that it was used to manipulate. We have no means to decide whether the new skeleton data fits that animation state, so we have to conservatively kill it. I suggest you modify the spine-ue4 code such that the animation state is retained, as you know what you are doing in your case.

Regarding your third question: I'm not a UE4 expert, but your best bet might be to render the skeleton into an offscreen buffer and render that. You could modify the renderer component to retain the vertices and materials it generated for the last frame which you could set on a static mesh, but that gets messy fast.

Regarding your fourth question: if you want a hard stop, you can call ClearTracks() which will stop everything at once.

Regarding your first problem, I've setup a test scene (see the 3.8-beta branch, latet spine-cpp, Content/Test/NewWorld). Here's my widget blueprint:

https://marioslab.io/uploads/screenshots/UE4Editor_K9gWp4AdP2.png

Here's the log output:

LogBlueprintUserMessages: [raptor-widget_C_0] Started  walk
LogBlueprintUserMessages: [raptor-widget_C_0] Interrupted walk
LogBlueprintUserMessages: [raptor-widget_C_0] Started  roar
LogBlueprintUserMessages: [raptor-widget_C_0] Completed walk
LogBlueprintUserMessages: [raptor-widget_C_0] Ended walk
LogBlueprintUserMessages: [raptor-widget_C_0] Completed roar

This works as intended. I also changed the blueprint using the UE4 Delay function:

https://marioslab.io/uploads/screenshots/UE4Editor_hdOseaQE8y.png

Here's the log output:

LogBlueprintUserMessages: [raptor-widget_C_0] Started  walk
LogBlueprintUserMessages: [raptor-widget_C_0] Interrupted walk
LogBlueprintUserMessages: [raptor-widget_C_0] Started  roar
LogBlueprintUserMessages: [raptor-widget_C_0] Completed walk
LogBlueprintUserMessages: [raptor-widget_C_0] Ended walk
LogBlueprintUserMessages: [raptor-widget_C_0] Completed roar

Again this works as intended. Can you maybe modify that test scene to reproduce your issue?

badlogic escribió

Regarding your first problem, I've setup a test scene (see the 3.8-beta branch, latet spine-cpp, Content/Test/NewWorld). Here's my widget blueprint:

https://marioslab.io/uploads/screenshots/UE4Editor_K9gWp4AdP2.png

Here's the log output:

LogBlueprintUserMessages: [raptor-widget_C_0] Started  walk
LogBlueprintUserMessages: [raptor-widget_C_0] Interrupted walk
LogBlueprintUserMessages: [raptor-widget_C_0] Started  roar
LogBlueprintUserMessages: [raptor-widget_C_0] Completed walk
LogBlueprintUserMessages: [raptor-widget_C_0] Ended walk
LogBlueprintUserMessages: [raptor-widget_C_0] Completed roar

This works as intended. I also changed the blueprint using the UE4 Delay function:

https://marioslab.io/uploads/screenshots/UE4Editor_hdOseaQE8y.png

Here's the log output:

LogBlueprintUserMessages: [raptor-widget_C_0] Started  walk
LogBlueprintUserMessages: [raptor-widget_C_0] Interrupted walk
LogBlueprintUserMessages: [raptor-widget_C_0] Started  roar
LogBlueprintUserMessages: [raptor-widget_C_0] Completed walk
LogBlueprintUserMessages: [raptor-widget_C_0] Ended walk
LogBlueprintUserMessages: [raptor-widget_C_0] Completed roar

Again this works as intended. Can you maybe modify that test scene to reproduce your issue?

I have modified it based on your project and can still reproduce the problem.


Here is a test project.:

The order is actually this:

LogBlueprintUserMessages: [raptor-widget_C_0] set 111
LogBlueprintUserMessages: [raptor-widget_C_0] set 222
LogBlueprintUserMessages: [raptor-widget_C_0] interrupt:    TrackEntry_0   current:TrackEntry_1
LogBlueprintUserMessages: [raptor-widget_C_0] Compile:  TrackEntry_1   current:TrackEntry_1

The order in your screenshot is inverted for whatever reason. Here's what happens:

  1. You set the animation "walk", looping. Var 0 is set to TrackEntry_6. set 111 is written to the log.
  2. After a delay, you set the animation "walk", non-looping. Var 0 is set to TrackEntry_7. set 222 to the log.
  3. The looping "walk" animation (TrackEntry_6) is interrupted and an event is broadcast. You fetch the content of Var 0, which is TrackEntry_7, and concatenate the string ìnterrupt: TrackEntry_6 current: TrackEntry_7. This works as intended.
  4. The non-looping "walk" animation (TrackEntry_7) completes and you output a string as such. This works as intended.

You do not receive a complete event for TrackEntry_6 as your delay is smaller than the animation duration. The animation is never played in full, so no complete event is generated.