Gameplay Ingredients是一组用于 Unity 游戏的运行时和编辑器工具:一组脚本的集合,可在制作游戏和原型时简化简单的任务。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

171 行
5.2 KiB

using NaughtyAttributes;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
namespace GameplayIngredients.Rigs
{
public class FollowPathRig : MonoBehaviour
{
public enum PlayMode
{
Playing,
Stopped,
Reverse
}
public enum LoopMode
{
Hold,
Loop,
PingPong
}
public LoopMode loopMode = LoopMode.PingPong;
public bool StopOnSteps = false;
public float Speed = 2.0f;
[ReorderableList, SerializeField, NonNullCheck]
protected GameObject[] Path;
public PlayMode initialPlayMode = PlayMode.Playing;
PlayMode m_PlayMode;
float m_Progress;
public void SetProgress(float progress)
{
m_Progress = Mathf.Clamp(progress, 0, Path.Length - 1);
}
public void Play(float progress = -1.0f)
{
if (progress >= 0.0f)
SetProgress(progress);
m_PlayMode = PlayMode.Playing;
}
public void Reverse(float progress = -1.0f)
{
if (progress >= 0.0f)
SetProgress(progress);
m_PlayMode = PlayMode.Reverse;
}
public void Stop(float progress = -1.0f)
{
if (progress >= 0.0f)
SetProgress(progress);
m_PlayMode = PlayMode.Stopped;
}
private void Start()
{
m_PlayMode = initialPlayMode;
m_Progress = 0.0f;
}
private void LateUpdate()
{
if(m_PlayMode != PlayMode.Stopped)
{
if(Path.Where(o => o == null).Count() > 0)
{
Debug.LogWarning("Path contains null objects. Cannot Compute.", this);
}
// Process loopMode and boundary reach
switch(loopMode)
{
case LoopMode.Hold:
if((m_PlayMode == PlayMode.Playing && m_Progress == Path.Length - 1) || (m_PlayMode == PlayMode.Reverse && m_Progress == 0.0f))
{
m_PlayMode = PlayMode.Stopped;
return;
}
break;
case LoopMode.Loop:
if (m_PlayMode == PlayMode.Playing && m_Progress == Path.Length -1)
{
m_Progress = 0.0f;
}
else if (m_PlayMode == PlayMode.Reverse && m_Progress == 0.0f)
{
m_Progress = Path.Length -1;
}
break;
case LoopMode.PingPong:
if (m_PlayMode == PlayMode.Playing && m_Progress == Path.Length -1)
{
m_PlayMode = PlayMode.Reverse;
}
else if (m_PlayMode == PlayMode.Reverse && m_Progress == 0.0f)
{
m_PlayMode = PlayMode.Playing;
}
break;
}
// Process move on path
float sign = 1.0f;
if (m_PlayMode == PlayMode.Reverse)
sign = -1.0f;
int idx = Mathf.Clamp( sign > 0? (int)Mathf.Floor(m_Progress) : (int)Mathf.Ceil(m_Progress), 0 , Path.Length-1);
int nextidx = idx + (int)sign;
Vector3 inPos = Path[idx].transform.position;
Vector3 outPos = Path[nextidx].transform.position;
Vector3 dir = ( outPos - inPos ).normalized;
Vector3 pos = Vector3.Lerp( sign > 0? inPos : outPos, sign > 0? outPos : inPos, m_Progress % 1.0f);
Vector3 move = dir * Speed * Time.deltaTime;
float moveT = move.magnitude / (outPos - inPos).magnitude * sign;
m_Progress = Mathf.Clamp(m_Progress + moveT, (sign > 0)? idx : nextidx, (sign > 0) ? nextidx : idx);
if(m_Progress == nextidx)
transform.position = outPos;
else
transform.position = Vector3.Lerp(inPos, outPos, (sign > 0) ? m_Progress % 1.0f : 1.0f - (m_Progress % 1.0f));
if((m_Progress %1.0f == 0.0f) && StopOnSteps)
{
m_PlayMode = PlayMode.Stopped;
}
}
}
private void OnDrawGizmos()
{
Gizmos.color = new Color(1.0f, 1.0f, 1.0f, 0.1f);
DrawGizmosPath();
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
DrawGizmosPath();
}
void DrawGizmosPath()
{
if(Path != null && Path.Length > 1 && Path.Where(o => o == null).Count() == 0)
{
for(int i = 0; i < Path.Length -1; i++)
{
Gizmos.DrawLine(Path[i].transform.position, Path[i + 1].transform.position);
}
}
}
}
}