文章目錄
- 3D數學
- 公共計算結構體Mathf
- 常用成員
- 三角函數
- 向量Vector3
- 基本成員
- 點乘
- 叉乘
- 插值運算
- 四元數
- 引出
- 基本概念
- Quaternion結構體成員
- 四元數運算
- 更多的Mono
- 延遲函數
- 協同程序
- 多線程相關
- 協程
- 概念辨析
- 協程本體
- 協程調度器
- Resources資源動態加載
- 特殊文件夾
- Resources同步加載
- Resources異步加載
- 監聽回調實現(線性)
- **協程實現(并行)**
- 封裝一個簡單的資源加載器
- 資源卸載
- 場景異步切換
- 事件回調
- 協程
- 封裝一個簡單的場景加載器
- LineRendnerer畫線組件
- 面板參數
- 代碼控制
- 范圍檢測
- 基本概念
- 代碼實現
- 盒狀的兩個重要方法
- 其他方法
- 射線檢測
- 基本概念
- 代碼控制
整個學的過程中碰到參數介紹就很痛苦.jpg
相比于入門來講小上了點強度了,但也還行,里面有談到GUI,但是但是我那個筆記一直拖到現在還沒寫完哈哈哈。。。。(明明是學基礎前就該寫完了)所以就將就看吧(卡姿蘭大眼睛),等把其他UI學了專門發一篇UI的筆記吧。。。。
3D數學
公共計算結構體Mathf
和c#的靜態類Math是一個定位,雖然是結構體,但它的成員全是const
和static
常用成員
Mathf.PI;//后續描述省略Mathf.都是可以直接.出來的
Abs(n);
CeilToInt(n);//向上取整
FloorToInt(n);//向下取整
Clamp(n, min, max);//鉗制方法,取n值,但范圍限制在min到max間
Max(a, b, c,...);
Min(a, b, b,...);
Pow(n, 冪);
RoundToInt(n);//四舍五入
Sqrt(n);
IsPowerOfTwo(n);
Sign(n);//判斷正負數int start = Mathf.Lerp(start, end, t);//插值運算=》可以放在Update里用來做跟隨系統
//start為初始位置,end為結束位置,t為0~1的插值系數
//通常end為需要跟隨的對象位置,將運算的結果賦給start并每幀計算就可以實現跟隨
//Lerp方法返回值的內部運算邏輯為start + (end - start) * t
//根據公式可以有先快后慢和勻速兩種表現形式的跟隨//先快后慢:令t = Time.deltaTime即可//勻速:假設是當前對象跟隨對象other
if (endpos != other.transform.position) {t = 0;startpos = this.transform.position;endpos = other.transform.position;
}
t += Time.deltaTime;
nowpos.x = Mathf.Lerp(startpos.x, endpos.x, t);
nowpos.y = Mathf.Lerp(startpos.y, endpos.y, t);
nowpos.z = Mathf.Lerp(startpos.z, endpos.z, t);
this.transform.position = nowpos;
//因為勻速實現傳入的t總會超過1,會導致后續更新時變成瞬移
//所以在運算前前需要進行位置的判斷,每次重置t
三角函數
Mathf.Rad2Deg;//弧度=》角度需要*的值,即180/Π(下同樣省略Mathf.)
Deg2Rad;//角度=》弧度需要*的值,即Π/180
Sin();
Cos();
Asin();//反正弦
Acos();//反余弦
//以上四個三角函數均只能傳弧度,同時返回弧度結果//利用正弦函數實現波浪式移動
this.transform.Translate(Vector3.forward * Speed * Time.deltaTime);
t += Time.deltaTime * Speed;
this.transform.Translate(Vector3.right * y * Time.deltaTime * Mathf.Sin(t));
向量Vector3
數學回顧:可以±,可以取負,可以*/標量,為負數時方向取反(AB = B - A)
基本成員
現在有對象Vector3 v
v.magnitude
:求模長v.normalized
:取方向向量
點乘
數學表示:a · b = x1 * x2 + y1 * y2 + z1 * z2(兩向量點乘得到標量)
幾何意義:b在a方向上的投影
實際用途:> 0 兩向量夾角為銳角,= 0 直角,< 0 鈍角 =>判斷敵人的前后大致方位
點乘方法Vector3.Dot(a, b)
:返回float
補充方法調試畫線
Debug.DrawLine(a, b, color)
:畫線段Debug.DrawRay(a, b, Color)
:畫射線
獲取兩向量夾角Vector3.Angle(a, b)
=》原理:若b為方向向量,則兩向量夾角余弦值cosβ = b在a方向上的投影 / b的模長(點乘的幾何意義就是投影)
即cosβ = a · b=》取反余弦則β = Acos(a · b)
tips:調用Angle
方法時不用取b的方向向量,內部處理好了
叉乘
數學表示:a × b = c,其中c = (Ya * Zb - Za * Yb, -(Xa * Zb - Za * Xb), Xa * Yb - Xb * Ya)
(兩向量點乘得到向量,該向量為法向量,垂直于兩向量所在平面)(相乘順序不能變,不然結果不同,a × b = -(b × a)
tips:高數里的內容,不用死記,把兩個向量的xyz列出來,要算哪個軸把哪個軸蓋住,剩下的交叉相乘,只不過算y的時候要取反,判斷c的方向時采用右手螺旋定則
實際用途:算出來的c,它的y > 0時說明a在b的左邊,< 0時說明在右邊 =》結合點乘可直接判斷出敵人的具體方向,再加上入門里里學的Vector3.Distance(a, b)
方法可直接得到敵人的具體位置
叉乘方法Vector3.Cross(a, b)
插值運算
線性插值Vector3.Lerp(start, end, t)
:和Mathf
里的用法基本一致,只不過傳入的參數直接是Vector3
了,不用之前那么麻煩
球形插值Vector3.Slerp(start, end, t)
:用法和線性一摸一樣,表現形式上為弧狀靠近,用的少
四元數
引出
在入門中控制旋轉時我們采用的方法是改變歐拉角,即面板上的參數來描述旋轉量
但是他不好=》
- 同一旋轉表示不唯一,比如360和0是一樣的
- 萬向節死鎖=》簡單解釋:
- 通常旋轉遵循yzx約定,即三個軸向的旋轉順序,轉y會帶動z,轉z會帶動x
- 在這種約定下轉著轉著,當兩個軸重合時他就變不回去了(當然其他所有約定都會出現這種情況)
- 在unity里的表現是當x軸達到90°時,控制y和z在表現上都是在控制z
為了解決這兩個問題就有了四元數
基本概念
數學里四元數由一個實數 + 三個虛數組成
而在unity里則是一個標量w
+ 一個向量(x, y, z)
組成
假設現在有一個軸n,繞著它轉β°,則有四元數Q = [cos(β/2), sin(β/2) * x, sin(β/2) * y, sin(β/2) * z]
(數學里的結論,感興趣的可以去看一下怎么推的)
Quaternion結構體成員
入門里其實提過一嘴transform.rotation
是一個四元數,它的類型在unity里就是Quaternion
//初始化
//法1new一個
Quaternion q = new Quaternion(sin(β/2) * x, sin(β/2) * y, sin(β/2) * z, cos(β/2));//一般不用這個
//法2軸角對
Quaternion q = Quaternion.AngleAxis(角度, 軸);//封裝萬歲,繞著哪個軸轉多少度
//這個角度必須在正負180°間//歐拉數=》四元數
Quaternion q = Quaternion.Eular(x, y, z);
//四元數=》歐拉數(就是入門那個獲取角度)
Vector3 v = q.eulerAngles;//物體的旋轉
transform.rotation *= Quaternion.AngleAxis(30, Vector3.forward);
//兩個四元數相乘代表旋轉四元數,是相對自身的旋轉量疊加//單位四元數:[±1, (0, 0, 0)]
Quaternion.identity;
//作用:Object里克隆方法重載Instantiate(obj, 生成點, 生成時的角度),如果要生成一個全新的物體這個角度就可以填單位四元數//插值運算:分為線性和球形,
//對于旋轉來說,球形的效果好,線性雖然快但是在范圍比較大的時候效果不好
//先快后慢:
target.transform.rotation = Quaternion.Slerp(this.transform.rotation, target.transform.rotation, t);
//勻速:參考上面的傳參和Mathf線性的處理邏輯//向量指向四元數
transform.rotation = Quaternion.LookRotation(面朝向量);
//這個傳參讓兩個物體的position一減就行
//效果上和入門里transform.LookAt(obj)一樣,它要更精細一點,可以和插值運算配合
//插值運算實現時把這個返回值作為目標即可
四元數運算
兩四元數相乘,即上面部分的旋轉
四元數 * 向量 = 向量(把原向量旋轉了,順序不可變不然報錯)=》可以做什么呢
- 發射不同角度子彈,用四元數去乘面朝的方向向量即可改變子彈的方向
- 第三人稱,其實就是把攝像機扔到人物后上方去,扔過去分為后方和上方兩部分,都需要用四元數去控制,這一部分知識加上上面的向量指向四元數讓攝像機一直看向人物,再加上向量部分的插值運算實現跟隨效果,就可以實現一個簡易的第三人稱了~~
更多的Mono
延遲函數
直入主題
Invoke("函數名", 時間)
- 時間的單位是秒,所調用的函數必須在當前腳本中,如果沒有的話會提示
- 既然是傳入字符串找,那么底層實現必然是反射,傳入字符串也意味著不能傳參
- 當前上面這兩點都可以間接解決,調用的無參函數中再調用其他有參或者其他腳本中的函數。即包裝一層
InvokeRepeating("函數名", 時間, 每次間隔的時間)
- 取消延遲函數
- 取消該腳本上的所有
CancelInvoke()
:有傳字符串指定取消的重載,沒有也不會報錯 - 判斷有沒有
if(IsInvoking())
:也有傳字符串指定的重載
- 取消該腳本上的所有
銷毀失活影響:延遲函數在對象銷毀或移除時不能執行,但在失活時仍然會執行(直接在面板上把腳本失活了實際上也還是不能執行)
有什么用=》做個計數器,或者延時銷毀前加入處理邏輯(入門里學過Destroy(obj, 時間)
,這種延時方法沒有辦法去處理邏輯,若是現在,那么把Destrot(obj)
放在Invoke()
里即可實現延遲銷毀并處理邏輯)
協同程序
多線程相關
unity支持多線程,但是在除主線程的其他線程內無法訪問對象
所以一般開的其他線程用來完成一些耗時的操作,比如尋路算法或者網絡相關,如果寫在主線程會導致主線程卡死
另外,開的其他線程實際上是編輯器里開的,無法通過unity的運行停止關閉,所以要在代碼里記得關
協程
概念辨析
協程是一種假的多線程,效果類似于多線程,但是運行實際上還是在主線程上
能達到類似于多線程的效果,主要在于它是將主線程分時分步執行,在異步下載文件時很有用
unity里的協程分為了協程本體和協程調度器兩部分
協程本體
協程本體是Mono
里的一個方法,這個方法本質上是一個迭代器
寫法:方法名和參數由自己決定,返回值必須是IEnumerator
或繼承它的類型,在方法內必須使用yield return
協程基本方法:
//若現在有自定義協程
IEnumerator MyCoroutine() {yield return 1;
}//開啟協程
Coroutine i = StartCoroutine(MyCoroutine());
//若直接使用MyCoroutine()是不能執行協程的,因為它本質上是一個迭代器
//有重載參數為方法名字符串,但不建議使用
//可以同時開啟多個相同協程,或者下面的方法也可以開啟協程
IEnumerator ii = MyCoroutine();
StartCoroutine(ii);//關閉所有協程
StopAllCoroutines();
//該方法無法阻止第一個yield前的邏輯執行//關閉指定協程
StopAllCoroutines(i);
//傳入的參數必須為Coroutine類型,通常為開啟的那個協程的返回值
yield return
方案:
- 數字/
null
:下一幀執行 new WaitForSeconds(秒數)
:停幾秒,和上面的都在Update
和LateUpdate
間執行new WaitForFixedUpdate()
:在FixedUpdate
和碰撞函數后執行new WaitForEndOfFrame()
:在Camera
和GUI
渲染后執行=,時間上是在LateUpdate
后執行》拍照截圖功能可以放到這后面break
:跳出- 其他如異步加載對象:一般都是在
Update
和LateUpdate
間執行
銷毀失活影響:物體銷毀和失活均不執行,但是組件失活時仍然執行(同樣直接在面板上把腳本失活了實際上也還是不能執行)
協程調度器
上面的StartCoroutine()
方法實際上是unity內部實現的調度器,當然可以自己大概實現一個簡單的只有讀秒的調度器
public class Data
{public float time;public IEnumerator ie;public Data(IEnumerator ie, float time){this.time = time;this.ie = ie;}
}public class Manager : MonoBehaviour
{private static Manager instance;//單例模式實現public static Manager Instance => instance;private List<Data> list;//容器,處理多個相同的協程函數一起調用private void Awake(){instance = this;list = new List<Data>();}private void Update(){for (int i = list.Count - 1; i >= 0; i--)//每幀都去檢測容器里面有沒有東西{if (list[i].time <= Time.time)//list只是檢測秒數的容器{if (list[i].ie.MoveNext())//這里的寫法和最開始基本相同{if (list[i].ie.Current is int){list[i].time = Time.time + (int)list[i].ie.Current;}else//同樣的,如果是其他的yield return在這里else if{list.RemoveAt(i);}}else{list.RemoveAt(i);}}}}public void MyStartCoroutine(IEnumerator ie){if (ie.MoveNext()){if (ie.Current is int)//這里只處理了int的情況,list容器儲存時間以便等待的時間打印{float time = Time.time + (int)ie.Current;list.Add(new Data(ie, time));}//如果有其他類型的yield return在下面else if就行}}
}//調用的時候用Manager.Instance.MyStartCoroutine(MyCoroutine());既可以了
Resources資源動態加載
特殊文件夾
獲取工程路徑Application.dataPath
:獲取的是Assets
的(發布游戲的時候不用這個路徑)
下面未說明的都是需要自己創建文件夾
Resources
資源文件夾:一般全部打包出去,打包后壓縮加密,只讀,只能API加載,放動態加載的資源,一般不獲取路徑,要獲取只能拼接字符串,打包時如果有多個同名,則會自動合并StreamingAssets
流動資源文件夾:打包后不會壓縮加密,移動平臺只讀,PC端可讀可寫,放自定義動態加載的初始資源,可以通過Application.streamingAssetsPath
獲取路徑persistentDataPath
持久數據文件夾:可讀可寫,放動態下載或創建的文件,不用自己創建=》多用于存檔和熱更,可以通過Application.persistentDataPath
獲取路徑
以下為相對而言不那么重要的
Plugins
插件文件夾:放Android和IOS提供的移動端功能Editor
編輯器文件夾:不會被打包,放一些GUI做的之類的Standard Assets
默認資源文件夾:放unity自帶的資源,unity會優先編譯這部分(很少用)
Resources同步加載
干什么的=》避免大量的拖曳關聯
普通方法Resources.Load()
-
加載預設體
GameObject
:加載對象時要實例化Object obj = Resources.Load("預設體名稱");//實際上是把配置文件加載到內存中 Instantiate(obj);
-
加載音效
AudioChip
Object obj = Resources.Load("文件路徑");//如Music/Mymusic AudioSource audio; audio.chip = obj as AudioChip;//這步可以和第一步直接合并 audio.play();
-
加載文本
TextAsset
:支持txt,xml,bytes,json,html,csvTextAsset t = Resources.Load("文件路徑") as TextAsset; //很眼熟啊,長得和入門里獲取腳本那個方法有異曲同工之妙,可以猜到一會還有更簡單的泛型方法了吧 print(t.text);//文本內容 print(t.bytes);//字節數組
-
加載圖片
Texture
Texture t = Resources.Load("文件路徑") as Texturevoid OnGUI() {DrawTexture(t); }
-
加載其他動畫模型等
如果有同一路經下同名的不同類型資源,有兩種解決方案,一是使用重載Resources.Load("路徑", typeof(Texture))
,二是獲取所有Object[] objs = Resources.LoadAll()
泛型方法Resources.Load<類型>("文件路徑")
:上面已經對不同類型闡述了,這里就簡單舉個例子,以后經常用的也是泛型方法
Texture t = Resources.Load<Texture>("文件路徑");
Resources異步加載
內部開一個假線程,不卡主線程,但是不能馬上得到資源(最少要等1幀),適合用來加載大資源
同樣的有普通和泛型方法,這里就以泛型方法為例了
監聽回調實現(線性)
ResourceRequest r = Resources.LoadAsync<>("文件路徑");
//ResourceRequest類繼承自AsyncOperation類,在這個類中有一個成員事件completed
//類型是Action<AsyncOperation>即有參無返回值類型
//這個事件會在資源加載完成后自動回調,所以如果要執行相關邏輯,可以給completed加上自定義函數
r.completed += LoadOver;//假設要加載一張圖片
public Texture t;
public void LoadOver(AsyncOperation r) {t = (r as ResourceRequest).asset as Texture;//asset成員用于存放加載后的資源
}
很容易能看出缺點:只能等資源加載完后處理邏輯
但是呢語法很簡單
協程實現(并行)
//同樣假設加載一張圖片
public Texture t;
IEnumerator Load() {ResourceRequest r = Resources.LoadAsync<>("文件路徑");//這里就可以寫邏輯了yield return r;//yield return的另一種用法,只有等待加載完后才會處理下面的邏輯t = r.asset as Texture;
}//yield return也不一定要返回r,這一行可以替換為以下寫法
while (!r.isDone) {print(r.priority);//打印進度,這個不太準確,以后可以寫寫其他UI的東西在這yield return null;
}
//isDone和priority都是AsyncOperation內的其他成員
優點很顯著:在加載和yield return
間可以寫邏輯,比如UI讀條(唉忽然想到造夢西游三悟空踩云那個過場)
~~但是呢寫法明顯復雜
封裝一個簡單的資源加載器
public class ResourceMgr
{private static ResourceMgr instance = new ResourceMgr();public static ResourceMgr Instance => instance;ResourceMgr(){}public void LoadRes<T>(string name, UnityAction<T> callback) where T : Object//必須寫這個約束,不然不給過編譯{ResourceRequest r = Resources.LoadAsync<T>(name);r.completed += (a) =>{callback((a as ResourceRequest).asset as T);};//回調中的回調。。。新手懵逼絲滑小連招。。。//最大的疑惑其實在這個參數a,你怎么知道他就是獲取了資源的那個對象//AI解答:Unity 的 API 設計保證了 completed 回調傳入的 AsyncOperation 一定是觸發該事件的 ResourceRequest 實例,因此類型轉換是安全的。}
}//外部調用只需
ResourceMgr.Instance.LoadRes<Texture>("hh", (obj) =>
{tex = obj;
});
資源卸載
卸載指定Resources.UnloadAsset(要卸載的資源)
:不能卸載預設體資源,因為他實例化了,直接卸了要出事(少用)
自動卸載未使用的Resources.UnloadUnusedAssets()
:這個就有用了,和GC.collect()
在過場時一塊用
場景異步切換
同步切換回顧SceneManager.LoadScene("場景名稱")
異步切換和異步資源加載的方法差不多,因為場景的東西一般都很多,同步加載會卡死,所以一般用異步
事件回調
AsyncOperation ao = SceneManager.LoadSceneAsync("場景名稱");
ao.completed += ...;
//需要注意的點在于,completed是c#中的事件,由GC管
//只要他還在回調就不會被回收,所以在場景切換依附對象刪除時照樣執行其中的邏輯
協程
和異步資源加載的步驟一摸一樣的,方法換成上面那個,yield return
時return ao
即可,不寫代碼了偷個懶
因為協程在物體銷毀后就會失效,場景切換會先把當前場景所有物體銷毀再創建另一個場景中的內容,所以你懂的會有問題
有沒有什么辦法解決呢=》入門時我們學過一個Mono
里的方法DontDestroyOnLoad(obj)
,即過場景不刪
同樣的可以加進度條,只不過這里的進度條可以有設計一點,比如加載出所有怪物后加百分之二十,加載出所有物品后再加百分之二十等等(越寫越想笑服了…)
封裝一個簡單的場景加載器
別忘了把要切換的場景加到Build Setting
里
public class SceneMgr
{private static SceneMgr instance = new SceneMgr();public static SceneMgr Instance => instance;SceneMgr(){}public void LoadScene(string name, UnityAction action){AsyncOperation ao = SceneManager.LoadSceneAsync(name);ao.completed += (a) =>//這個a沒啥用,因為場景資源自己就切換了,不需要自己存{action();};}
}//外部調用,這個就要簡單得多了,不需要接返回值
SceneMgr.Instance.LoadScene("testScene", () =>
{print("加載完成");
});
LineRendnerer畫線組件
右下角加腳本,可用于畫攻擊范圍,紅外線等等
面板參數
Loop
:起始點是否自動相連Positions
:線段點的坐標(世界坐標系下)Color
:有材質才有用Corner Vertices
:角頂點,增大時會使棱角更平滑End Cap Vertices
:終端頂點Use World Space
:不勾的話畫的線會跟著物體動Meterials
:材質球,使用時需要勾選下面的接收光
以下相對不重要:
Alignment
:對齊方式Texture Mode
:紋理模式,會影響材質球Shadow Bias
:陰影偏移Generate Lighting Data
:生成光源數據,即接收光Lighting
:開啟陰影和接受陰影Probes
:光照探針,以后學Additional Settings
:以后學
新版功能(用的少):
選擇左邊選項:
Simplify Preview
:簡化預覽Subdivide Selected
:啟用后可以拉點加線Show Wireframe
:顯示線框
選擇右邊功能:
Input
:輸入模式
代碼控制
GameObject obj = new GameObject();
obj.name = "line";
LineRenderer l = obj.AddComponent<LineRenderer>();LineRenderer.loop = true;//即面板上是否自動相連,以下方法直接用l點出來也是可以的//改變線段的寬度(面板上Positions里的Width)和顏色
LineRenderer.startWidth / endWidth = 10;
LineRenderer.startColor / endColor = Color.Red;//設置點連成線
LineRenderer.positionCount = 4;//設置點數,在進行其他設置前必須先設置這個
LineRenderer.SetPositions(new Vector3[]{...});//設置每個點的位置
LineRenderer.SetPosition(0, new Vector3(1, 1, 1));//設置指定索引
LineRenderer.useWorldSpace = false;//不用世界坐標系,即線跟著物體動
LineRenderer.generateLightingData = true;//接收光//有了這些方法便可以實現傳入中心點和半徑繪制圓:
//知識回顧:點+向量->平移點 四元數*向量->旋轉向量
//核心代碼
l.SetPosition(i, centerPos + Quaternion.AngleAxis(angle * i, Vector3.up) * Vector3.forward * r);//同樣,也可以實現長按鼠標畫線
//核心代碼
Vector3 v = Input.mousePosition;
v.z = 10;
if (Input.GetMouseButton(0)) {l.positionCount += 1;l.SetPositions(l.positionCount - 1, Camera.main.ScreenToWorldPoint(v));
}
//這樣寫下來的代碼每次都用的是同一個畫線腳本,每次畫線時都會相連
//如果不想自動相連再加一條按下即新建一個腳本的判斷即可
范圍檢測
基本概念
和碰撞檢測一樣屬于物理系統,主要用于瞬時的攻擊范圍判定
=》本質上是在指定范圍內產生一個碰撞器效果(并沒有真的創一個碰撞器),碰了就認為在范圍內
基于這個本質,那么范圍內要被檢測的物體就必須要有碰撞器
代碼實現
主要分為盒裝,球形和膠囊狀檢測,參數大差不差,只是方法不同
盒狀的兩個重要方法
以盒狀為例,重載最多的參數情況下
Collider[] c = Physics.OverlapBox(中心點,邊長,角度,檢測層級,是否忽略觸發器)
- 返回范圍內所有符合條件物體的碰撞體數組
- 中心點和邊長都是
Vector3
的形式傳入,其中邊長僅為實際的一半 - 角度是
Quaternion
傳入,一般傳this.transform.rotation
,實現當前物體面向檢測 - 檢測層級是一個
int
,需要左移構建一個二進制數,在內部用位運算檢測是第幾層(避免32個if
的判斷)- 為什么是一個
int
:整形有32位,剛好對應了右上角Layer
中的0到31層 - 到底怎么寫:
1 << LayerMask.NameToLayer("層名") | 其他層
,當前直接寫具體的層數也可以,但一般為了可讀性,采用LayerMask
里的方法,若要檢測多層,則使用或運算將相應位置為1,但是如果要檢測非常多層,可以直接用異或算出結果傳入 - 若不傳該參數,則默認檢測所有
- 為什么是一個
- 是否忽略觸發器填枚舉
QuergTriggerInteraction
,有UsGlocal
全局(左上角環境設置里的),Collide
不忽略,Ignore
忽略三個成員,不填默認使用全局
除了上面的方法,還有一個
int count = Physics.OverlapBoxNonAlloc(中心點,邊長,碰撞器數組,...)
- 該方法返回范圍內符合條件的個數,但需要在第三個參數傳一個數組進去接收符合條件的物體碰撞器,其余參數與上面的方法一致
其他方法
球形:Physics.OverlapSphere
和Physics.OverlapSphereNonAlloc
,傳邊長變成傳半徑,沒角度
膠囊狀:Physics.OverlapCapsule
和Physics.OverlapCapsuleNonAlloc
,前兩個參數變成三個參數=》上下半圓中心,半圓半徑
射線檢測
基本概念
同樣是和碰撞檢測一樣屬于物理系統,和范圍檢測一樣是瞬時的
=》有什么用:FPS打人,子彈是沒有實體的,用入門中學習的方法太損耗性能了,以及選中物體移動
代碼控制
//創建射線對象
Ray r = new Ray(起點,方向);
r.origin;
r.direction;
//由攝像機發射創建
Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);//屏幕轉視口//射線檢測
bool b = Physics.Raycast(r, 最大距離, 檢測層級, 是否忽略觸發器);
//有重載,第一個參數換成兩個參數起點和方向也可以
//返回值為打中沒
//相對于范圍檢測有一個坑點,最大距離和檢測層級都是int
//且沒有單個參數的重載,要填檢測層級一定要先填最大距離//重載之獲取相交物體
RaycastHit hitInfo;//這是一個物體信息結構體
bool b = Physics.Raycast(r, out hitInfo, ...);
//第二個參數傳RaycastHit,且必須用out修飾(c#那個傳全局變量的關鍵字,傳入后函數內部必須賦值)//RaycastHit的有用成員
hitInfo.collider;
hitInfo.transform;
hitInfo.distance;//如果子彈受重力影響,那么這個成員就很有用了(斜拋運動)
hitInfo.point;//碰撞點
hitInfo.normal;//法線向量
//碰撞點和法線向量可以用來創建特效,前者創建,后者矯正
//創建特效偽代碼
if (鼠標按下) {if (射線檢測) {obj = Instantiate(資源加載);obj.position = info.point;obj.rotation = Quaternion.LookRotation(info.normal);延時銷毀;}
}//獲取多個相交物體,參數大差不差不再演示
RaycastHit[] hits = Physics.RaycastAll(...);
int count = Physics.RaycastNonAlloc(r, hits, ...);
哎呀沒了,就這么多再擠也擠不出來了
趕緊學核心了,基礎實踐會做的會做的。。。有個比較重要的配置文件,不在這寫了
參考資料與學習課程:
b站唐老獅