• 【Unity】Timeline探索记(4)第二个例子——动作特写/子弹时间


    写在前面

    • 这次例子参考这篇实现博文(附带项目下载),博文前面介绍非常具体,可惜后面特写轨实现代码不是按照我想要的标准四大件(data、mixer、clip、track)来组织的,所以这里我略过介绍,只记录我在实现中遇到的问题。
    • 测试环境Unity2019.2.6:因为移动镜头用到了Cinemachine插件来实现,而该插件需要在Unity2018以上用Package安装(以前Cinemachine是放在Asset Store里的,现在已下架),Unity2017也不支持最新的Cinemachine,所以这里统一用Unity2019.2.6来测试。
    • 因为实现重点是“动作特写”,而不是研究Cinemachine,所以这里我没有去深入了解Cinemachine。

     记录

    • 用Cinemachine插件Create Virtual Camera后,MainCamera想要移动位置都要靠这个Virtual Camera/vcam,而且vcam要改变位置(位置+角度)只能在场景中手动调,不能直接改坐标。
    • 【问题1】在测试“动作特写”时,注视target的vcam的中心很低(见下图),而参考做的就很合适(见下下图),怎么回事?

    我做的测试:中心(黄线处)很低

    参考:别人做的位置(黄线处)就很合适

      ——> targetGroup是不能移动的。但我的测试中放的target是人物脚下(见下方左图),而参考放的target是人物的腰(见下方右图),所以中心不一致。

                        

    • 【问题2】人物加完动作后,是原地做动作,不是朝着敌人跑过去,怎么朝敌人跑过去?——> 解决方案就是加入override轨,在override轨记录人物的位置。
      • override轨如果mute的话,编辑时会看不到效果
      • 空白的override轨要先点录制,随便加入一个关键帧,后面双击override轨才能编辑效果
      • 我想过用MatchOffsets来改动作,但这功能是为了两个动作顺滑过渡用的,而人物要跑向敌人,这之间位移之大,是不能用MatchOffsets来完成的。
    • 【问题3】人物有rising和idle两个动作融合不好,有位移 ——> 解决方法同上。
    • 参考博文用Animation Curve来实现时间变速,实现了自定义特写轨,但它不按标准四大件data、mixer、clip、track来组织,只写了一个脚本,而且还覆盖了Unity暴露出的参考轨Playable Track。我给特写轨起名为Time,按标准四大件重新组织了代码,依次如下:
      • data:TimeBehaviour.cs
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Playables;
    
    
    [Serializable]
    public class TimeBehaviour : PlayableBehaviour
    {
        public AnimationCurve curve;
    
    }
      • mixer:TimeMixerBehaviour.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Playables;
    
    public class TimeMixerBehaviour : PlayableBehaviour
    {
        private float curTime = 0;
        private float maxTime = 0;
    
        public override void OnGraphStart(Playable playable)
        {
    
        }
    
        public override void OnGraphStop(Playable playable)
        {
            Time.timeScale = 1;
        }
    
        public override void OnBehaviourPlay(Playable playable, FrameData info)
        {
    
        }
    
        public override void OnBehaviourPause(Playable playable, FrameData info)
        {
    
        }
    
        public override void PrepareFrame(Playable playable, FrameData info)
        {
    
        }
    
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            float scale = 1;
            int inputCount = playable.GetInputCount();
            for (int i = 0; i < inputCount; i++)
            {
                float inputWeight = playable.GetInputWeight(i);
                if (!Mathf.Approximately(inputWeight, 0f))
                {
                    curTime += info.deltaTime;
                    ScriptPlayable<TimeBehaviour> inputPlayable = (ScriptPlayable<TimeBehaviour>)playable.GetInput(i);
                    TimeBehaviour input = inputPlayable.GetBehaviour();
                    // maxTime 当前clip的时长
                    maxTime = (float)PlayableExtensions.GetDuration(playable.GetInput(i));
                    // curTime 当前clip的执行到哪个时刻
                    scale = input.curve.Evaluate(curTime / maxTime);
                }
                else
                {
                    curTime = 0;
                }
            }
            Time.timeScale = scale;
    
        }
    
    }
      • clip:TimeClip.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Playables;
    using UnityEngine.Timeline;
    
    [System.Serializable]
    public class TimeClip : PlayableAsset, ITimelineClipAsset
    {
        public TimeBehaviour template = new TimeBehaviour();
    
        public ClipCaps clipCaps
        {
            get
            {
                return ClipCaps.Blending; //选择None,clip当然不会支持快捷键淡入淡出操作
            }
        }
    
        public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
        {
            var playable = ScriptPlayable<TimeBehaviour>.Create(graph, template);
            return playable;
    
        }
    
    }
      • track:TimeTrack.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Playables;
    using UnityEngine.Timeline;
    using UnityEngine.UI;
    
    [TrackColor(0.898f, 0.701f, 0.207f)]
    [TrackClipType(typeof(TimeClip))]
    [System.Serializable]
    public class TimeTrack : TrackAsset
    {
        public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
        {
            return ScriptPlayable<TimeMixerBehaviour>.Create(graph, inputCount);
    
        }
    
        public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
        {
            base.GatherProperties(director, driver);
    
        }
    }
    • 和博文的参考代码相比,我的代码修改重点:
      • 【重点1】如下图,博文这里的maxTime:因为不用mixer脚本,所以maxTime可以直接拿到当前clip的时长;

    博文的maxTime

      我写的mixer脚本如下图,maxTime应该像这样取值才行。如果像博文那样写,得到的maxTime会是无穷尽。

     我写的maxTime

      • 【重点2】如下图,博文这里的curTime会得到当前clip的进行时刻,意味着没有clip或切到下一个clip时,curTime会变为0;

    博文的curTime

      我写的curTime如下图,应该像这样取值才会拿到当前clip的进行时刻。

  • 相关阅读:
    python操作redis之hash操作
    mongodb数据库分片实现链接
    python连接redis数据库的两种方式
    python操作rabbitmq实现消息过滤接收
    python操作rabbitmq实现广播效果
    关于java和python同时使用rabbitmq时队列同名问题的探讨
    java操作rabbitmq实现简单的消息发送(socket编程的升级)
    python使用rabbitmq实现简单的消息转发
    optiongroup标签选项组
    day05_日常SQL练习(一)
  • 原文地址:https://www.cnblogs.com/caiger-blog/p/13754738.html
Copyright © 2020-2023  润新知