1. [C#語言基礎]請簡述拆箱和裝箱。
答:
裝箱操作:
值類型隱式轉換為object類型或由此值類型實現的任何接口類型的過程。
1.在堆中開辟內存空間。
2.將值類型的數據復制到堆中。
3.返回堆中新分配對象的地址。
拆箱操作:
object類型顯示轉換為值類型或從接口類型到實現該接口值類型的過程。
1.判斷給定類型是否是裝箱時的類型。
2.返回已裝箱實例中屬於原值類型字段的地址。
2. [.NET(C#)] attribute,property,markup,tap翻譯
答:attribute翻譯成特性,用來標識類,方法 。
property翻譯為屬性,性質用於存取類的字段 。
markup翻譯成標記。
tag翻譯成標簽。
3. [.NET(C#)] 程序集的重要特性
答:程序集的一個重要特性是它們包含的元數據描述了對應代碼中定義的類型和方法。
4. [.NET(C#)] ref與out關鍵字
答:ref 關鍵字使參數按引用傳遞。其效果是,當控制權傳遞回調用方法時,在方法中對參數所做的任何更改都將反映在該變量中。若要使用 ref 參數,則方法定義和調用方法都必須顯式使用 ref 關鍵字。
out 關鍵字會導致參數通過引用來傳遞。這與 ref 關鍵字類似,不同之處在於 ref 要求變量必須在傳遞之前進行初始化。若要使用 out 參數,方法定義和調用方法都必須顯式使用 out 關鍵字。
5. [.NET(C#)] new 關鍵字用法。
答:1) new 運算符 :用於創建對象和調用構造函數。
2) new 修飾符 :用於向基類成員隱藏繼承成員。
3) new 約束 :用於在泛型聲明中約束可能用作類型參數的參數的類型。
6. [.NET(C#)] C#中,string str = null 與 string str = "",說明區別。
答:string str = "" 初始化對象分配空間。
string str = null 表示一個空引用,沒有占用空間。//實際情況是,string為null時依然為"",但該題常考。
7. [.NET(C#)]什么是序列化?
答:序列化是將對象狀態轉換為可保持或傳輸的格式的過程。 與序列化相對的是反序列化,它將流轉換為對象。這兩個過程結合起來,可以輕松地存儲和傳輸數據。
8. [.NET(C#)] sealed 修飾符有什么特點
答:
1) sealed 修飾符可以應用於類、實例方法和屬性。密封類不能被繼承。密封方法會重寫基類中的方法,但其本身不能在任何派生類中進一步重寫。當應用於方法或屬性時,sealed 修飾符必須始終與 override一起使用。
2) 將密封類用作基類或將 abstract 修飾符與密封類一起使用是錯誤的。
3) 結構是隱式密封的;因此它們不能被繼承。
9. [.NET(C#)] 詳述.NET里class和struct的異同。
答:
相同點:
1) 語法類似。
不同點:
1) class是引用類型,繼承自System.Object類; struct是值類型,繼承自System.ValueType類,因此不具多態性。但是注意,System.ValueType是個引用類型。
2) 從職能觀點來看,class表現為行為; 而struct常用於存儲數據。
3) class支持繼承,可以繼承自類和接口; 而struct沒有繼承性,struct不能從class繼承,也不能作為class的基類,但struct支持接口繼承。
4) 實例化時,class要使用new關鍵字; 而struct可以不使用new關鍵字,struct在聲明時就進行了初始化過程,所有的成員變量均默認為0或null。
10. [.NET(C#)]如何選擇結構還是類。
答:1) 堆棧的空間有限,對於大量的邏輯的對象,創建類要比創建結構好一些。
2) 結構表示如點、矩形和顏色這樣的輕量對象。例如,如果聲明一個含有 1000 個點對象的數組,則將為引用每個對象分配附加的內存。在此情況下,結構的成本較低。
3) 在表現抽象和多級別的對象層次時,類是最好的選擇。
4) 大多數情況下該類型只是一些數據時,結構時最佳的選擇。
11. [.NET(C#)]抽象類(abstract class)和接口(interface)的區別。
答:
抽象類:
1) 抽象方法只作聲明,而不包含實現,可以看成是沒有實現體的虛方法。
2) 抽象類不能被實例化。
3) 抽象類可以但不是必須有抽象屬性和抽象方法,但是一旦有了抽象方法,就一定要把這個類聲明為抽象類。
4) 具體派生類必須覆蓋基類的抽象方法。
5) 抽象派生類可以覆蓋基類的抽象方法,也可以不覆蓋。如果不覆蓋,則其具體派生類必須覆蓋它們。
接口:
1) 接口不能被實例化。
2) 接口只能包含方法聲明。
3) 接口的成員包括方法、屬性、索引器、事件。
4) 接口中不能包含常量、字段(域)、構造函數、析構函數、靜態成員。
5) 接口中的所有成員默認為public,因此接口中不能有private修飾符。
6) 派生類必須實現接口的所有成員。
7) 一個類可以直接實現多個接口,接口之間用逗號隔開。
8) 一個接口可以有多個父接口,實現該接口的類必須實現所有父接口中的所有成員。
抽象類和接口的異同:
相同點:
1) 都可以被繼承。
2) 都不能被實例化。
3) 都可以包含方法聲明。
4) 派生類必須實現未實現的方法。
區 別:
1) 抽象基類可以定義字段、屬性、方法實現。接口只能定義屬性、索引器、事件、和方法聲明,不能包含字段。
2) 抽象類是一個不完整的類,需要進一步細化,而接口是一個行為規范。微軟的自定義接口總是后帶able字段,證明其是表述一類“我能做。。。”。
3) 接口可以被多重實現,抽象類只能被單一繼承。
4) 抽象類更多的是定義在一系列緊密相關的類間,而接口大多數是關系疏松但都實現某一功能的類中。
5) 抽象類是從一系列相關對象中抽象出來的概念, 因此反映的是事物的內部共性;接口是為了滿足外部調用而定義的一個功能約定, 因此反映的是事物的外部特性。
6) 接口基本上不具備繼承的任何具體特點,它僅僅承諾了能夠調用的方法。
7) 接口可以用於支持回調,而繼承並不具備這個特點。
8) 抽象類實現的具體方法默認為虛的,但實現接口的類中的接口方法卻默認為非虛的,當然您也可以聲明為虛的。
9) 如果抽象類實現接口,則可以把接口中方法映射到抽象類中作為抽象方法而不必實現,而在抽象類的子類中實現接口中方法。
12. [.NET(C#)]什么叫應用程序域?
答:1) 操作系統和運行庫環境通常會在應用程序間提供某種形式的隔離。
2) 應用程序域為安全性、可靠性、版本控制以及卸載程序集提供了隔離邊界。
3) 應用程序域可以理解為一種輕量級進程。起到安全的作用。占用資源小。
13. [.NET(C#)]什么是強類型?
答:為所有變量指定數據類型稱為“強類型”。C#是強類型語言。
14. [.NET(C#)]托管代碼。
答:使用基於公共語言運行庫的語言編譯器開發的代碼稱為托管代碼;托管代碼具有許多優點,例如:跨語言集成、跨語言異常處理、增強的安全性、版本控制和部署支持、簡化的組件交互模型、調試和分析服務等。
15. [.NET(C#)]什么是CTS?
答:CTS:通用系統類型 Common Type System。所有.NET語言共享這一類型系統,實現它們之間無縫的互操作。該方案還提供了語言之間的繼承性。
16. [.NET(C#)]什么是CLR?
答:CLR:公共語言運行庫 Common Language Runtime。是一個運行時環境,它負責資源管理(內存分配和垃圾收集),並保證應用和底層操作系統之間必要的分離。
17. [.NET(C#)]什么是CLS?
答:CLS:公共語言規范 Common Language Specification。可以保證C#組件與其他語言組件間的互操作性。
18. [.NET(C#)]什么是委托?
答:1) 委托是一種引用方法的類型。
2) 委托類似於 C++ 函數指針,但它是類型安全的。
3) 委托允許將方法作為參數進行傳遞。
4) 委托可用於定義回調方法。
19. [.NET(C#)]活動目錄的作用。
答:1) Active Directory存儲了有關網絡對象的信息,並且讓管理員和用戶能夠輕松地查找和使用這些信息。
2) Active Directory使用了一種結構化的數據存儲方式,並以此作為基礎對目錄信息進行合乎邏輯的分層組織。
20. [.NET(C#)]在.NET中,配件的意思。
答:程序集(中間語言,源數據,資源,裝配清單)。
21. [.NET(C#)]值類型和引用類型的區別。
答:1) 值類型通常被分配在棧上,它的變量直接包含變量的實例,使用效率比較高。
2) 引用類型分配在托管堆上,引用類型的變量通常包含一個指向實例的指針,變量通過該指針來引用實例。
3) 一個是值COPY,一個是地址COPY。
值類型 |
引用類型 |
||
內存分配地點 |
分配在棧中 |
分配在堆中 |
|
效率 |
效率高,不需要地址轉換 |
效率低,需要進行地址轉換 |
|
內存回收 |
使用完后,立即回收 |
使用完后,不是立即回收,等待GC回收 |
|
賦值操作 |
進行復制,創建一個同值新對象 |
只是對原有對象的引用 |
|
函數參數與返回值 |
是對象的復制 |
是原有對象的引用,並不產生新的對象 |
|
類型擴展 |
不易擴展 |
容易擴展,方便與類型擴展 |
22. [.NET(C#)].NET中的垃圾回收機制。
答:.NET Framework 的垃圾回收器管理應用程序的內存分配和釋放。每次使用 new 運算符創建對象時,運行庫都從托管堆為該對象分配內存。只要托管堆中有地址空間可用,運行庫就會繼續為新對象分配空間。但是,內存不是無限大的。最終,垃圾回收器必須執行回收以釋放一些內存。垃圾回收器優化引擎根據正在進行的分配情況確定執行回收的最佳時間。當垃圾回收器執行回收時,它檢查托管堆中不再被應用程序使用的對象並執行必要的操作來回收它們占用的內存。
23. [.NET(C#)]什么是索引器?如何使用索引器?
答:索引器允許類或結構的實例按照與數組相同的方式進行索引。索引器類似於屬性,不同之處在於它們的訪問器采用參數。可以用任意類型索引。
1) 索引器使得對象可按照與數組相似的方法進行索引。
2) get 訪問器返回值。set 訪問器分配值。
3) this 關鍵字用於定義索引器。
4) value 關鍵字用於定義由 set 索引器分配的值。
5) 索引器不必根據整數值進行索引,由您決定如何定義特定的查找機制。
6) 索引器可被重載。
7) 索引器可以有多個形參,例如當訪問二維數組時。
24. [.NET(C#)]進程和線程的區別。
答:1) 進程是系統進行資源分配和調度的單位。
2) 線程是CPU調度和分派的單位。
3) 一個進程可以有多個線程,這些線程共享這個進程的資源。
25. [.NET(C#)]啟動一個線程是用run()還是start()?
答:啟動一個線程是調用start()方法,導致操作系統將當前實例的狀態更改為ThreadState.Running。
26. [.NET(C#)]構造器Constructor是否可被override(重寫)?
答:構造器Constructor不能被繼承,因此不能重寫override,但可以被重載Overloade。
27. [.NET(C#)]靜態成員和抽象類
答:靜態成員override、virtual 或 abstract。
抽象類不能是密封的sealed或靜態的static。
28. [.NET(C#)]在C#中using和new這兩個關鍵字有什么意義。
答:using 關鍵字有兩個主要用途:
1) 作為指令,用於為命名空間創建別名或導入其他命名空間中定義的類型。
2) 作為語句,用於定義一個范圍,在此范圍的末尾將釋放對象。
new 關鍵字:新建實例或者隱藏父類方法
29. [.NET(C#)].NET的錯誤處理機制。
答:.NET錯誤處理機制采用try->catch->finally結構。 throw
發生錯誤時,層層上拋,直到找到匹配的catch為止。
30. [.NET(C#)]error和exception有什么區別。
答:error 表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說內存溢出。
不可能指望程序能處理這樣的情況。
exception 表示一種設計或實現問題。
也就是說,它表示如果程序運行正常,從不會發生的情況。
31. [.NET(C#)]UDP連接和TCP連接的異同。
答:1) TCP(Transmission Control Protocol)傳輸控制協議:一種面向連接的、可靠的、基於字節流的運輸層通信協議,三次握手。
2) UDP(User Datagram Protocol)用戶數據報協議:它不屬於連接型協議,因而具有資源消耗小,處理速度快的優點。缺點是易丟失數據包。
32. [.NET(C#)]System.String 和System.StringBuilder有什么區別?
答:1) System.String是不可變的字符串。
2) System.StringBuilder存放了一個可變的字符串,並提供一些對這個字符串修改的方法。
3) String類在執行字符串拼接的操作上,用“+”會產生新的對象,占用內存。
4) StringBuilder類只是修改字符串的內容,不建立新的對象。
33. [.NET(C#)]const和readonly有什么區別?
答:1) const 字段只能在該字段的聲明中初始化。
2) 不允許在常數聲明中使用 static 修飾符。
3) readonly 字段可以在聲明或構造函數中初始化。因此,根據所使用的構造函數,readonly 字段可能具有不同的值。
4) 另外,const 字段是編譯時常數,而 readonly 字段可用於運行時常數。
34. [.NET(C#)]C#中的委托是什么?事件是不是一種委托?
答:委托可以把一個方法作為參數代入另一個方法。
委托可以理解為指向一個函數的引用。
事件是一種特殊的委托。
35. [.NET(C#)]什么是受管制的代碼?
答:在類型或成員的聲明中使用 unsafe 修飾符。因此,類型或成員的整個正文范圍均被視為不安全上下文,無法由 CLR 進行驗證的代碼。
36. [.NET(C#)]面向對象語言三大特性。
答:封裝、繼承、多態。
37. [.NET(C#)]能用foreach遍歷訪問的對象需要實現什么接口或聲明什么方法的類型。
答:聲明IEnumerable接口或實現GetEnumerator()方法。
38. [.NET(C#)]接口是否可繼承接口? 抽象類是否可實現(implements)接口? 抽象類是否可繼承實體類(concrete class)?
答:接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是否可繼承實體類,但前提是實體類必須有明確的構造函數。
39. [.NET(C#)]是否可以繼承String類?
答:String類是sealed類故不可以繼承。
40. [.NET(C#)]數組有沒有length()這個方法? String有沒有length()這個方法?
答:數組、String類都沒有Length()方法,它們只有Length屬性。
41. [.NET(C#)]成員變量和成員函數前加static的作用。
答:即使沒有創建類的實例,也可以調用該類中的靜態方法、字段、屬性或事件。如果創建了該類的任何實例,不能使用實例來訪問靜態成員。靜態成員通常用於表示不會隨對象狀態而變化的數據或計算。
42. [.NET(C#)]什么是虛函數?什么是抽象函數?
答:1) 虛函數:沒有實現的,可由子類繼承並重寫的函數。
2) 抽象函數:規定其非虛子類必須實現的函數,必須被重寫。
43. [.NET(C#)]C#中的三元運算符是?
答:?:。格式如下:ndition ? first_expression : second_expression。
44. [.NET(C#)]當整數a賦值給一個object對象時,整數a將會被?
答:裝箱。
45. [.NET(C#)]委托聲明的關鍵字是?
答:delegate.
46. [.NET(C#)]在.Net中所有可序列化的類都被標記為?
答:[Serializable]
47. [.NET(C#)]利用operator聲明且僅聲明了==,有什么錯誤么?
答:要同時修改Equale和GetHash() ? 重載了"==" 就必須重載 "!="。
48. [智力題] 62-63=1 等式不成立,請移動一個數字(不可以移動減號和等於號),使得等式成立,如何移動?
答:62移動成2的6次方,26。
49. [.NET(C#)]C#可否對內存進行直接的操作?
答:可以使用指針。也就是非安全代碼,就是不在 CLR 完全控制下執行的代碼,它有可能會導致一些問題,因此他們必須用 “unsafe” 進行表明。
50. [.NET(C#)] &和&&的區別。
&是位運算符,表示按位與運算。
&&是邏輯運算符,表示邏輯與(and)
51. [.NET(C#)]重載的方法是否可以改變返回值的類型?
可以。
52. [.NET(C#)]如何把一個Array復制到ArrayList里?
(1) 實現1
string[] s ={ "111", "22222" };
ArrayList list = new ArrayList();
list.AddRange(s);
(2)實現2
string[] s ={ "111", "22222" };
ArrayList list = new ArrayList(s);
53. [.NET(C#)]什么是強名?
強名是由程序集的標識加上公鑰和數字簽名組成的,其中,程序集的標識包括簡單文本名稱、版本號和區域性信息(如果提供的話)。它使用對應的私鑰從程序集文件中生成。(程序集文件包含程序集清單,其中包含組成程序集的所有文件的名稱和哈希。)
54. [.NET(C#)]C#中幾種循環的方法,並指出他們的不同:
1. for:使用於確定次數的循環。
2. foreach:使用於遍歷的元素是只讀的。//Unity中此處是個坑,建議不要用foreach
3. while:次數不確定,條件隨機變化。
4. do...while:次數不確定,條件隨機變化,但至少要保證能被執行一次。
55. [.NET(C#)]請簡述一下用Socket進行同步通訊編程的詳細步驟
1. 在應用程序和遠程設備中使用協議和網絡地址初始化套接字。
2. 在應用程序中通過指定端口和地址建立監聽。
3. 遠程設備發出連接請求。
4. 應用程序接受連接產生通信scoket。
5. 應用程序和遠程設備開始通訊(在通訊中應用程序將掛起直到通訊結束)。
6. 通訊結束,關閉應用程序和遠程設備的Socket回收資源。
56. [.NET(C#)] try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執行,什么時候被執行,在return前還是后?
答:會執行,在return前執行。
57. [.NET(C#)] 寫出程序的輸出結果:
public class A { public virtual void Fun1( int i ) { Console.WriteLine( i ); } public void Fun2( A a ) { a.Fun1( 1 ); Fun1( 5 ); } } public class B : A { public override void Fun1( int i ) { base.Fun1( i + 1 ); } public static void Main() { B b = new B(); A a = new A(); a.Fun2( b ); b.Fun2( a ); } }
答案:
2
5
1
6
58. [.NET(C#)]求以下表達式的值,寫出您想到的一種或幾種實現方法:1 - 2 + 3 - 4 +......+ m
答案:
public static void Main() { int input = int.Parse( Console.ReadLine() ); int sum = 0; for( int i = 0; i <= input; i++ ) { if( ( i % 2 ) == 1 ) { sum += i; } else { sum = sum - i; } } Console.WriteLine( sum ); }
59. [.NET(C#)]兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?
答:不對,有相同的hash code。
60. [.NET(C#)] swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
答案:可以作用在byte和long上,也可以作用在string上。
61. [.NET(C#)] short s1 = 1; s1 = s1 + 1;有什么錯?short s1 = 1; s1 += 1;有什么錯?
答: 1. short s1 = 1; s1 = s1 + 1;有錯,s1是short型,s1+1是int型,不能隱式轉化為short型。可修改為s1 =(short)(s1 + 1) 。
2. short s1 = 1; s1 += 1正確。
62. [.NET(C#)] 字符串處理問題
題目:需要實現對一個字符串的處理,首先將該字符串首尾的空格去掉,如果字符串中間還有連續空格的話,僅保留一個空格,即允許字符串中間有多個空格,但連續的空格數不可超過一個。
答案:
string inputStr = " xx xx ";
inputStr = Regex.Replace( inputStr.Trim(), @"/s+", " " );
63. [.NET(C#)]下面這段代碼輸出什么?為什么?
int i = 5;
int j = 5;
if( Object.ReferenceEquals( i, j ) )
Console.WriteLine( "Equal" );
else
Console.WriteLine( "Not Equal" );
答案:Not Equal。因為比較的是對象
64. [.NET(C#)] public static const int A=1;這段代碼有錯誤么?是什么?
答:const不能用static修飾。
65. [.NET(C#)]下面的代碼中有什么錯誤嗎?
class A { public virtual void F() { Console.WriteLine( "A.F" ); } } abstract class B : A { public abstract override void F();//abstract與override關鍵字可以同時使用 }
答案:沒有錯誤!可以通過編譯器。
注意:網上有資料說abstract與override關鍵字不可以同時使用,這種說法是錯誤的 !
66. [.NET(C#)] 以下是一些C#中的枚舉型的定義,其中錯誤的用法有?
A. public enum var1{ Mike = 100, Nike = 102, Jike }
B. public enum var1{ Mike = “1”, Nike, Jike }
C. public enum var1{ Mike=-1 , Nike, Jike }
D. public enum var1{ Mike , Nike , Jike }
答案B
67. [.NET(C#)] 下面的例子中產生的輸出結果是什么?
class A
{
public static int X;
static A()
{
X = B.Y + 1;
}
}
class B
{
public static int Y = A.X + 1;
static B()
{
}
static void Main()
{
Console.WriteLine( "X={0},Y={1}", A.X, B.Y );
}
}
答:x=1,y=2
68. [.NET(C#)] 寫出程序的輸出結果
class Class1
{
private string str = "Class1.str";
private int i = 0;
static void StringConvert( string str )
{
str = "string being converted.";
}
static void StringConvert( Class1 c )
{
c.str = "string being converted.";
}
static void Add( int i )
{
i++;
}
static void AddWithRef( ref int i )
{
i++;
}
static void Main()
{
int i1 = 10;
int i2 = 20;
string str = "str";
Class1 c = new Class1();
Add( i1 );
AddWithRef( ref i2 );
Add( c.i );
StringConvert( str );
StringConvert( c );
Console.WriteLine( i1 );
Console.WriteLine( i2 );
Console.WriteLine( c.i );
Console.WriteLine( str );
Console.WriteLine( c.str );
}
}
答案:10, 21, 0, str, string being converted
注意:此處加逗號“,”是為了答案看起來清晰,實際結果是縱向排列的,因為調用了Console.WriteLine()。
69. [.NET(C#)] 寫出程序的輸出結果
public abstract class A
{
public A()
{
Console.WriteLine( 'A' );
}
public virtual void Fun()
{
Console.WriteLine( "A.Fun()" );
}
}
public class B : A
{
public B()
{
Console.WriteLine( 'B' );
}
public new void Fun()
{
Console.WriteLine( "B.Fun()" );
}
public static void Main()
{
A a = new B();
a.Fun();
}
}
答案:
A
B
A.Fun()
70. [C#語言基礎]簡述string與StringBuilder相比的優點。
答:
string的字符串為常量不可修改。
1.可以滿足字符串常量池的需要。即對於創建相同文本時,string為同一對象。
2.允許string對象緩存HashCode。字符串不變形保證了hash碼的唯一性。
3.安全性,string被許多的類庫用來當做參數。
StringBuilder實際是一個char類型的集合,完成了組裝拼接等工作。
String更適合做程序的參數,StringBuilder用於做String類型的組裝。
71. [C#語言基礎]C#StringBuilder類型比string類型的優勢是什么?
答:
StringBuilder的優勢在於拼接字符串。
//String的優勢在於對字符串做一些處理,在使用過程中看具體的需求。
72. [C#語言基礎]編寫程序判斷整數46234的每位相加和。
答:
int number = 46234;
string strNumber=number.ToString();
int length = strNumber.Length;
方法1:
int result=0;
for (int i = 0; i < length; i++)
{
result += number % 10;
number \= 10;
}
方法2:
for (int i = 0; i < length; i++)
{
result += number / (int)Math.Pow(10, i) % 10;
}
方法3:
for (int i = 0; i < strNumber.Length; i++)
{
result += int.Parse(strNumber[i].ToString());
}
注:
73. [算法]請使用冒泡排序,對一維數組進行降序排列。
答:
冒泡排序:它重復地走訪過要排序的數列,一次比較兩個元素,如果它們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換。
冒泡排序算法的運作如下:
l 比較相鄰元素。如果第一個比第二個大,就交換它們。
l 對每一對相鄰元素做同樣的工作,從開始第一隊到結尾的最后一對。在這一點,最后的元素會使最大的數。
l 針對所有的元素重復以上的步驟,除了最后一個。
l 持續每次對越來越少的元素重復上面的步驟,知道沒有任何一對數字需要比較。
寫法1
public void Bubble1(int[] a)
{
bool b;
int tmp;
for (int i = 0; i < a.Length; i++)
{
b = false;
for (int j = i+1; j < a.Length ; j++)
{
if (a[j] > a[i])
{
tmp = a[j];
a[j] = a[i];
a[i] = tmp;
b = true;
}
}
if(!b)break;
}
}
寫法2
void Bubble2(int[] a)
{
bool b=false;
int tmp;
for(int i=0;i<a.Length;i++)
{
b=false;
for(int j=0;j<a.Length-i;j++)
{
if(a[j]<a[j+1])
{
tmp=a[j];
a[j]=a[j+1];
a[j+1]=tmp;
b=true;
}
}
if(!b) break;
}
}
寫法3
void Bubble3(int[] a)
{
bool b=true;
int j=0;
int temp;
do
{
b=false;
for(int i;i<a.Length-j;i++)
{
if(a[i]<a[i+1])
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
b=true;
}
}
j++;
}
while(b);
}
74. [C#語言基礎][值類型引用類型]以下代碼輸出結果是什么?原因是什么?
object o1 = 1;
object o2 = o1;
o1 = 2;
Console.WriteLine(o2);
答:
1;
原因:o1將數據1在堆中引用賦值給o2,而后又將引用指向數據2,故o2仍指向數據1的引用。
75. [C#語言基礎]請寫出定義方法的語法。
答:
[訪問修飾符][可選修飾符] 返回類型 方法名稱(參數列表)
{
//方法體;
return 結果;
}
76. [C#語言基礎]請簡述string字符串不可變性的原因?
答:
在很多語言當中如Java\C#中字符串string被設計成具有不可變性的。從系統優化方面考慮這樣的設計好處主要由三點。
首先,它允許在一個字符串上執行各種操作,而不實際地更改字符串。
字符串不可變,還因為這在操作或訪問一個字符串時不會發成線程同步問題。
除此之外,CLR可通過一個String對象共享多個完全一致的String內容。這樣能減少系統中的字符串數量,者正是字符串留用技術的目的。
1.字符串常量池的需要。字符串常量池是內存堆中一個特殊的存儲區域,當創建一個string對象時,假設此字符串值已經存在於常量池中,則不會創建一個新的對象,而是引用已經存在的對象。
2.允許string對象緩存HashCode。字符串不變性保證了hash碼的唯一性,因此可以放心地進行緩存,這是一種性能優化手段,因為這不必每次都去計算新的哈希碼。
3.安全性。string被許多的類庫用來當做參數,例如網絡連接URL,文件路徑Path,還有反射機制所需要的String參數等,假若string可變的,將會引起各種安全隱患。
綜上,string不可變的原因包括設計考慮,效率優化問題,以及安全性三大方面。
另:在C++中string類型是可變的。
77. [C#語言基礎]請簡述方法重載OverLoad?
答:
方法名稱相同,但參數列表不同稱為方法重載。用於在不同條件下解決同一類型的問題。
78. [C#語言基礎]請給出以下代碼輸出結果:
class A
{
public static int a;
static A()
{
a = B.b + 1;
}
}
class B
{
public static int b;
static B()
{
b = A.a + 1;
}
}
static void Main()
{
Console.WriteLine(A.a);
Console.WriteLine(B.b);
}
答:2 ,1
79. [C#語言基礎]請給出以下代碼輸出結果:
class C
{
public static int a;
public C()
{
a++;
}
static C()
{
a++;
}
}
static void Main()
{
C c1 = new C();
C c2 = new C();
C c3 = new C();
Console.WriteLine(C.a);
}
答:4
80. [C#語言基礎]在類的構造函數前加上static會報什么錯?為什么?
答:
靜態函數沒有訪問修飾符,其他C#代碼從來不調用它,但在加載類時,總是由.NET運行庫調用它,所以像public或private這樣的訪問修飾符就沒有任何意義。出於同樣原因,靜態構造函數不能帶任何參數,一個類也只能有一個靜態構造函數。靜態構造函數只能訪問類的靜態成員,不能訪問類的實例成員。
也就是說只加static不會報錯,加了static再加了別的就會報錯。
81. [C#語言基礎]C#函數Func(string a,string b)用Lambda表達式怎么寫?
答:(a,b)=>{}
注:該題有兩種錯誤可能:
一種是方法沒有些返回值即Func(string a,string b)為 void Func(string a,string b)此時,Lambda表達式可寫作(a,b)=>{}
一種是Func為Func<string,string>此時Lambda可寫作a=>b//a,b為string類型
82. [C#語言基礎]數列1,1,2,3,5,8,13...第n為數是多少?用C#遞歸算法實現。答:
public static int Fibonacci(int num)//Fibonacci
{
return (num==0||num==1)?1:(Fibonacci(num-2)+Fibonacci(num-1));
}
注:計算斐波那契數列依據數列定義來建立方法是不推薦的寫法。因為此時計算第n位的數的時間復雜度為O((3/2)n)。相比較而言,利用循環可以將時間復雜度縮小到O(n)該方法較為實用,而且實現簡單,在沒有特殊要求的情況下屬於建議的寫法。另一種優化的寫法可以將時間復雜度優化到O(logn),實現代碼較復雜,且隱含的時間常數較大。但適合面試者展示其知識面和代碼實現的能力。
兩種寫法如下:
寫法一:
public long Fibonacci1(int num)
{
return (num==0||num==1)?1:(Fibonacci1(num-2)+Fibonacci1(num-1));
}
寫法二:
public long Fibonacci2(int num)
{
int result[2]={0,1};
if(n<2)
return result[n];
long fibOne=1;
long fibTwo=0;
long fibN=0;
for(int i=2;i<=n;i++)
{
fibN=fibOne+fibTwo;
fibTwo=fibOne;
fibOne=fibN;
}
return fibN;
}
83. [C#語言基礎]請簡述值類型和引用類型的區別。
答:
從概念上區分,值類型時直接存儲其值,而引用類型是存儲對值的引用。
實際中,對於值類型的對象,初始化一個實例,該實例代表的是其內部存儲的數據本身。而引用類型的對象,初始化一個實例,該實例代表的是其初始化數據在內存當中的引用。
值類型隱式繼承自System.ValueType.該類為抽象類,只能序列化,不能被顯式繼承。
值類型:枚舉,結構
引用類型:數組,委托,類,接口
84. [C#語言基礎]請簡述ArrayList和List<>的主要區別
答:
ArrayList是非泛型列表,存儲數據是把所有的數據都當成object類型數據,存在裝箱問題,取出來使用的時候存在拆箱問題,裝箱拆箱會使性能變差,而且存在數據安全問題,但是優點在於可以讓值類型和引用類型相互轉換。
List是泛型列表,在使用的時候才會去定義數據類型,泛型避免了拆裝箱的問題,存入讀取熟讀較快,類型也更安全。
85. [C#語言基礎]請簡述GC(垃圾回收)產生的原因,並描述如何避免?
解析:首先,這道題的描述是不嚴謹的,GC作為CLR的一種機制是由系統調用的,只要運行與CLR上的托管代碼GC的工作本身是不可避免的。
但是拋開這些細節不談,我可以在這里寫把我認為這道題可能涉及到的東西寫一下。
如果只把GC理解成一種可以自動釋放內存的方式,使程序員省去了手動釋放內存的煩惱,或試圖引用已釋放的內存空間的錯誤,這無疑是片面的,雖然這的確是GC非常重要的功能。但GC的作用遠不如此。
GC的產生是與CLR堆內存特殊的分配方式有關的。CLR要求所有的資源都從托管堆分配,托管堆有一個指針NextObjPtr它的初始為保留地址空間的基地址。NextObjPtr指向下一個對象在堆中的分配位置。每當添加一個對象,NextObjPtr指針的值就會加上對象占據的字節數。這樣做有兩個好處:
首先,在許多應用程序中,差不多同時分配的對象彼此間有較強的聯系,而且經常差不多在同一時間訪問。在垃圾回收環境中,如果對象在內存中連續分配,會由於引用的本地性而獲得性能上的提升。具體地說,這意味着進程的工作集小於非托管環境中運行相似的應用程序。
另一方面,這意味着代碼使用的對象可以全部駐留在CPU的緩存中,加快CPU對這些對象的訪問速度。
但托管堆具有這些好處,是因為它做了一個相當大膽的假設,地址的空間和存儲是無限的。那么如何讓它由假設變為可實現的,這就是GC垃圾回收的工作。
GC的垃圾回收算法是基於世代法和啟發式算法的。
世代法是指將堆分為0代,1代,2代。每當0代的堆滿時就觸發一次垃圾回收。當第0代的的內存並沒被釋放,就會被提升到1代,如果1代在被回收時仍然保留的內存,就會被提升到2代。這樣壓縮空間的的方法保證了堆內存的連續性,增加了訪問對象的速度。而啟發式算法是指在基於應用程序對新建對象的模式,進行啟發式的對第1代,第2代堆進行釋放,或擴大第0代的堆空間。
建議只有在以下兩種情況下才調用Dispose或Close:確定必須清理資源;或者確定可以安全地調用Dispose或Close,並希望將對象從中介列表中刪除,禁止對象提升(到另一代)從而提高性能。
那么避免因為GC過程而影響性能的編程方法如下:
- 因為GC的目標引用地址都是存在棧上的,所以盡量不要用太深的棧,比如遞歸。
- 合理的使用new避免不必要的對象新建次數。
- 不要一次性大量申請內存。
- 對運行時string對象盡量不要使用+來構建,而要用StringBuilder
86. [C#語言基礎]請描述Interface接口與abstract抽象類之間的不同。
答:
語法不同:
1.抽象類中可以有字段,接口沒有。
2.抽象類中可以有實現成員,接口只能包含抽象成員。
3.抽象類中所有成員修飾符都可以使用,接口中所有的成員都是對外的,所以不需要修飾符修飾。
用法不同:
1.抽象類是概念的抽象,接口關注與行為。
2.抽象類的子類與父類的關系是泛化關系,耦合度較高,而實現類和接口之間是實現關系,耦合度比泛化低。
3.一個類只能繼承自一個類,但是可以實現多個接口。
87. [C#語言基礎]下列代碼在運行時會產生幾個臨時對象?
string a="abc";//1個對象
a=(a.ToUpper()+"123").Substring(0,2);
答:三個臨時對象
注:string a="abc";//1個對象
a=(a.ToUpper()+"123").Substring(0,2);
a.ToUpper()//1個臨時對象
"123"//1個臨時對象
a.ToUpper()+"123"//1臨時個對象
.Substring(0,2)//1個對象由於它將引用賦給了a所以它不是臨時對象
在語句運行時結束后不存在引用的對象。
88. [C#語言基礎]下列代碼在運行中會發生什么問題?如何避免?
List<int> Is=new List<int>(new int[]{1,2,3,4,5});
foreach(int item in Is)
{
Console.WriteLine(item*item);
Is.Remove(item);
}
答:會產生運行時錯誤,拋出一個InvalidOperationException異常,因為foreach是只讀的。不能一邊遍歷一邊修改。使用foreach時候不要對內容進行修改。
89. [C#語言基礎]請簡述關鍵字Sealed用在類聲明和函數(方法)聲明時的作用?
答:sealed訪問修飾符用於類時,表示該類不能被繼承;對於方法表示不能重寫該方法。當應用於方法或屬性時,sealed 修飾符必須始終與 override 一起使用。
注:
若要確定是否密封類、方法或屬性,通常應考慮以下兩點:
派生類利用自定義類的功能所獲得的可能好處。
派生類在修改類之后導致其無法正常工作或按預期工作的可能性。
90. [C#語言基礎]請簡述private,public,protected,internal的區別?
答:public:對任何類和成員都公開,無限制訪問
private:僅對該類公開
protected:對該類和其他派生類公開
internal:只能在包含該類的程序集中訪問該類
protected internal:protected+internal
注:
可見性修飾符:
修飾符 |
應用於 |
說明 |
public |
所有類型或成員 |
任何代碼均可以訪問該項 |
protected |
類型和內嵌類型的所有成員 |
只有派生的類型能夠訪問該項 |
internal |
所有類型或成員 |
只能在包含它的程序集中訪問該項 |
prvate |
類型和內嵌類型的所有成員 |
只能在它所述的類型中訪問該項 |
protected internal |
類型和內嵌類型的所有成員 |
只能在包含它的程序集和派生類型的代碼中訪問該項。 |
其他修飾符
修飾符 |
應用於 |
說明 |
new |
函數成員 |
成員用相同的簽名隱藏繼承的成員 |
static |
所有成員 |
成員不作用於類的具體實例 |
virtual |
僅函數成員 |
成員可以由派生類重寫 |
abstract |
僅函數成員 |
虛擬成員定義了成員的簽名,但沒有提供實現代碼 |
override |
僅函數成員 |
成員重寫了繼承的而虛擬或抽象成員 |
sealed |
類、方法和屬性 |
對於類,不能繼承自密封類。對於屬性和方法,成員重寫已繼承的虛擬成員,但任何派生類中的任何成員都不能重寫該成員。當應用於方法或屬性時,sealed 修飾符必須始終與 override 一起使用。 |
extern |
僅靜態[DllImport]方法 |
成員在外部用另一種語言實現
|
91. [C#語言基礎]反射的實現原理?
答:審查元數據並收集關於它的類型信息的能力。
注:
公共語言運行時程序管理應用程序域,應用程序域構成具有相同應用程序范圍的對象周圍定義的邊界。 此管理包括將每個程序集加載到相應的應用程序域中和控制每個程序集內的類型層次結構的內存布局。
程序集包含模塊、模塊包含類型,而類型包含成員。 反射提供封裝程序集、模塊和類型的對象。 可以使用反射動態地創建類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。然后,可以調用類型的方法或訪問其字段和屬性。
Reflection,中文翻譯為反射。
這是.Net中獲取運行時類型信息的方式,.Net的應用程序由幾個部分:‘程序集(Assembly)’、‘模塊(Module)’、‘類型(class)’組成,而反射提供一種編程的方式,讓程序員可以在程序運行期獲得這幾個組成部分的相關信息,例如:
Assembly類可以獲得正在運行的裝配件信息,也可以動態的加載裝配件,以及在裝配件中查找類型信息,並創建該類型的實例。
Type類可以獲得對象的類型信息,此信息包含對象的所有要素:方法、構造器、屬性等等,通過Type類可以得到這些要素的信息,並且調用之。
MethodInfo包含方法的信息,通過這個類可以得到方法的名稱、參數、返回值等,並且可以調用之。
諸如此類,還有FieldInfo、EventInfo等等,這些類都包含在System.Reflection命名空間下。
92. [C#語言基礎].NET與Mono的關系?
答:MONO是.NET的一個開源跨平台工具。.NET只能在Windows下運行,Mono可以實現跨平台,可以運行與Linux,Unix,Mac OS等。
93. [面對對象]請說出4中面向對象的設計原則,並分別簡述它們的含義。
答:
1)單一職責原則:一個類,最好只做一件事,只有一個引起它的變化。
2)開放-封閉原則:對於擴展是開放的,對於更改是封閉的。
3)里氏替換原則:子類必須能夠替換其基類。
4)依賴倒置原則:設計應該依賴於抽象而不是具體實現。
A.高層模塊不應該依賴底層模塊,兩個都應該依賴抽象。
B.抽象不應該依賴細節,細節應該依賴抽象(要對抽象編程,不要對實現編程。)
5)接口隔離原則:使用多個小的專門的接口而不要使用一個大的總接口。
6)迪米特法則:如果兩個類不彼此直接通信,那么這兩個類就不應當發生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。
7)合成/聚合復用原則:盡量使用合成/聚合,盡量不要使用類繼承。
注:
94. [C#語言基礎]Hashtable是無序的嗎?
答:電腦沒有絕對的無序,hashtable是通過哈希碼讓開發者感覺無序。
注:這里的無序是指集合的添加順序與其輸出順序無關。Hashtable是通過哈希碼或哈希函數,對其內部元素進行排列的,所以其元素的添加順序與其輸出順序無關。
95. [設計模式]請描述你所了解的設計模式,並說明在你的項目中哪里使用過?
答:
單例: 對象池,游戲管理器
抽象工廠,
狀態:有限狀態機,
橋接:有限狀態機
策略:AI自動行為操控中每種操控算法的獨例
注:擴展補充。
創建型模式:單例模式、抽象工廠模式、建造者模式、工廠模式、原型模式。
結構型模式:適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。
行為型模式:模版方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式(Interpreter模式)、狀態模式、策略模式、職責鏈模式(責任鏈模式)、訪問者模式。
96. [數據結構]說出你所了解的數據結構,並說明它們的特點。
答:列表:
特點:有序,內存空間連續,讀取速度快,大小可變,通過位置索引取元素.
缺點:輸入,刪除的速度慢
類庫已實現:List<T>、 ArrayList
字典:
特點:鍵值對的集合,通過鍵查找值,查找方便,無序
類庫已實現:Dictionary<TKey,TValue>、Hashtable
棧:
特點:后進前出 LIFO(Last In First Out)
支持操作:入棧,出棧,讀棧頂,
類庫已實現:Stack<T>、Stack
隊列:
特點:前進前出 FIFO(First In First Out)
支持操作:入隊,出隊,讀隊首
類庫已實現:Queue<T>、Queue
鏈表:
特點:節點內存空間不連續,插入,刪除速度快,讀取速度慢.
類庫已實現:LinkedList<T>
數組:
特點:內存空間連續,長度固定,讀取速度快
類庫已實現:Array
樹:
特點:可以將對象組織為層次結構,
實現:可使用設計模式中的組合模式實現樹結構
97. [C#語言基礎]Override 與 Overload的區別。
答:
Override: 是指方法的重寫,C#中可重寫abstract、vritual 、override三類方法,重寫是子類重寫父類的以上三種方法,是動態綁定的,調用速度比方法隱藏慢,但靈活性好,重寫本質是對方法表的修改
Overload:是指方法的重載,一個類中的多個同名方法,參數列表不同,主要指參數個數或類型不同,重載的目的是為了讓實現相似功能的方法用一個名稱表示,方便程序員編寫和理解代碼。可讀性好。
重寫和重載都是多態的一種體現。
98. [C#語言基礎]對比數組與集合。
答:
數組:長度固定,大小不變,存儲空間連續,讀取速度快,插入,刪除速度慢。
集合:長度不定,大小可變,存儲空間可能不連續,適合存放不確定數量的數據。
99. [C#語言基礎]假如有一個Person類,包含姓名,年齡字段,如對Person數組按年齡升序排列,也可以按姓名升序排列,將來可以會有更多的排序方式,你該怎么實現,說出思路。
答:
方法一:實現IComparer, 使用Array.Sort(Array, IComparer )
方法二:使用OrderBy或OrderByDescending 方法加Lambda表達式
如:arr = arr.OrderBy(p=>p.age).ToArray();
Uinty筆試題
100. [UI]NGUI Button怎樣接受用戶點擊並調用函數,具體方法名稱是什么?
答: 在按鈕上綁定一個帶有OnClick事件List<EventDelegate>;
EventDelegate();
EventDelegate(Callback call);//void Callback()
EventDelegate(MonoBehaviour target,string methodName)
101. [Unity]Unity在PC端播放視頻注意的問題是什么?
答:必須安裝QuickTime播放器,不支持FLV視頻格式。
102. [Unity]PC端播放視頻是與哪一個類有關?
答:MovieTexture。
103. [Unity]通過Unity持久化存儲PlayerPrefs,如何實現存儲以及獲取一個整數數據。
答:
存儲:PlayerPrefs.SetInt ("MyKey", 1);
獲取:int myKey = PlayerPrefs.GetInt ("MyKey");
104. [Unity]通過Unity持久化存儲PlayerPrefs,如何刪除數據。
答:
PlayerPrefs.DeleteKey ("MyKey");
PlayerPrefs.DeleteAll ();
105. [Unity]一個角色要用到unity中尋路系統,應該添加哪個組件?
答:NavMeshAgent。
106. [Unity]NavMeshObstacle組件的作用?
答:尋路網格動態碰撞組件,用於運動的物體阻礙尋路物體效果。
107. [Unity]射線中RaycastHit代表什么?
答:射線碰到的碰撞信息
108. [Unity]通過什么可以區分射線碰到的游戲對象?
答:通過LayerMask(層的遮罩),RaycastHit返回的碰撞的標簽。
109. [動畫系統]角色的AnimationType中(Generic,Legacy ,Humanoid),哪個動畫樣式可應用在Mecanim動畫系統。
答:Generic Humanoid類人樣式。
110. [動畫系統]Unity支持幾種動畫?
關鍵幀動畫
默認骨骼動畫(人型)
CAT
111. [動畫系統]如何將其他類型的動畫轉換成關鍵幀動畫?
動畫->點緩存->關鍵幀
112. [動畫]Unity引擎Mecanim動畫系統功能優點?
答:
l 簡單化對類人角色動畫設計與功能實現的工作流程。
l Mecanim動畫系統使用一個可視化編程工具來管理動畫之間復雜的交互。
l 對完成綁定骨骼的類人角色,能夠對身體不同的地方使用不同的邏輯進行動畫控制。
l 可以在角色動畫播放過程中添加動畫事件。
l 人形動畫骨骼動畫可重復使用。
113. [UI]請簡述NGUI中Panel和Anchor的作用 。
答:Panel是一個容器,它將包含所有UI小部件,並負責將所包含的部件組合。
Anchor是NGUI中屏幕分辨率的自適應性,來適應不同的分辨率的屏幕顯示。
注:
114. [碰撞]怎么判斷兩個平面是否相交?不能用碰撞體,說出計算方法。
答:以平面任意兩點,取兩平面法向量,鏈接兩點線段,線段是否與法向量的夾角來判斷是否平行。
法向量如果平行,看線段與法向量的夾角,如果平行則兩平面重合,判斷邊界是否相交。
如果平行,且有夾角,說明不重合兩平面平行,一定不相交。
如果法向量不平行,將該線段的在兩平面投影方向上的射線判斷與平面的邊界條件,如果兩條射線的交點都在邊界內,則相交,否則不相交。
注:
115. [碰撞]MeshCollider和其他Collider的一個主要不同點?
答:MeshCollider是網格碰撞器,對於復雜網狀模型上的碰撞檢測,比其他的碰撞檢測精確的多,但是相對其他的碰撞檢測計算也增多了,所以一般使用網格碰撞也不會在面數比較高的模型上添加,而會做出兩個模型,一個超簡模能表示物體的形狀用於做碰撞檢測,一個用於顯示。
MeshCollider有Mesh屬性
116. [碰撞]Unity3d中的碰撞器和觸發器的區別?
答:
- 碰撞器物體不能互相進入到對方內部,觸發器可以。
- 觸發器角色控制器可以使用,碰撞器中不能使用。
- 觸發器沒有物理屬性了,碰撞器可以有力存在。
- 碰撞器調用OnCollisionEnter/Stay/Exit函數,觸發器調用OnTriggerEnter/Stay/Exit函數。
117. [碰撞]物體發生碰撞的必要條件。
答:兩個物體都必須帶有碰撞器(Collider),其中一個物體還必須帶有Rigidbody剛體。
注:動的物體,你希望發生碰撞效果的物體要帶能接受物理引擎的操作,最常見的就是掛載Rigidbody組件。
118. [碰撞]CharacterController和Rigidbody的區別?
答:CharacterController自帶膠囊碰撞器,里面包含有剛體的屬性;
Rigidbody就是剛體,使物體帶有剛體的特征。
注:
119. [碰撞]當一個細小的高速物體撞向另一個較大的物體時,會出現什么情況?如何避免?
答:穿透(碰撞檢測失敗)。將物體移動放在FixedUpdate中,盡量使用物理引擎自己的移動方法。
避免的方法:把剛體的實時碰撞檢測打開Collision Detection修改為Continuous Dynamic
注:
120. [碰撞]在unity3d中物體發生碰撞的整個過程中,有幾個階段,分別列出對應的階段函數?
答:
主要是三個階段:
1.Collider.OnCollisionEnter 進入碰撞,當collider/rigidbody開始觸動另一個rigidbody/collider時OnCollisionEnter被調用。
2.Collider.OnCollisionStay 逗留碰撞,每個collider/rigidbody觸動rigidbody/collider,將在每幀調用OnCollisionStay。通俗的說,一個碰撞器或剛體觸動另一個剛體或碰撞器,在每幀都會調用OnCollisionStay,直到它們之間離開不接觸。
3.Collider.OnCollisionExit 退出碰撞,當 collider/rigidbody停止觸動另一個 rigidbody/collider時,OnCollisionExit被調用。
121. [動畫]一個簡單的游戲,怪物會走動\攻擊\死亡,游戲角色會走動,跳躍\攻擊\格擋\死亡,還會接受玩家從輸入端輸入的指令,NPC會走動,他們彼此之間可以互相通信.請畫出以上三種角色的UML圖示.
答:
122. [動畫]請描述游戲動畫有哪幾種,以及其原理?
答:主要有關節動畫、單一網格模型動畫(關鍵幀動畫)、骨骼動畫。
1.關節動畫:把角色分成若干獨立部分,一個部分對應一個網格模型,部分的動畫連接成一個整體的動畫,角色比較靈活,Quake2中使用這種動畫。
2.單一網格模型動畫由一個完整的網格模型構成,在動畫序列的關鍵幀里記錄各個頂點的原位置及其改變量,然后插值運算實現動畫效果,角色動畫較真實。
3.骨骼動畫,廣泛應用的動畫方式,集成了以上兩個方式的優點,骨骼按角色特點組成一定的層次結構,有關節相連,可做相對運動,皮膚作為單一網格蒙在骨骼之外,決定角色的外觀,皮膚網格每一個頂點都會受到骨骼的影響,從而實現完美的動畫。
123. [動畫]反向旋轉動畫的方法是什么?
答:反轉動畫,將動畫的播放速度調到-1。
124. [動畫]寫出Animation的五個方法。
答:AddClip 添加剪輯、Blend 混合、Play 播放、Stop 停止、Sample 采樣 、CrossFade淡入淡出切換動畫、IsPlaying是否正在播放某個動畫
125. [動畫]動畫層(AnimationState Layers)的作用是什么?
答:動畫層作為一個具有層級動畫編輯概念的工具,可以用來制作和處理任何類型的動畫。202,203題
126. [動畫]Itween插件的作用是什么,Itween作用於世界坐標還是局部坐標,請列舉出3個其常用方法?
答:ITween是補間動畫的一個插件,主要作用就是給出開始、結束的值、時間,此插件實現各種動畫,晃動,旋轉,移動,褪色,上色,音量控制等等。
方法: 1.MoveTo 物體移動
2.ColorTo:隨着時間改變對象的顏色組
3.LookTo:隨時間旋轉物體讓其臉部朝向所提供的Vector3或Transform位置
127. [動畫]什么是法線貼圖 、CG動畫 ?
答:
法線貼圖:是一種特殊的紋理,可以應用在3D表面,讓低模呈現出更明顯的凹凸效果。一
般應用在CG動畫、美術效果要求較高的單機游戲
CG動畫:游戲中的CG動畫其實是用3D模擬引擎制作的游戲短片,一般畫面效果比較真實。
128. [線程和協程]Unity3D是否支持寫成多線程程序?如果支持的話需要注意什么?(?)
答:Unity支持多線程,如果同時要處理很多事情或者與Unity的對象互動小可以用thread,否則使用coroutine。
注意:1.雖然支持多線程,但是僅能從主線程中訪問Unity3D的組件,對象和Unity3D系統調用,所以如果使用的話需要把組件中的數值傳到開啟的新線程中。
2.C#中有lock這個關鍵字,以確保只有一個線程可以在特定時間內訪問特定的對象
129. [線程和協程]Unity3D的協程和C#線程之間的區別是什么?
答:多線程程序同時運行多個線程,除主線程之外的線程無法訪問Unity3D的對象、組件、方法,而在任一指定時刻只有一個協程在運行。
130. [線程和協程]什么是協同程序?
答:在主線程運行時同時開啟另一段邏輯處理,來協助當前程序的執行。使用戶可以編寫更靈活的程序來控制運動、序列以及對象的行為。
131. [3D數學]四元數是什么?主要作用什么?對歐拉角的優點是什么?
答:所謂四元數,就是把4個實數組合起來的東西。4個元素中,一個是實部,其余3個是虛部
作用:四元數用於表示旋轉
優點:
1)能進行增量旋轉
2)避免萬向鎖
3)給定方位的表達方式有兩種,互為負(歐拉角有無數種表達方式)
四元數不會有歐拉角存在的 gimbal lock 問題[萬向節死鎖]
四元數由4個數組成,旋轉矩陣需要9個數
兩個四元數之間更容易插值
四元數、矩陣在多次運算后會積攢誤差,需要分別對其做規范化(normalize)和正交化 (orthogonalize),對四元數規范化更容易
與旋轉矩陣類似,兩個四元組相乘可表示兩次旋轉
132. [攝像機]在場景中放置多個Camera並同時處於活動狀態會發生什么?
答:游戲界面可以看到很多攝像機的混合。
133. [攝像機]Unity攝像機有幾種工作方式,分別是什么?
答:正交和透視。
正交無法看到一個物體距離自己有多遠,或者遠近的變化,物體也不會隨着距離而收縮,所以一般做2D游戲或者是UI時會使用正交攝像機。
透視一般看物體會隨着距離有大小的變化,一般3D游戲里經常使用這種攝像機。
134. [預制件]Prefab的作用?如何在移動環境的設備下恰當地使用它?
答:Prefab是預制件(預制物),一般當游戲中需要頻繁創建一個物體時,使用預制物可以節省內存,方便創建,方便對游戲物體進行操作,方便對屬性進行修改。
135. [預制件]unity當需要頻繁創建一個物體對象時,怎樣減少內存?
答:動態加載再實例化,如果自己不主動清理內存的話,再次加載不會增加內存的,會自動去取之前已經加載好的assets,如果這一個assets你都嫌多的話,那你只能減資源了,比如,模型面數,紋理尺寸等
136. [ Shader]寫出光照計算中的diffuse的計算公式
答:實際光照強度l=環境光(lambient)+漫反射光(Idiffuse)+鏡面高光(lspecular)
環境光:lambient=環境光強度(Aintensity)*環境光顏色(Acolor)
漫反射光:ldiffuse=鏡面光照強度(Dintensity)*鏡面光顏色(Scolor)*(光的反射向量(R).觀察者向量(V))^鏡面光指數(n)
137. [ Shader]MeshRender中material和shader的區別?
答:MeshRender是模型渲染的組件,有此組件物體才能顯示出來
Material是材質球,實際就是shader的實例,並進行賦值,貼圖、紋理、顏色等。
Shader是着色器,實際上是一段程序,還可以用來實現一些僅靠貼圖不容易實現的效果,如玻璃。
Shader大致分為:1.表面着色器
2.頂點和片元着色器
3.固定功能着色器
138. [ Shader]alpha blend工作原理
答:Alpha Blend是 實現透明效果,Color = 原顏色*alpha/255+目標色*(255-alpha)/255
139. [ Shader]光照貼圖 的優勢是什么?
答:1.使用光照貼圖比使用實時光源渲染要快
2.可以降低游戲內存消耗
3.多個物體可以使用同一張光照貼圖
140. [ Shader]Vertex Shader是什么,怎么計算?
答:頂點着色器:頂點着色器是一段執行在GPU上的程序,用來取代fixed pipeline中的
transformation和lighting,Vertex Shader主要操作頂點。
Vertex Shader對輸入頂點完成了從local space到homogeneous space(齊次空間)的變換過程,homogeneous space即projection space的下一個space。在這其間共有world transformation, view transformation和projection transformation及lighting幾個過程。
141. [ Shader] Unity3d提供了幾種光源,分別是什么?
答:4種,Directionl light ,Point Light ,Spot Light,Area Light
平行光:Directional Light
點光源:Point Light
聚光燈:Spot Light
區域光源:Area Light
142. [Unity]物理更新一般在哪個系統函數里?
答:FixedUpdate,每固定幀繪制時執行一次,和Update不同的是FixedUpdate是渲染幀執行,如果你的渲染效率低下的時候FixedUpdate調用次數就會跟着下降。FixedUpdate比較適用於物理引擎的計算,因為是跟每幀渲染有關。Update就比較適合做控制。
143. [Unity]OnEnable、Awake、Start運行時的發生順序?哪些可能在同一個對象周期中反復的發生?
答:Awake –>OnEnable->Start
OnEnable在同一周期中可以反復地發生
Awake用於在游戲開始之前初始化變量或游戲狀態。在腳本整個生命周期內它僅被調用一次.Awake在所有對象被初始化之后調用,所以你可以安全的與其他對象對話或用諸如GameObject.FindWithTag這樣的函數搜索它們。每個游戲物體上的Awke以隨機的順序被調用。因此,你應該用Awake來設置腳本間的引用,並用Start來傳遞信息。
Start在腳本的生命周期中只被調用一次。它和Awake的不同是Start只在腳本實例被啟用時調用。你可以按需調整延遲初始化代碼。Awake總是在Start之前執行。這允許你協調初始化順序。
但Start可以作為協程,達到在同一周期調用多次的效果。不過實質上依然是調用一次。
144. [Unity]接上題,在上題當中假設有一物體,一個腳本掛了兩次,請指出Awake的執行順序。
答:ExcutionOrder有關,不設定順序的時候初始化Start的順序不確定。
145. [Unity]Unity3d腳本從喚醒到銷毀有着一套比較完整的生命周期,請列出系統自帶的幾個重要的方法。
答:
|
方法名(按腳本聲明周期排列) |
作用 |
備注 |
Editor |
Reset |
重置為默認值。 |
在用戶點擊見識版面的Reset按鈕或者首次添加該組件時被調用。此方法只在編輯模式下被調用。 |
Initialization |
Awake |
|
|
OnEnable |
|
|
|
Start |
Start在behaviour的生命周期中只被調用一次。它和Awake的不同是Start只在腳本實例被啟用時調用。你可以按需調整延遲初始化代碼。Awake總是在Start之前執行。這允許你協調初始化順序。 |
Start僅在Update方法第一次被調用前調用。 |
|
Physics |
FixedUpdate |
處理Rigidbody時,需要用FixedUpdate代替Update。例如:給剛體加一個作用力時,你必須應用作用力在FixedUpdate里的固定幀,而不是Update中的幀。(兩者幀長不同) |
如果固定時間步長小於實際幀更新時間,那么每一幀物理周期將會可能發生不止一次。 |
yield WaitForFixedUpdate |
|
||
Internal physics update |
|
||
OnTriggerXXX |
|
||
OnCollisionXXX |
|
||
Input events |
OnMouseXXX |
|
|
Game logic |
Update |
|
如果一個協成之前已經yield了,但是現在由於恢復了,那么將執行剩下的部分。 |
yield null |
|
||
yield WaitForSeconds |
|
||
yield WWW |
|
||
yield StartCoroutine |
|
||
Internal animation update |
|
||
LateUpdate |
|
||
Scene rendering |
OnWillRenderObject |
如果對象可見每個相機都會調用它。此函數在消隱過程中被調用,在渲染所有被消隱的物體之前被調用。你可以用它來創建具有依賴性的紋理並且只有在被渲染的物體可見時才更新這個紋理。舉例來講,它已用於水組件中。 |
|
OnPreCull |
消隱決定哪個物體對於相機來說是可見的.OnPreCull僅是在這個過程被調用。 |
只有腳本被附加到相機上時才會調用這個函數。 |
|
OnBecameVisible |
|
|
|
OnBecameInvisible |
|
|
|
OnPreRender |
在相機渲染場景之前被調用。 |
只有腳本被附加到相機並被啟用時才會調用這個函數。 |
|
OnRenderObject |
|
|
|
OnPostRender |
在相機完成場景渲染之后被調用。 |
只有該腳本附於相機並啟用時才會調用這個函數。OnPostRender可以是一個協同程序。 |
|
OnRenderImage |
|
|
|
Gizmo rendering |
OnDrawGizmos |
|
只在編輯模式下調用 |
GUI rendering |
OnGUI |
|
在每一幀更新時調用多次 |
End of frame |
yield WaitForEndOfFrame |
|
|
Pausing |
OnApplicationPause |
|
在程序檢測到暫停時,會在幀的結尾處被調用。 |
Disable/enable |
OnDisable |
|
在腳本是失效時被調用,被銷毀時也會被調用。如果再啟用的話,OnEnable會再一次被調用。 |
Decommissioning |
OnDestroy |
|
|
OnApplicationQuit |
|
|
146. [Unity]物理更新一般放在哪個系統函數里?
答:FixedUpdate因為不受到計算機幀頻的影響,所以適合於做物理方面的更新。
147. [Unity]移動攝像機的動作放在哪個系統函數中,為什么放在這個函數中?
答:LateUpdate,它是在Update結束后才調用。一般來說攝像機的跟隨,都是在所有Update操作完成后進行的,以免出現攝像機已經推進了,但是還有角色未刷新的空幀出現。
148. [Unity]請簡述OnBecameVisible及OnBecameInvisible的發生時機,以及這一對回調函數的意義?
答:當物體是否可見切換之時。可以用於只需要在物體可見時才進行的計算。
當renderer(渲染器)在任何相機上都不可見時調用:OnBecameInvisible
當renderer(渲染器)在任何相機上可見時調用:OnBecameVisible
149. [Unity]Unity3d提供了一個用於保存和讀取數據的類(PlayerPrefs),請列出保存和讀取整形數據的函數。
答:PlayerPrefs.SetInt()
PlayerPrefs.GetInt()
150. [動畫]動畫狀態是動畫狀態機的基本構件。每種狀態包含的可能性有哪兩種?
答:單獨的動畫狀態,混合樹。
151. [動畫]簡述一下動畫層中權重(Weight )的概念
答:
動畫層中的權重是指某個動畫層在整個動畫中的影響,Weight的取值范圍為(0~1)
若權重值為1則此層動畫將與整個動畫融合
若權重值為0則此層動畫與整個動畫完全不融合
152. [動畫]簡述一下Mecanim動畫層中動畫層的作用?
答:使用動畫層來管理身體不同部分的復雜狀態機。比如:你可以使用下半身(動畫)層來管理走動/跑動;使用上半身(動畫)層來控制攻擊/揮手動作。
153. [動畫]簡述一下以下代碼的功能?
Animator anim ;
int idle = Animator.StringToHash("Base Layer.Idle");
AnimatorStateInfo currentBaseStage;
void Start () {
anim = GetComponent<Animator>();
}
void Update () {
currentBaseStage = anim.GetCurrentAnimatorStateInfo(0);
if (currentBaseStage.nameHash == idle && !anim.IsInTransition(0)) {
anim.SetBool("hit", false);
}
答:判斷當前播放的動畫名字若是默認層的Idle,並且沒有在進行動畫切換,則設置hit動畫參數為false。
154. [動畫]若想讓尋路的物體在Walkable跟Red層可以尋路GetComponent<NavMeshAgent>(). areaMask等於幾?
答案:9
155. [動畫]若想實現敵人攻擊動畫播放一半的時候角色減血,可用Mecanim動畫系統中的哪個功能處理比較好?
答:動畫事件。
156. [動畫]Mecanim動畫系統中2DBlendTree與1DBlendTree的區別?
答:
1D是使用一個動畫參數來控制blend tree中幾個動畫判斷的融合,
2D是使用兩個動畫參數來控制blend tree中幾個動畫判斷的融合。
157. [物理引擎]如何實現把射線碰到的點(hit)轉為非主攝像機的屏幕坐標?
答:
public Camera myCamera;
myCamera.WorldToScreenPoint(hit);
158. [Unity]Unity中的尋路系統屬於那種尋路方式?
答:網格尋路。
159. [Unity]動態加載資源的方式?區別是什么?
答:
1.Resources.Load();
2.AssetBundle
區別:
Resources資源的加載是動態加載內部的,AssetBundle 是動態加載外部的。
Resources是動態內部調用,Resources在編輯環境下是project窗口的一個文件夾,調用里面的資源,可以用Resources類,比如Resources.Load,打包后這個文件夾是不存在的,會統一生成Assets資源。
AssetBundle 是外部調用,要用AssetBundle 首先要先把資源打包為.assetbundle文件,再動態的去加載這個文件,本地或者網絡服務器都可以。
WWW讀取文件
160. [Unity]以下哪個函數在游戲進入新場景后會被馬上調用?
答: MonoBehaviour.OnLevelWasLoaded
161. [Unity]如何銷毀一個UnityEngine.Object及其子類
答:Destory
162. [Unity]獲取、增加、刪除組件的命令分別是什么?
答:獲取:GetComponent
增加:AddComponent
沒有刪除組件只有讓組件不生效:enable
163. [Unity]Application.loadLevel命令是什么?//過時了
答:加載關卡 。
UnityEngine.SceneManagement名稱空間下
SceneManager.LoadScene//加載場景
SceneManager.LoadSceneAsync//異步加載場景
164. [Unity]調試記錄到控制台的命令是什么?
答: Debug.Log();
165. [Unity]LayerMask.NameToLayer()這個方法有什么作用?
答:層索引。射線。
166. [Unity]localPosition與Position的使用區別?
答:
localPosition:自身位置,相對於父級物體的變換的位置,局部坐標其實就是自身的坐標。
Position:在世界坐標transform的位置,世界坐標是不會變的,一直以世界坐標軸的XYZ為標准。
167. [Unity]物體自身旋轉使用的函數?
答:Transform.Rotate()。
168. [Unity]現有物體A和物體B,使物體A圍繞B旋轉並保持物體A的Y軸朝向不變,請寫出你的方法。
答:
public class TestAround : MonoBehaviour
{
public GameObject ObjA;
public GameObject ObjB;
Vector3 NormalVector3;//法線
float speed = 5;
void Start()
{
GetNormal(AroundType.Horizontal);
}
private void GetNormal(AroundType aroundType)
{
Vector3 temp = ObjB.transform.position - ObjA.transform.position;
switch (aroundType)
{
case AroundType.Vertical:
NormalVector3=Vector3.Cross(Vector3.forward,temp);
break;
case AroundType.Horizontal:
NormalVector3 = Vector3.Cross(Vector3.up, temp);
break;
default:
break;
}
}
void Update()
{
Debug.DrawLine(NormalVector3,ObjA.transform.position);
Vector3 temp = ObjB.transform.position - ObjA.transform.position;
Debug.DrawLine(temp, ObjA.transform.position);
Around(ObjA, ObjB);
}
private void Around(GameObject objA, GameObject objB)
{
Quaternion quater=Quaternion.Euler( NormalVector3*Time.deltaTime*speed);
objB.transform.position = quater * objB.transform.position;
}
}
enum AroundType
{
Vertical,
Horizontal
}
169. [Unity]U3D中用於記錄節點空間幾何信息的組件名稱,及其父類名稱。
答:Transform 父類是 Component
170. [物理引擎]<憤怒的小鳥>給予初速度以后,怎么讓小鳥受到重力和空氣阻力的影響而繪制拋物線軌跡,說出具體的計算方法。
答:添加剛體使小鳥模擬受到重力和空氣阻力影響。不添加剛體的話寫受力分析。
設橫軸為方向的加速度為ax,垂直軸為ay。
小鳥的Vx,Vy
Vx=Vx+t*ax;(Vx>=0)
Vy=Vy+t*ay;
171. [物理引擎]Material和Physic Material區別?
答:PhysicMaterial 物理材質:主要是控制物體的摩擦,彈力等物理屬性。
Material材質:主要是控制一個物體的顏色,質感等顯示。
172. [物理引擎]Unity3d的物理引擎中,有幾種施加力的方式,分別描述出來。
答:rigidbody.AddForce/AddForceAtPosition,都在rigidbody系列函數中。
173. [物理引擎]什么叫做鏈條關節?
答:Hinge Joint,可以模擬兩個物體間用一根鏈條連接在一起的情況,能保持兩個物體在一個固定距離內部相互移動而不產生作用力,但是達到固定距離后就會產生拉力。
174. [自動尋路]什么是導航網格( NavMesh)?
答: Unity內一種用於實現自動尋路的網格。
175. [ Unity]簡述Unity3D支持的作為腳本的語言的名稱。
答: JavaScript,C#,Boo
176. [3D數學]向量的點乘、叉乘以及歸一化的意義?
答:1)點乘計算兩個向量之間的夾角,還可表示某一方向的投影。
2)叉乘得到的是法向量。
3)標准化向量:用在只關系方向,不關心大小的時候。
177. [3D數學]矩陣相乘的意義及注意點?
答:用於表示線性變換:旋轉、縮放、投影、平移、仿射。
注意:矩陣的蠕變:誤差的積累。
178. [Unity引擎]為什么dynamic font在unicode環境下優於static font?
答:Unicode是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。
使用動態字體時,Unity將不會預先生成一個與所有字體的字符紋理。當需要支持亞洲語言或者較大的字體的時候,若使用正常紋理,則字體的紋理將非常大。
179. [Unity引擎]Render的作用?描述MeshRender和SkinnedMeshRender的關系與不同。
答:render是渲染器,渲染器可以使物體顯示在屏幕上。
MeshRender是網格渲染,SkinnedMeshRender是蒙皮網格渲染器
180. [Unity引擎]簡述SkinnedMesh的實現原理。
答:骨骼蒙皮動畫,模型本身是靜態的,是因為通過蒙皮,使模型每個點都有Skin數據,Skin數據包括頂點受到哪些骨骼影響以及這些骨骼影響頂點的權重值,還有動畫數據,有了Skin數據的模型就可以根據動畫數據進行顯示動畫了。
181. [Unity引擎]如何安全的在不同工程間安全地遷移asset數據?三種方法。
答:1)將Assets目錄和Library目錄一起遷移。
2)導出包。
3)用unity自帶的assets Server功能。
182. [ Unity引擎]Lod是什么,優缺點是什么?
答:LOD是Level of detail簡稱,意為多層次細節,是最常用的游戲優化技術,LOD技術指根據物體模型的幾點在顯示環境中所處的位置和重要性,決定物體渲染的資源分配,降低非重要物體的面數和細節度,從而獲得高效率的渲染運算。
優點:可根據距離動態的選擇渲染不同細節的模型
缺點:增加美工工作量,增大了游戲的容量。
注:精簡文字描述。
答:LOD(Level of detail)多層次細節,是最常用的游戲優化技術,LOD技術指根據物體模型的幾點在顯示環境中所處的位置和重要性,決定物體渲染的資源分配,降低非重要物體的面數和細節度,從而獲得高效率的渲染運算。
優點:可根據距離動態的選擇渲染不同細節的模型
缺點:增加美工工作量,增大了游戲的容量。
183. [ Unity]兩種陰影判斷的方法、工作原理。
答:自身陰影:因物體自身的遮擋而使光線照射不到它上面的某些可見面
工作原理:利用背面剔除的方法求出,即假設視點在點光源的位置。
投射陰影:因不透明物體遮擋光線使得場景中位於該物體后面的物體或區域收不到光照照射而形成的陰影。
工作原理:從光源處向物體的所有可見面投射光線,將這些面投影到場景中得到投影面,再將這些投影面與場景中的其他平面求交得出陰影多邊形,保存這些陰影多邊形信息,然后在按視點位置對場景進行相應處理得到所要求的視圖(利用空間換時間,每次只需依據視點位置進行一次陰影計算即可,省去了一次消隱過程)若是動態光源此方法就無效了。
184. [ Unity]MipMap是什么,作用?
答:MipMapping:在三維計算機圖形的貼圖渲染中有常用的技術,為加快渲染進度和減少圖像鋸齒,貼圖被處理成由一系列被預先計算和優化過的圖片組成的文件,這樣的貼圖被稱為MipMap。
185. [ Unity]Mecanim系統中,Body Mask的作用是?
答:指定身體的某一部分是否參與渲染
186. [ Unity]Unity連接數據庫。
答:需要得到Mono.Data.Sqlite.dll 文件與System.Data.dll文件。
187. [ Unity]如何優化內存?
答:1.壓縮自帶類庫;
2.將暫時不用的以后還需要使用的物體隱藏起來而不是直接Destroy掉;
3.釋放AssetBundle占用的資源;
4.降低模型的片面數,降低模型的骨骼數量,降低貼圖的大小;
5.使用光照貼圖;
6.使用多層次細節(LOD);
7.使用着色器(Shader);
8.使用預設(Prefab)等。
解析:內存開銷無外乎三大部分:1.資源內存占用;2.引擎模塊自身內存占用;3.托管堆內存占用
- 資源內存占用。
在一個較為復雜的大型項目中,資源的內存占用往往占據了總體內存的70%以上。因此,資源使用是否恰當直接決定了項目的內存占用情況。一般來說,一款游戲項目的資源主要可以分為以下幾種:紋理(Texture),網絡(Mesh),動畫片段(AnimationClip)、音頻片段(AudioClip)、材質(Material)、着色器(shader)、字體資源(Font)以及文本資源(TextAsset)等等。其中,紋理,網格、動畫片段和音頻片段則容易造成較大內存開銷的資源。
- 紋理
紋理資源可以說是幾乎所有游戲項目中占據最大內存開銷的資源。一個6萬片的場景,網格資源最大才不過10MB,但一個2048*2048的紋理,可能直接就達到16MB,因此,項目中紋理資源的使用是否恰當會及大地印象項目的內存占用。
那么,紋理資源再使用時應該注意哪些地方呢?
紋理格式。紋理格式是研發團隊最需要關注的紋理屬性。因為它不僅影響紋理的內粗你占用,同時還決定了紋理的加載效率。一般來說,我們建議開發團隊盡可能根據硬件的種類選擇硬件支持的紋理格式比如Android平台的ETC、iOS平台的PVRTC、WindowsPC上的DXT等等。因此,我們在UWA測評報告中,將紋理格式進行了羅列,一邊開發團隊進行快速查找,一步定位。
在使用硬件支持的紋理格式時,你可能會遇到以下幾個問題:
色階問題
由於ETC、PVRTC等格式均為有損壓縮,因此,當紋理色差范圍跨度較大時,均不可避免地造成不同程度的階梯狀的色階問題。因此,很多研發團隊使用RGBA32/ARGB32格式來實現更好的效果。但是,這種做法將造成很大的內存占用。比如,同樣一張1024*1024的紋理,如果不開啟Mipmap,並且為PVRTC格式,則其內存占用為512KB,而如果轉換為RGBA32位,則很可能占用更達到4MB。所以,研發團隊在使用RGBA32或ARGB32格式的紋理時,一定要慎重考慮,更為明智的選擇是盡量減少紋理的色差范圍,時期盡可能使用硬件支持的壓縮格式進行存儲。
ETC1不支持透明通道問題
在Android平台上,對於使用OpenGLES2.0的設備,其紋理格式僅能支持ETC1格式,該格式有個較為嚴重的問題,即不支持Alpha透明通道,使得透明貼圖無法直接通過ETC1格式來進行存儲。對此。我們建議研發團隊將透明貼圖盡可能分成兩張,即一張RGB24位紋理記錄原始紋理的顏色部分和一張Alpha8紋理記錄原始紋理的透明通道部分。然后,將這輛張貼圖分別轉化為ETC1格式的紋理,並通過特定的Shader來進行渲染,從而來達到支持透明貼圖的效果。該種方法不僅可以極大程度上逼近RGBA透明貼圖的渲染效果,同時還可以降低紋理的內存占用,是我們非常推薦的使用方式。
當然,目前已經有越來越多的設備支持了OpenGLES3.0這樣Android平台上你可以進一步使用ETC2甚至ASTC,這些紋理格式均為支持透明通道且壓縮比更為理想的紋理格式。如果你的游戲適合人群為中高端設備用戶,那么不妨直接使用這兩種格式來作為主要存儲格式。
紋理尺寸
一般來說,紋理尺寸越大,占用內存越大。
Mipmap功能
Mipmap旨在有效降低渲染帶寬的壓力,提升游戲的渲染效率。但是,開啟Mipmap會有將紋理內存提升1.33倍。對於具有較大縱深感的3D游戲來說,3D場景模型和角色我們一般是建議開啟Mipmap功能的,但很多2DUI紋理就不必要了。
Read&Write
一般情況下,文理資源“Read&Write”功能在Unity引擎中是默認關閉的。但是,我們仍然在項目深度優化時發現了不少項目的紋理資源會開啟該選項。對此,我們建議壓發團隊密切關注文理資源中該選項的使用,因為開啟該選項將會使文理內存增大一倍。
- 網格
網格資源在比較復雜的游戲中,往往占據較高的內存。對於網格資源來說,它在使用時應該注意那方面呢?
1) Normal\Color和Tangent(切線)
在我們深度優化過的大量項目中,Mesh資源的數據經常會含有大量的Color數據,Normal數據和Tangent數據。這些數據的存在將大幅增加Mesh資源的文件體積和內存占用。其中Color數據和Normal數據主要為3DMax、Maya等建模軟件導出時設計所生成,而Tangent一般為導入引擎時生成。
更為麻煩的是,如果項目對Mesh進行DrawCallBatching操作的話,那么狠有可能進一步增加總體內存的占用。正因如此,我們在UWA測評報告中為每個Mesh展示了其Normal,Color和Tangent屬性的具體使用情況,研發團隊可以直接針對每種屬性進行排序查看,直接定位出現冗余數據的資源。一般來說這些數據主要為Shader所用,來生成較為酷炫的效果。所以,建議研發團隊針對項目中的網格資源進行詳細檢測,查看該模型的渲染Shader中是否需要這些數據進行渲染。
- 動畫片段
- 音頻片段
- 引擎模塊自身內存占用。
- 托管堆內存占用
188. [ Unity]如何優化CPU?
答:
解析:CPU方面
就目前Unity移動游戲而言,CPU方面的性能開銷主要可歸結為兩大類:引擎模塊性能開銷和自身代碼性能開銷。其中,引擎模塊中又可細致划分為渲染模塊、動畫模塊、物理模塊、UI模塊、粒子系統、加載模塊和GC調用等等。
通過大量的性能測評數據,我們發現渲染模塊、UI模塊和加載模塊,往往占用了CPU性能開銷的Top3。
- 1. 渲染模塊
1降低DrawCall
降低DrawCall的方法則主要是減少渲染物體的材質種類,並通過DrawCallBatching來減少其數量。Unity文檔對DrawCallBatching的原理和注意事項非常詳盡,感興趣的朋友可以直接查看Unity官方文登。
但是,需要注意的是游戲性能並非DrawCall越小越好。這是因為,決定渲染模塊心梗的除了DrawCall之外,還有用於傳輸渲染數據的總先帶寬。當我們使用DrawCallBatching將同種的材質和網絡模型拼合在儀器室,可能會造成同一時間需要傳輸的數據(Texture、VB/IB等)大大增加,以至於造成堵塞。在資源無法計時傳輸過去的情況下,GPU只能等待,從而反倒降低了游戲的運行幀率。
DrawCall和總線帶寬是天平的兩端,我們需要做的是盡可能維持天平的平衡,任何一邊過高或過低,對性能來說都是無益的。
2簡化資源
簡化資源師非常行之有效的優化手段。在大量的移動游戲中,其渲染資源其實是過量的。過量的過量的網絡資源、不合規的紋理資源等等。
關於渲染模塊在CPU方面的優化方法還有很多,比如LOD、Occlusion Culling和Culling Distance等等。
2 UI模塊
UI模塊同樣也是幾乎所有的游戲項目中必備的模塊。一個性能優異的UI模塊可以將游戲的用戶體驗再抬高一個檔次。
在NGUI優化方面,UIPanel.LateUpdate為性能優化的重中之重。
對於UIPanel.LateUpdate的優化,主要着眼與UIPanel的布局,其原則如下:
盡可能將動態UI元素和靜態UI元素分離到不同的UIPanel中,從而盡可能將因為變動的UI元素引起的沖歐控制在較小的范圍內;
盡可能讓動態UI元素按照同步性進行划分,即運動幀率不同的UI元素盡可能分離放在不同的UIPanel中;
控制同一個UIPanel中動態UI元素的數量,數量越多,所創建的Mesh越大,從而使得重構的開銷曾加。比如戰斗過程中的HUD運動協調會出現的比較多,此時,建議研發團隊將運動血條分離成不同的UIPanel,每組UIPanel下5~10個動態UI為宜。這種做法,其本質是從概率上盡可能降低單振中UIPanel的重建開銷。
3加載模塊
加載模塊同樣也是任何游戲項目中所不可缺少的組成成分。與之前兩個模塊不同的是,加載模塊的性能開銷比較集中,主要出現於場景切換處,且CPU占用峰值均較高。
這里,我們先來說說場景切換時,其性能開銷的主要體現形式。對於目前的Unity版本而言,場景切換時的主要性能開銷主要體現在兩個方面,前一場景的場景卸載和下一場景的場景加載。下面,我們就具體來說說兩個方面的性能瓶頸:
1場景卸載,對於Unity引擎而言,場景卸載一般是由引擎自動完成的,即當我們調用類似Application.LoadLevel的API時,引擎即會開始對上一場景進行處理,其性能開銷主要被以下幾部分占據。
Destroy
引擎在切換場景時會手機為表示成DontDestoryOnLoad的GameObject及其Component,然后進行Destroy。同時,代碼中的OnDestory被觸發執行,這里的性能開銷主要取決於OnDestroy回調函數中的代碼邏輯。
Resources.UnloadUnusedAssets
一般情況下,場景切換過程中,該API會被調用兩次,依次為引擎在切換場景是自動調用,另一次則為用戶手動調用(一般出現在場景加載后,用戶調用它來確保上一場景的資源被卸載干凈)。在我們測評過的大量項目中,該API的CPU開銷主要集中在500ms~3000m之間。其耗時開銷主要取決於場景中Asset和Object的數量,數量越多,則耗時越慢。
2場景加載
場景加載過程的性能開銷又可細分成以下幾個部分:
資源加載
資源加載幾乎占據整個加載過程的90%以上,其加載效率主要取決於資源的加載方式(Resource.Load或AssetBundle加載)、加載量(紋理、網格、材質等資源數據的大小)和資源格式(紋理、音頻格式等)。不同的加載方式、不同的資源格式,其加載效率可謂千差萬別。
Instantiate實例化
在場景加載過程中,往往伴隨着大量的Instantiate實例化操作。在Instantiate實例化時,引擎底層會查看相關的資源是否已經被加載,如果沒有,則會先加載其相關資源,再進行實例化,這其實是大家遇到大多數“Instantiate”實例化問題的根本原因。
AssetBundle文章中所提倡的資源依賴關系打包並進行預加載,從而來緩解Instantiate實例化的壓力。
另一方面,Instantiate實例化的性能開銷還體現在腳本代碼的序列化上,如果腳本中序列化的信息很多,則Instantiate實例化時的時間亦會很長。最直接的例子就是NGUI,其代碼中存在很多SerializedField標識,從而在實例化時帶來了較多的代碼序列化開銷。因此,在打架增加序列化信息時,這一點是需要大家時刻關注的
以上是游戲項目中性能開銷最大的三個模塊,當然,游戲類型的不同、設計的不同,其他模塊仍然會有較大的CPU占用。比如ARPG游戲中動畫系統和物理系統,音樂休閑類游戲中的音頻系統和例子系統等。
4 代碼效率
邏輯代碼在一個較為復雜的游戲項目中往往占據較大的CPU開銷。這種情況在MOBA\ARPG\MMORPG等游戲類型中非常常見。
在項目優化過程中,我們經常會想知道,到底哪些函數占據了大量的CPU開銷。同時,絕大多數的項目其中性能開銷都遵循着“二八原則”,即80%的性能消耗都集中在20%的函數上。
189. [ Unity]你用過哪些插件?
答:
插件功能 |
插件名稱 |
界面制作 |
NGUI |
2D游戲制作 |
2D Toolkit |
可視化編程 |
PlayMaker |
插值插件 |
iTween、HOTween |
路徑搜尋 |
SimplePath |
美術及動畫制作 |
RageSpline、Smooth Moves |
畫面增強 |
Bitmap2Material、Strumpy Shader Editor |
攝像機管理 |
Security Camera |
資源包 |
Nature Pack |
造路插件 |
EasyRoads3D |
即時遮擋剔除/LOD多細節層次 |
Instant Occlusion Culling |
190. [3D圖形學]什么是渲染管道?
答:是指在顯示器上為了顯示出圖像而經過的一系列必要操作。
渲染管道中的很多步驟,都要將幾何物體從一個坐標系中變換到另一個坐標系中去。
主要有三步:應用程序階段,幾何階段 光柵階段
本地坐標->視圖坐標->背面裁剪->光照->裁剪->投影->視圖變換->光柵化。
191. [3D圖形學]什么是矢量圖 ?
答:計算機中顯示的圖形一般可以分為兩大類——矢量圖和位圖。矢量圖使用直線和曲線來描述圖形,這些圖形的元素是一些點、線、矩形、多邊形、圓和弧線等等,它們都是通過數學公式計算獲得的。例如一幅花的矢量圖形實際上是由線段形成外框輪廓,由外框的顏色以及外框所封閉的顏色決定顯示出的顏色。由於矢量圖形可通過公式計算獲得,所以矢量圖形文件體積一般較小。矢量圖形最大的優點是無論放大、縮小或旋轉等不會失真;最大的缺點是難以表現色彩層次豐富的逼真圖像效果。
192. [3D圖形學]什么是矩陣?矩陣運算?
答:矩陣:橫軸排列的二維數據表格
矩陣運算:
加減 限制條件:行和列必須相同,對應相加相減得到結果
乘法 限制條件:要求左矩陣的行和右矩陣的列必須同,行數和左矩陣相等,列數和右矩陣相等,結果的第i行第j列,是左矩陣的第i行和右矩陣的第j列逐個相乘並把結果相加,得到結果是結果 的 第i行第j列。
193. [3D圖形學]角度和弧度的轉換。
答:角度和弧度
度和弧度之間的換算 1弧度 = 180度 /pi(約57.3)
1度=pi/180弧度(約0.017)
194. [3D圖形學]矢量標量。
答:矢量有方向如力速度 標量只有大小沒有方向如溫度
矢量取模就是只要大小不要方向
單位向量 有方向 大小為1的向量
矢量的加法:是矢量的幾何和,服從平行四邊形規則
矢量滿足交換律,滿足結合律
在直角坐標系中,矢量等於騎在坐標軸上投影的矢量之和(二維矢量可以看做三維矢量的特例也就是說,三維成立,二維也成立)
矢量減法:
大小相等 方向相反 稱為逆矢量。
任意多個矢量首尾相連接組成閉合多邊形,其結果必為0
矢量的乘法:點積(內積、標量積)、叉積(外積)結果是矢量
點積方法 dot
注:這題要問什么?
195. [ Unity]動態加載資源的方式?
答:
1.Resources
2.AssetBundle
3.WWW
196. [ Unity]場景中有大量物體及實時光源,會對性能帶來影響嗎?應該如何解決?
答:實時光源會對性能有影響,解決方案有以下幾種:
1使用unity的烘焙系統烘焙替代實時光源。
2使用三維建模軟件的烘焙系統烘焙代替實時光源。
3一般移動端開發實時光源只為了提供實時陰影效果,所以設置實施光照的有效層。
197. [ Unity]如何實現游戲的暫停、加速和減速?
答:
Time.timeScale = 0;即可讓游戲暫停。
Time.timeScale = 1時,Update、LateUpdate、FixedUpdate 都按正常的時間來執行。
Time.timeScale = 2時,Update和 LateUpdate的執行速度是之前的2倍,而FixedUpdate還是按正常時間來執行
198. [ Unity]請描述Prefab的作用,並描述如何在移動設備的環境下恰當的使用它?
答:Prefab可以理解為是一個游戲對象及其組件的集台,作用是使游戲對象及資源能夠被重復使用。相同的對象可以通過一個預設來創建,此過程可理解為實例化,預設可以進行批量修改。
199. [ Unity]請簡述如何在不同分辨率下保持 UI 的一致性?
答:NGUI 很好的解決了這一點,屏幕分辨率的自適應性,原理就是計算出屏幕的寬高比跟原來的預設的屏幕分辨率求出一個對比值,然后修改攝像機的 size 。
注:
200. [ Unity]加載關卡和異步加載關卡的方法?
答:
SceneManager.LoadScene//加載場景
SceneManager.LoadSceneAsync//異步加載場景
201. [Shader]在unity中,開發者可以編寫幾種類型的Shader?
答:1、表面着色器(surface shaders)
通常情況下用戶都會使用這種Shader,它可以與燈光、陰影、投影器進行交互。表面着色器的抽象層次比較高,它可以容易地以簡潔方式實現復雜的着色器效果。表面着色器可同時正常工作在前向渲染及延遲渲染模式下。表面着色器以句Cg/HLsL語言進行編寫。
2、頂點和片段着色器(Vertex and fragment Shaders)
如果需要一些表面着色器無法處理的酷炫效果,或者編寫的Shader不需要與燈光進行交互,或是想要的只是全屏圖像效果,那么可以使用頂點和片段着色器。這種Shader可以非常靈活地實現需要的效果,但是需要編寫更多的代碼,並且很難與Unity的渲染管線完美集成。頂點和片段着色器同樣是用Cg/HLsL語言來編寫。
3、固定功能管線着色器(Fixed Function Shaders)
如果游戲要運行在不支持可編程管線的老舊硬件上,那么需要編寫這種Shader了。固定功能管線着色器可以作為片段或表面着色器的備用選擇,這在當硬件無法運行那些酷炫Shader的時候,還可以通過固定功能管線着色器來繪制出一些基本的內容。固定功能管線着色器完全以ShaderLab語言編寫,類似於微軟的Effects或是Nvidia的CgFX。
202. [ UI]什么用途的紋理通常可以不強制使用2次冪的寬高數值?
答:UI紋理不需要強制使用2次冪,以NGUI舉例,NGUI會制作圖集,圖集是2次冪的。
203. [Unity引擎]unity中碰撞器(Collider)和觸發器(Trigger)的區別?
答:
碰撞器(Collider)有碰撞效果,IsTrigger=false,可以調用OnCollisionEnter/Stay/Exit函數
觸發器(Trigger)沒有碰撞效果,isTrigger=true,可以調用OnTriggerEnter/Stay/Exit函數
204. [網絡]請簡述TCP與UDP的區別。
答:TCP是基於連接的,UDP基於無連接的
TCP對系統資源的要求多,UDP較少
UDP程序結構較簡單
TCP是面向流數據的,UDP是數據報
TCP保證數據正確性,UDP可能丟包。
TCP保證數據的順序,UDP不保證。
205. [網絡]為什么建立連接協議是三次握手,而關閉連接卻是四次握手呢?
答:這是因為服務段的LISTEN狀態下的SOCKET當收到SYN報文的建立請求后,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文里來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你未必會馬上關閉SOCKET,也即你可能還需要發送一些數據給對方之后,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這里的ACK報文和FIN報文多數情況下都是分開發的。
206. [網絡]為什么TIME_WAIT狀態還需要等2MSL后才能返回到CLOSED狀態?
答:這是因為雖然雙反都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,案例可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);但是因為我們必須要家鄉網絡是不可靠的,你無法保證你最后發送的ACK報文會一定被對方收到,因此對方處於LASK_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是來重發可能都是的ACK報文。
207. [Unity引擎]請簡述角色控制器中Move和SimpleMove函數的區別。
答:角色控制器中Move和SimpleMove函數都是用於實現角色游戲對象移動的函數,它們的區別在於當我們在每一幀調用SimpleMove函數時,引擎將為該角色控制器對象添加一個重力,而Move函數則不會添加重力,需要我們通過代碼去實現重力的效果。
208. [Unity引擎]請簡述一下什么是游戲引擎?
答:游戲引擎是指一些已經編寫好的可編輯電腦游戲系統或者一些交互式實時圖像應用程序的核心組件。這些系統為游戲設計者提供各種編寫游戲所需要的各種工具,其目的在於讓游戲設計者能容易和快速地做出游戲程序而不用由零開始。大部分都支持多種操作系統平台,如Linux、Mac OS、微軟Windows。游戲引擎包含以下系統:渲染引擎(即“渲染器”,含二維圖像引擎和三維圖像引擎)、物理引擎、碰撞檢測系統、音效、腳本引擎、電腦動畫、人工智能、網絡引擎以及場景管理。
209. [Unity引擎]請簡述Unity中有哪些特殊文件夾及其作用?
1.Editor
Editor文件夾可以在根目錄下,也可以在子目錄里,只要名子叫Editor就可以。比如目錄:/xxx/xxx/Editor 和 /Editor 是一樣的,無論多少個叫Editor的文件夾都可以。Editor下面放的所有資源文件或者腳本文件都不會被打進發布包中,並且腳本也只能在編輯時使用。一般呢會把一些工具類的腳本放在這里,或者是一些編輯時用的DLL。 比如我們現在要做類似技能編輯器,那么編輯器的代碼放在這里是再好不過了,因為實際運行時我們只需要編輯器生成的文件,而不需要編輯器的核心代碼。
2.Editor Default Resources
Editor Default Resources注意中間是有空格的,它必須放在Project視圖的根目錄下,如果你想放在/xxx/xxx/Editor Default Resources 這樣是不行的。你可以把編輯器用到的一些資源放在這里,比如圖片、文本文件、等等。它和Editor文件夾一樣都不會被打到最終發布包里,僅僅用於開發時使用。
3.Gizmos
我覺得這個文件夾其實沒什么用處,如下代碼所示它可以在Scene視圖里給某個坐標繪制一個icon。它的好處是可以傳一個Vecotor3 作為圖片顯示的位置。
4.Plugins
如果做手機游戲開發一般 andoird 或者 ios 要接一些sdk 可以把sdk依賴的庫文件 放在這里,比如 .so .jar .a 文件。這樣打完包以后就會自動把這些文件打在你的包中。
5.Resources
可以在根目錄下,也可以在子目錄里,只要名子叫Resources就可以。比如目錄:/xxx/xxx/Resources 和 /Resources 是一樣的,無論多少個叫Resources的文件夾都可以。Resources文件夾下的資源不管你用還是不用都會被打包進.apk或者.ipa
Resource.Load :編輯時和運行時都可以通過Resource.Load來直接讀取。
Resources.LoadAssetAtPath() :它可以讀取Assets目錄下的任意文件夾下的資源,它可以在編輯時或者編輯器運行時用,它但是它不能在真機上用,它的路徑是”Assets/xx/xx.xxx” 必須是這種路徑,並且要帶文件的后綴名。
AssetDatabase.LoadAssetAtPath():它可以讀取Assets目錄下的任意文件夾下的資源,它只能在編輯時用。它的路徑是”Assets/xx/xx.xxx” 必須是這種路徑,並且要帶文件的后綴名。
我覺得在電腦上開發的時候盡量來用Resource.Load() 或者 Resources.LoadAssetAtPath() ,假如手機上選擇一部分資源要打assetbundle,一部分資源Resource.Load().那么在做.apk或者.ipa的時候 現在都是用腳本來自動化打包,在打包之前 可以用AssetDatabase.MoveAsset()把已經打包成assetbundle的原始文件從Resources文件夾下移動出去在打包,這樣打出來的運行包就不會包行多余的文件了。打完包以后再把移動出去的文件夾移動回來。
6. StreamingAssets
這個文件夾下的資源也會全都打包在.apk或者.ipa 它和Resources的區別是,Resources會壓縮文件,但是它不會壓縮原封不動的打包進去。並且它是一個只讀的文件夾,就是程序運行時只能讀不能寫。它在各個平台下的路徑是不同的,不過可以用Application.streamingAssetsPath 它會根據當前的平台選擇對應的路徑。
有些游戲為了讓所有的資源全部使用assetbundle,會把一些初始的assetbundle放在StreamingAssets目錄下,運行程序的時候在把這些assetbundle拷貝在Application.persistentDataPath目錄下,如果這些assetbundle有更新的話,那么下載到新的assetbundle在把Application.persistentDataPath目錄下原有的覆蓋掉。
因為Application.persistentDataPath目錄是應用程序的沙盒目錄,所以打包之前是沒有這個目錄的,直到應用程序在手機上安裝完畢才有這個目錄。
StreamingAssets目錄下的資源都是不壓縮的,所以它比較大會占空間。
http://www.xuanyusong.com/archives/3229