unity筆記(指令碼4)
阿新 • • 發佈:2022-03-10
/// <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,floatt) { 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); } }