Unity中对Spine动画播放、暂停、事件处理管理类

Unity中对Spine动画播放、暂停、事件处理管理类

介绍

最近在做设计spine动画的抖音小程序,正好借此机会分享一下我对Spine动画的管理等相关知识,我们公司使用的是Spine4.0.64开发的动画,Unity使用的是Spine4.0,这里不分享spine的导入等其他操作了,如果想要了解可以看一下我之前的Unity如何使用Spine动画导出的动画文章。

Spine的事件处理

动画师制作沟通

这个地方动画师是需要跟unity前端沟通好,因为事件本身是在做动画的时候插入的,所以事件的时间节点和事件名称都需要提前定义好(事件的用法也会有很多,我们通常是攻击卡帧的时候需要)。如下图所示动画的事件。

Unity前端使用事件

当动画师将编辑好的事件动画给到Unity前段后的使用方式如下

csharp 复制代码
//动画开始时执行开始事件
skeleton.AnimationState.Start += (t)=> 
{
    Debug.LogError("开始事件");
};
//中断或者结束都触发结束事件
skeleton.AnimationState.End += (t) =>
{
    Debug.LogError("结束事件");
};
//播放完成事件
skeleton.AnimationState.Complete += (t) =>
{
    Debug.LogError("动画播放完成");
};
//在Spine软件中制作动画时添加的自定义事件
skeleton.AnimationState.Event += (t, e) =>
{
    Debug.LogError("自定义事件 e.Time = " + e.Time + " , e = " + e.ToString());
};

当调用该动画时会执行自定义事件打印如下

Unity中动画播放

csharp 复制代码
skeleton.timeScale = timeScale;
skeleton.AnimationState.SetAnimation(trackIndex, animName, loop);

Unity中动画暂定和继续

csharp 复制代码
//暂停
skeleton.timeScale = 0;
//继续
skeleton.timeScale = 1;

Unity中停止动画

注意这里是将动画恢复至默认开始状态那一帧

csharp 复制代码
skeleton.AnimationState.SetEmptyAnimation(trackIndex, mixDuration);

Unity中动画转向

csharp 复制代码
skeleton.Skeleton.ScaleX = x;

Unity中获取骨骼和设置插槽附件

csharp 复制代码
//获取骨骼
Bone b = skeleton.Skeleton.FindBone(boneName);

skeleton.Skeleton.SetAttachment(slotName, attachmentName);

完整管理类分享

csharp 复制代码
using Spine;
using Spine.Unity;
using System;
using System.Net.Mail;
using UnityEngine;
using static Spine.AnimationState;

/// <summary>
/// Spine动画控制器
/// </summary>
public class SpineAnimManager : Singleton<SpineAnimManager>
{
    private TrackEntryDelegate ac = null;

    /// <summary>
    /// 播放动画
    /// </summary>
    /// <param name="skeleton">骨骼</param>
    /// <param name="action">回调</param>
    /// <param name="trackIndex"></param>
    /// <param name="animName">动画名</param>
    /// <param name="loop">是否循环</param>
    /// <param name="timeScale">时间缩放</param>
    public void PlayAnim(SkeletonGraphic skeleton, Action action, int trackIndex, string animName, bool loop, float timeScale = 1)
    {
        if (skeleton != null)
        {
            PlayAnim(skeleton, trackIndex, animName, loop, timeScale);
            if (action != null)
            {
                ac = delegate
                {
                    action?.Invoke();
                    skeleton.AnimationState.Complete -= ac;
                    ac = null;
                };
                skeleton.AnimationState.Complete += ac;
            }
        }
    }

    /// <summary>
    /// 停止播放动画
    /// </summary>
    /// <param name="sg"></param>
    /// <param name="trackIndex"></param>
    /// <param name="mixDuration"></param>
    public void StopAnim(SkeletonGraphic sg, int trackIndex, float mixDuration) 
    {
        //sg.Clear();--开启这个则动画和对象都消失
        sg.AnimationState.SetEmptyAnimation(trackIndex, mixDuration);
    }

    /// <summary>
    /// 暂停动画
    /// </summary>
    /// <param name="sg"></param>
    public void PauseAnim(SkeletonGraphic sg) 
    {
        sg.timeScale = 0;
    }

    /// <summary>
    /// 继续动画
    /// </summary>
    /// <param name="sg"></param>
    public void ResumeAnim(SkeletonGraphic sg) 
    {
        sg.timeScale = 1;
    }

    /// <summary>
    /// 设置动画时间缩放
    /// </summary>
    /// <param name="sg"></param>
    /// <param name="timeScale"></param>
    public void SetAnimTimeScale(SkeletonGraphic sg, float timeScale) 
    {
        sg.timeScale = timeScale;
    }

    /// <summary>
    /// 播放动画
    /// </summary>
    /// <param name="skeleton"></param>
    /// <param name="trackIndex"></param>
    /// <param name="animName"></param>
    /// <param name="loop"></param>
    /// <param name="timeScale"></param>
    public void PlayAnim(SkeletonGraphic skeleton, int trackIndex, string animName, bool loop, float timeScale = 1) 
    {
        if (skeleton != null)
        {
            skeleton.timeScale = timeScale;
            skeleton.AnimationState.SetAnimation(trackIndex, animName, loop);
        }
    }

    /// <summary>
    /// 动画添加事件
    /// </summary>
    /// <param name="skeleton"></param>
    /// <param name="startCall"></param>
    /// <param name="endCall"></param>
    /// <param name="completeCall"></param>
    /// <param name="eventCall"></param>
    public void AddEvent(SkeletonGraphic skeleton,Action<TrackEntry> startCall,Action<TrackEntry> endCall, Action<TrackEntry> completeCall, Action<TrackEntry, Spine.Event> eventCall) 
    {
        if (skeleton != null) 
        {
            skeleton.AnimationState.Start += (t)=> 
            {
                Debug.LogError("开始事件");
                startCall?.Invoke(t); 
            };
            //中段结束都算
            skeleton.AnimationState.End += (t) =>
            {
                Debug.LogError("结束事件");
                endCall?.Invoke(t);
            };
            //播放完成
            skeleton.AnimationState.Complete += (t) =>
            {
                Debug.LogError("动画播放完成");
                completeCall?.Invoke(t);
            };
            //在Spine软件中制作动画时添加的自定义事件
            skeleton.AnimationState.Event += (t, e) =>
            {
                Debug.LogError("自定义事件 e.Time = " + e.Time + " , e = " + e.ToString());
                eventCall?.Invoke(t,e);
            };
        }
    }

    /// <summary>
    /// 转向
    /// </summary>
    public void Rotate(SkeletonGraphic skeleton, float x) 
    {
        skeleton.Skeleton.ScaleX = x;
    }

    /// <summary>
    /// 获取骨骼、设置插槽附件
    /// </summary>
    /// <param name="skeleton"></param>
    /// <param name="slotName">插槽</param>
    /// <param name="boneName">骨骼名</param>
    /// <param name="attachmentName">特性</param>
    public void GetBone(SkeletonGraphic skeleton,string slotName, string boneName, string attachmentName) 
    {
        //获取骨骼
        Bone b = skeleton.Skeleton.FindBone(boneName);

        skeleton.Skeleton.SetAttachment(slotName, attachmentName);
    }

    /// <summary>
    /// 队列播放spine动画
    /// </summary>
    /// <param name="skeleton">spine组件</param>
    /// <param name="startFunc">动画开始的时候调用的方法</param>
    /// <param name="endFunc">动画结束的时候调用的方法</param>
    /// <param name="trackIndex">轨道索引(通过索引可实现多个动画同时播放)</param>
    /// <param name="animName">动画名字</param>
    /// <param name="loop">是否循环播放</param>
    /// <param name="timeScale">动画速度0-1</param>
    /// <param name="delay">动画播放完毕延迟时间</param>
    public void QueuePlayAni(SkeletonGraphic skeleton, Action startFunc, Action endFunc, int trackIndex, string animName, bool loop, float timeScale = 1, float delay = 0f)
    {
        if (skeleton != null)
        {
            TrackEntry tr = skeleton.AnimationState.AddAnimation(trackIndex, animName, loop, delay);
            if (startFunc != null)
                tr.Start += (sp) =>
                {
                    startFunc.Invoke();
                };
            if (endFunc != null)
                tr.Complete += (sp) =>
                {
                    endFunc.Invoke();
                };
        }
    }
}

总结

上述是我对Spine的一些控制和理解,希望可以帮助到大家。感谢大家的支持。

相关推荐
牙膏上的小苏打23334 小时前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
Unity大海6 小时前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
浅陌sss11 小时前
Unity中 粒子系统使用整理(一)
unity·游戏引擎
维度攻城狮16 小时前
实现在Unity3D中仿真汽车,而且还能使用ros2控制
python·unity·docker·汽车·ros2·rviz2
为你写首诗ge19 小时前
【Unity网络编程知识】FTP学习
网络·unity
神码编程21 小时前
【Unity】 HTFramework框架(六十四)SaveDataRuntime运行时保存组件参数、预制体
unity·编辑器·游戏引擎
菲fay1 天前
Unity 单例模式写法
unity·单例模式
火一线1 天前
【Framework-Client系列】UIGenerate介绍
游戏·unity
ZKY_241 天前
【工具】Json在线解析工具
unity·json
ZKY_241 天前
【Unity】处理文字显示不全的问题
unity·游戏引擎