Dotween路径转为Animation

  世界上总有各种奇怪的需求, 这不就来了吗.

  "把DotweenPath编辑的路径, 转为动画"...

    public static DOTweenPath doTweenPath;
    public static bool keep_y = true;
    public static bool markOriginDir = true;
    public const float insertInter = 0.95f;
    public const float minTime = 0.1f;

    public List<Keyframe> positionKeyFrames = new List<Keyframe>();
    public List<Keyframe> rotationKeyFrames = new List<Keyframe>();

   public static void BakeInNotPlayEditor(string saveFile, DOTweenPath path, AnimationClip exists = null)
    {
        var clip = exists ? exists : new AnimationClip();
        clip.ClearCurves();

        clip.name = path.gameObject.name;
        clip.legacy = false;

        List<Keyframe> position_X_KeyFrames = new List<Keyframe>();
        List<Keyframe> position_Y_KeyFrames = new List<Keyframe>();
        List<Keyframe> position_Z_KeyFrames = new List<Keyframe>();

        List<Keyframe> rotation_X_KeyFrames = new List<Keyframe>();
        List<Keyframe> rotation_Y_KeyFrames = new List<Keyframe>();
        List<Keyframe> rotation_Z_KeyFrames = new List<Keyframe>();

        var startPoint = path.transform.position;
        var wps = new List<Vector3>() { startPoint };
        wps.AddRange(path.wps);
        if (keep_y)
        {
            for (int i = 0; i < wps.Count; i++)
            {
                var p = wps[i];
                wps[i] = new Vector3(p.x, startPoint.y, p.z);
            }
        }
        var totalLen = CaculateLen(wps);
        var speed = totalLen / path.duration;
        var time = 0f;
        var startRot = path.transform.localRotation;
        var lastDir = path.transform.forward;

        if (wps != null && wps.Count > 1)
        {
            var start = path.transform.position;
            if (markOriginDir)
            {
                lastDir.y = 0;
                var nextDir = wps[1] - start;
                nextDir.y = 0;
                startRot = (Quaternion.FromToRotation(lastDir, nextDir) * startRot);
                AddKeyFrame_Rot(rotation_X_KeyFrames, rotation_Y_KeyFrames, rotation_Z_KeyFrames, time, startRot);
            }


            AddKeyFrame_Pos(position_X_KeyFrames, position_Y_KeyFrames, position_Z_KeyFrames, time, start);
            AddKeyFrame_Rot(rotation_X_KeyFrames, rotation_Y_KeyFrames, rotation_Z_KeyFrames, time, startRot);
            for (int i = 1; i < wps.Count; i++)
            {
                var p = wps[i];
                var dis = Vector3.Distance(start, p);
                var lastTime = time;
                time += (dis / speed);
                AddKeyFrame_Pos(position_X_KeyFrames, position_Y_KeyFrames, position_Z_KeyFrames, time, p);
                var insertTime = Mathf.Lerp(lastTime, time, insertInter);
                var gapTime = time - insertTime;
                if (gapTime > minTime)
                {
                    insertTime = time - minTime;
                }
                AddKeyFrame_Rot(rotation_X_KeyFrames, rotation_Y_KeyFrames, rotation_Z_KeyFrames, insertTime, startRot);

                var nextIndex = i + 1;
                if (nextIndex < wps.Count)
                {
                    lastDir = p - start;
                    lastDir.y = 0;
                    var nextPoint = wps[nextIndex];
                    var nextDir = nextPoint - p;
                    nextDir.y = 0;
                    startRot = (Quaternion.FromToRotation(lastDir, nextDir) * startRot);
                    AddKeyFrame_Rot(rotation_X_KeyFrames, rotation_Y_KeyFrames, rotation_Z_KeyFrames, time, startRot);
                }

                start = p;
            }
        }

        clip.SetCurve("", typeof(Transform), "localPosition.x", SetCurveLinear(new AnimationCurve(position_X_KeyFrames.ToArray())));
        clip.SetCurve("", typeof(Transform), "localPosition.y", SetCurveLinear(new AnimationCurve(position_Y_KeyFrames.ToArray())));
        clip.SetCurve("", typeof(Transform), "localPosition.z", SetCurveLinear(new AnimationCurve(position_Z_KeyFrames.ToArray())));

        clip.SetCurve("", typeof(Transform), "localEulerAngles.x", SetCurveLinear(new AnimationCurve(rotation_X_KeyFrames.ToArray())));
        clip.SetCurve("", typeof(Transform), "localEulerAngles.y", SetCurveLinear(new AnimationCurve(rotation_Y_KeyFrames.ToArray())));
        clip.SetCurve("", typeof(Transform), "localEulerAngles.z", SetCurveLinear(new AnimationCurve(rotation_Z_KeyFrames.ToArray())));

        var filePath = FilePathToAssetPath(saveFile);
        Debug.Log(filePath);
        if (exists == false)
        {
            AssetDatabase.CreateAsset(clip, filePath);
        }
        BackUpToFile(filePath);

        Save();

        Selection.activeObject = AssetDatabase.LoadAssetAtPath<Object>(filePath);
    }

    private static void AddKeyFrame_Pos(List<Keyframe> x, List<Keyframe> y, List<Keyframe> z, float time, Vector3 vec3)
    {
        x.Add(new Keyframe(time, vec3.x));
        y.Add(new Keyframe(time, vec3.y));
        z.Add(new Keyframe(time, vec3.z));
    }
    private static void AddKeyFrame_Rot(List<Keyframe> x, List<Keyframe> y, List<Keyframe> z, float time, Quaternion q)
    {
        var eular = q.eulerAngles;
        x.Add(new Keyframe(time, eular.x));
        y.Add(new Keyframe(time, eular.y));
        z.Add(new Keyframe(time, eular.z));
    }

    public static AnimationCurve SetCurveLinear(AnimationCurve curve)
    {
        for (int i = 0; i < curve.keys.Length; ++i)
        {
            float intangent = 0;
            float outtangent = 0;
            bool intangent_set = false;
            bool outtangent_set = false;
            Vector2 point1;
            Vector2 point2;
            Vector2 deltapoint;
            Keyframe key = curve[i];

            if (i == 0)
            {
                intangent = 0;
                intangent_set = true;
            }

            if (i == curve.keys.Length - 1)
            {
                outtangent = 0;
                outtangent_set = true;
            }

            if (!intangent_set)
            {
                point1.x = curve.keys[i - 1].time;
                point1.y = curve.keys[i - 1].value;
                point2.x = curve.keys[i].time;
                point2.y = curve.keys[i].value;

                deltapoint = point2 - point1;

                intangent = deltapoint.y / deltapoint.x;
            }
            if (!outtangent_set)
            {
                point1.x = curve.keys[i].time;
                point1.y = curve.keys[i].value;
                point2.x = curve.keys[i + 1].time;
                point2.y = curve.keys[i + 1].value;

                deltapoint = point2 - point1;

                outtangent = deltapoint.y / deltapoint.x;
            }

            key.inTangent = intangent;
            key.outTangent = outtangent;
            curve.MoveKey(i, key);
        }
        return curve;
    }

    private static float CaculateLen(List<Vector3> points)
    {
        float len = 0f;
        if(points != null && points.Count > 1)
        {
            var start = points[0];
            for(int i = 1; i < points.Count; i++)
            {
                var p = points[i];
                len += Vector3.Distance(start, p);
                start = p;
            }
        }
        return len;
    }

  有那么几个问题, 一个是如果计算朝向, 顺着路径的方向, 就不能直接设置Transform因为物体的初始方向并不是跟你要的朝向相同的.

  还有一个问题是旋转的插值问题, 在Waypoint的地方才进行旋转的话, 必须要在前后补帧, 要不然它就会在路径中插值了, 成了边走边转.

  还有一个就是AnimationCurve的线性设置, 需要设置两头的tangent

posted @ 2022-08-22 09:33  tiancaiKG  阅读(99)  评论(0编辑  收藏  举报