C# 为什么反过来不起作用?如何添加旋转部分?
文章有点长,但两个脚本都是相互连接的。我试图减少代码量 Waypoints脚本附加到空游戏对象上,我在其中添加了一个旋转部分:C# 为什么反过来不起作用?如何添加旋转部分?,c#,unity3d,C#,Unity3d,文章有点长,但两个脚本都是相互连接的。我试图减少代码量 Waypoints脚本附加到空游戏对象上,我在其中添加了一个旋转部分: [Header("Rotation")] public Quaternion rotationTothinkWhatToDoHere; 但我不知道如何在Waypoints脚本和Waypoints Follower脚本中使用它 using System.Collections; using System.Collections.Generic; us
[Header("Rotation")]
public Quaternion rotationTothinkWhatToDoHere;
但我不知道如何在Waypoints脚本和Waypoints Follower脚本中使用它
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;
}
}
}
}
当goForward为false时,将对象从最后一个航路点移动到第一个航路点,然后在到达第一个航路点时,将goForward切换为true,并从第一个航路点移动到最后一个航路点
当goForward第一次为真时,它工作,然后从第一个航路点移动到最后一个航路点,然后从最后一个航路点移动到第一个航路点,但当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;
}
}
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用UnityEngine;
公共类航路点如下:单行为
{
公众浮标速度;
公共航路点航路点;
公共图书馆;
公共事业发展;
私有整数指数=0;
专用整数计数器=0;
私有int c=0;
私有列表curvedLinePoints=新列表();
公共int-numofpos点与点之间;
私人布尔盖特恩斯;
私有void Start()
{
waypoints=GameObject.Find(“waypoints”).GetComponent();
curvedLinePoints=GameObject.FindGameObjectsWithTag(“曲线点”).ToList();
if(waypoints.moveInReverse==假)
{
goForward=true;
}
其他的
{
goForward=false;
}
如果(前进)
{
指数=0;
}
其他的
{
索引=航路点.LineRenderPositions.Count-1;
}
}
私有void更新()
{
if(getonce==false)
{
numofposbetweenpoints=曲线线点。计数;
getonce=true;
}
if(go==true&&waypoints.linerenderpositions.Count>0)
{
Move();
}
}
私人空位移动()
{
Vector3 newPos=变换位置;
浮动距离到行程=速度*时间.deltaTime;
bool=true;
当(仍在旅行)
{
向量3 oldPos=newPos;
//错误异常超出第55行的界限,请检查!!!!!
newPos=Vector3.向(oldPos、航路点、linerenderpositions[索引]、distanceToTravel)移动;
distanceToTravel-=矢量3.距离(新位置、旧位置);
如果(newPos==waypoints.lineRenderPositions[index])///Vector3比较是近似值,那么这是确定的
{
//当您到达一个航路点时:
如果(前进)
{
布尔atLastOne=索引>=航路点.LineRenderPositions.Count-1;
如果(!atLastOne)
{
索引++;
计数器++;
if(计数器==numoffosbetweenpoints)
{
C++;
计数器=0;
}
if(c==curvedLinePoints.Count-1)
{
c=0;
}
}
else{index--;goForward=false;}
}
其他的
{//倒退:
bool atFirstOne=index在删除之前,我看到了你的前一篇文章,因此,以下是我对你的原始问题的答案:通过旋转和移动在航路点之间移动,并选择在运动结束时发生什么。如果回答你上次删除的问题仍然没有解决你的iss问题,我可以回答你当前的问题ue
// 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;
}
与其使用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;
}
我宁愿定义移动和旋转速度,并使用MoveTowards
和RotateTowards
,而不是按时间移动。否则,即使两个航路点非常接近,时间也会相同,但移动速度会慢得多etc@derHugo非常正确!为了完整性,我将添加一个额外的代码段,它使用速度而不是时间。绝对同意使用航路点速度会更好。@derHugo添加了一个新的示例片段,现在使用了MoveTowards
和RotateTowards
。
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;
}