這幾天在准備找工作,拿出了以前的一些資料,整理了一下分享出來看看,一是方便自己查漏補缺,二來其中的大部分問題是自己理解概括的,有大佬如果看到有錯誤的地方能夠評論交流一下自然是最好的啦!希望早點找到一個工作可以不用在家躺屍了......
以下開始歸納題目——第一部分
1.點乘與叉乘,幾何意義及公式
點乘:計算投影和兩個向量之間的夾角 |a||b|cos<a,b>
叉乘:計算兩個向量組成平面的法線方向,計算法線,可以計算出a向量與b向量組成的平行四邊形的面積 |a||b|sin<a,b>
2.以下代碼的意圖是什么?有沒有什么問題?應該怎么寫?
for(int i=0;i<10;i++)
{
if(list[i]==9)
{
list.RemoveAt(i);
}
}
超出索引值,因為在移除指定下標的元素后會丟失元素,所以索引最多只能到8,而不能到9,並且在遍歷的時候不應該刪除元素。
3.數組,List,ArrayList的區別
數組:在內存中是連續存儲的,有下標,訪問迅速,便於賦值以及修改數據,但是需要預先向內存申請指定的空間。
ArrayList:在ArrayList中插入不同類型的數據是允許的,將所有數據都轉化為Object來使用,可能出現不匹配的問題,類型是屬於不安全的數據結構類型,而且裝箱和拆箱操作會導致性能受到很大的損耗。
因此導致了List誕生,也因此衍生了泛型的概念。
List:可以使用泛型來動態的指定對象的類型,減少了類型轉換和運行時出錯的可能性,動態地根據加入或減少的元素數量進行空間的刪減,存儲不是連續的,移除某個元素之后會導致后面的元素移動到前面。
4.有一個需求,要求體力每5分鍾增加1點,可以通過int GetTimeStamp()函數獲取當前時間戳,如何實現該需求,要保存什么數據,或者應當用什么方式來刷新體力。
時間戳:從1970年1月1日00點00分00秒開始至今的總毫秒數。
方法:通過記錄上一次保存的時間戳,使用當前的時間戳與上次保存時的時間戳相減,得到的時間除以5分鍾換算而成的毫秒數,得到中途經過了多少個5分鍾,再增加體力值。
PS:如果需求改為在每天的0點更新(增加2點),則將此時的時間戳減去上次更新的時間戳,並且除以86400秒,則可以得到距離上次更新的時間戳的間隔時間為多少天,多一天則增加2點。
PPS:如果改為在每天的凌晨5點更新,則應該將此時的時間戳以及上次的時間戳都移除去5小時*86400秒,整體偏移5個小時的差別,則可以得到應該更新的次數,並且作出更新。
5.舉例說明對象池的作用,設計一個對象池,應該具有哪些重要字段以及方法
對象池的作用:對象池能夠節省創建和初始化所耗費的時間,簡化對象獲取和使用的過程,對於那些被系統頻繁請求和使用的對象,使用這種機制可以使性能達到很大提高,是以空間來換時間的操作。
在C#中為了避免GC機制,對象池可以較好地節省消耗的資源。
重要字段有:對象池所使用的對象,能用來判斷當前對象是否在使用的flag標簽
重要方法有:保存方法,對象池中所使用的保存當前對象的方法,取出對象並且使用對象的方法,都是需要有的。
6.LinkedList是什么?優缺點是什么?用途是什么?
LinkedList是鏈表,是一種可雙向鏈表的數據結構,底層是用鏈表實現,由相互引用的節點組成的雙向鏈表,插入數據到某個位置時,數據會形成一個新的節點,改變鏈表中的對應的兩個節點的引用關系就可以完成
插入,刪除操作同樣可以使用引用修改來完成。
優點為:增刪數據,修改數據非常方便,直接修改引用即可。
缺點為:遍歷某個數據必須從頭開始,直到遍歷到那個數字為止,十分不方便。
7.private public protected internal四種修飾符分別是什么含義?
private:私有修飾符,僅在當前的類中可以使用調用。
public:公有修飾符,公開的數據類型,所有的類在引用時都可以訪問到,是較為公開的數據類型
protected:保護修飾符,用於當前的類和繼承的類都可以調用,可以自由使用,非繼承或者外部類無法使用
internal:在同一個程序集中都可以使用的修飾符,修飾在當前程序集中可以使用的變量。
8.反射是什么?用途是什么?
反射提供了封裝程序集、模塊和類型的對象(Type類型)。可以使用反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型並調用其方法或訪問其字段和屬性。
如果代碼中使用了特性,可以利用反射對它們進行訪問。
用途:
1.需要訪問程序元數據的特性。
2.檢查和實例化程序集中的類型。
3.在運行時構建新類型。使用System.Reflection.Emit中的類。
4.執行后期綁定,訪問在運行時創建的類型的方法。
9.ref關鍵字有什么用?和out關鍵字有什么區別?
ref可以使一個值成為引用,處理的數據需要有輸入也需要有輸出,能被大部分的值引用。且使用時需要顯示使用ref關鍵字,ref關鍵字在使用前必須要先初始化。
out可以讓參數通過引用來傳遞,與ref類似,但是在傳遞前可以不用初始化,若要使用,則必須顯示使用out關鍵字。out適用於多個return返回值的地方,ref適用於在需要被調用的方法中修改調用者的引用。
10.舉例Unity的四個特殊文件夾,分別是干什么用的?
StreamingAssets:文件夾中的文件目錄結構和文件會被原封不動地打包進安裝包中
Resources:需要動態加載的資源存放的位置
Editors:編輯器,特殊編輯工具存放的位置
Plugins:插件存放的位置
11.類與結構有什么區別?它們和堆,棧有什么聯系?
類屬於引用類型,類使用堆存儲,空間較大,但是訪問效率低,類是反應事物的抽象,類可以在聲明時進行初始化。具備繼承和多態的特點。
結構是值類型。結構使用棧來存儲,棧的空間相對較小,但是效率較高。結構體是包含了具體不同類別數據的包裝,不具備繼承和多態,在聲明時不能對結構進行初始化
12.Unity協程和C#線程的區別
Unity中的協程與多線程下的情況類似,有自己的堆棧,自己的局部變量,自己的指令指針,但是與其他協同程序共享全局變量等很多信息。線程,多線程是阻塞式的,每個IO必須開啟新的線程,對於多個CPU可以使用Thread開啟多線程。
主要不同在於:多處理器情況下,在概念上多線程同時運行多個線程,協程是通過協作來完成的,在任意一個指定時刻只有一個協同程序在工作,其他協程處於休眠狀態,協程實際是在一個線程中,只不過每個協程
對CPU進行分時,協程可以訪問和使用Unity的所有方法和組件。
同一時間只能執行某個協程,協程適合對某個任務進行分時處理。控制代碼在特定的時間執行。協程不是線程,也不是異步執行,跟Update一樣,在主線程中執行。不用考慮同步和鎖的問題。
協程是一個分部組件,遇到條件(yield return)會掛起,直到條件滿足才會被喚起執行后面的語句。
協程要關閉只能使用StopCoroutine函數,且函數的參數只能是字符串形式的輸入,否則不會生效。
13.舉例說明狀態機在游戲中的使用,行為樹和狀態機的區別和聯系
狀態機在游戲中的使用,AI、動畫系統、UI邏輯、玩家自動掛機。區別在於:狀態機是將AI行為分為一個接一個的狀態,狀態與狀態之間通過事件觸發來形成,“事件觸發型”的控制,行為樹是一種流行的AI技術,
涵蓋了層次狀態機,事件調度,事件計划和行為等一系列技術,是屬於高度模塊化的狀態,去掉了狀態中的跳轉邏輯,使得狀態變成了一個行為。行為與行為之間的跳轉主要是通過父節點的類型來進行決定的,可以
並行處理兩個行為。同時可以增加控制的節點類型,達到復用行為的目的。
14.stack,Array,List,Queue,Hashset,Dictionary分別說明他們的特點,區別以及應用場景。
stack是棧,先進后出,后進先出的一種數據結構,屬於特定的線性表,常用於實現遞歸方面的場景,還有撤銷功能的實現。
Array是數組,是一種順序存儲結構,分配在連續內存中,不能隨意擴展,數據類型一致,插入數據慢,占用空間較大,性能高,數據多性能不受到影響。
List是列表,內部采用數組進行實現,可以實現泛型,沒有拆箱和裝箱的風險,類型安全,但是不是線程安全,動態地根據加入和刪除的數據進行空間的分配。
LinkedList是鏈表,內存中存儲不一定是連續的,無法用下標訪問,增加刪除塊,適用於經常增減節點的情況,查詢較慢,需要通過遍歷來從頭挨個找。
HashTable是哈希集合,包含不重復項的無序列表,插入的數據快,類似不支持泛型的字典,存入取出數據時需要使用到哈希值來進行處理。
Dictionary是字典,可以實現泛型,增刪改查非常快,鍵值對的形式來存儲數據,可以用來代替實體,當只有ID和另一個屬性時,可以大幅度地提升效率。
Queue是隊列,先進先出,入隊和出隊兩個操作,同樣不是線程安全,特殊的線性表,只允許在表前端進行刪除操作,表后端進行插入操作,隊列中沒有元素時,稱為空隊列。
15.使用兩個stack來實現一個Queue
首先使用一個Stack來進行存儲,稱為s1然后將s1中的元素存入到s2中,然后循環放入數據時就可以進行操作了,在存儲數據時將數據放入s1中,取出數據時將s2的數據取出,就可以實現一個先進先出的隊列了。
16.GC是什么意思?在代碼設計中為什么要考慮它?
GC是C#獨特的垃圾回收機制,在運行.net應用程序時,程序創造出來的對象實例都是被CLR追蹤的,CLR會判斷在什么時候,內存中的這些對象沒有被用到,沒有被引用到,它就會去整理這些不再被用到的對象,
在恰當的時機銷毀部分對象,釋放出這些內存。但是由於銷毀的操作非常耗費資源,因此在程序設計中需要盡可能地考慮減少GC的次數。
17.Unity中sharedmaterial和material有什么區別?
一個是可分享材質,另外一個是不共享材質,共享材質可以在程序運行時進行批處理,能夠減少程序的消耗。
18.mipmap是什么?它如何使用?有什么優缺點?
mipmap是一種貼圖處理方式,將貼圖以2倍數縮小,直到1X1將縮小的圖存儲起來,在渲染時根據像素離眼睛的距離來判斷從一個合適的圖層中取出texel顏色賦值給像素,可以加速渲染的速度以及減少圖像鋸齒,
渲染的速度得到了提升,但是消耗了部分的空間來存儲不同大小的貼圖使用空間來換時間的一種方式。
19.描述AssetBundle的用法
部分特殊資源打包,單獨打包,通過更新還有加載加入的方式來把資源加載到游戲中,節省了程序存儲空間,控制了游戲包的大小,實現了游戲的熱更新。可以把文件分為序列化文件和資源文件,
資源打碎放在對象中,最后統一寫進一個單獨的文件中,某些二進制資源被單獨保存,方便快速加載。
20.Unity中熱更新的原理及流程
熱更新原理:表示在機器不停機的情況下對於系統進行更改,在游戲運行的過程中進行下載更新,不重啟的情況下變更了資源,用戶重啟客戶端就可以實現客戶端資源代碼的更新的需求或者功能。
熱更新流程:資源打包為AssetBundle,並且打包的文件的MD5保存到文件中,更新版本號>>資源提交到資源服務器>>客戶端啟動,從服務器獲得版本號V1,讀取本地版本號V2,比較v1和v2,若相等則進入游戲,否則就從服務器下載md5列表,讀取本地md5文件列表,對比文件,找到md5改變的文件>>下載md5改變的文件>>更新本地版本配置文件>>進入游戲
21.描述接口用途,接口和抽象類有什么相似和區別?
接口的用途:定義一種協議,任何實現當前接口的類都必須要遵循這個協議來完成,滿足這個協議的要求。接口中的方法必須要被繼承接口的類實現,這是一種約束。
相似:都可以被繼承,都不能實例化,都可以包含方法聲明,都要實現未實現的方法。
區別:抽象類可以有構造方法,普通成員變量,靜態方法。接口都不能有以上三個,但接口可以多繼承,一個類只能繼承一個抽象類。
22.值類型和引用類型賦值的區別?
值類型數據存放在棧上,引用類型數據存放在堆上,地址存放在棧上。值類型聲明后編譯器為其分配內存,聲明引用類時僅僅在棧中分配內存存放地址,並沒有為其分配堆上的內存空間。
在賦值時,值類型變量會直接賦值給另一個變量,執行一次賦值。但是引用類型會復制引用對象的內存地址,在賦值后會有多個變量指向同一個引用對象實例。
23.面向對象,面向過程的特點,對比的優缺點分別是什么?
面向對象構成問題事務分解為各個對象,建立對象的目的,是為了描述事物在解決問題的步驟中的行為。
面向過程是解決問題的按部就班,分析問題的步驟,用函數一步步實現即可。
優缺點分別是:
面向過程:性能更高,但是開銷更大,更消耗資源,例如單片機,嵌入式開發,linux和Unix,性能是較為重要的因素。
面向對象:容易維護,容易復用,容易擴展由於面向對象有封裝繼承多態的特性,可以設計出低耦合的系統,更靈活,容易進行維護。但是性能較低。
24.舉例說明如何使用射線來檢測實現碰撞?
AI的射線檢測玩家,地面判定條件,碰撞盒檢測等。
25.DrawCall是什么?如何降低DrawCall?
DrawCall是CPU調用圖像編程接口,來命令GPU進行渲染的操作。
CPU和GPU通過一個命令緩沖區實現並進行工作,其包含一個命令隊列,CPU在其中添加命令,GPU讀取命令實現並行工作,添加和讀取相對獨立,使得可以獨立工作。
如何降低DrawCall,使用批處理技術,盡量讓資源模型公用材質,減少DrawCall的次數,通過將紋理打包成圖集的方式來減少材質的使用,盡量減少使用反光材質,陰影以及透明材質,減少物體的多次渲染。使用圖集,可以有效減少DrawCall,例如在圖集中減少渲染的次數,減少盡可能的多的渲染的次數使用
26.已知三角形的三條邊的長度,求三個角度分別是什么?
余弦定理表達式
cosa=(b*b+c*c-a*a)/2bc
cosb=(a*a+c*c-b*b)/2ac
cosc=(a*a+b*b-c*c)/2ab
27.生成一個指定長度的隨機字符串,要求只包含大小寫字母和數字?
定義一個字符串,內容為“abcdefghijkl.....1234567.....ABCDEF...”再根據指定長度來隨機取出字符串中的字母和數字。
28.位運算有哪些?舉例說明用途?
&常用於二進制取位操作,將任意數與1取&得到的結果,是判斷整數的奇偶,最末尾為0則為偶數,為1為奇數, | 用於無條件賦值,任意數 |1就是把二進制的末尾數變為1,如果需要變為0則只需要把任意數|1后再減一即可,^可以用於比較大小,兩次異或同一個數不變,可以用於簡單加密,設定一個數為密鑰,將要傳遞的數據與其進行異或,得到新數據,再異或一次,就可以得到原數據了
29.overload和override的相同點和區別點是什么?
重載函數名相同,但是參數名,返回值,參數類型不能相同,名字一樣,靜態多態。
重寫在子類繼承父類時,可以定義某方法與父類方法相同的名稱和參數,子類在調用時自動調用子類的方法,父類的方法相當於被重寫了
相同點:函數方法名相同。
區別點:
重寫:方法名,參數,返回值相同,子類不能縮小父類的訪問權限,子類不能拋出比父類多的異常,存在子類和父類之間,父類方法必須有virtual關鍵字。
重載:參數類型,個數,順序至少有一個不相同,但是方法名相同,不能重載只有返回值不同的方法名。存在於父類,子類和同類中,virtual關鍵字可有可無。
30.C++頭文件保護符的原理和作用?
頭文件相當於文本替換,在定義頭文件保護符時,因為其第一次被包含,所以沒有宏定義過“A_H”因此經過定義
得到了宏“A_H”然后進入編譯。如果第二次進入,判斷是否定義過宏了,這樣可以保證頭文件不會被多次包含,只會包含一次,只要有一次就行了,否則編譯都會報錯。C++頭文件保護符
的目的就是避免這類錯誤。
為了避免命名沖突,預處理器變量經常用全大寫字母表示。預處理器變量有兩種狀態:一定義和未定義。定義預處理器變量和檢測器狀態所用的預處理器指示不同。
#define指示接受一個名字並定義該名字為預處理器變量。
#ifndef指示檢測指定的預處理器變量是否未定義。如果預處理器變量未定義,那么跟在其后面的所有指示都被處理,直到出現#endif。
為了保證頭文件在給定的源文件中只處理一次,我們首先檢測#ifndef。第一次處理頭文件時,測試會成功,因為相應的預處理器還未定義。下一條語句就定義了該預處理器變量。
那樣的話,如果我們編譯的文件敲好又一次包含了該頭文件,#ifndef指示會發現該預處理器已經定義,並且忽略該頭文件的剩余部分。