Unity學習筆記二

文章目錄

  • 3D數學
    • 公共計算結構體Mathf
      • 常用成員
      • 三角函數
    • 向量Vector3
      • 基本成員
      • 點乘
      • 叉乘
      • 插值運算
    • 四元數
      • 引出
      • 基本概念
      • Quaternion結構體成員
      • 四元數運算
  • 更多的Mono
    • 延遲函數
    • 協同程序
      • 多線程相關
      • 協程
        • 概念辨析
        • 協程本體
        • 協程調度器
  • Resources資源動態加載
    • 特殊文件夾
    • Resources同步加載
    • Resources異步加載
      • 監聽回調實現(線性)
      • **協程實現(并行)**
      • 封裝一個簡單的資源加載器
    • 資源卸載
  • 場景異步切換
    • 事件回調
    • 協程
    • 封裝一個簡單的場景加載器
  • LineRendnerer畫線組件
    • 面板參數
    • 代碼控制
  • 范圍檢測
    • 基本概念
    • 代碼實現
      • 盒狀的兩個重要方法
      • 其他方法
  • 射線檢測
    • 基本概念
    • 代碼控制

整個學的過程中碰到參數介紹就很痛苦.jpg

相比于入門來講小上了點強度了,但也還行,里面有談到GUI,但是但是我那個筆記一直拖到現在還沒寫完哈哈哈。。。。(明明是學基礎前就該寫完了)所以就將就看吧(卡姿蘭大眼睛),等把其他UI學了專門發一篇UI的筆記吧。。。。

3D數學

公共計算結構體Mathf

和c#的靜態類Math是一個定位,雖然是結構體,但它的成員全是conststatic

常用成員

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(兩向量點乘得到標量)

幾何意義:ba方向上的投影

實際用途:> 0 兩向量夾角為銳角,= 0 直角,< 0 鈍角 =>判斷敵人的前后大致方位

點乘方法Vector3.Dot(a, b):返回float

補充方法調試畫線

  • Debug.DrawLine(a, b, color):畫線段
  • Debug.DrawRay(a, b, Color):畫射線

獲取兩向量夾角Vector3.Angle(a, b)

=》原理:若b為方向向量,則兩向量夾角余弦值cosβ = ba方向上的投影 / 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時說明ab的左邊,< 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(秒數):停幾秒,和上面的都在UpdateLateUpdate間執行
  • new WaitForFixedUpdate():在FixedUpdate和碰撞函數后執行
  • new WaitForEndOfFrame():在CameraGUI渲染后執行=,時間上是在LateUpdate后執行》拍照截圖功能可以放到這后面
  • break:跳出
  • 其他如異步加載對象:一般都是在UpdateLateUpdate間執行

銷毀失活影響:物體銷毀和失活均不執行,但是組件失活時仍然執行(同樣直接在面板上把腳本失活了實際上也還是不能執行)

協程調度器

上面的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,csv

    TextAsset 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 returnreturn 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.OverlapSpherePhysics.OverlapSphereNonAlloc,傳邊長變成傳半徑,沒角度

膠囊狀:Physics.OverlapCapsulePhysics.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站唐老獅

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80001.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80001.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80001.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為什么Transformer推理需要做KV緩存

一、我們先來回憶一下在transformer中KV在哪里出現過&#xff0c;都有什么作用&#xff1f; α的計算過程&#xff1a; 這里引入三個向量&#xff1a; 圖中的q為Query&#xff0c;用來匹配key值 圖中的k為key,用來被Query匹配 圖中的Value&#xff0c;是用來被進行加權平均的 由…

【大模型面試】大模型(LLMs)高頻面題全面整理(★2025年5月最新版★)

【大模型面試】大模型&#xff08;LLMs&#xff09;高頻面題全面整理&#xff08;★2025年5月最新版★&#xff09; &#x1f31f; 嗨&#xff0c;你好&#xff0c;我是 青松 &#xff01; &#x1f308; 自小刺頭深草里&#xff0c;而今漸覺出蓬蒿。 本筆記適合大模型初學者和…

JAVA:使用 iTextPDF 處理 PDF 的技術詳解

1、簡述 iTextPDF 是一個功能強大的 Java PDF 庫,可以用來創建、修改和處理 PDF 文檔。通過它,我們可以完成如生成 PDF、讀取 PDF 內容、添加水印、合并 PDF 等多種操作。本篇博客將詳細介紹 iTextPDF 的使用方法,并提供一些實踐樣例,幫助開發者快速上手。 樣例代碼: htt…

模態與非模態窗口及使用時的數據交互

模態窗口使用exec()方法顯示&#xff0c;會阻塞父窗口&#xff0c;直到對話框關閉&#xff1b; 非模態對話框允許同時操作主窗口和設置窗口&#xff0c;使用show()。 模態和非模態的主要區別在于用戶能否與父窗口交互&#xff0c;非模態更適合需要頻繁切換的場景。非模態窗口需…

Docker進入MySQL之后如何用sql文件初始化數據

關閉Docker-compose.yml里面所有容器 docker compose -f docker_compose.yml down后臺形式開啟Docker-compose.yml所有容器 docker compose -f docker_compose.yml up -d羅列出所有啟動過的&#xff08;包括退出過的&#xff09;容器 docker ps -a進入指定容器ID內部 docke…

MAC 地址

MAC地址&#xff08;Media Access Control Address&#xff09;是指網絡設備在數據鏈路層使用的唯一標識符&#xff0c;也稱為硬件地址或物理地址。它用于標識設備之間的網絡通信&#xff0c;是網絡適配器&#xff08;如網卡、Wi-Fi適配器等&#xff09;的唯一標識。每個網絡設…

Redis 7.0中5種新特性及實戰應用

Redis 7.0引入了多項革命性的新特性&#xff0c;不僅在性能和可靠性方面有所提升&#xff0c;更在功能和使用體驗上有了質的飛躍。本文將介紹Redis 7.0的五大關鍵新特性&#xff0c;可以根據實際情況利用Redis 7.0的強大功能&#xff0c;構建更高效、更可靠的應用系統。 特性一…

PHP實現PDF自動簽名

技術要點&#xff1a;在PDF中找到一個固定錨點&#xff0c;在需要放置圖片的地方找到測試出錨點對應的XY位 // 使用了poppler方法&#xff0c;其他PDF庫在獲取坐標方面有各種問題&#xff0c;他的安裝是在Linux底層&#xff0c;比在PHP項目中用Composer安裝的庫看上去更穩定&a…

中達瑞和便攜式高光譜相機:珠寶鑒定領域的“光譜之眼”

在珠寶行業中&#xff0c;真偽鑒定始終是核心需求。隨著合成技術與優化處理手段的日益精進&#xff0c;傳統鑒定方法逐漸面臨挑戰。中達瑞和推出的便攜式高光譜相機&#xff0c;憑借其獨特的“圖譜合一”技術&#xff0c;為珠寶真假鑒定提供了科學、高效且無損的解決方案&#…

2025年滲透測試面試題總結-某戰隊紅隊實習面經(附回答)(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 某戰隊紅隊實習面經 個人經歷與技術能力 2. HVV/攻防演練成績 3. 上一個工作主要內容 4. 有意思的邏…

【PostgreSQL數據分析實戰:從數據清洗到可視化全流程】5.1 描述性統計分析(均值/方差/分位數計算)

&#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 文章大綱 5.1 描述性統計分析&#xff1a;均值、方差與分位數計算實戰5.1.1 數據準備與分析目標數據集介紹分析目標 5.1.2 均值計算&#xff1a;從整體到分組分析總體均值計算加權均值…

npm下載插件無法更新package.json和package-lock.json文件的解決辦法

經過多番查證&#xff0c;使用npm config ls查看相關配置等方式&#xff0c;最后發現全局的.npmrc文件的配置多寫了globaltrue&#xff0c;去掉就好了 如果參數很多&#xff0c;不知道是哪個參數引起的&#xff0c;先只保留registryhttp://xxx/&#xff0c;試試下載&#xff0…

基于Anaconda的Pycharm環境配置

一、前提條件&#xff1a; 1、默認已安裝完Anaconda&#xff0c;且創建虛擬環境&#xff0c;參見https://blog.csdn.net/XIAOWEI_JIN/article/details/147657029?spm1001.2014.3001.5501 2、已安裝pycharm&#xff0c;下載鏈接見Pycharm官網&#xff0c;以下以PyCharm 2024.…

Word域操作記錄(從1開始的畢業論文格式排版)

傻逼Word。 寫在最前面 如果你的文章不包括&#xff1a;自動目錄、交叉引用、自動題注。請關閉此頁面。繼續閱讀本文是在浪費您用于跟格式如泥潭里纏斗的時間。 本文內容概述 從指導手冊到畢設初稿 基于多級列表的自動目錄生成方法 正片開始 關于文字 拿到畢設手冊&#…

Linux中的web服務

什么是www www是world wide web的縮寫&#xff0c;及萬維網&#xff0c;也就是全球信息廣播的意思 通常說的上網就是使用www來查詢用戶所需要的信息。 www可以結合文字、圖形、影像以及聲音等多媒體&#xff0c;超鏈接的方式將信息以Internet傳遞到世界各 處去。 當你連接w…

linux -c程序開發

目的是在linux中創建可執行的c語言程序的步驟 和gcc,make和git的簡單運用 建立可執行程序的步驟: -1:預處理: --:頭文件展開;--去掉注釋;--宏替換;--條件編譯 -2:編譯 --:將預處理之后的c語言替換為匯編語言帶阿米 --:語法分析,語義分析,代碼生成 --:檢查語法正確性并且優…

Netty 是一個基于 Java NIO 的高性能網絡通信框架

Netty 是一個基于 Java NIO 的高性能網絡通信框架&#xff0c;廣泛應用于構建分布式系統、RPC 框架、即時通信系統等場景。它的核心設計目標是 異步、非阻塞、高可擴展性&#xff0c;其底層原理涉及 事件驅動模型、線程模型、內存管理 等關鍵技術。以下是 Netty 的核心原理和架…

UI 庫 Ant Design 中的 Table 表格和分頁器:快速實現數據展示和分頁功能

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

Java實現堆排序算法

1. 堆排序原理圖解 堆排序是一種基于二叉堆&#xff08;通常使用最大堆&#xff09;的排序算法。其核心思想是利用堆的性質&#xff08;父節點的值大于或等于子節點的值&#xff09;來高效地進行排序。堆排序分為兩個主要階段&#xff1a;建堆和排序。 堆排序步驟&#xff1a; …

【Hive入門】Hive安全管理與權限控制:審計日志全解析,構建完善的操作追蹤體系

目錄 引言 1 Hive審計日志概述 1.1 審計日志的核心價值 1.2 Hive審計日志類型 2 HiveServer2操作日志配置 2.1 基礎配置方案 2.2 日志格式解析 2.3 日志輪轉配置 3 Metastore審計配置 3.1 Metastore審計啟用 3.2 審計事件類型 4 高級審計方案 4.1 與Apache Ranger…