前言
? ? ? ?求職這件事,不管是新人還是老鳥,都得謹(jǐn)慎對待。因為往往就是一面定終生(薪資),而且面試,也是一個很好的充電突破的契機,可以讓我們有時間對以往經(jīng)驗知識體系進行梳理,并且了解當(dāng)前行業(yè)動向。我個人總結(jié)了以下三點:
1.堅持一個原則。凡事預(yù)則立,不預(yù)則廢。堅決不“裸”面,哪怕HR熱情得像你初戀女友,看上去你來了就立馬給你辦入職。面試時間一定要自己掌控,復(fù)習(xí)好再應(yīng)邀,不然你會體驗到面試不過,HR態(tài)度的冰火兩重天。HR尋找并邀請候選人是工作職責(zé),熱情是工作態(tài)度,并不代表公司一定會錄取一個毫無準(zhǔn)備的你。
2.抓住兩個基本點。HR面試,一些離職原因,工作內(nèi)容,職業(yè)生涯,還有對你個性人品潛在內(nèi)容的調(diào)查,這些是容易忽視的細(xì)節(jié),小心無大錯。技術(shù)面試,這個是重中之重,一般涉及三大塊:語言基礎(chǔ)(C++, ?lua), 業(yè)務(wù)知識(cocos2dx常用游戲開發(fā)知識), 項目經(jīng)歷(根據(jù)你做過的功能,深挖,或者假設(shè)各種突發(fā)情況,檢驗?zāi)銓I(yè)務(wù)的理解和解決問題,所以平常工作中一定要多總結(jié),多回顧,多反思)。
3.復(fù)習(xí)三個方向(除此之外最好先去玩一玩面試公司的游戲):
A.計算機基礎(chǔ):c++, ?lua, 常用的數(shù)據(jù)結(jié)構(gòu)與算法,設(shè)計模式;
B.cocos2dx專業(yè)知識技能,熱更新機制,分包加載,屏幕適配,性能優(yōu)化,幀率優(yōu)化,內(nèi)存更新,跨平臺,圖片壓縮處理, UDP/TCP/WebSocket,OpenGL基礎(chǔ)知識,AI戰(zhàn)斗機制,引擎底層原理;
C.項目經(jīng)驗, 具體自行查看自身簡歷,簡歷上寫的每個點,都有可能是面試官的提問來源。一定要對自己所做的東西,有個條理分明的認(rèn)知,對自己做過的業(yè)務(wù)里面運用到的知識,盡量摸清其原理還有實現(xiàn)細(xì)節(jié)。
? ? ? ?因為本篇博客只是起個引導(dǎo)歸納作用,許多細(xì)節(jié)或者有出入的地方,還望各位自行查閱。話不多說,下面進入正題
C++部分
? ? ? ?C++常見的面試字眼一般是:野指針,引用,內(nèi)存分配,堆和棧,模板和泛型,STL, SizeOf。詳細(xì)可以搜索C++面試題等,推薦的面試書籍:《劍指offer》《C++程序員面試秘籍》。面試的書籍只限于臨時抱佛腳,C++是一門易學(xué)難精的語言,建議注重平時工作中的積累和領(lǐng)悟,像《C++Primer》《C++Primer Plus》《Effective C++》《More Effective C++》等經(jīng)典書籍,有時間可以通讀,沒時間可以選中其中一部分精讀,面試官也喜歡拿里面的知識點提問。
1.指針與引用有啥區(qū)別?
答:1)定義:指針是指存儲了一個內(nèi)存地址的變量,引用是原來變量的一個別名。2)初始化:
引用在創(chuàng)建的同時必須初始化,即引用只能引用一個有效對象。指針在創(chuàng)建的時候可不初始化,可在定義后的任何地方重新賦值。3)空值:引用不能指向Null,指針可以指向任意對象。4).效率:由于引用不會指向空值,使用前可不用測試合法性,因此使用引用的代碼效率比使用指針的更高。5).應(yīng)用:指向?qū)ο蟛蛔儯瑧?yīng)該使用引用,不同時刻存在指向不同對象,應(yīng)該使用指針。
2. 什么是野指針?
答:野指針不是NULL指針,而是指指向“垃圾”內(nèi)存的指針。產(chǎn)生原因:指針變量在被創(chuàng)建的時候沒有被初始化,沒有指向合法內(nèi)存;指針P被Free或者delete之后,沒有置NULL,讓人誤以為p是合法的指針。
3. sizeof有哪些用途?
答:1)與存儲分配和I/O系統(tǒng)那樣的例程進行通信;
? ? ? ? 2)查看某個類型的對象在內(nèi)存中所占的單元字節(jié);
? ? ? ? 3)在動態(tài)分配一對象時,可以讓系統(tǒng)知道要分配多少內(nèi)存;
? ? ? ? 4).便于一些類型的擴充,在Windows中很多結(jié)構(gòu)類型
4.malloc/free和new/delete?
答:1).malloc與free是C++的標(biāo)準(zhǔn)庫函數(shù),new/delete是C++的運算符。它們都是可用于申請動態(tài)內(nèi)存和釋放內(nèi)存。
2) .malloc/free為函數(shù)只是開辟空間并釋放,new/delete則不僅會開辟空間,并調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)進行初始化和清理。
5.內(nèi)存的分配方式有幾種?
答:1).在靜態(tài)存儲區(qū)域分配。內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運行期間都是存在,例如全局變量。
2).在棧上創(chuàng)建。在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放,效率高,但是分配的內(nèi)存容量有限。
3).在堆上分配,亦稱動態(tài)內(nèi)存分配。程序在運行的時候用malloC或者new申請任意多的內(nèi)存,程序員自己負(fù)責(zé)在何時用free或者delete釋放內(nèi)存。
6.關(guān)鍵字static的作用是什么?
答:1).在函數(shù)體內(nèi),一個被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用的過程中維持其指不變。
2).在模塊內(nèi),函數(shù)體外,一個被聲明為靜態(tài)的變量可以被模塊內(nèi)所有函數(shù)訪問,但不能被模塊外其他函數(shù)訪問。它時一個本地的全局變量。
3).在模塊內(nèi),一個被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其他函數(shù)調(diào)用。那就是,這個函數(shù)被限制在聲明它模塊的本地范圍內(nèi)使用。
7.構(gòu)造函數(shù)與析構(gòu)函數(shù)的區(qū)別?
答:構(gòu)造函數(shù)函數(shù)名與類名相同,它的作用是在建立一個對象時,做些初始化工作。析構(gòu)函數(shù)的函數(shù)名也和類名相同,不過需要在前面加上~,它主要是一個對象離開作用域時,一個做些清理工作,比如釋放從堆中分配的內(nèi)存。
8. 什么是STL?
答:STL(Standard Template Library),即標(biāo)準(zhǔn)模板庫,它涵蓋了常用的數(shù)據(jù)結(jié)構(gòu)和算法,并且具有跨平臺的特點。STL是C++標(biāo)準(zhǔn)函數(shù)庫的一部分,它的基本觀念就是把數(shù)據(jù)與操作分離。
是一個具有工業(yè)強度的,高效的C++程序庫。它是最新的C++標(biāo)準(zhǔn)函數(shù)庫中的一個子集,包括容器,算法,迭代器等組件。
9.map和hashmap有什么區(qū)別?
答:1).底層數(shù)據(jù)結(jié)構(gòu)不同,map是紅黑樹,hashmap是哈希表。
2).map的優(yōu)點在于元素可以自動按照鍵值排序,而hash map的優(yōu)點在于它的個項目操作的平均時間復(fù)雜度接近常數(shù)。
3).map屬于標(biāo)準(zhǔn)的一部分,而hashMap則不是。
lua部分
Lua相對于C++來說,語法相對簡單,內(nèi)容也較少,面試內(nèi)容一般包括: 語法基礎(chǔ)知識,
元表,協(xié)同程序,跨平臺調(diào)用,lua優(yōu)缺點,熱更新機制,垃圾回收機制,虛擬機。在掌握以上內(nèi)容,最好對Lua的底層實現(xiàn)有一定了解,就是對Lua核心機制的底層源碼有一定了解,推薦的話《lua設(shè)計與實現(xiàn)》,或者閱讀源碼。
1.lua的基本數(shù)據(jù)類型?
答:nil、boolean、number、string、userdata、function、thread 和 table
2.pairs和 ipairs區(qū)別?
答:pairs:迭代 table,遍歷表中全部key,value, 可以返回 nil;
ipairs:迭代數(shù)組,不能返回 nil, 如果某個下標(biāo)元素不存在,則退出;
4. lua如何實現(xiàn)面向?qū)ο螅?/h2>
答:首先面向?qū)ο蟮奶卣鳎?/p>
a.封裝(將事務(wù)抽象成類,實現(xiàn)細(xì)節(jié)和數(shù)據(jù)只對可信的類和對象操作,對外只提供接口);
b.繼承(子類通過對父類繼承,實現(xiàn)父類的一些方法和屬性,并且可以擴展)
c.多態(tài)(一個接口,多個方法。子類可以繼承父類方法,但是有可以有不同實現(xiàn)方式。比如可以重寫父類的方法。也可以通過和父類方法名相同,參數(shù)不同的重載形式實現(xiàn)多態(tài))
d.抽象
Lua可以通過table和元表將面向?qū)ο蟮奶卣髂M出來,組合成一個類,借用菜鳥教程案例:
-- 元類
Rectangle?=?{area?=?0,?length?=?0,?breadth?=?0}
-- 派生類的方法 new
function?Rectangle:new?(o,length,breadth)
o?=?o?or?{}
?setmetatable(o,?self)
? self.__index?=?self
? self.length?=?length?or?0
? self.breadth?=?breadth?or?0
? self.area?=?length*breadth;
?return?o
end
-- 派生類的方法 printArea
function?Rectangle:printArea?()
?print("矩形面積為 ",self.area)
end
5. 什么是協(xié)同程序?
答:定義:Lua協(xié)同程序(coroutine)與線程比較類似:擁有獨立的堆棧,獨立的局部變量,獨立的指令指針,同時又與其它協(xié)同程序共享全局變量和其它大部分東西
與線程的區(qū)別:線程與協(xié)同程序的主要區(qū)別在于,一個具有多個線程的程序可以同時運行幾個線程,而協(xié)同程序卻需要彼此協(xié)作的運行。在任一指定時刻只有一個協(xié)同程序在運行,并且這個正在運行的協(xié)同程序只有在明確的被要求掛起的時候才會被掛起。協(xié)同程序有點類似同步的多線程,在等待同一個線程鎖的幾個線程有點類似協(xié)同。
主要的語法:create()(創(chuàng)建), resume()(重啟), yield()(掛起), status()(協(xié)程的狀態(tài),包含:dead,suspended,running)。
6. lua跨平臺交互?
答:1).lua與Andorid端java交互,主要通過?JNI 提供了完善的接口來操作 Java,比如查找特定的 Class、Method,可以參考(LuaJavaBridge):
https://www.cnblogs.com/mokey/p/4443561.html
2).lua與Ios端Object-c交互,首先cocos2d 對oc和lua調(diào)用進行了封裝,這就更有利于我們調(diào)用cocos/cocos2d/luaoc,網(wǎng)上經(jīng)典的封裝(luaoc?):
https://www.cnblogs.com/guangyun/p/5020201.html
3).lua與C#交互(用于Unity),原理其實和java , OC差不多,都是通過封裝一些對外的接口類,通過解釋器LuaInterface.dll來互相調(diào)用對方的靜態(tài)函數(shù),具體可以自行搜索,就不班門弄斧了。
7.lua的優(yōu)缺點?
?答:優(yōu)點:a.可以執(zhí)行高。在Mac,Win,Windows多個平臺輕松編譯通過。
???????????b.良好的嵌入性。有豐富的的API,可供宿主和lua腳本之間進行通信和交換數(shù)據(jù)。
???????????c.空間占用非常小,壓縮包只有208KB, 解壓縮也不過835KB.
???????????d.效率高,是速度最快的腳本語言之一。
?????缺點:內(nèi)建功能少,自帶語言庫少,lua的學(xué)習(xí)文檔也少,夠小夠簡潔(優(yōu)缺點)。
8.lua的熱更新機制?
答:原理:Lua的?require(modelname)?把一個lua文件加載存package.loaded[modelname]。?當(dāng)我們加載一個模塊的時候,會先判斷是否在package.loaded中已存在,若存在則返回改模塊,不存在才會加載(loadfile),防止重復(fù)加載。
? ? ? ?方法:最簡單粗暴的熱更新就是將package.loaded[modelname]的值置為nil,強制重新加載,但是舊有的模塊無法更新。所以,我們在更新某一個模塊的時候,需要將引用該模塊的地方的值也做對應(yīng)的更新。
function reload_module(module_name)
????local old_module = _G[module_name]
????package.loaded[module_name] = nil
????require (module_name)
????local new_module = _G[module_name]
????for k, v in pairs(new_module) do
????????old_module[k] = v
????end
????package.loaded[module_name] = old_module
end
9. lua垃圾回收機制
答:1).lua采用了自動內(nèi)存管理,??Lua 運行了一個垃圾收集器來收集所有死對象?(即在 Lua 中不可能再訪問到的對象)來完成自動內(nèi)存管理的工作
? ? ? 2).通過兩個數(shù)字來控制垃圾收集循環(huán):
???*垃圾收集器間歇率:控制著收集器需要在開啟新的循環(huán)前要等待多久.<100:在開啟新的循環(huán)前不會有等待。=200:會讓收集器等到總內(nèi)存使用量達(dá)到之前的兩倍時才開始新的循環(huán)。
???*垃圾收集器步進倍率:控制著收集器運作速度相對于內(nèi)存分配速度的倍率,默認(rèn)值是200?,增大這個值不僅會讓收集器更加積極,還會增加每個增量步驟的長度。
? ? 3).主要函數(shù):
collectgarbage("collect"):?做一次完整的垃圾收集循環(huán)。通過參數(shù)opt 它提供了一組不同的功能:
collectgarbage("count"):?以?K 字節(jié)數(shù)為單位返回 Lua 使用的總內(nèi)存數(shù)。這個值有小數(shù)部分,所以只需要乘上1024 就能得到 Lua 使用的準(zhǔn)確字節(jié)數(shù)(除非溢出)。
collectgarbage("restart"):?重啟垃圾收集器的自動運行。
collectgarbage("setpause"):?將 arg 設(shè)為收集器的 間歇率。 返回 間歇率 的前一個值。
collectgarbage("setstepmul"):?返回 步進倍率 的前一個值。
collectgarbage("step"):?單步運行垃圾收集器。步長"大小"由 arg 控制。 傳入 0 時,收集器步進(不可分割的)一步。 傳入非 0 值, 收集器收集相當(dāng)于 Lua 分配這些多(K 字節(jié))內(nèi)存的工作。 如果收集器結(jié)束一個循環(huán)將返回 true 。
collectgarbage("stop"):?停止垃圾收集器的運行。在調(diào)用重啟前,收集器只會因顯式的調(diào)用運行。
10.lua虛擬機原理?
答:扮演一個中間件的角色,對上負(fù)責(zé)解釋執(zhí)行字節(jié)碼,對下屏蔽平臺相關(guān)內(nèi)容。
->程序員編碼lua文件
->語法詞法分析生成Lua的字節(jié)碼文件(對應(yīng)Lua工具鏈的Luac.exe)
->Lua虛擬機解析字節(jié)碼,并執(zhí)行其中的指令集
->輸出結(jié)果。
cocos2dx部分
??經(jīng)過那么多年的發(fā)展,cocos2dx已經(jīng)有了完善的體系,網(wǎng)上社區(qū)也有大量專業(yè)的書籍可供參考,比較知名的quick+skynet框架,也被許多大型游戲應(yīng)用。
1. 導(dǎo)演,節(jié)點,場景,層,精靈
答:導(dǎo)演:是游戲的組織者,和領(lǐng)導(dǎo)者,負(fù)責(zé)游戲開始結(jié)束的初始化和銷毀工作,游戲場景的切換,暫?;蚧謴?fù),導(dǎo)演還可以設(shè)置和獲取系統(tǒng)信息,屏幕大小。
節(jié)點:是cocos2d-Lua中可見元素的基礎(chǔ)類,場景,層,精靈,標(biāo)簽,菜單等都是繼承自Node。它封裝了可見元素的基礎(chǔ)屬性和方法,可以包含字節(jié)點,可以運行動作,內(nèi)部也有跟隨節(jié)點生命周期的調(diào)度器。
場景:是容納其他可見與不可見元素的容器,一個游戲至少需要一個場景。特定時間內(nèi)只有一個場景是處于活動狀態(tài)的。
層:是對場景布局的細(xì)分,主要也起容器作用,一般分角色場景層,和系統(tǒng)UI層。
精靈:精靈是容器中盛放的內(nèi)容。精靈總綁定一個紋理對象或精靈幀對象,引擎渲染精靈實際上是把精靈綁定的紋理或精靈幀按照屬性設(shè)定渲染到屏幕上??梢哉f,精靈是圖像的載體,游戲中看得見的場景如背景圖片,房屋,敵人,玩家角色及子彈等,都可以通過精靈實現(xiàn)。
2. 熱更新機制。
答:熱更新也叫不停機更新,是在游戲服務(wù)器運行期間對游戲進行更新。實現(xiàn)不停機修正bug、修改游戲數(shù)據(jù)等操作,其基本原理:
1).登入游戲先向服務(wù)端請求當(dāng)前游戲版本號信息,與本地版本號比較,如果相同則說明沒有資源需要更新直接進入游戲,而如果不相同,則說明有資源需要更新進入第2步。
2).向服務(wù)端請求當(dāng)前所有資源的列表(資源名+MD5),與本地資源列表比較,找出需要更新的資源。
3).根據(jù)找出的需要更新資源,向服務(wù)端請求下載下來。
Cocos自帶也封裝了熱更新模塊(AssetsManager, AssetsManagerEx)。
3. 如何解決卡頓或崩潰(fps/流暢度)問題?
答:卡頓和崩潰兩個問題通常可以放在一起,因為兩者都屬于性能優(yōu)化的范疇,可以從CUP和GPU兩個方面著手。
成因:造成卡頓也就是掉幀的原因主要是CPU計算量和GPU渲染壓力過大。造成程序崩潰的原因基本也是兩種情況,一種是代碼錯誤造成的崩潰,另一種是我們主要討論的內(nèi)存過高造成的崩潰。
從減少cpu計算量來說:
1).優(yōu)化代碼,保持良好的編碼規(guī)范,選擇恰當(dāng)時間復(fù)雜度較少的算法;
2).游戲邏輯優(yōu)化,不在主邏輯做復(fù)雜操作,減少頻繁創(chuàng)建和銷毀對象,反饋不高的邏輯可以適當(dāng)?shù)牟扇〕閹?,不用每幀運算刷新。
3).對游戲游戲引擎級別的優(yōu)化,如修spine的內(nèi)存泄漏問題、ui加載速度優(yōu)化。
從減少GPU渲染壓力來說:
1).分幀加載。加載較大的紋理或者資源時,分幀加載的策略可以高效的使用內(nèi)存防止內(nèi)存峰值過高造成崩潰。
2).選擇合適的資源格式。使用pvr.ccz格式紋理減少內(nèi)存使用。紋理使用的每種顏色位數(shù)越多,圖像質(zhì)量越好,但是越耗內(nèi)存,使用顏色深度為RGB4444的紋理代替RGB8888。如果圖片不需要透明通道就不要加上透明通道。
3).減少繪制調(diào)用,即減少DrawCall??梢越梃bU3D的一些圖形渲染知識,使用大圖集,批處理,共享材質(zhì),減少顯示精靈數(shù)。
4).優(yōu)化UI布局。減少UI層的嵌套深度,提高繪制遍歷的速度??刂瀑Y源的規(guī)格,將通用的按鈕,圖標(biāo),打成一張通用大圖,作為常用資源常駐。
5).UI設(shè)計的時候要提高UI通用資源的使用率, 比如使用九宮格,圖片縮放旋轉(zhuǎn)。
6).動畫優(yōu)化。幀動畫可以適量精簡幀數(shù),減少內(nèi)存占用。骨骼動畫,合理的控制骨骼數(shù),減少cpu計算量。
7).音頻優(yōu)化,因為Android平臺和iOS平臺均支持MP3格式,而且MP3格式經(jīng)過壓縮和硬件加速,推薦使用mp3格式。
4.使用到的網(wǎng)絡(luò),UDP/TCP/WebSocket等
答:TCP:著名的三次握手原理(自行搜索),它的特點是,面向連接(在開始真正通信前需要三次握手),安全可靠(每一次通信都要對方應(yīng)答,如果沒收到應(yīng)答則認(rèn)為數(shù)據(jù)包丟失,會按一定策略重發(fā)),全雙工通信(建立連接后,雙方均可通過通道進行數(shù)據(jù)傳輸)。
? ? ? ?UDP:無需建立連接,只需要指定目標(biāo)的IP和端口即可向其發(fā)送數(shù)據(jù)報,可以一對一,一對多,多對多,發(fā)送數(shù)據(jù)也是無序狀態(tài),容易發(fā)生丟包。丟包一般解決方案,借鑒TCP協(xié)議原理,增加握手,或者增加回包機制,就是每個發(fā)包必須收到回包,才能再發(fā)下一個。還有一些如控制發(fā)包速度,發(fā)包大小,在接收方,將通信和處理分開,增加個應(yīng)用緩沖區(qū)等等。具體需要根據(jù)項目要求具體分析解決,丟包只能改善。UDP想要可靠,可以增加回包機制,每個包有遞增序號,接收方發(fā)現(xiàn)中間丟了包就發(fā)重傳請求,但是這樣其實也就重新實現(xiàn)了TCP。具體詳細(xì)可以去了解定時重傳和RUDP等。
? ? ? ?WebSocket:是Html5興起的一種新的協(xié)議,在通信前會做一個類似于TCP建立連接的握手動作。要實現(xiàn)即時通信,一般會采用下面兩種方式:
短輪詢,即在特定時間間隔內(nèi)不斷發(fā)送Http請求來詢問服務(wù)端是否有最新數(shù)據(jù),如果有,服務(wù)端就返回最新的數(shù)據(jù)給客戶端,沒有,服務(wù)端就丟棄這次的輪詢請求,缺點是存在大量無用的HTTP請求,十分消耗網(wǎng)絡(luò)寬帶資源。
? ? ? ?長輪詢,和短輪詢大同小異,客戶端請求服務(wù)端數(shù)據(jù),服務(wù)端如果沒有最新數(shù)據(jù)就一直保持連接不斷開,直到有最新數(shù)據(jù)后再返回給客戶端,斷開連接,客戶端處理完之后對服務(wù)端進行長輪詢,周而復(fù)始。缺點是,服務(wù)端在同一個時間可能需要保持與多個客戶端的連接,在用戶量大的時候,極其浪費服務(wù)器資源。
? ? ? ? 面試其實是雙向選擇,公司最終目的也是尋找到能幫公司解決問題,帶來價值的人。只要你將你能解決公司問題的能力展現(xiàn)出來,綜合素質(zhì)無大問題,一般都能入選。最后,祝大家都能找到心儀的工作。
5. 屏幕適配
app每種機型用不同的適配方案
游戲內(nèi)部:等比例縮放,不要黑邊,全屏
6.分包加載:
初始化只加載主城資源