using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
namespace game
{
[ExecuteAlways]
[DisallowMultipleComponent]
public class CameraFollowPathMoveController : MonoBehaviour
{
/// The path to follow
[Tooltip("The path to follow")]
public CinemachinePath Path;
[Tooltip("路径停歇点索引,循环执行。eg:5个点,执行到最后一个位置会从移动到初始位置开始。")]
public List m_RestIndexList = new List();
[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;
/// This enum defines the options available for the update method.
public enum UpdateMethod
{
/// Updated in normal MonoBehaviour Update.
Update,
/// Updated in sync with the Physics module, in FixedUpdate
FixedUpdate,
/// Updated in normal MonoBehaviour LateUpdate
LateUpdate
};
/// When to move the cart, if Velocity is non-zero
[Tooltip("When to move the cart, if Velocity is non-zero")]
public UpdateMethod m_UpdateMethod = UpdateMethod.Update;
/// How to interpret the Path Position
[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;
/// Move the cart with this speed
[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;
/// The cart's current position on the path, in distance units
[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 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 m_RestPointDistance = new List();
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(new EventWashingCameraStopData());
return tmpArr[0].y;
}
}
else if (Speed < 0f)
{
if (distanceAlongPath <= 0f)
{
m_State = MoveState.Stationary;
m_IsTestRest = false;
FishingYachtAct.Publish(new EventWashingCameraStopData());
return tmpArr[0].y;
}
}
}
else
{
if (Speed > 0f)
{
if (distance >= tmpArr[0].x)
{
m_State = MoveState.Stationary;
m_IsTestRest = false;
FishingYachtAct.Publish(new EventWashingCameraStopData());
return tmpArr[0].y;
}
}
else if (Speed <= 0f)
{
if (distance <= tmpArr[0].z)
{
m_State = MoveState.Stationary;
m_IsTestRest = false;
FishingYachtAct.Publish(new EventWashingCameraStopData());
return tmpArr[0].y;
}
}
}
return distance;
}
}
}