三維向量
// 向量的長度:求模的大小 void Update1() { Vector3 po = this.transform.position; // 向量的模 var l1 = Mathf.Sqrt(Mathf.Pow(po.x, 2) + Mathf.Pow(po.y, 2) + Mathf.Pow(po.z, 2)); var l2 = Vector3.Distance(Vector3.zero, po); //po.magnitude: po向量的模,po點相對於世界座標原點的距離 var l3 = po.magnitude; Debug.LogFormat("{0}-{1}-{2}", l1, l2, l3); // 標準向量,歸一向量,單位向量:模長度爲1的向量 //po.normalized: 標準向量,歸一向量,指的是將向量的模變成1,方向不變。改變後的向量。 //debug劃線,從世界座標系原點,到當前的座標點 Debug.DrawLine(Vector3.zero, po); Debug.DrawLine(Vector3.zero, po.normalized,Color.red); } // 向量的方向:求方向,求向量模的方向,求標準向量,歸一化向量 private void Update2() { Vector3 po = this.transform.position; //向量/向量模長 = 標準化向量 Vector3 n1 = po / po.magnitude; //使用向量API 求的 標準化向量 Vector3 n2 = po.normalized; Debug.DrawLine(Vector3.zero,po); Debug.DrawLine(Vector3.zero,n2,Color.blue); }
public Transform t1, t2, t3; private void Update3() { //減 向量:結果是 結果向量從減數箭頭點指向t1【被減數箭頭點】+ 平移到t1和t2的起點交點處 Vector3 n1 = t1.position - t2.position; if (Input.GetKey(KeyCode.A)) { // 每次移動單位向量,這樣距離越長,花費的時間就越長,能體現出距離感 t3.Translate(n1.normalized); } // 加 向量:結果是 兩個向量分別生成各自的輔助虛線向量,組成一個平行四邊形,加向量的結果就是這個平行四邊形的中間連線 Vector3 n2 = t1.position + t2.position; if (Input.GetKey(KeyCode.B)) { // 每次移動單位向量,這樣距離越長,花費的時間就越長,能體現出距離感 t3.Translate(n2.normalized); } Debug.DrawLine(Vector3.zero, n1); Debug.DrawLine(Vector3.zero, n2, Color.red); }
public float dotDegValue; private void Update() { Debug.DrawLine(Vector3.zero, t1.position); Debug.DrawLine(Vector3.zero, t2.position); //根據向量的點乘,求夾角 //注意:點乘求出來的夾角是2個單位向量的最小夾角,如果兩個向量的夾角大於180,比如270,則求出來的結果是哪個小部分,90度。 float dotValue = Vector3.Dot(t1.position.normalized, t2.position.normalized); dotDegValue = Mathf.Acos(dotValue) * Mathf.Rad2Deg; Debug.Log(dotDegValue); //根據2個向量的叉乘求夾角是否大於180,當小於180時,結果向量的y是大於0的,大於180時,結果向量的y是小於0的 //2個向量叉乘的意義爲:得出2個向量組成平面的垂直向量 Vector3 crossValue = Vector3.Cross(t1.position, t2.position); Debug.DrawLine(this.transform.position, crossValue, Color.red); //y小於0,大於180 if (crossValue.y < 0) { dotDegValue = 360 - dotDegValue; } }
private void Update4() { //角度 -> 弧度: 弧度 = 角度數 * PI/180 float d1 = 60; float r1 = d1 * Mathf.Deg2Rad; float r2 = d1 * Mathf.PI / 180; print("r1: "+r1 + " r2:"+r2); //弧度 -> 角度: 角度 = 弧度數 * 180/PI float r02 = Mathf.PI / 3; float g02 = r02 * 180 / Mathf.PI; float g03 = r02 * Mathf.Rad2Deg; print("g02: "+g02+" g03:"+g03); }
private void Update5() { //列如:已知角度x, 邊長b, 求邊長a //根據公式:tanx = a/b float x = 50, b = 20; float a = Mathf.Tan(x * Mathf.Deg2Rad) * b; //Debug.Log(a); //已知:邊長a, 邊長b, 求角度 angle //公式:angle = arc tan(a/b) float angle = Mathf.Atan(a / b); float angle2gad = Mathf.Rad2Deg * angle; //Debug.Log(string.Format("{0}:{1}", angle, angle2gad)); //三角函數在項目中的運用 //TransformPoint將自身座標系中的點轉成世界座標系中的點, //TransformPoint(0, 0, 10)的意思是延物體自身座標向前(z軸)走10米,然後將這個點轉到世界座標系中對應的點 Vector3 worldSpaceP = transform.TransformPoint(0, 0, 10); Debug.DrawLine(this.transform.position, worldSpaceP); //練習:計算物體右前方30度,10m遠的座標 // 根據題目可知,是知道角度和斜邊,求a,b邊 // 由公式:sinx = a/c, cosx = b/c 得: // x = a = c * sinx; z = b = c * cosx; float movX = 10 * Mathf.Sin(30 * Mathf.Deg2Rad); float movZ = 10 * Mathf.Cos(30 * Mathf.Deg2Rad); Vector3 worldSpaceP2 = transform.TransformPoint(movX, 0, movZ); Debug.DrawLine(this.transform.position, worldSpaceP2, Color.red); }
private void OnGUI() { //歐拉角 if (GUILayout.RepeatButton("歐拉角X軸")) { //歐拉角採用Vector3類型設置是因爲Vector3中有對應x,y,z的值,這和歐拉角中設置x,y,z軸上的旋轉角度雖然數值意義不同,但它們有相同的數據結構,這是 //歐拉角選擇使用Vector3表示的原因 //兩者的區別如下: //1.位置:有方向(從世界座標系原點指向當前點),有大小(從世界座標原點到當前點的位置) //向量的x,y,z分別表示當前點在各個軸向上的有向位移 Vector3 pos = this.transform.position; //2.歐拉角,沒有方向,大小的概念。它表示的是在x,y,z軸上轉了多少度 Vector3 euler = this.transform.eulerAngles; //各分量相加 this.transform.eulerAngles += new Vector3(1, 0,0); } if (GUILayout.RepeatButton("歐拉角Y軸")) { this.transform.eulerAngles += Vector3.up; } if (GUILayout.RepeatButton("歐拉角Z軸")) { this.transform.eulerAngles += Vector3.forward; } //四元數就是用來旋轉用的,它是軸角模式的旋轉,與歐拉角不同的是四元數的旋轉全部是繞自己的x,y,z軸旋轉。而歐拉角是x,z繞自身的軸y是繞世界座標系的y,用來解決歐拉角的萬向節死鎖問題 if (GUILayout.RepeatButton("四元數旋轉")) { //四元數設置需要2個條件:1.繞哪個軸,2.轉多少度 //繞y軸 Vector3 axis = Vector3.right; //旋轉弧度 float radValue = 60 * Mathf.Deg2Rad; //組建四元數 Quaternion qt = new Quaternion(); qt.x = axis.x * Mathf.Sin(radValue / 2); qt.y = axis.y * Mathf.Sin(radValue / 2); qt.z = axis.z * Mathf.Sin(radValue / 2); qt.w = Mathf.Cos(radValue / 2); //設置四元數 //this.transform.rotation = qt; //使用系統便捷方式設置四元數。歐拉角轉成四元數 this.transform.rotation = Quaternion.Euler(60,0,0); } if (GUILayout.RepeatButton("四元數X軸旋轉")) { this.transform.rotation *= Quaternion.Euler(1,0,0); } if (GUILayout.RepeatButton("四元數Y軸旋轉")) { this.transform.rotation *= Quaternion.Euler(0, 1, 0); } if (GUILayout.RepeatButton("四元數Z軸旋轉")) { this.transform.rotation *= Quaternion.Euler(0, 0, 1); } } void Update() { //四元數應用:求當前座標右前方30度,距離10的座標 if (Input.GetMouseButtonDown(1)) { Vector3 v0 = new Vector3(0,0,10); // v0向量繞y軸旋轉60度 Vector3 v1 = Quaternion.Euler(0, 30, 0) * v0; // v1隨自身四元數的旋轉而旋轉 Vector3 v2 = this.transform.rotation * v1; // 兩個向量相加,意義:將這個v0向量的起點移動到當前物體的位置上。 target = this.transform.position + v2; } Debug.DrawLine(this.transform.position, target,Color.blue); }
碰撞回調方法 // 碰撞開始時,接觸的第一幀,觸發回調 private void OnCollisionEnter(Collision collision) //中間的每一幀 private void OnCollisionStay(Collision collision) // 碰撞結束時,接觸的最後一幀,觸發回調 private void OnCollisionExit(Collision collision)
public class ColisionDemo : MonoBehaviour { public float speet = 300; // 碰撞開始時,接觸的第一幀,觸發回調 private void OnCollisionEnter(Collision collision) { //通過collision.collider拿到了另一碰撞對象的碰撞器,那麼就可以通過這個碰撞器獲取這個對象上所有的其他組件。 //collision.collider.GetComponent<MeshRenderer>(); //Debug.Log(collision.collider.name); Debug.Log(string.Format("碰撞器碰撞了:{0}", collision.collider.name)); //撞擊的碰撞點 ContactPoint cp = collision.contacts[0]; //cp.point碰撞點的世界座標 //cp.normal碰撞點接觸面的法線 } //中間的每一幀 private void OnCollisionStay(Collision collision) { } // 碰撞結束時,接觸的最後一幀,觸發回調 private void OnCollisionExit(Collision collision) { } //觸發回調,接觸的第一幀,觸發回調 private void OnTriggerEnter(Collider other) { Debug.Log(string.Format("觸發器觸發了:{0}", other.name)); } private void OnTriggerStay(Collider other) { } private void OnTriggerExit(Collider other) { } //當物體的移動速度非常快時可能檢測不到觸發和碰撞,情況是在接觸前那一刻檢測,等第二次檢測時已經穿過去了,判斷結果還是沒有接觸 private void FixedUpdate() { Debug.Log(string.Format("frameCount: {0}", Time.frameCount)); this.transform.Translate(Time.deltaTime * speet * -1, 0, 0); } private RaycastHit hit; public LayerMask layer; private Vector3 targetPos; // 使用射線解決移動速度過快,接觸檢查失效問題 void Start() { //射線投射命中 //射線投射:Raycast(起點座標,方向,受擊物體信息,距離,圖層) var res = Physics.Raycast(this.transform.position, -this.transform.right, out hit, 500, layer); if (res) { //擊中的位置 targetPos = hit.point; } else { //沒有命中目標 //targetPos = this.transform.TransformPoint(0,0,500); targetPos = this.transform.position + (-this.transform.right * 100); } } // Update is called once per frame void Update() { transform.position = Vector3.MoveTowards(transform.position, targetPos, speet*Time.deltaTime); //子彈從發射位置走到擊中的位置就停止了 if ((transform.position - targetPos).sqrMagnitude < 0.1) { //擊中: 擊中的物體銷燬,子彈也銷燬 Destroy(hit.collider.gameObject); Destroy(this.gameObject); } } }
public class VectorAPIDemo : MonoBehaviour { public Transform t1; private Vector3 tangent; private Vector3 binNormal; public Vector3 currentSpeed; public AnimationCurve curve; private float x; public float time = 5; //test private float speetScall = 1/30; // Start is called before the first frame update void Start1() { //屬性設置注意,因爲this.transform.position返回的是position的副本,無法真正修改position的值,所以會報錯。 //this.transform.position.z = 1; //解決方案:將position作爲一個整體設置 Vector3 p = this.transform.position; p.z = 2; this.transform.position = p; //Distance: 爲模長。 //sqrMagnitude: 爲(位置1-位置2).模長平方。 Vector3.Distance(tangent, binNormal); } // Update is called once per frame void Update() { Vector3 vect = new Vector3(); Vector3 vect0 = vect.normalized; vect.Normalize(); //計算垂直向量:在三維座標系中,一個向量的垂直向量有2條 //OrthoNormalize(ref Vector3 normal, ref Vector3 tangent); //計算t1物體在地面上的投影 Vector3 norm = t1.position; Vector3 project = Vector3.ProjectOnPlane(norm, Vector3.up); Debug.DrawLine(Vector3.zero, norm); Debug.DrawLine(Vector3.zero, project, Color.red); //計算反射向量:Vector3.Reflect; //向量的加,減,點乘,差乘等。 } private void OnGUI() { if (GUILayout.RepeatButton("Lerp")) { //Lerp有快到慢,每次前進總長度的10%,無限接近目標點; //每次都是起點改變,終點和比例不變。 this.transform.position = Vector3.Lerp(transform.position, new Vector3(0, 0, 10), 0.1f*Time.deltaTime); } if (GUILayout.RepeatButton("MoveTowards---------------")) { //勻速前進,無限接近目標點; this.transform.position = Vector3.MoveTowards(transform.position, new Vector3(0, 0, 10), 0.1f); } if (GUILayout.RepeatButton("SmoothDamp")) { //平滑阻尼,速度按固定的速率在減弱 this.transform.position = Vector3.SmoothDamp(transform.position, new Vector3(0,0,10),ref currentSpeed,2); } if (GUILayout.RepeatButton("變速運動")) { x += Time.deltaTime / time; Vector3 begin = Vector3.zero; //與Lerp變速對比變速運動爲:起點,終點不變,比例改變 //curve.Evaluate(x):隨着時間的變化,根據x值取y值。因爲x值沒有,這裏自己造一個,通過x += Time.deltaTime累加法,每秒加一 transform.position = Vector3.LerpUnclamped(begin, new Vector3(0,0,10),curve.Evaluate(x)); } } }
public class QuaternionAPIDemo : MonoBehaviour { public float moveSpeed = 1; // Start is called before the first frame update void Start() { //四元數 Quaternion qt = transform.rotation; //1.四元數 -> 歐拉角 Vector3 euler = qt.eulerAngles; //2.歐拉角 -> 四元數 Quaternion qt02 = Quaternion.Euler(0, 90, 0); //3.軸、角轉換 //transform.rotation = Quaternion.AngleAxis(30, Vector3.up); //transform.localRotation = Quaternion.AngleAxis(30,Vector3.up); } // Update is called once per frame public Transform target; private void OnGUI() { Quaternion dir = Quaternion.LookRotation(target.position - transform.position); if (GUILayout.RepeatButton("LookRotation+++++++++++++++++++")) { //4.注視旋轉 //方法1 //Quaternion dir2 = Quaternion.LookRotation(target.position - transform.position); //transform.rotation = dir2; //方法2 transform.LookAt(target.position); } if (GUILayout.RepeatButton("Lerp")) { //5.Lerp差值旋轉,由快到慢 //它與注視旋轉的區別是:注視旋轉是一幀設置完成,Lerp是多幀設置完成 transform.rotation = Quaternion.Lerp(transform.rotation, dir, 0.1f); } if (GUILayout.RepeatButton("RotateTowards")) { //6.RotateTowards: 勻速旋轉 transform.rotation = Quaternion.RotateTowards(transform.rotation, dir, 0.1f); } if (GUILayout.RepeatButton("Angle角度判斷")) { Quaternion dir2 = Quaternion.Euler(0, 180, 0); transform.rotation = Quaternion.Lerp(transform.rotation, dir2, 0.005f); //7.2個四元數角度差計算 if (Quaternion.Angle(transform.rotation, dir2) < 30) { transform.rotation = dir2; } } } void Update() { //上面提供的方法默認的旋轉軸是繞z軸,如果想繞x軸旋轉,可通過下面的方式 //this.transform.right = target.position - this.transform.position; //從x軸正方向 -> 注視目標位置的方向 //8.從?到?的旋轉 //transform.rotation = Quaternion.FromToRotation(Vector3.right, target.position - transform.position); //課後作業:物體隨ad/sw進行上下旋轉 var hRes = Input.GetAxis("Horizontal"); var vRes = Input.GetAxis("Vertical"); if (hRes != 0 || vRes != 0) { Debug.Log(string.Format("hRes:{0}- vRes:{1}", hRes, vRes)); //transform.rotation = Quaternion.LookRotation(new Vector3(hRes, 0, vRes)); //帶旋轉過程 var targetRotation = Quaternion.LookRotation(new Vector3(hRes, 0, vRes)); transform.rotation = Quaternion.Lerp(this.transform.rotation, targetRotation, moveSpeed *Time.deltaTime); transform.Translate(0, 0, moveSpeed * Time.deltaTime); } } }