贪吃小怪兽介绍之动画同步

21 篇文章 1 订阅
17 篇文章 0 订阅

自己写一个Animation叫GAnimation,用组件的方式添加到Player类中,这不是一个框架,而是一个类似于状态机的东西,我使用的是Animation动画,然后给每个动画定义优先级,比如攻击的优先级小于被攻击,即是说一个人的攻击可以被打断,类似这样的。辅助类有Trigger和GAnimationClip(带动画帧事件)。如何做到同步,如果数据是同步的,那么我只要根据数据来一帧一帧播放,来一个数据包就播放一帧,因为状态机是我写的,所以他的状态转移是确定的(或者说精确的)。现在只要精确播放动画的哪一帧即可,精确的播放只要利用Animation的NormalizeTime,比如我现在播放Idle动画,长度是30帧,现在来一个数据包,那我就播放第一帧,设置的NormalizeTime = 1.0f/30,再来一帧,播放第二帧,NormalizeTime = 2.0f/30,动画的长度和名字均可通过配置管理器加载,这样就可以操纵动画播放到哪里了。因为每一帧都是整数,所以也可以精确触发动画帧事件。这样动画就同步了。

注意:因为网络卡了没有数据包,动画是不该继续播放的,所以Animation在初始化的时候要把每一个AnimationClip的Speed设置为0,这样他就不会自己播放了。附上代码,状态转移那里可以不看,因为我想歪了把配置文件的AnimationState和这里的AnimStatement分开了,其实是可以合并的,很乱。

namespace Eating.Module.Game.Component
{
    /// <summary>
    /// 只有第一次get的时候才翻转,而不是每get一次就翻转一次
    /// </summary>
    public class Trigger
    {
        private bool _isFirstTimeToGet;
        private bool _val;
        public bool Value
        {
            get
            {
                if (_isFirstTimeToGet)
                {
                    _isFirstTimeToGet = !_isFirstTimeToGet;
                    bool temp = _val;
                    _val = !_val;
                    return temp;
                }
                return _val;
            }
            set
            {
                _val = value;
                _isFirstTimeToGet = true;
            }
        }
    }
    public class GAnimationClip
    {
        //private int _frameCount;

        public int FrameCount;
        public int CurFrame;
        /// <summary>
        /// 动画帧事件
        /// </summary>
        public Dictionary<int, Action> FrameEvent;

        public bool IsRoop;
        public GAnimationClip(bool isRoop)
        {
            CurFrame = 0;
            FrameEvent = new Dictionary<int, Action>();
            IsRoop = isRoop;
        }
    }
    public class GAnimation : IComponent
    {
        enum AnimStatement
        {
            Idle,
            Attack,
            Damage,
            Move,
            Die,
        };
        //父对象的Animation
        public Dictionary<int, string> AnimClipID;
        //动画播放的信息
        private  Dictionary<int, GAnimationClip> _animInfo;
        private bool _isInit = false;
        private Player _player;
        private AnimStatement _animStatement;

        public Trigger IsDamage;
        public Trigger IsDead;
        public void Release()
        {
            _isInit = false;
            _player = null;
            AnimClipID = null;
            _animInfo = null;
        }

        public GAnimationClip GetClip(int ID)
        {
            return _animInfo[ID];
        }

        public void Init(object arg = null)
        {
            if (_isInit)
            {
                this.LogWarning("Init() Has Been Inited");
                return;
            }
            IsDamage =new Trigger();
            IsDead = new Trigger();
            _animStatement = AnimStatement.Idle;
            Player player = (Player) arg;
            if (player == null)
            {
                this.LogError("Init() arg Is Null!");
                return;
            }
            _isInit = true;
            _player = player;
            AnimClipID = ConfigManager.Instance.GetMonsterAnimClipName();
            _animInfo = ConfigManager.Instance.GetAnimationClipsInfo();
        }

        public void UpdateFrame(FClientKey fk = null)
        {
            HandleAnim(fk);
            SetPlayerAnimState();
        }

        private void SetPlayerAnimState()
        {
            _player.AnimName = AnimClipID[GetID(_animStatement)];
            _player.AnimNormalizeTime = 1.0f * _animInfo[GetID(_animStatement)].CurFrame
                                        / _animInfo[GetID(_animStatement)].FrameCount;
        }

        private void HandleAnim(FClientKey fk = null)
        {
            if (IsDead.Value && _animStatement != AnimStatement.Die)
            {
                ResetCurStatement();
                _animStatement = AnimStatement.Die;
            }
            if (_animStatement == AnimStatement.Die)
            {
                PlayCurAnim();
            }
            else
            {
                //这个做成trigger把
                if (IsDamage.Value)
                {
                    ResetCurStatement();
                    _animStatement = AnimStatement.Damage;
                }
                if (_animStatement == AnimStatement.Damage)
                {
                    bool isEnding = PlayCurAnim();
                    if (isEnding)
                    {
                        HandleAttackAnim(fk);
                    }
                    else this.Log("Damage");
                }
                else
                {
                    HandleAttackAnim(fk);
                }
            }
        }

        private void HandleAttackAnim(FClientKey fk = null)
        {
            //攻击中 忽略重复的攻击
            if (_animStatement == AnimStatement.Attack)
            {
                bool isEnding = PlayCurAnim();
                if (isEnding)
                {
                    HandleMoveAnim(fk);
                }
            }
            //正在开始攻击
            else if (fk != null && fk.IsAttack)
            {
                ResetCurStatement();
                EnterNewState(AnimStatement.Attack);
            }
            //不在攻击中,检查移动
            else
            {
                HandleMoveAnim(fk);
            }
        }

        private void HandleMoveAnim(FClientKey fk = null)
        {
            //没有移动
            if (fk == null || (fk.MoveX == 0 && fk.MoveY == 0))
            {
                if (_animStatement != AnimStatement.Idle)
                {
                    ResetCurStatement();
                    EnterNewState(AnimStatement.Idle);
                }
                else PlayCurAnim();
            }
            else
            {
                //x和y有值
                if (_animStatement != AnimStatement.Move)
                {
                    ResetCurStatement();
                    EnterNewState(AnimStatement.Move);
                }
                else
                {
                    PlayCurAnim();
                }
            }
        }
        //把AnimStatement转化为AnimClipNameDef
        private int GetID(AnimStatement statement)
        {
            int id = -1;
            if (statement
                == AnimStatement.Idle)
            {
                id = AnimClipNameDef.IDLE;
            }
            else if (statement
                     == AnimStatement.Attack)
            {
                id = AnimClipNameDef.ATTACK;
            }
            else if (statement
                     == AnimStatement.Damage)
            {
                id = AnimClipNameDef.DAMAGE;
            }
            else if (statement
                     == AnimStatement.Move)
            {
                id = AnimClipNameDef.MOVE;
            }
            else if (statement
                     == AnimStatement.Die)
            {
                id = AnimClipNameDef.DEAD;
            }
            return id;
        }
        private bool PlayCurAnim()
        {
            int id = GetID(_animStatement);
            //如果已经播放完这个动画而且不是一个循环动画
            //就该播放其他动画了
            //则通知调用者播放其他动画比如IDLE或者MOVE
            
            if (_animInfo[id].CurFrame == _animInfo[id].FrameCount && !_animInfo[id].IsRoop)
            {
                return true;
            }
            _animInfo[id].CurFrame %= _animInfo[id].FrameCount;
            _animInfo[id].CurFrame++;
            if (_animInfo[id].FrameEvent.ContainsKey(_animInfo[id].CurFrame))
            {
                _animInfo[id].FrameEvent[_animInfo[id].CurFrame].Invoke();
            }
            return false;
        }
        private void EnterNewState(AnimStatement statement)
        {
            int id = GetID(statement);
            if (id == -1)
            {
                this.LogError("EnterNewState() No Such Statement In AnimClipNameDef. statement:{0}!",
                    statement.ToString());
                return;
            }
            _animStatement = statement;
            PlayCurAnim();
        }
        private void ResetCurStatement()
        {
            _animInfo[GetID(_animStatement)].CurFrame = 0;
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值