如果半径不相等,如果它是椭圆,如何在绘制的圆半径上移动对象?
How to move object on drawn circle radius if the radius is not equal if it's ellipse?
如果半径相等且为圆形,则物体可以围绕它旋转。
但是如果半径例如 xRadius 是 1 并且 yRadius 是 5 并且它是椭圆形然后对象旋转远离半径。现在我只使用 xRadius,因为我认为 xRadius 和 yRadius 是相同的。
但现在 dc.xRadius 和 dc.yRadius 不是相同的值。如截图所示。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateAroundTarget : MonoBehaviour
{
public Transform target;
public float rotatingSpeed;
public float movingSpeed;
public Vector3 axis;
public bool randomHeight;
public float setRandomHeight = 1;
public float radius;
public DrawCircle dc;
private float lastRadius;
private bool move = false;
private float t = 0.0f;
public float upperLimit, lowerLimit, delay;
private float prevHeight;
private Vector3 radiusPosition;
private void Start()
{
if (dc != null)
{
lastRadius = dc.xRadius;
radius = dc.xRadius;
}
else
{
lastRadius = radius;
}
move = true;
}
private void Update()
{
if (target != null)
{
if (dc != null)
{
radiusPosition = new Vector3(target.position.x,
target.position.y, target.position.z + dc.xRadius);
radius = dc.xRadius;
}
else
{
radiusPosition = new Vector3(target.position.x, target.position.y, target.position.z + radius);
}
}
if (move == false)
{
if (target != null)
{
transform.RotateAround(target.position, axis, rotatingSpeed * Time.deltaTime);
}
if (randomHeight)
{
t += Time.deltaTime;
if (t > delay)
{
prevHeight = setRandomHeight;
setRandomHeight = Random.Range(lowerLimit, upperLimit);
t = 0;
}
var tt = transform.position;
tt.y = Mathf.Lerp(prevHeight, setRandomHeight, t);
transform.position = tt;
}
}
if (dc != null)
{
if (lastRadius != dc.xRadius)
{
move = true;
lastRadius = dc.xRadius;
}
}
else
{
if (lastRadius != radius)
{
move = true;
lastRadius = radius;
}
}
if (move)
{
if (transform.position != radiusPosition)
{
float step = movingSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position,
radiusPosition, step);
}
else
{
move = false;
}
}
}
}
这是绘制circle/ellipse的脚本:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteAlways]
[RequireComponent(typeof(UnityEngine.LineRenderer))]
public class DrawCircle : MonoBehaviour
{
[Range(1, 50)] public int segments = 50;
[Range(1, 500)] public float xRadius = 5;
[Range(1, 500)] public float yRadius = 5;
[Range(0.1f, 5)] public float width = 0.1f;
[Range(0, 100)] public float height = 0;
public bool controlBothXradiusYradius = false;
public bool draw = true;
[SerializeField] private LayerMask targetLayers;
[SerializeField] private LineRenderer line;
private void Start()
{
if (!line) line = GetComponent<LineRenderer>();
if (draw)
CreatePoints();
}
private void Update()
{
if (Physics.CheckSphere(transform.position, xRadius, targetLayers))
{
Debug.Log("player detected");
}
else
{
Debug.Log("player NOT detected");
}
}
public void CreatePoints()
{
line.enabled = true;
line.widthMultiplier = width;
line.useWorldSpace = false;
line.widthMultiplier = width;
line.positionCount = segments + 1;
float x;
float y;
var angle = 20f;
var points = new Vector3[segments + 1];
for (int i = 0; i < segments + 1; i++)
{
x = Mathf.Sin(Mathf.Deg2Rad * angle) * xRadius;
y = Mathf.Cos(Mathf.Deg2Rad * angle) * yRadius;
points[i] = new Vector3(x, height, y);
angle += (380f / segments);
}
// it's way more efficient to do this in one go!
line.SetPositions(points);
}
#if UNITY_EDITOR
private float prevXRadius, prevYRadius;
private int prevSegments;
private float prevWidth;
private float prevHeight;
private void OnValidate()
{
// Can't set up our line if the user hasn't connected it yet.
if (!line) line = GetComponent<LineRenderer>();
if (!line) return;
if (!draw)
{
// instead simply disable the component
line.enabled = false;
}
else
{
// Otherwise re-enable the component
// This will simply re-use the previously created points
line.enabled = true;
if (xRadius != prevXRadius || yRadius != prevYRadius || segments != prevSegments || width != prevWidth || height != prevHeight)
{
CreatePoints();
// Cache our most recently used values.
prevXRadius = xRadius;
prevYRadius = yRadius;
prevSegments = segments;
prevWidth = width;
prevHeight = height;
}
if (controlBothXradiusYradius)
{
yRadius = xRadius;
CreatePoints();
}
}
}
#endif
}
如果您想直接在您发布的代码绘制的线上放置一些东西,您可以在 points[]
数组中的 Vector3 位置之间移动它。
如果您只想让代码在椭圆中移动一个对象,您可以这样做:
using UnityEngine;
public class Orbit : MonoBehaviour
{
public float radiusX, radiusY;
public float speed;
public float currentAngleInRadians;
void Update()
{
currentAngleInRadians += speed * Time.deltaTime;
transform.localPosition = new Vector3(
Mathf.Cos(currentAngleInRadians) * radiusX,
Mathf.Sin(currentAngleInRadians) * radiusY,
0);
}
}
使用此脚本将对象放入父游戏对象中,您可以移动和旋转该父对象以更改轨道的中心和轴。顺时针旋转速度为负值
如果半径相等且为圆形,则物体可以围绕它旋转。 但是如果半径例如 xRadius 是 1 并且 yRadius 是 5 并且它是椭圆形然后对象旋转远离半径。现在我只使用 xRadius,因为我认为 xRadius 和 yRadius 是相同的。
但现在 dc.xRadius 和 dc.yRadius 不是相同的值。如截图所示。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateAroundTarget : MonoBehaviour
{
public Transform target;
public float rotatingSpeed;
public float movingSpeed;
public Vector3 axis;
public bool randomHeight;
public float setRandomHeight = 1;
public float radius;
public DrawCircle dc;
private float lastRadius;
private bool move = false;
private float t = 0.0f;
public float upperLimit, lowerLimit, delay;
private float prevHeight;
private Vector3 radiusPosition;
private void Start()
{
if (dc != null)
{
lastRadius = dc.xRadius;
radius = dc.xRadius;
}
else
{
lastRadius = radius;
}
move = true;
}
private void Update()
{
if (target != null)
{
if (dc != null)
{
radiusPosition = new Vector3(target.position.x,
target.position.y, target.position.z + dc.xRadius);
radius = dc.xRadius;
}
else
{
radiusPosition = new Vector3(target.position.x, target.position.y, target.position.z + radius);
}
}
if (move == false)
{
if (target != null)
{
transform.RotateAround(target.position, axis, rotatingSpeed * Time.deltaTime);
}
if (randomHeight)
{
t += Time.deltaTime;
if (t > delay)
{
prevHeight = setRandomHeight;
setRandomHeight = Random.Range(lowerLimit, upperLimit);
t = 0;
}
var tt = transform.position;
tt.y = Mathf.Lerp(prevHeight, setRandomHeight, t);
transform.position = tt;
}
}
if (dc != null)
{
if (lastRadius != dc.xRadius)
{
move = true;
lastRadius = dc.xRadius;
}
}
else
{
if (lastRadius != radius)
{
move = true;
lastRadius = radius;
}
}
if (move)
{
if (transform.position != radiusPosition)
{
float step = movingSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position,
radiusPosition, step);
}
else
{
move = false;
}
}
}
}
这是绘制circle/ellipse的脚本:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteAlways]
[RequireComponent(typeof(UnityEngine.LineRenderer))]
public class DrawCircle : MonoBehaviour
{
[Range(1, 50)] public int segments = 50;
[Range(1, 500)] public float xRadius = 5;
[Range(1, 500)] public float yRadius = 5;
[Range(0.1f, 5)] public float width = 0.1f;
[Range(0, 100)] public float height = 0;
public bool controlBothXradiusYradius = false;
public bool draw = true;
[SerializeField] private LayerMask targetLayers;
[SerializeField] private LineRenderer line;
private void Start()
{
if (!line) line = GetComponent<LineRenderer>();
if (draw)
CreatePoints();
}
private void Update()
{
if (Physics.CheckSphere(transform.position, xRadius, targetLayers))
{
Debug.Log("player detected");
}
else
{
Debug.Log("player NOT detected");
}
}
public void CreatePoints()
{
line.enabled = true;
line.widthMultiplier = width;
line.useWorldSpace = false;
line.widthMultiplier = width;
line.positionCount = segments + 1;
float x;
float y;
var angle = 20f;
var points = new Vector3[segments + 1];
for (int i = 0; i < segments + 1; i++)
{
x = Mathf.Sin(Mathf.Deg2Rad * angle) * xRadius;
y = Mathf.Cos(Mathf.Deg2Rad * angle) * yRadius;
points[i] = new Vector3(x, height, y);
angle += (380f / segments);
}
// it's way more efficient to do this in one go!
line.SetPositions(points);
}
#if UNITY_EDITOR
private float prevXRadius, prevYRadius;
private int prevSegments;
private float prevWidth;
private float prevHeight;
private void OnValidate()
{
// Can't set up our line if the user hasn't connected it yet.
if (!line) line = GetComponent<LineRenderer>();
if (!line) return;
if (!draw)
{
// instead simply disable the component
line.enabled = false;
}
else
{
// Otherwise re-enable the component
// This will simply re-use the previously created points
line.enabled = true;
if (xRadius != prevXRadius || yRadius != prevYRadius || segments != prevSegments || width != prevWidth || height != prevHeight)
{
CreatePoints();
// Cache our most recently used values.
prevXRadius = xRadius;
prevYRadius = yRadius;
prevSegments = segments;
prevWidth = width;
prevHeight = height;
}
if (controlBothXradiusYradius)
{
yRadius = xRadius;
CreatePoints();
}
}
}
#endif
}
如果您想直接在您发布的代码绘制的线上放置一些东西,您可以在 points[]
数组中的 Vector3 位置之间移动它。
如果您只想让代码在椭圆中移动一个对象,您可以这样做:
using UnityEngine;
public class Orbit : MonoBehaviour
{
public float radiusX, radiusY;
public float speed;
public float currentAngleInRadians;
void Update()
{
currentAngleInRadians += speed * Time.deltaTime;
transform.localPosition = new Vector3(
Mathf.Cos(currentAngleInRadians) * radiusX,
Mathf.Sin(currentAngleInRadians) * radiusY,
0);
}
}
使用此脚本将对象放入父游戏对象中,您可以移动和旋转该父对象以更改轨道的中心和轴。顺时针旋转速度为负值