Unity---Spine animation

Table of contents

1 Introduction

2. Advantages

3. Unity resources exported by spine

4. Import

5. Import the solution to the error

6. use

7. Code example

1. Load Spine skeleton animation:

2. Control the playback of Spine animation:

3. Pause and resume animation playback:

4. Listen to animation events:

5. Switch skins (dressup)

6. Get the Transform information of the bone:

7. Control the mixing and cross-fading of skeletal animation:

8. Control the speed of the animation:

9. Get animation status information:

10. Dynamically replace bone texture:

11. Play the specified track of the Spine animation:

12. Get the time and duration of the current animation:

13. Control animation loop times:

14. Dynamically change the weight of the animation blend:

15. Pause and resume all animation tracks:

16. Dynamically create and replace the Attachment of the slot:

17. Use Spine animation events to trigger Unity events:

18. Control animation playback speed randomization:

19. Dynamically switch the Spine Atlas atlas:

20. Create skeletal animation dynamically:

21. Event monitoring and processing of skeletal animation:

8.unity-spine runtime library download


1 Introduction

Unity Spine is a powerful cross-platform 2D skeletal animation tool that can easily create complex character animations.

To use spine animation in unity, you need to download the corresponding spine runtime library

⚠️Note that the version of the spine runtime library used should correspond to the version of unity,

The corresponding relationship is shown in the figure below:

 

2. Advantages

  1. Lightweight and efficient: Spine animations use bone-based animation techniques, which have smaller file sizes and lower memory footprint than traditional frame-by-frame animations. This makes Spine animations perform better on mobile devices and low-end hardware.

  2. Flexibility: With Spine, you can create highly customizable animations, including deformation, scaling, rotation and translation of bones. You can easily adjust the speed of animations, blend different animations, and implement complex character animation controls.

  3. Runtime animation: Spine animations can be modified and controlled in real time at runtime. This means that you can change the playback state of the animation through code, and perform corresponding animation interactions according to the character's behavior and environmental conditions.

  4. Platform compatibility: Unity supports multiple platforms, including PCs, mobile devices, and consoles, and Spine animations can be easily deployed and played on these platforms.

3. Unity resources exported by spine

Under normal circumstances, art will export the following 3 files

.json Stores bone information.png
The picture atlas used.atlas.txt
The position information of the picture in the atlas
When we import these three resources into the Unity project that has introduced the Spine runtime library, it will be automatically generated for us

_Reference configuration files for Atlas materials and .atlas.txt files_Material
material files_SkeletonData
json and _Reference configuration files for Atlas resources

⚠️: But using the .json format to read animation data is a slower and less efficient way.

Because the post-optimization effect of spine animation using json files is not very good, it is easy to cause freezes, slow loading, etc. Binary files load faster.

Spine supports Binary format, binary data export, the formats exported in this way are: .png, .skel and .atlas 

4. Import

1. Add the .txt suffix after the atlas.atlas

2. Add the .betys suffix to the binary file .skel

5. Import the solution to the error

1. It may be a problem when exporting from the art side. You can ask the artist to export it again. The same spine animation allows art to export json files and binary files. If there is an error in the import of the json file, it is a problem with the export of the art side.

  2. If you import json, there is no problem. If there is a problem with importing the binary, it may be that the version of the runtime library is inconsistent with the version of the spine. First of all, you can check the version of the spine runtime library in unity. Is it consistent with the spine version.

 3. After the binary file is imported into unity, if the object is not automatically instantiated, then you need to create it manually. During the creation process, sometimes you will find that the objects you create become larger when used in the scene. Specifically, it has become 100 times larger. Some people say that I also modified the size of the scale (0.01) when I created it. How can it be so large? There are some tricks in this. When you create, modify the scale value first, and then drag the required files to the corresponding position after modification. Then the size you create is the normal size after scaling. Directly used in the scene is the normal size given to you by the art.

6. use

1. There are three ways to add spine in unity , as shown in the figure below:

 2. Use SkeletonGraphic (UnityUI) in ugui

 

3. Other use SkeletonAnimation

4. Generally speaking, you may use SkeletonRenderer in the following situations:

  1. Character animation: If you have a 2D character in your game that requires complex skeletal animation, you can use Spine to create character animation and add the SkeletonRenderer component to the character object in the Unity scene. This component will then be responsible for rendering the character's skeletal animation at runtime.

  2. UI Animations: You can use Spine to create animations of 2D UI elements such as buttons, icons, menus, etc. By adding SkeletonRenderer to UI elements, you can play spine animations at runtime to enhance the interaction and visual effects of the user interface.

  3. Enemy/monster animation: If you have enemies, monsters or NPCs in your game that require complex animations, you can use Spine to create skeletal animations and add the SkeletonRenderer component to the corresponding game objects.

  4. Special effects animation: Spine can also be used to create 2D special effects animations, such as explosions, flames, magic, etc. Use the SkeletonRenderer component together with special effect objects to achieve more vivid and realistic effects.

7. Code example

1. Load Spine skeleton animation:

Use the SkeletonDataAsset class of Spine to load the Spine skeleton data, and play the animation through the SkeletonAnimation component.

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }
}

explain:

  • First, you need to create an empty GameObject in Unity and attach the SkeletonAnimation component. This component is used to play Spine animations.
  • Create a public field to store the SkeletonDataAsset, which is the skeleton data for the Spine animation.
  • In the Start() method, get the reference of the SkeletonAnimation component, and assign SkeletonDataAsset to skeletonAnimation.skeletonDataAsset.
  • Call the Initialize(true) method to initialize the SkeletonAnimation. Passing true means enabling MeshRenderer to display skeletal animation in the scene.

2. Control the playback of Spine animation:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            skeletonAnimation.AnimationState.SetAnimation(0, "walk", true);
        }
    }
}

explain:

  • In the Update() method, we can use Input.GetKeyDown(KeyCode.Space) to detect whether the space bar is pressed.
  • If the space bar is pressed, we use the skeletonAnimation.AnimationState.SetAnimation() method to play the animation named "walk".
  • The first parameter 0 indicates trackIndex, indicating which track (track) to place the animation on. Spine allows multiple animations to be played on multiple tracks at the same time, 0 is the default track.
  • The second parameter is the name of the animation, in this case "walk". You can replace this with the name of another Spine animation.
  • The third parameter true means to play the animation in a loop, if it is set to false, the animation will only be played once.

3. Pause and resume animation playback:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            skeletonAnimation.AnimationState.SetAnimation(0, "walk", true);
        }

        if (Input.GetKeyDown(KeyCode.P))
        {
            if (skeletonAnimation.AnimationState.GetCurrent(0) != null)
            {
                skeletonAnimation.AnimationState.GetCurrent(0).TimeScale = 0f; // Pause animation
            }
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            if (skeletonAnimation.AnimationState.GetCurrent(0) != null)
            {
                skeletonAnimation.AnimationState.GetCurrent(0).TimeScale = 1f; // Resume animation
            }
        }
    }
}

explain:

  • In the Update() method, we added code to detect pressing the "P" and "R" keys to pause and resume the animation.
  • When the "P" key is pressed, we get the currently playing animation track through the GetCurrent(0) method, and set its TimeScale to 0, which will pause the animation.
  • When the "R" key is pressed, we set the animation track's TimeScale to 1, which resumes normal playback of the animation.

4. Listen to animation events:

using Spine;
using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);

        // 订阅动画事件
        skeletonAnimation.AnimationState.Event += HandleAnimationEvent;
    }

    private void HandleAnimationEvent(TrackEntry trackEntry, Spine.Event e)
    {
        Debug.Log("Animation Event: " + e.Data.Name);
        // 在此处执行事件相关的逻辑
    }
}

explain:

  • In the Start() method, we subscribed to the animation event through skeletonAnimation.AnimationState.Event += HandleAnimationEvent;
  • Create the HandleAnimationEvent method to handle animation events.
  • When a Spine animation event is triggered, HandleAnimationEvent will be called, and you can execute event-related logic in it. For example, you can add an event to an animation frame in the Spine editor, and trigger the corresponding logic in the code according to the name of the event.

5. Switch skins (dressup)

using Spine.Unity;

public class SpineSkinController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    private string currentSkinName;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);

        // 设置初始皮肤
        currentSkinName = "default";
        skeletonAnimation.Skeleton.SetSkin(currentSkinName);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            // 切换到另一个皮肤
            string newSkinName = "alternate";
            skeletonAnimation.Skeleton.SetSkin(newSkinName);
            skeletonAnimation.Skeleton.SetSlotsToSetupPose(); // 刷新插槽以更新换装后的显示
            skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
        }
    }
}

explain:

  • In the Start() method, we set the initial skin through skeletonAnimation.Skeleton.SetSkin(currentSkinName), where the "default" skin is used.
  • In the Update() method, when the "S" key is pressed, we switch to another skin via skeletonAnimation.Skeleton.SetSkin(newSkinName), here the "alternate" skin is used.
  • After switching the skin, in order to ensure that the new skin is displayed immediately in the scene, we also need to call skeletonAnimation.Skeleton.SetSlotsToSetupPose() to refresh the slot to update the display after the change. Finally, apply the changes to the animation state via skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton) .

6. Get the Transform information of the bone:

using Spine.Unity;
using UnityEngine;

public class SpineBoneTransform : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.G))
        {
            // 获取指定骨骼的Transform信息
            Bone bone = skeletonAnimation.Skeleton.FindBone("boneName");
            if (bone != null)
            {
                Vector3 bonePosition = new Vector3(bone.WorldX, bone.WorldY, 0f);
                Quaternion boneRotation = Quaternion.Euler(0f, 0f, bone.WorldRotationX);
                Vector3 boneScale = new Vector3(bone.WorldScaleX, bone.WorldScaleY, 1f);

                Debug.Log("Bone Position: " + bonePosition);
                Debug.Log("Bone Rotation: " + boneRotation.eulerAngles);
                Debug.Log("Bone Scale: " + boneScale);
            }
        }
    }
}

explain:

  • In the Update() method, we detect whether the "G" key is pressed through Input.GetKeyDown(KeyCode.G).
  • When the "G" key is pressed, we use skeletonAnimation.Skeleton.FindBone("boneName") to find the bone with the specified name (need to replace "boneName" with the actual bone name).
  • If the bone is found, we can use the bone's WorldX, WorldY, WorldRotationX and WorldScaleX, WorldScaleY properties to get the bone's position, rotation, and scale information. Note that these attributes represent the information of the bone in the world coordinate system.

7. Control the mixing and cross-fading of skeletal animation:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            // 播放动画1,并在1秒内淡入混合到目标动画
            skeletonAnimation.AnimationState.SetAnimation(0, "animation1", true);
        }

        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            // 播放动画2,并在0.5秒内交叉淡入混合到目标动画
            skeletonAnimation.AnimationState.SetAnimation(1, "animation2", true).MixDuration = 0.5f;
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Alpha1) and Input.GetKeyDown(KeyCode.Alpha2) to detect whether the number keys 1 and 2 are pressed.
  • When the number key 1 is pressed, we use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation1". Since MixDuration is not set, the default mixing time (usually 0.2 seconds) is used here.
  • When the number key 2 is pressed, we use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation2", and set the MixDuration to 0.5 seconds. This will cause Animation 2 and the currently playing animation to cross-fade into the blend within 0.5 seconds.

8. Control the speed of the animation:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public float animationSpeed = 1.0f;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            // 增加动画速度
            animationSpeed += 0.5f;
            skeletonAnimation.timeScale = animationSpeed;
        }

        if (Input.GetKeyDown(KeyCode.DownArrow))
        {
            // 减少动画速度,但不低于0.1
            animationSpeed -= 0.5f;
            animationSpeed = Mathf.Max(animationSpeed, 0.1f);
            skeletonAnimation.timeScale = animationSpeed;
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.UpArrow) and Input.GetKeyDown(KeyCode.DownArrow) to detect if the up and down arrow keys are pressed.
  • When the up arrow key is pressed, we increment the animationSpeed ​​variable and apply the new value to skeletonAnimation.timeScale, thereby increasing the playback speed of the animation.
  • When the down arrow key is pressed, we decrease the value of the animationSpeed ​​variable, making sure it never goes below 0.1, and then apply the new value to skeletonAnimation.timeScale, reducing the animation's playback speed.

9. Get animation status information:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        TrackEntry currentAnimation = skeletonAnimation.AnimationState.GetCurrent(0);
        if (currentAnimation != null)
        {
            Debug.Log("Current Animation: " + currentAnimation.Animation.Name);
            Debug.Log("Animation Time: " + currentAnimation.Time);
            Debug.Log("Animation Is Complete: " + currentAnimation.IsComplete);
        }
    }
}

explain:

  • In the Update() method, we get the currently playing animation state (TrackEntry) through skeletonAnimation.AnimationState.GetCurrent(0).
  • Then, we can get information about the current animation through the properties of TrackEntry, such as the name of the animation, the playing time of the animation, and whether the animation has been played.

10. Dynamically replace bone texture:

using Spine.Unity;
using UnityEngine;

public class SpineTextureReplacement : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    public Texture2D newTexture;
    public string slotName;

    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            // 获取插槽的当前Attachment并替换纹理
            Slot slot = skeletonAnimation.Skeleton.FindSlot(slotName);
            if (slot != null)
            {
                Attachment currentAttachment = slot.Attachment;
                if (currentAttachment is RegionAttachment)
                {
                    RegionAttachment regionAttachment = (RegionAttachment)currentAttachment;
                    regionAttachment.SetRegion(newTexture);
                    skeletonAnimation.Update(0f); // 强制更新以显示新纹理
                }
            }
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.T) to detect whether the "T" key is pressed.
  • When the "T" key is pressed, we find the slot with the specified name via skeletonAnimation.Skeleton.FindSlot(slotName) (need to replace "slotName" with the actual slot name).
  • Then, we get the current Attachment of the slot, and do a type check to make sure the Attachment is a RegionAttachment (a texture type Attachment).
  • If it's a RegionAttachment, we convert it to a RegionAttachment and use the SetRegion method to replace its texture with newTexture.
  • Since the Attachment is changed, we need to call skeletonAnimation.Update(0f) to force an update of the SkeletonAnimation so that the new texture is displayed in the scene.

11. Play the specified track of the Spine animation:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public int trackIndex = 0;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            // 播放动画1在指定轨道
            skeletonAnimation.AnimationState.SetAnimation(trackIndex, "animation1", true);
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Alpha1) to detect whether the number key 1 is pressed.
  • When the number key 1 is pressed, we use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation1" and specify trackIndex as the first parameter. trackIndex is the index of the track, used to play different animations on multiple tracks. By default, 0 is used as the track index.

12. Get the time and duration of the current animation:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public int trackIndex = 0;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        TrackEntry currentAnimation = skeletonAnimation.AnimationState.GetCurrent(trackIndex);
        if (currentAnimation != null)
        {
            float currentTime = currentAnimation.Time;
            float animationDuration = currentAnimation.Animation.Duration;

            Debug.Log("Current Animation Time: " + currentTime);
            Debug.Log("Animation Duration: " + animationDuration);
        }
    }
}

explain:

  • In the Update() method, we get the currently playing animation state (TrackEntry) through skeletonAnimation.AnimationState.GetCurrent(trackIndex).
  • We then use currentAnimation.Time to get the playing time of the current animation, and currentAnimation.Animation.Duration to get the total duration of the current animation.

13. Control animation loop times:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            // 播放动画1并设置循环次数
            TrackEntry trackEntry = skeletonAnimation.AnimationState.SetAnimation(0, "animation1", true);
            trackEntry.Loop = false; // 关闭循环
            trackEntry.LoopCount = 2; // 设置循环次数为2次
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Alpha1) to detect whether the number key 1 is pressed.
  • When the number key 1 is pressed, we use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation1" and get the returned TrackEntry.
  • Then, we can turn off the looping of the animation by setting the TrackEntry's Loop property to false.
  • At the same time, by setting the LoopCount property to 2 to specify the number of loops for the animation to be 2 times.

14. Dynamically change the weight of the animation blend:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            // 播放动画1并增加混合权重
            TrackEntry trackEntry = skeletonAnimation.AnimationState.SetAnimation(0, "animation1", true);
            trackEntry.Alpha = 0.5f; // 设置混合权重为0.5
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Alpha1) to detect whether the number key 1 is pressed.
  • When the number key 1 is pressed, we use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation1" and get the returned TrackEntry.
  • We can then adjust the animation's blend weight by setting the TrackEntry's Alpha property. Alpha ranges from 0 to 1, where 1 means the animation is fully displayed and 0 means the animation is completely hidden. In this example, we set the blend weight to 0.5 so that the animation blends with half the transparency.

15. Pause and resume all animation tracks:

using Spine.Unity;

public class SpineAnimationController : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 切换暂停和恢复动画
            bool isPaused = skeletonAnimation.timeScale == 0f;
            skeletonAnimation.timeScale = isPaused ? 1f : 0f;
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Space) to detect whether the space bar is pressed.
  • When the spacebar is pressed, we check to see if the current animation's timescale (timeScale) is 0. If it is 0, it means that the current animation is paused and we set the time scale to 1 to resume the animation. If it is not 0, it means that the current animation is playing, we set the time scale to 0 to pause the animation.

16. Dynamically create and replace the Attachment of the slot:

using Spine;
using Spine.Unity;
using UnityEngine;

public class SpineAttachmentReplacement : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public string slotName;
    public Sprite newSprite;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            // 获取插槽并替换Attachment为新的Sprite
            Slot slot = skeletonAnimation.Skeleton.FindSlot(slotName);
            if (slot != null)
            {
                Attachment currentAttachment = slot.Attachment;
                if (currentAttachment is RegionAttachment)
                {
                    RegionAttachment regionAttachment = (RegionAttachment)currentAttachment;
                    Material material = new Material(Shader.Find("Sprites/Default"));
                    Material newMaterial = new Material(material); // 复制原始Material
                    newMaterial.mainTexture = newSprite.texture; // 设置新的Sprite纹理
                    regionAttachment.GetRegion().RenderObject.SetMeshMaterial(newMaterial);
                    skeletonAnimation.Update(0f); // 强制更新以显示新Attachment
                }
            }
        }
    }
}
  • In the Update() method, we use Input.GetKeyDown(KeyCode.R) to detect if the 'R' key is pressed.
  • When the 'R' key is pressed, we find the slot with the specified name via skeletonAnimation.Skeleton.FindSlot(slotName) (need to replace 'slotName' with the actual slot name).
  • Then, we get the current Attachment of the slot and perform a type check to ensure that the Attachment is a RegionAttachment (attachment of texture type).
  • If it is a RegionAttachment, we create a new Material and assign the new Sprite texture to it.
  • Then, we use regionAttachment.GetRegion().RenderObject.SetMeshMaterial(newMaterial) to apply the new Material to the Attachment, and force call skeletonAnimation.Update(0f) to update the SkeletonAnimation to show the new Attachment.

17. Use Spine animation events to trigger Unity events:

using Spine.Unity;
using UnityEngine;
using UnityEngine.Events;

public class SpineAnimationEventTrigger : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    public UnityEvent onAnimationEvent;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);

        // 订阅动画事件
        skeletonAnimation.AnimationState.Event += HandleAnimationEvent;
    }

    private void HandleAnimationEvent(TrackEntry trackEntry, Spine.Event e)
    {
        if (e.Data.Name == "eventName") // 将"eventName"替换为实际动画中设置的事件名称
        {
            onAnimationEvent.Invoke(); // 触发Unity事件
        }
    }
}

explain:

  • In the Update() method, we use skeletonAnimation.AnimationState.Event += HandleAnimationEvent; to subscribe to animation events.
  • In the Start() method, we create a Unity event (UnityEvent), called onAnimationEvent. The event name set in the Spine animation (such as "eventName") needs to be replaced with the event name set in the actual animation.
  • When a Spine animation event is triggered, the HandleAnimationEvent method will be called. In this method, we check whether the name of the event matches the set name, and if so, trigger the Unity event onAnimationEvent.Invoke().

18. Control animation playback speed randomization:

using Spine.Unity;
using UnityEngine;

public class SpineRandomAnimationSpeed : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public float minSpeed = 0.8f;
    public float maxSpeed = 1.2f;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 播放动画,并随机设置播放速度
            float randomSpeed = Random.Range(minSpeed, maxSpeed);
            skeletonAnimation.timeScale = randomSpeed;
            skeletonAnimation.AnimationState.SetAnimation(0, "animation1", true);
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.Space) to detect whether the space bar is pressed.
  • When the space bar is pressed, we randomly generate a playback speed (randomSpeed) between minSpeed ​​and maxSpeed.
  • Then, we set the randomSpeed ​​to skeletonAnimation.timeScale to adjust the playback speed of the animation, and use skeletonAnimation.AnimationState.SetAnimation() to play the animation named "animation1".

19. Dynamically switch the Spine Atlas atlas:

using Spine;
using Spine.Unity;
using UnityEngine;

public class SpineAtlasSwitch : MonoBehaviour
{
    public TextAsset newAtlasText;
    public Material newMaterial;
    public SkeletonDataAsset skeletonDataAsset;

    private SkeletonData currentSkeletonData;
    private Atlas currentAtlas;

    void Start()
    {
        LoadNewAtlas();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            LoadNewAtlas();
        }
    }

    private void LoadNewAtlas()
    {
        if (currentAtlas != null)
        {
            currentAtlas.Dispose();
        }

        currentAtlas = new Atlas(newAtlasText, "", newMaterial);
        currentSkeletonData = SkeletonData.CreateFromatlas(currentAtlas);

        skeletonDataAsset.Clear();
        skeletonDataAsset.Reset();
        skeletonDataAsset.atlasAssets[0].materials[0] = newMaterial;
        skeletonDataAsset.atlasAssets[0].materials = new Material[] { newMaterial };
        skeletonDataAsset.skeletonJSON = new TextAsset(currentSkeletonData.Json.ToString());
        skeletonDataAsset.GetSkeletonData(true);

        skeletonDataAsset.GetSkeletonData(false).AssetAtPath("path/to/asset");

        skeletonDataAsset.GetSkeletonData(false).FindSlot("slotName");

        skeletonDataAsset.GetSkeletonData(false).FindAnimation("animationName");

        skeletonDataAsset.GetSkeletonData(false).FindSkin("skinName");
    }
}

explain:

  • This is a more complex use case for dynamically switching Spine Atlas atlases. We use Input.GetKeyDown(KeyCode.S) to detect whether the "S" key is pressed to trigger the switching of the atlas.
  • In the LoadNewAtlas() method, a new Atlas is loaded and a new SkeletonData is created. Then, update the SkeletonDataAsset to use the new Atlas and SkeletonData.

20. Create skeletal animation dynamically:

using Spine;
using Spine.Unity;
using UnityEngine;

public class SpineDynamicAnimation : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;
    public string newAnimationName;
    public AnimationReferenceAsset newAnimationReference;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.N))
        {
            // 动态创建并播放新的骨骼动画
            Animation newAnimation = new Animation(newAnimationName, newAnimationReference.GetAnimation().Timelines);
            skeletonAnimation.Skeleton.Data.AddAnimation(newAnimationName, newAnimation, skeletonAnimation.Skeleton.Data.FindAnimation(skeletonAnimation.AnimationState.GetCurrent(0).Animation.Name).Duration, true);

            skeletonAnimation.AnimationState.SetAnimation(1, newAnimationName, false);
        }
    }
}

explain:

  • In the Update() method, we use Input.GetKeyDown(KeyCode.N) to detect whether the "N" key is pressed.
  • When the "N" key is pressed, we dynamically create a new skeleton animation (newAnimation) and add it to the SkeletonData. Here newAnimationName and newAnimationReference are used as the name and reference animation of the new animation.
  • Then, we use skeletonAnimation.AnimationState.SetAnimation() to play the newly created animation.

21. Event monitoring and processing of skeletal animation:

using Spine;
using Spine.Unity;
using UnityEngine;

public class SpineAnimationEvent : MonoBehaviour
{
    public SkeletonDataAsset skeletonDataAsset;
    private SkeletonAnimation skeletonAnimation;

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonAnimation>();
        skeletonAnimation.skeletonDataAsset = skeletonDataAsset;
        skeletonAnimation.Initialize(true);

        // 订阅动画事件
        skeletonAnimation.AnimationState.Event += HandleAnimationEvent;
    }

    private void HandleAnimationEvent(TrackEntry trackEntry, Spine.Event e)
    {
        // 根据动画事件名称做相应处理
        if (e.Data.Name == "event_name_1")
        {
            Debug.Log("Event 1 triggered!");
            // 在这里添加处理事件1的逻辑
        }
        else if (e.Data.Name == "event_name_2")
        {
            Debug.Log("Event 2 triggered!");
            // 在这里添加处理事件2的逻辑
        }
    }
}

explain:

  • In the Update() method, we use skeletonAnimation.AnimationState.Event += HandleAnimationEvent; to subscribe to animation events.
  • In the HandleAnimationEvent method, we execute different processing logic according to the name of the animation event (such as "event_name_1" and "event_name_2"). You can add corresponding logic to respond to these events based on the event names set in the animation.

⚠️ NOTE: The usage here may vary depending on Spine version and Unity project structure. Please adjust it according to your specific situation.

8.unity-spine runtime library download

official website

local download

Guess you like

Origin blog.csdn.net/lalate/article/details/131794128