先在Unity里导入包com.unity.splines
工厂产线工件路线模拟,第一种连续整体动画,先创建路线轨迹。
使用脚本,将模型按照路线运动。
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Splines;
using Unity.Mathematics;
[ExecuteAlways]
public class CustomSplineAnimate : MonoBehaviour
{
[System.Serializable]
private struct StopPoint
{
public float time;
public float duration;
public AnimationType animationType; // 添加动画类型字段
public Animation animation; // 保留Animation字段
public Animator animator; // 添加Animator字段
public string animationName; // 添加动画名称字段
}
public enum AnimationType
{
Animation,
Animator
}
[SerializeField] private SplineContainer _spline;
[SerializeField] private float _duration;
[SerializeField] private float _startOffset;
[SerializeField] private StopPoint[] _stopPoints;
[Header("Preview")]
[SerializeField, Range(0, 1)] private float _previewTime;
private Transform _transform;
private float _time = 0;
private void Awake()
{
if (Application.isPlaying)
{
_transform = transform;
_time += _startOffset;
}
}
private void Start()
{
if (Application.isPlaying)
{
if (_spline != null && _duration > 0)
{
StartCoroutine(Animate());
}
}
}
private IEnumerator Animate()
{
bool[] isPassed = new bool[_stopPoints.Length];
float stopOverrun = 0;
for (int i = 0; i < _stopPoints.Length; i++)
{
if (_time > _stopPoints[i].time && !isPassed[i])
{
isPassed[i] = true;
}
}
while (true)
{
for (int i = 0; i < _stopPoints.Length; i++)
{
if (_time > _stopPoints[i].time && !isPassed[i])
{
isPassed[i] = true;
stopOverrun = _time - _stopPoints[i].time;
PlayAnimation(_stopPoints[i]); // 调用播放动画的方法
_time = _stopPoints[i].time;
SetPositionAndRotation(_time);
yield return new WaitForSeconds(_stopPoints[i].duration);
}
}
_time = _time + stopOverrun + Time.deltaTime / _duration;
stopOverrun = 0;
if (_time > 1)
{
_time %= 1;
for (int i = 0; i < isPassed.Length; i++)
{
isPassed[i] = false;
}
}
SetPositionAndRotation(_time);
yield return null;
}
}
private void PlayAnimation(StopPoint stopPoint)
{
switch (stopPoint.animationType)
{
case AnimationType.Animation:
if (stopPoint.animation != null)
{
stopPoint.animation.Play(); // 使用配置的动画名称
}
break;
case AnimationType.Animator:
if (stopPoint.animator != null)
{
stopPoint.animator.Play(stopPoint.animationName); // 使用配置的动画名称
}
break;
}
}
private void SetPositionAndRotation(float time)
{
Vector3 position = _spline.EvaluatePosition(time);
float3 tangent = _spline.EvaluateTangent(time);
_transform.position = position;
_transform.rotation = Quaternion.LookRotation(tangent, Vector3.up);
}
#if UNITY_EDITOR
private void Update()
{
if (!Application.isPlaying && _spline != null)
{
if (_transform == null)
{
_transform = transform;
}
SetPositionAndRotation(_previewTime);
}
}
#endif
}
配置动画信息。
这里遇到Animation 动画不执行问题。引用
默认是右上角点设置,改debug
勾上Legacy
再改成normal。最好复制一份动画文件,两者不可兼容。
动画状态机示例