359 lines
13 KiB
C#
359 lines
13 KiB
C#
using Cinemachine;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.Serialization;
|
||
|
||
namespace game
|
||
{
|
||
[ExecuteAlways]
|
||
[DisallowMultipleComponent]
|
||
public class CameraFollowPathMoveController : MonoBehaviour
|
||
{
|
||
/// <summary>The path to follow</summary>
|
||
[Tooltip("The path to follow")]
|
||
public CinemachinePath Path;
|
||
|
||
[Tooltip("路径停歇点索引,循环执行。eg:5个点,执行到最后一个位置会从移动到初始位置开始。")]
|
||
public List<int> m_RestIndexList = new List<int>();
|
||
|
||
[Tooltip("磁性距离,距离目标点一定距离,即认为到达目标点。")]
|
||
public float m_MagneticDistance = 0.01f;
|
||
|
||
[Tooltip("一直移动,可以查看整个移动过程,主要用于本地测试。发包时关闭。")]
|
||
public bool IsAlwaysMoving = false;
|
||
|
||
[Tooltip("是否开启测试停歇点,配合TestRestIndex使用,主要用于本地测试。发包时关闭。")]
|
||
public bool m_IsTestRest = false;
|
||
[Tooltip("测试用停歇点索引,配合IsTestRest使用,默认为-1,在0-停歇点索引位之间生效。")]
|
||
public int m_TestRestIndex = -1;
|
||
|
||
/// <summary>This enum defines the options available for the update method.</summary>
|
||
public enum UpdateMethod
|
||
{
|
||
/// <summary>Updated in normal MonoBehaviour Update.</summary>
|
||
Update,
|
||
/// <summary>Updated in sync with the Physics module, in FixedUpdate</summary>
|
||
FixedUpdate,
|
||
/// <summary>Updated in normal MonoBehaviour LateUpdate</summary>
|
||
LateUpdate
|
||
};
|
||
|
||
/// <summary>When to move the cart, if Velocity is non-zero</summary>
|
||
[Tooltip("When to move the cart, if Velocity is non-zero")]
|
||
public UpdateMethod m_UpdateMethod = UpdateMethod.Update;
|
||
|
||
/// <summary>How to interpret the Path Position</summary>
|
||
[Tooltip("How to interpret the Path Position. If set to Path Units, values are as follows: 0 represents the first waypoint on the path, 1 is the second, and so on. Values in-between are points on the path in between the waypoints. If set to Distance, then Path Position represents distance along the path.")]
|
||
[HideInInspector] public CinemachinePathBase.PositionUnits m_PositionUnits = CinemachinePathBase.PositionUnits.Distance;
|
||
|
||
/// <summary>Move the cart with this speed</summary>
|
||
[Tooltip("Move the cart with this speed along the path. The value is interpreted according to the Position Units setting.")]
|
||
[FormerlySerializedAs("m_Velocity")]
|
||
public float Speed;
|
||
|
||
/// <summary>The cart's current position on the path, in distance units</summary>
|
||
[Tooltip("The position along the path at which the cart will be placed. This can be animated directly or, if the velocity is non-zero, will be updated automatically. The value is interpreted according to the Position Units setting.")]
|
||
[FormerlySerializedAs("m_CurrentDistance")]
|
||
[HideInInspector] public float m_Position;
|
||
|
||
private enum MoveState
|
||
{
|
||
Stationary,
|
||
Moving
|
||
}
|
||
private MoveState m_State = MoveState.Stationary;
|
||
private int m_MoveIndex = 0;
|
||
private int m_CurPathIndex = 0;
|
||
//private int m_MoveDirection = 0;
|
||
|
||
void Awake()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (Path != null)
|
||
{
|
||
ResamplePath();
|
||
JumpToRestIndex(0);
|
||
SetCartPosition(0f);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
void FixedUpdate()
|
||
{
|
||
if (m_State == MoveState.Stationary && !IsAlwaysMoving) return;
|
||
if (m_UpdateMethod == UpdateMethod.FixedUpdate)
|
||
SetCartPosition(m_Position + Speed * Time.deltaTime);
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
CheckTestRest();
|
||
if (m_State == MoveState.Stationary && !IsAlwaysMoving) return;
|
||
float speed = Application.isPlaying ? Speed : 0;
|
||
if (m_UpdateMethod == UpdateMethod.Update)
|
||
SetCartPosition(m_Position + speed * Time.deltaTime);
|
||
}
|
||
|
||
void LateUpdate()
|
||
{
|
||
if (m_State == MoveState.Stationary && !IsAlwaysMoving) return;
|
||
if (!Application.isPlaying)
|
||
SetCartPosition(m_Position);
|
||
else if (m_UpdateMethod == UpdateMethod.LateUpdate)
|
||
SetCartPosition(m_Position + Speed * Time.deltaTime);
|
||
}
|
||
|
||
public void ResetAndInit(CinemachinePath followPath, List<int> restIndexList, float magneticDistance)
|
||
{
|
||
if (followPath == null || restIndexList == null) return;
|
||
|
||
if (Path)
|
||
{
|
||
Path = null;
|
||
}
|
||
|
||
if (m_RestIndexList != null)
|
||
{
|
||
m_RestIndexList = null;
|
||
}
|
||
|
||
m_MagneticDistance = magneticDistance;
|
||
Path = followPath;
|
||
m_RestIndexList = restIndexList;
|
||
|
||
ResamplePath();
|
||
}
|
||
|
||
void SetCartPosition(float distanceAlongPath)
|
||
{
|
||
if (Path != null)
|
||
{
|
||
m_Position = Path.StandardizeUnit(distanceAlongPath, m_PositionUnits);
|
||
if (!IsAlwaysMoving) m_Position = CheckPosition(distanceAlongPath, m_Position);
|
||
transform.position = Path.EvaluatePositionAtUnit(m_Position, m_PositionUnits);
|
||
transform.rotation = Path.EvaluateOrientationAtUnit(m_Position, m_PositionUnits);
|
||
}
|
||
}
|
||
private void CheckTestRest()
|
||
{
|
||
if (m_IsTestRest)
|
||
{
|
||
if (m_TestRestIndex >= 0 && m_TestRestIndex < m_RestIndexList.Count)
|
||
{
|
||
m_MoveIndex = m_TestRestIndex;
|
||
if (!IsEffective()) return;
|
||
GoToPositionIndex(m_RestIndexList[m_MoveIndex]);
|
||
}
|
||
}
|
||
}
|
||
|
||
List<Vector3[]> m_RestPointDistance = new List<Vector3[]>();
|
||
private void ResamplePath()
|
||
{
|
||
int stepsPerSegment = Path.DistanceCacheSampleStepsPerSegment;
|
||
float minPos = Path.MinPos;
|
||
float maxPos = Path.MaxPos;
|
||
float stepSize = 1f / Mathf.Max(1, stepsPerSegment);
|
||
|
||
// Sample the positions
|
||
int numKeys = Mathf.RoundToInt((maxPos - minPos) / stepSize) + 1;
|
||
float[] m_PosToDistance = new float[numKeys];
|
||
|
||
m_RestPointDistance.Clear();
|
||
Vector3[] firstRestDistance = new Vector3[2];
|
||
Vector3 firstDest = new Vector3(-m_MagneticDistance, 0f, m_MagneticDistance);
|
||
firstRestDistance[0] = firstDest;
|
||
m_RestPointDistance.Add(firstRestDistance);
|
||
|
||
int index = 0;
|
||
float m_PathLength = 0f;
|
||
Vector3 p0 = Path.EvaluatePosition(0);
|
||
m_PosToDistance[0] = 0;
|
||
float pos = minPos;
|
||
for (int i = 1; i < numKeys; ++i)
|
||
{
|
||
pos += stepSize;
|
||
Vector3 p = Path.EvaluatePosition(pos);
|
||
float d = Vector3.Distance(p0, p);
|
||
m_PathLength += d;
|
||
p0 = p;
|
||
m_PosToDistance[i] = m_PathLength;
|
||
|
||
if (i % stepsPerSegment == 0)
|
||
{
|
||
Vector3[] tmpArr = new Vector3[1];
|
||
Vector3 tmp = new Vector3(m_PathLength - m_MagneticDistance, m_PathLength, m_PathLength + m_MagneticDistance);
|
||
tmpArr[0] = tmp;
|
||
m_RestPointDistance.Add(tmpArr);
|
||
++index;
|
||
}
|
||
}
|
||
if (Path.Looped)
|
||
m_RestPointDistance.RemoveAt(index);
|
||
Vector3 lastDest = new Vector3(m_PathLength - m_MagneticDistance, m_PathLength, m_PathLength + m_MagneticDistance);
|
||
firstRestDistance[1] = lastDest;
|
||
}
|
||
private bool IsEffective()
|
||
{
|
||
return (m_MoveIndex >= 0 && m_MoveIndex < m_RestIndexList.Count && m_RestIndexList.Count > 0) ? true : false;
|
||
}
|
||
|
||
public int RestCount
|
||
{
|
||
get
|
||
{
|
||
if (m_RestIndexList == null) return 0;
|
||
return m_RestIndexList.Count;
|
||
}
|
||
}
|
||
public int MoveIndex
|
||
{
|
||
get => m_MoveIndex;
|
||
}
|
||
public int ForwardToNextRest()
|
||
{
|
||
m_MoveIndex++;
|
||
|
||
if (m_MoveIndex > m_RestIndexList.Count - 1)
|
||
{
|
||
if (Path.Looped)
|
||
m_MoveIndex = 0;
|
||
else
|
||
m_MoveIndex = m_RestIndexList.Count - 1;
|
||
}
|
||
|
||
GoToPositionIndex(m_RestIndexList[m_MoveIndex]);
|
||
if (Speed < 0)
|
||
{
|
||
Speed = -Speed;
|
||
}
|
||
return m_MoveIndex;
|
||
}
|
||
public int BackwardToNextRest()
|
||
{
|
||
m_MoveIndex--;
|
||
if (m_MoveIndex < 0)
|
||
{
|
||
if (Path.Looped)
|
||
m_MoveIndex = m_RestIndexList.Count - 1;
|
||
else
|
||
m_MoveIndex = 0;
|
||
}
|
||
|
||
GoToPositionIndex(m_RestIndexList[m_MoveIndex]);
|
||
if (Speed > 0)
|
||
{
|
||
Speed = -Speed;
|
||
}
|
||
return m_MoveIndex;
|
||
}
|
||
public int JumpToNextRestForward()
|
||
{
|
||
JumpToRestIndex(++m_MoveIndex);
|
||
return m_MoveIndex;
|
||
}
|
||
public int JumpToNextRestBackward()
|
||
{
|
||
JumpToRestIndex(--m_MoveIndex);
|
||
return m_MoveIndex;
|
||
}
|
||
public int JumpToRestIndex(int index)
|
||
{
|
||
m_MoveIndex = index;
|
||
|
||
if (m_MoveIndex < 0)
|
||
{
|
||
if (Path.Looped)
|
||
m_MoveIndex = m_RestIndexList.Count - 1;
|
||
else
|
||
m_MoveIndex = 0;
|
||
}
|
||
else if (m_MoveIndex > m_RestIndexList.Count - 1)
|
||
{
|
||
if (Path.Looped)
|
||
m_MoveIndex = 0;
|
||
else
|
||
m_MoveIndex = m_RestIndexList.Count - 1;
|
||
}
|
||
|
||
GoToPositionIndex(m_RestIndexList[m_MoveIndex]);
|
||
|
||
var tmpArr = m_RestPointDistance[m_CurPathIndex];
|
||
|
||
Vector3 boundary = tmpArr[0];
|
||
float distanceAlongPath = boundary.y;
|
||
|
||
m_Position = Path.StandardizeUnit(distanceAlongPath, m_PositionUnits);
|
||
|
||
SetCartPosition(m_Position);
|
||
|
||
m_State = MoveState.Stationary;
|
||
|
||
return m_MoveIndex;
|
||
}
|
||
|
||
public void GoToPositionIndex(int index)
|
||
{
|
||
m_CurPathIndex = index;
|
||
m_State = MoveState.Moving;
|
||
}
|
||
float CheckPosition(float distanceAlongPath, float distance)
|
||
{
|
||
if (m_CurPathIndex < 0 || m_CurPathIndex >= m_RestPointDistance.Count) return distance;
|
||
var tmpArr = m_RestPointDistance[m_CurPathIndex];
|
||
int count = tmpArr.Length;
|
||
if (count == 0) return distance;
|
||
|
||
if (m_CurPathIndex == 0)
|
||
{
|
||
if (Speed > 0f)
|
||
{
|
||
if (distanceAlongPath >= Path.PathLength)
|
||
{
|
||
m_State = MoveState.Stationary;
|
||
m_IsTestRest = false;
|
||
FishingYachtAct.Publish<EventWashingCameraStopData>(new EventWashingCameraStopData());
|
||
return tmpArr[0].y;
|
||
}
|
||
}
|
||
else if (Speed < 0f)
|
||
{
|
||
if (distanceAlongPath <= 0f)
|
||
{
|
||
m_State = MoveState.Stationary;
|
||
m_IsTestRest = false;
|
||
FishingYachtAct.Publish<EventWashingCameraStopData>(new EventWashingCameraStopData());
|
||
return tmpArr[0].y;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (Speed > 0f)
|
||
{
|
||
if (distance >= tmpArr[0].x)
|
||
{
|
||
m_State = MoveState.Stationary;
|
||
m_IsTestRest = false;
|
||
FishingYachtAct.Publish<EventWashingCameraStopData>(new EventWashingCameraStopData());
|
||
return tmpArr[0].y;
|
||
}
|
||
}
|
||
else if (Speed <= 0f)
|
||
{
|
||
if (distance <= tmpArr[0].z)
|
||
{
|
||
m_State = MoveState.Stationary;
|
||
m_IsTestRest = false;
|
||
FishingYachtAct.Publish<EventWashingCameraStopData>(new EventWashingCameraStopData());
|
||
return tmpArr[0].y;
|
||
}
|
||
}
|
||
}
|
||
|
||
return distance;
|
||
}
|
||
}
|
||
}
|