为什么反向不起作用?如何添加旋转部分



帖子有点长,但两个脚本都相互连接。我试图减少代码的数量。

Waypoints脚本附加到空的GameObject上,我在其中添加了一个旋转部分:

[Header("Rotation")]
public Quaternion rotationTothinkWhatToDoHere;

但我不知道如何在Waypoints脚本和WaypointsFlower脚本中使用它。

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Cinemachine;
public class Waypoints : MonoBehaviour
{
[Header("Objects To Move")]
public Transform objectToMovePrefab;
public int numberOfObjectsToMove = 1;
public bool moveInReverse = false;
[Header("Speed")]
public float speed;
public bool randomSpeed = false;
public float minRandomSpeed = 1;
public float maxRandomSpeed = 100;
private bool changeSpeedOnce = false;
[Header("Rotation")]
public Quaternion rotationTothinkWhatToDoHere;
[Header("Waypoints")]
[SerializeField] private List<Transform> waypoints;
public bool moveOnWaypoints = false;
[Header("Delay")]
public bool useDelay = false;
public float delay = 3;
public bool randomDelay = false;
public float minRandomDelay = 0.3f;
public float maxRandomDelay = 5;
[Header("LineRenderer")]
public LineRenderer lineRenderer;
public bool moveOnLineRenderer = false;
public List<Vector3> lineRendererPositions = new List<Vector3>();
[Header("Cinemachine Cameras")]
public CinemachineVirtualCamera virtualCamera;
private List<WaypointsFollower> waypointsFollowers = new List<WaypointsFollower>();
private void Start()
{
for (int i = 0; i < numberOfObjectsToMove; i++)
{
var parent = GameObject.Find("Moving Object Parent");
var objectToMove = Instantiate(objectToMovePrefab, parent.transform);
objectToMove.name = "Platfrom";
waypointsFollowers.Add(objectToMove.GetComponent<WaypointsFollower>());
}
virtualCamera.Follow = waypointsFollowers[0].gameObject.transform;
virtualCamera.LookAt = waypointsFollowers[0].gameObject.transform;
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.goForward = moveInReverse;
}
WaypointsMovementStates();
SpeedUpdater();
if (useDelay)
StartCoroutine(SendObjectstomoveWithDelay());
}
private void Update()
{
lineRendererPositions.Clear();
lineRendererPositions.AddRange(GetLinePointsInWorldSpace());
SpeedUpdater();
}
IEnumerator SendObjectstomoveWithDelay()
{
{
foreach (WaypointsFollower follower in waypointsFollowers)
{
if (randomDelay)
{
delay = Random.Range(minRandomDelay, maxRandomDelay);
}
yield return new WaitForSeconds(delay);
follower.go = true;
}
}
}
private void SpeedUpdater()
{
if (changeSpeedOnce == false)
{
foreach (WaypointsFollower follower in waypointsFollowers)
{
if (randomSpeed)
{
follower.speed = Random.Range(minRandomSpeed, maxRandomSpeed);
}
else
{
follower.speed = speed;
}
}
changeSpeedOnce = true;
}
}
Vector3[] GetLinePointsInWorldSpace()
{
var positions = new Vector3[lineRenderer.positionCount];
//Get the positions which are shown in the inspector 
lineRenderer.GetPositions(positions);

//the points returned are in world space
return positions;
}
private void WaypointsMovementStates()
{
// If moving on both linerenderer positions and waypoints objects
if (moveOnLineRenderer && moveOnWaypoints && waypoints.Count > 0)
{
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}

// If moving on linerenderer positions only without moving on waypoints objects
if (moveOnLineRenderer && moveOnWaypoints == false)
{
if (waypoints.Count > 0)
waypoints.Clear();
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}

// If only to move on waypoints objects without moving on linerenderer positions
if (moveOnWaypoints && waypoints.Count > 0 && moveOnLineRenderer == false)
{
lineRendererPositions.Clear();
foreach (Transform wp in waypoints)
{
lineRendererPositions.Add(wp.position);
}
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
if(moveInReverse)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
}

在WaypointsFlower脚本中,此脚本附加到沿waypoints移动的每个对象。如果goForward为真,它工作得很好,但当goFoward由于某种原因为假时,索引值为-1,我得到的异常超出了第73行的索引范围:

newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);

当goForward为false时,将对象从最后一个航路点移动到第一个航路点,然后当它到达第一个航路时,将goForward切换为true,并从第一个航路点将其向前移动到最后一个。

当goFoward第一次为真时,它起作用,然后从第一个航路点移动到最后一个航路点,然后从最后一个航点移动到第一个航点,但当goForward第一次是假时,它不起作用。

我不明白为什么是-1

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class WaypointsFollower : MonoBehaviour
{
public float speed;
public Waypoints waypoints;
public bool go;
public bool goForward;
private int index = 0;
private int counter = 0;
private int c = 0;
private List<GameObject> curvedLinePoints = new List<GameObject>();
public int numofposbetweenpoints;
private bool getonce;
private void Start()
{
waypoints = GameObject.Find("Waypoints").GetComponent<Waypoints>();
curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
if(waypoints.moveInReverse == false)
{
goForward = true;
}
else
{
goForward = false;
}
if(goForward)
{
index = 0;
}
else
{
index = waypoints.lineRendererPositions.Count - 1;
}
}
private void Update()
{
if (getonce == false)
{
numofposbetweenpoints = curvedLinePoints.Count;
getonce = true;
}
if (go == true && waypoints.lineRendererPositions.Count > 0)
{
Move();
}
}
private void Move()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
// error exception out of bound on line 55 to check !!!!!
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= waypoints.lineRendererPositions.Count - 1;
if (!atLastOne)
{
index++;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne)
{
index--;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
}

我在你之前的帖子被删除之前就看过了,所以下面是我对你最初的问题的答案,即通过旋转和移动在路点之间移动,并选择在运动结束时发生什么。如果回答您上次删除的问题仍未解决您的问题,我可以回答您当前的问题。

我建议使用Coroutine,而不是使用Update函数来处理列表中一系列路点之间的旋转和移动。如果你不熟悉,可以把它们想象成一个处理加班小增量的过程,并会跳回到它停止的地方。它应该把轮换和移动的问题简化为更小的逻辑块,让你更容易理解你的问题。

// new enum - outside of your class
public enum WaypointMovementType
{
REPEAT_START,       // will repeat to the start waypoint when end is reached
REPEAT_REVERSE,     // will reverse the waypoint list when end is reached
STOP                // will terminate when end is reached
};
// new variables - this is inside your class
// keep a reference of our coroutine to not run duplicates
Coroutine movingWayPoints = null;
// time it takes to rotate to our goal waypoint
private float rotateTime = 0.5f;
// time it takes to move to our goal waypoint
private float movementTime = 1.5f;
// Start is called before the first frame update
void Start()
{
parent = GameObject.Find("Waypoints");
// generate the waypoints
GenerateWaypoints();
// run our process 
if (movingWayPoints == null)
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(tmpList, WaypointMovementType.STOP));
}
private IEnumerator MoveBetweenWaypoints(List<Vector3> waypoints, WaypointMovementType movementType)
{
int currentWaypointIdx = 0;
// continue our loop until we have reached our end goal waypoint 
while (currentWaypointIdx < waypoints.Count)
{
// rotate towards out goal point
yield return StartCoroutine(RotateTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// move towards our goal point
yield return StartCoroutine(MoveTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// increment our index count or wait for further time if you would like a delay between rotation / movement
++currentWaypointIdx;
}
// coroutine is done, so set the motion to null
movingWayPoints = null;
// now that we have reached the end, determine what we want to do
if (movementType != WaypointMovementType.STOP)
{
// if we want to reverse, then reverse our list
if (movementType == WaypointMovementType.REPEAT_REVERSE)
waypoints.Reverse();
// now call the coroutine again
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(waypoints, movementType));
}
}
private IEnumerator RotateTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// store our current rotation
Quaternion initialRotation = transform.rotation;
// find our direction to the goal
Vector3 dir = goalWaypoint - transform.position;
// calculate the final / goal rotation
Quaternion finalRotation = Quaternion.LookRotation(dir);
// store our current time
float currentTime = 0.0f;
// rotate until we reach our goal
while (currentTime <= rotateTime)
{
currentTime += Time.deltaTime;
transform.rotation = Quaternion.Lerp(initialRotation, finalRotation, currentTime / rotateTime);
yield return null;
}
// set our rotation in case there are floating point precision errors
transform.rotation = finalRotation;
}
private IEnumerator MoveTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// store our current position
Vector3 initialPostion = transform.position;
// store our current time
float currentTime = 0.0f;
while (currentTime <= movementTime)
{
currentTime += Time.deltaTime;
transform.position = Vector3.Lerp(initialPostion, goalWaypoint, currentTime / movementTime);
yield return null;
}
// set our position in case there are floating point precision errors
transform.position = goalWaypoint;
}

当前代码使用时间而不是速度,可以通过改变Lerp步进的输入方式来改变速度。目前的另一个问题是,向后重复将移动并旋转到反向列表中的第一个元素,但这可以通过传递index参数来解决,该参数用于列表中的起始位置。

如果你更愿意使用当前的实现,我可以帮助调试它,但将来不要删除你期望得到答案的问题,除非你有充分的理由这样做。我还应该提到,由于你最初的问题只有一个脚本,当前脚本期望生成路点的对象是在它们之间移动的同一对象。通过创建一个新的公共字段来引用应该在路点之间移动的其他Transform,然后用yourObject.positionyourobject.rotation替换所有的transform.rotationtransform.position,可以很容易地修复。

我还应该补充一点,要改变单程完成后航路点移动的功能,只需在进行初始调用之前将WaypointMovementType参数更改为不同的值。

编辑:正如derHugo提到的,答案的速度变体更适合用例的需要,这里有一个额外的片段,它的速度而不是时间。

private IEnumerator MoveBetweenWaypoints(List<Vector3> waypoints, WaypointMovementType movementType)
{
int currentWaypointIdx = 0;
// continue our loop until we have reached our end goal waypoint 
while (currentWaypointIdx < waypoints.Count)
{
// rotate towards out goal point
yield return StartCoroutine(RotateTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// move towards our goal point
yield return StartCoroutine(MoveTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// increment our index count or wait for further time if you would like a delay between rotation / movement
++currentWaypointIdx;
}
// coroutine is done, so set the motion to null
movingWayPoints = null;
// now that we have reached the end, determine what we want to do
if (movementType != WaypointMovementType.STOP)
{
// if we want to reverse, then reverse our list
if (movementType == WaypointMovementType.REPEAT_REVERSE)
waypoints.Reverse();
// now call the coroutine again
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(waypoints, movementType));
}
}
private IEnumerator RotateTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// find our direction to the goal
Vector3 dir = goalWaypoint - transform.position;
// calculate the final / goal rotation
Quaternion finalRotation = Quaternion.LookRotation(dir);
// continue until our angles match
while(Vector3.Angle(transform.forward, dir) > ROTATION_CHECK_EPSILON)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, finalRotation, Time.deltaTime * rotateSpeed);
yield return null;
}
// set our rotation in case there are floating point precision errors
transform.rotation = finalRotation;
}
private IEnumerator MoveTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// continue until our distance is close to our goal
while(Vector3.Distance(transform.position, goalWaypoint) > DISTANCE_CHECK_EPSILON)
{
transform.position = Vector3.MoveTowards(transform.position, goalWaypoint, Time.deltaTime * movementSpeed);
yield return null;
}
// set our position in case there are floating point precision errors
transform.position = goalWaypoint;
}

最新更新