/// <summary>
/// 贝塞尔曲线生成器
/// </summary>
public class BezierGenerate : MonoBehaviour
{
public Transform beginTF;
public Transform controlTF01;
public Transform controlTF02;
public Transform endTF;
/// <summary>
/// 创建贝塞尔曲线坐标点
/// </summary>
/// <param name="beginPos"></param>
/// <param name="controlPos01"></param>
/// <param name="controlPos02"></param>
/// <param name="endPos"></param>
/// <param name="t"></param>
/// <returns></returns>
public static Vector3 CreateBezierCurvePoint(Vector3 beginPos, Vector3 controlPos01, Vector3 controlPos02, Vector3 endPos,float t)
{
return beginPos * Mathf.Pow(1 - t, 3) + 3 * controlPos01 * t * Mathf.Pow(1 - t, 2) + 3 * controlPos02 * Mathf.Pow(t, 2) * (1 - t) + endPos * Mathf.Pow(t, 3);
}
/// <summary>
/// 节点
/// </summary>
public int nodeCount = 20;
public List<Vector3> pointList;
private void Start()
{
pointList = new List<Vector3>(nodeCount);
GeneratePoints();
DrawCurve();
CalculateNodeIntervals();
}
public void GeneratePoints()
{
//计算比例的间隔
float interval = 1.0f / (nodeCount - 1);
float t =0;
for (int i = 0; i < nodeCount; i++)
{
Vector3 pos = CreateBezierCurvePoint(beginTF.position, controlTF01.position, controlTF02.position, endTF.position, t);
pointList.Add(pos);
t += interval;
}
}
public void DrawCurve()
{
var renderer = GetComponent<LineRenderer>();
renderer.SetVertexCount(pointList.Count);
renderer.SetPositions(pointList.ToArray());
}
//节点间距
private float[] nodeIntervals;
private void CalculateNodeIntervals()
{
nodeIntervals = new float[nodeCount - 1];
for (int i = 0; i < nodeIntervals.Length; i++)
{
nodeIntervals[i] = Vector3.Distance(pointList[i], pointList[i + 1]);
}
}
private void CalculateIndexAndRatioByDistance(float distance, out int index, out float ratio)
{
float sum = 0;
for (int i = 0; i < nodeIntervals.Length; i++)
{
sum += nodeIntervals[i];
if (sum >= distance)
{
ratio = 1 - (sum - distance) / nodeIntervals[i];
index = i;
return;
}
}
//移动距离超过曲线长度
ratio = -1;
index = -1;
}
public Vector3 GetPoint(float distance)
{
int index;
float ratio;
CalculateIndexAndRatioByDistance(distance, out index, out ratio);
if (index == -1) return pointList[pointList.Count - 1];
return Vector3.Lerp(pointList[index], pointList[index + 1], ratio);
}
}
public class DoMovement : MonoBehaviour
{
public float distance = 0;
public float speed = 10;
private void Update()
{
distance += speed * Time.deltaTime;
transform.position
= FindObjectOfType<BezierGenerate>().GetPoint(distance);
}
}
/// <summary>
/// 椭圆生成器
/// </summary>
public class EllipseGenerate : MonoBehaviour
{
/// <summary>
/// 创建椭圆坐标
/// </summary>
/// <param name="a">长轴长度</param>
/// <param name="b">短轴长度</param>
/// <param name="rad">弧度</param>
/// <returns>坐标</returns>
public static Vector3 CreatePoint(float a, float b, float rad)
{
return new Vector3(a * Mathf.Cos(rad), 0, b * Mathf.Sin(rad));
}
/// <summary>
/// 曲线的节点数量
/// </summary>
public int nodeCount = 10;
/// <summary>
/// 椭圆角度
/// </summary>
public float angle = 360;
/// <summary>
/// 长轴
/// </summary>
public float a;
/// <summary>
/// 短轴
/// </summary>
public float b;
public List<Vector3> pointList;
/// <summary>
/// 曲线所有节点总和
/// </summary>
public float length;
private void Start()
{
pointList = new List<Vector3>(nodeCount);
GeneratePoint();
CalculateNodeInterval();
CalculateLength();
DrawCurve();
}
/// <summary>
/// 生成贝塞尔曲线
/// </summary>
public void GeneratePoint()
{
pointList.Clear();
//将最大角度转换为最大弧度
float radMax = angle * Mathf.Deg2Rad;
//每段占比
float ratio = radMax / (nodeCount - 1);
float t = 0;
for (int i = 0; i < nodeCount; i++)
{
Vector3 point = CreatePoint(a, b, t);
Vector3 worldPoint = this.transform.TransformPoint(point);
pointList.Add(worldPoint);
t += ratio;
}
}
//绘制曲线 建议创建单独脚本
private void DrawCurve()
{
LineRenderer line = GetComponent<LineRenderer>();
line.SetVertexCount(pointList.Count);
line.SetPositions(pointList.ToArray());
}
/// <summary>
/// 获取曲线中坐标
/// </summary>
/// <param name="distance">距离</param>
/// <returns>坐标</returns>
public Vector3 GetPoint(float distance)
{
//1.计算distance在哪段节点(索引) ,以及比例
//2.计算比例
int index;
float ratio;
CalculateIndexAndRatio(distance, out index, out ratio);
if (index == -1) return pointList[pointList.Count - 1];
//3.通过Vector3.Lerp根据比例计算坐标
return Vector3.Lerp(pointList[index], pointList[index + 1], ratio);
}
/// <summary>
/// 根据比例获取曲线坐标
/// </summary>
/// <param name="ratio">比例</param>
/// <returns></returns>
public Vector3 GetPoint01(float ratio)
{
return GetPoint(ratio * length);
}
private float[] nodeIntervals;
//计算各节点间距
private void CalculateNodeInterval()
{
nodeIntervals = new float[nodeCount - 1];
for (int i = 0; i < nodeIntervals.Length; i++)
{
nodeIntervals[i] = Vector3.Distance(pointList[i], pointList[i + 1]);
}
}
//计算曲线总长度
private void CalculateLength()
{
float sum = 0;
for (int i = 0; i < nodeIntervals.Length; i++)
{
sum += nodeIntervals[i];
}
this.length = sum;
}
//根据曲线距离,计算节点索引以及比例
private void CalculateIndexAndRatio(float distance, out int index, out float ratio)//8
{
float sum = 0;
for (int i = 0; i < nodeIntervals.Length; i++)
{
sum += nodeIntervals[i];
if (sum >= distance)
{
ratio = 1 - (sum - distance) / nodeIntervals[i];
index = i;
return;//退出方法
}
}
//如果移动距离超过所有节点总和
index = -1;
ratio = -1;
}
}
public class EulerDemo : MonoBehaviour
{
public Vector3 euler;
private void OnGUI()
{
euler = transform.eulerAngles;
if (GUILayout.RepeatButton("沿X轴旋转"))
{
//Vector3 euler = transform.eulerAngles;
//欧拉角 没有 方向 和 大小的概念。
//x y z 沿某个轴的旋转角度
transform.eulerAngles += new Vector3(1, 0, 0);
}
if (GUILayout.RepeatButton("沿Y轴旋转"))
{
transform.eulerAngles += Vector3.up;
}
if (GUILayout.RepeatButton("沿Z轴旋转"))
{
transform.eulerAngles += Vector3.forward;
}
}
}
public class QuaternionDemo : MonoBehaviour
{
private void Start()
{
//物体沿Y轴旋转50度
Vector3 axis = Vector3.up;
float rad = 50 * Mathf.Deg2Rad;
Quaternion qt = new Quaternion();
qt.x = Mathf.Sin(rad / 2) * axis.x;
qt.y = Mathf.Sin(rad / 2) * axis.y;
qt.z = Mathf.Sin(rad / 2) * axis.z;
qt.w = Mathf.Cos(rad / 2);
//transform.rotation = qt;
transform.rotation = Quaternion.Euler(0, 50, 0);
Debug.Log(transform.eulerAngles);
}
//计算
private void OnGUI()
{
if (GUILayout.RepeatButton("沿X轴旋转"))
{
transform.rotation *= Quaternion.Euler(1, 0, 0);
//transform.Rotate(1, 0, 0); //Rotate通过四元数实现
}
if (GUILayout.RepeatButton("沿Y轴旋转"))
{
transform.rotation *= Quaternion.Euler(0, 1, 0);
}
if (GUILayout.RepeatButton("沿Z轴旋转"))
{
transform.rotation *= Quaternion.Euler(0, 0, 1);
}
}
private void Update()
{
Demo01();
}
private void Demo01()
{
//计算物体右前方30度10m处坐标
Vector3 worldPos =
transform.position + Quaternion.Euler(0, 30, 0) * transform.rotation * new Vector3(0, 0, 10);
Debug.DrawLine(transform.position, worldPos);
}
}
/// <summary>
/// 切点探测器
/// </summary>
public class TangentDetector : MonoBehaviour
{
private Vector3 leftTangent;
private Vector3 rightTangent;
private Transform playerTF;
private float radius;
private void Start()
{
GameObject playerGO = GameObject.FindWithTag("Player");
if (playerGO != null)
{
playerTF = playerGO.transform;
radius = playerGO.GetComponent<CapsuleCollider>().radius;
}
else
{
this.enabled = false;
}
}
public void CalaculateTangent()
{
Vector3 playerToExplosion = transform.position - playerTF.position;
Vector3 playerToExplosionRadius = playerToExplosion.normalized * radius;
float angle = Mathf.Acos(radius / playerToExplosion.magnitude) * Mathf.Rad2Deg;
rightTangent =playerTF .position + Quaternion.Euler(0, angle, 0) * playerToExplosionRadius;
leftTangent = playerTF.position + Quaternion.Euler(0, -angle, 0) * playerToExplosionRadius;
}
//**************测试**************
private void Update()
{
CalaculateTangent();
Debug.DrawLine(transform.position, leftTangent);
Debug.DrawLine(transform.position, rightTangent);
}
}