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