1. 程式人生 > 其它 >unity筆記(指令碼4)

unity筆記(指令碼4)

/// <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);
    }
}