第一篇:Unity之工作總結(jié)
圖片格式
----------1 DrawCall
-----------2
? 圖片格式:
NGUI生成的圖集的圖片格式是PNG格式,但是無論是什么格式的圖片 Unity都會自己生成一套格式,并且打包的時候不會用文件夾下面的格式,而是Unity自己格式。
如果你用的UITexture 你可以對每一張圖來修改格式,比如顏色數(shù)比較少的圖片可以使用16bit,如果沒有透明,可以使用pvr或者etc 這樣圖片會小很多。如果是UISprite 只要有透明的 就必須使用RGBA32 要不然UI會很難看。
除去 UITextuer和Atlas的圖片之外(因為有透明),其余的貼圖必須是2的冪次方。因為只有2的冪次方圖片,并且沒有透明通道的才會被壓縮。Ios會被壓縮成pvr格式,Andriod會壓縮成etc格式。壓縮之后會小很多。
人物貼圖 場景題圖 特效貼圖 一定要是2的冪次方。
貼圖透明通道分離,壓縮格式設為ETC/PVRTC 最初我們使用了DXT5作為貼圖壓縮格式,希望能減小貼圖的內(nèi)存占用,但很快發(fā)現(xiàn)移動平臺的顯卡是不支持硬件解壓DXT5的。因此對于一張1024x1024大小的RGBA32貼圖,雖然DXT5可將它從4MB壓縮到1MB,但系統(tǒng)將它送進顯卡之前,會先用CPU在內(nèi)存里將它解壓成4MB的RGBA32格式(軟件解壓),然后再將這4MB送進顯存。于是在這段時間里,這張貼圖就占用了5MB內(nèi)存和4MB顯存;而移動平臺往往沒有獨立顯存,需要從內(nèi)存里摳一塊作為顯存,于是原以為只占1MB內(nèi)存的貼圖實際卻占了9MB!
所有不支持硬件壓縮格式都有相同的問題。解決方案:
現(xiàn)在Andriod硬件最廣泛支持的時Etc ,IOS上支持的時PVRTC。但這兩種格式都是不帶透明(Alpha)通道的,因此我們需要將每張原始貼圖的透明通道分離出來,寫進另一張貼圖的紅色通道里,這兩張?zhí)貓D都采用Etc/Pvrtc壓縮。渲染的時候 將兩張貼圖都送進顯存。同時 我們修改了NGUI的shader 在渲染時第二張貼圖的紅色通道寫入到第一張貼圖的透明通道里恢復原來的顏色:
1.2.3.4.5.6.} fixed4 frag(v2f i): COLOR {
fixed4 col;
col.rgb = tex2D(_MainTex, i.texcoord).rgb;col.a = tex2D(_AlphaTex, i.texcoord).r;return col * i.color;
這樣,一張4MB的1024x1024大小的RGBA32原始貼圖,會被分離并壓縮成兩張0.5MB的ETC/PVRTC貼圖(我們用的是ETC/PVRTC 4 bits)。它們渲染時的內(nèi)存占用則是2x0.5+2x0.5=2MB。
? DrawCall 當兩個renderQueue相鄰的DrawCall使用了相同的貼圖、材質(zhì)和shader實例時,這兩個DrawCall就可以合并。但需要注意的是DrawCall合并不見得會提高性能,有時反而會降低性能
如果是UIGeometry為了渲染繪制準備數(shù)據(jù),那么UIDrawCall其實是定義了渲染繪制需要的基本組件。這里拿煮菜做個比喻幫助理 解:UIGeometry好比為煮菜準備食材,UIDrawCall好比是煮菜的工具(鍋,爐子等),UIPanel就是大廚了決定著什么時候該煮 菜,UIWidget(UILabel,UISprite和UITexture)是這道菜怎么樣的最終呈現(xiàn)。
UIWidget分別用UpdateGeometry和WriteToBuffers對UIGeometry的ApplyTransform和 WriteToBuffers進行封裝調(diào)用,ApplyTransform是根據(jù)UIPanel的坐標調(diào)整Vertices的坐 標,WriteToBuffers將UIGeometry的Vertices,UVs和Colors添加進UIPanel的Vertices,UVs和 Colors的BetterList中。
這里還有一個細節(jié)就是:UIGeometry中的Vertices,UVs和Colors的BetterList的buffer什么時候得到,因為這些都 是UIWidget或其子類的信息,所以在UIWidget的子類UILabel,UISprite和UITexture中OnFill函數(shù)生成 UIGeometry的BetterList的buffer。
UIWidget這個腳本中的兩個函數(shù):WriteToBuffers,OnFill,UpdateGeometry。
WriteToBuffers和OnFill這兩個函數(shù)都是將Vertices,UVs和Colors等add進參數(shù)的List中去,查看 WriteToBuffers的調(diào)用出發(fā)現(xiàn)其參數(shù)是UIPanel的Vertices,UVs和Colors,而OnFill的參數(shù)是 UIGeometry的Vertices,UVs和Colors。
WriteToBuffers只是對UIGeometry的封裝調(diào)用,也就是說將UIGeometry的Vertices,UVs和Colors等信息add進UIPanel的對應List中。
UIGeometry的腳本,一直有一個疑問:UIGeometry的Vertices,UVs和Colors的List沒有看到add方法的執(zhí)行,只有在WriteToBuffers被add。直到看到了OnFill才恍然大悟,雖然UIWidget的OnFill是虛函數(shù),沒有具體實現(xiàn),看了下 UISprite重寫的OnFill函數(shù),就是把Vertices,UVs和Colors 添加到UIGeometry的Vertices,UVs和Colors中。所有UI組件的Vertices,UVs和Colors都匯集到UIPanel的Vertices,UVs和Colors去了,然后 UIPanel指定給UIDrawCall渲染就行了
UIWidget的一些實現(xiàn)細節(jié),MakePixelPerfect():對gameObject的localPosition和locaScale進行微調(diào)和糾正。SetDirty():調(diào)用UIPanel的SetDirty()對組件的變更進行重建(rebuilt)。Uiwidge UIGeometry& UIDrawCall 的關系:
UIWidget 中有兩個變量UiDrawCall mDrawcall 和UIGeometry mGeo 的verts uvs cols 的BetterList,然后UiWidget 的UpdateGeometry函數(shù)對UIGeometry 的ApplyTransform()和WriteToBuffer()調(diào)用進行更新.每一個UIwidget都有一個UIGeometry 但是不都有一個UIDrawCall,而是通過Batch合并達到減少DrawCall的數(shù)量,UiDrawCall是有UiPanel生成的。
DrawCall的數(shù)量優(yōu)化
根據(jù)上述描述可以得出一個結(jié)論:使用相同material的連續(xù)的Uiwidget(UILable UiSprite)公用一個UIDrawcall。通過這個結(jié)論我們可以得到一個解決DrawCall過多的問題,UIPanel生成DrawCall時是Fill()方法。Fill 方法對UiWidget.list進行檢測把使用相同Material的連續(xù)的Uiwidget合并生成一個DrawCall ,UIWidget.List 的排序是根據(jù)UiWidget的Depth進行的。所以解決方案有兩種:
1.修改UiWidget(UiLable UIwidget)的Depth,限定UIwidget.List的排序 2.重寫Uiwidget的CompareFunc()方法。(重寫UIWidget的CompareFunc也是可以的,按照Material的name優(yōu)先排序,只有當material一樣是才考慮depth進行排序:)
3.無重疊時自動重排。繪制順序按照Hierarchy
采用第二種方式減少DrawCall: Material leftMat = left.material;Material rightMat = right.material;if(leftMat == rightMat){ if(left.mDepth < right.mDepth)return-1;else if(left.mDepth > right.mDepth)return 1;else return 0;} if(leftMat!=null & rightMat!= null)return string.Compare(leftMat.name,rightMat.name);if(leftMat!= null)return-1;if(rightMat!= null)return 1;
return(leftMat.GetInstanceID()< rightMat.GetInstanceID())?-1 : 1;
夾層問題:
因為Material使用的Shader使用了透明,這樣就不能做深度測試,也就是Mesh的“深度”是不影響的,這樣最終的顯示就跟Shader的 renderQueue有關了,即renderQueue越大,顯示的越靠前面(重疊的圖層,renderQueue越大,越靠前)。當然現(xiàn)在只有增加一 個DrawCall(如多使用一個UIPanel或用另外一個Material)來做到Material的夾層效果。
特效層級:
粒子系統(tǒng)的渲染順序列默認為3000 而NGUI的渲染順序默認是從3000開始,當有嵌套的Panel或者Deoth更高的panel時,NGUI的渲染順序會高于3000
解決方案:
1.修改Ngui中的panel腳本中的默認RenderQueue 調(diào)整到3000以下,這樣就不會擋住粒子特效。當窗口顯示在特效上面時把窗口的RenderQueue調(diào)整到3000以上,就解決了。
2.使用另外一個攝像機顯示特效,但是Ui窗口切換時不太好控制
3.修改例子特效的shader中的RenderQueue的值(需要考慮特效中的層級關系)一級界面 二級界面..浮動窗口
1.不同圖集
項目中做到復雜一些的界面,經(jīng)常會用到多個圖集,以技能界面為例,項目中常用的圖片放到共用圖集中,這是一個圖集,技能界面本身獨有的元素,比如跟技能職業(yè)相關的背景,算作第二個圖集,還有一些技能圖標,圖標單獨歸類到一個圖集中,再一個就是字體的圖集。基本一個界面如此分法,最多需要4個圖集。NGUI的圖集之間的 處理,默認是靠調(diào)整控件的Z值來區(qū)分的,但是這里他可以調(diào)整同一個圖集每個一個控件的Z值,其實不是很好。經(jīng)常會出現(xiàn)圖層相互遮擋的情況,尤其對于控件比較多的界面,一段時間回過來再修改界面的時候,整個要崩潰。
解決方案:在UIPanel中,為每一個Material添加一個layer的變量,當同一圖層靠depth來決定前后關系,不同圖層靠 layer來決定前后關系,在繪制UIDrawCall的時候,根據(jù)layer對跟節(jié)點做一定偏移。這樣就能從Z值中解放出來。如果大家也有碰到圖層的問題,可以參考這樣的做法,以此種方法來處理圖層關系,簡單,做過項目的圈套UI,還未有不能解決的情況。
? UI自適應
Scaling Style 的作用是制定UiRoot的縮放類型,如果是PixelPerfect ,Minimum Height 和Maximum Height 才起作用,scaling style 選擇的是
Pixelperfect 要對Minimum Height和Maximum Height進行設置。(如果是PixelPerfect縮放類型,當屏幕的分辨率大于Maximum Height,則以Maximum Height 為基礎縮放,反之,如果屏幕分辨率小于Minimum Height 則以Minimum Height為基礎進行縮放。例如,如果屏幕高度為1000,而設置的Maximum Height值為800,則UI界面整體放大為原來的1000/800=1.25倍。)FixedSize : 跟Manual Height有關
FixedSizeOnMobiles :跟Manual Height有關
只是針對IOS和Android上的判斷,也就是說只有IOS和Android平臺下FixedSizeOnMobiles才起作用.FixedSize或FixedSizeOnMobiles,則縮放只以Manual Height為參考,屏幕分辨率的高度值不同于此設置值時,則根據(jù)其比例(即Screen Height / Manual Height)對整棵UI樹的進行“等比”縮放(寬度的縮放比也是此比例值)。
注釋:如果設置FixedSize,UIWidget.height(以UiRoot默認值進行高度縮放)是不會改變的,不管實際屏幕分辨率的像素是多少,Anchor Stretch的背景圖片高度始終是manualHeight.UIRoot下的UIWidget的height參數(shù)一直都是實際的值
UIRoot 是基于高度進行縮放的如何做以寬度適配。
UIRoot是基于高度放縮的,即放縮的比例是以高度為參考的,所以UIRoot有一個manualHeight的參數(shù)。那么對于橫版游戲顯然不行,要是 能實現(xiàn)基于寬度放縮。所以可以通過設置一個“manualWidth”的參數(shù)來做。比如我們項目中使用的是 1024 作為UI的寬屏尺寸,通過換算設置manualHeight的值:
int height = Mathf.Max(2, Screen.height);manualHeight = Screen.height * 1024 / Screen.width;//基于寬度的屏幕分辨率自適應
注釋:UIRoot其實就做了一件事情:根據(jù)Screen.height和UIRoot.activeHeight的比例來調(diào)整UIRoot的 loaclScal,從而保證UIWidget(UISprite,UILabel)可以按照其本身的大小進行設置,而不用經(jīng)過復雜的換算過程。
? 資源分離打包與加載
資源分離打包與加載是最有效的減小安裝包體積與運行時內(nèi)存占用的手段。一般打包粒度越細,這兩個指標就越小。但打包粒度也并不是越細就越好。如果運行時要同時加載大量小bundle,那么加載速度將會非常慢——時間都浪費在協(xié)程之間的調(diào)度和多批次的小I/O上了。此需要有策略地控制打包粒度。一般只分離字體和貼圖這種體積較大的公用資源。
? 關閉貼圖的讀寫選項
Unity中導入的每張貼圖都有一個啟用可讀可寫(Read/Write Enable)的開關,對應的參數(shù)是TextureImporter.isReadable。選中貼圖后可在Import Setting選項卡中看到這個開關。只有打開這個開關才可以對貼圖使用Textuer2D.GetPixel,讀取或改寫貼圖資源的像素,但這就需要系統(tǒng)在內(nèi)存中保留一份貼圖的拷貝,以供Cpu訪問,但是一般游戲運行過程中不會有這樣的需求,因此我們對所有貼圖都關閉這個開關,只在中做貼圖導入后處理(比如對原始提貼圖分離透明通道)時需要打開這個選項。這樣,上文提到的1024x1024大小的貼圖,其運行時的2MB內(nèi)存占用又可以少一半,減小到1MB。Texture圖片空間和內(nèi)存占用分析
紋理大小影響:
可以將其他(非二的冪-“NPOT”)紋理大小用于 Unity非二的冪紋理大小通常占用的內(nèi)存稍多一點,由 GPU 進行讀取的速度可能較慢,因此考慮到性能,最好盡可能使用二的冪大小。如果平臺或 GPU 不支持 NPOT 紋理大小,則 Unity 會縮放紋理并將其填補為下一個二的冪大小,這甚至會使用更多內(nèi)存并使加載更慢
Iphone:
空項目
空間占用量42.3M
ipa包10M 10張1200*520 無壓縮Texture 單張圖占用量2.8M
空間占用兩70.2M ipa包 22.9M 10張1200*520壓縮成1024*1024 PVRTC4 單圖占用量0.5M 空間占用量47.3M ipa包 13.2M 10張1024*1024 無壓縮Texture
單圖占用量4M
空間占用量82.M
ipa包14.6M 10張1024*1024壓縮為PVRTVC4格式
單張圖占用量0.5M 空間占用量 47.3M ipa包 11.6M
綜上所述:
1.2的N次方大小的圖片會得到引擎更大的支持,包括壓縮比率,內(nèi)存消耗 打包壓縮大小,而且支持的力度非常大。
2.減小圖片的占用大小和內(nèi)存方式有:圖片大小變化(Maxsize),色彩位數(shù)變化(16位色 32位色),壓縮PVRC格式
3.U3D對于圖片的格式是自己生成的,而并不是你給它什么它用什么格式。一張1024*1024圖在無壓縮的格式下,他會被U3D無壓縮文件像是存放,也就是說U3D 里的Texture Perview 里顯示的占用大小**M 不只是內(nèi)存占用的大小,還是空間占用大小。
Unity 圖片壓縮格式介紹:
U3D 的內(nèi)部機制為自動生成圖片類型來替代我們的圖片在圖片的壓縮方式需要進行謹慎的選擇。幾種比較主要的壓縮格式:
RGBA32 BIT/AutomaticTurecolor(256*256 256k)
格式為無壓縮最保真格式,最消耗內(nèi)存和空間的格式。RGBA16 BIT/
格式為無壓縮16位格式,比32位節(jié)省一半的空間和內(nèi)存,與Automatic16 相同。RGBA Compressed PVRTC 4bits格式為PVRTC 圖片格式,它相當于把圖片更改了壓縮方式新生成了一個圖片來替換原來的圖片格式
貼圖格式:
3D游戲中貼圖的的分類:
UI貼圖
ui是按照 1280*853比例出的圖
3D場景貼圖 主要是因為多重采樣的緣故。3D游戲一般來說都是受攝像機遠近大小改變而采取不同的采樣大小,如果不設置多重采樣的話,在遠處有非常多的白色噪點。
2D游戲
所有都不需要勾選多重采樣,具有3D性質(zhì)的貼圖,我們都需要勾選上GENERATE MIP MAPS,這樣會使貼圖大小增加25%這樣。
正方貼圖與非正方貼圖也要區(qū)分: 非正方貼圖只有16位的壓縮(相當于真彩色減半),所以最好游戲中都是正方的貼圖。正方貼圖: IOS:
普通不透明: RGB PVRTC 4 BITS
普通透明: RGBA PVRTC 4 BITS(256*256 32kb)Androis:
普通不透明: RGB ETC 4 BITS(256*256 32kb)
普通透明:因為沒有通用的兼容模式,所以一般情況是用RGBA 16 BITS 或是針對不同的GPU選擇 DXT5/ATC8 BITS/ETC2 8BITS。如果技術支持,可以采用 RGB ETC 4 BITS 加一張Alpha 8的貼圖來實現(xiàn)透明效果。
非正方形:
一般采用16位壓縮,16位色會帶來顏色損失,如果本來美術就按16位色畫的話,就不會帶來損失。日本的很多2D游戲都是采用那個16位來畫的。少漸變 和艷色。
不透明貼圖: RGB 16 BIT(256*256 128KB)
透明貼圖: RGBA 16 BIT(256*256 128KB)
高清不壓縮貼圖:
RGBA 32 BIT(256*256 256kb)
對于不重要的貼圖,模糊度低的貼圖,建議不僅要采取像素壓縮,還要直接壓縮其大小。如光照貼圖壓到512或256。如背景原本1024的圖直接壓到256。玩家不注意到就可以了。
注意:
U3D所有圖片的壓縮格式都會以另一種方式存儲,不會以你給的方式存儲,只有你指定了某種格式,他才會轉(zhuǎn)換成你要的格式。而且在Andriod 里的并不一定有效,因為Andriod的機型多,GPU的渲染方式也不一樣,RGBA16 適應于所有機型
? GameObject數(shù)量
場景中GameObject的數(shù)量也是衡量性能的重要指標,頻繁的創(chuàng)建 和銷毀GameObjec 是非常耗時,場景中存在的GameObject會占用內(nèi)存,如果GameObject上掛有物體的話,每個GameOject的腳本都需要實力化。
? 整理圖集
整理圖集的主要目的是節(jié)省運行時內(nèi)存(雖然有時也能起到合并DrawCall的作用)。從這個角度講,顯示一個界面時送進顯存的圖集尺寸之和是越小越好。一般有如下方法可以幫助我們做到這點: 1)在界面設計上,盡量讓美術控件設計成九宮格拉伸,即UiSprite的類型是Sliced.這樣美術素材可以切出一張很小的圖片在unity中做拉伸。當然一個九宮格也就意味著其定點數(shù)量會從4個增加到16個(如果九宮格的中心格子采用Tiled做平鋪類型的話,定點數(shù)會更多),構(gòu)建DrawCall的開銷會更大。但一般只要DrawCall安排合理就不會出問題 2)同樣在界面設計上 盡量設計成對稱的形式,這樣在切圖的時候美術切圖的時候就可以只切一部分,我們在Untiy中將完整的圖案拼出來,比如一個圓形圖案我們可以只切四分之一,不過與上述第一點類似這樣會增加定點個數(shù),同時也會增加場景中GameObject的個數(shù),因為GameObject的數(shù)量增多時會占用跟多的內(nèi)存,所以只對尺寸較大的圖案采用這種方法。3)4)確保不要讓不必要的貼圖素材駐留內(nèi)存,更不要在渲染時將無關的貼圖素材送進顯存。為此需要將圖集按照界面分開,按模塊劃分圖集,一個界面中的UISprite也不要使用別的界面的圖集。數(shù)量龐大 且數(shù)量不固定的物品不要使用圖集 要采用UITexture 減少圖集中的空白地方。完全透明的像素和不透明的像素所占用的空間是一樣的,因此在像素量不變的情況下,要盡量減少圖集中的空白。比如有時一張1024x1024的圖集中,素材所占的面積還沒超過一半,這時可以考慮將這張圖集切成兩張512x512的圖集。(可能有人會問為什么不能做成一張1024x512的圖集,這是因為iOS平臺似乎要求送進顯存的貼圖一定是方形。)當然,兩張不同圖集的DrawCall是無法合并的,但這并不是什么問題。5)
? 根據(jù)各個UI控件的設計安放Panle,隔開DrawCall 在合并DrawCall時需要注意,如果將會移動變化的UI控件和一個靜止不變的UI控件的DrawCall合在一起,當其中一個UI控件(UiWeight)的位置 大小 或顏色等屬性發(fā)生變化時,UIPanle就需要重建這個Panle上的所有DrawCall。有時重建一個DrawCall會消耗不少的CPU,它需要計算這個DrawCall上的所有頂點信息,包括頂點位置 UV和顏色等,如果很多的控件都集中在同一個DrawCall上,那么其中一個控件上有一點點變化,這個DrawCall上的所有的頂點就都需要遍歷一遍。而如果我們的UI又大量的采用九宮格拉伸,使控件的頂點數(shù)量就會變得更多。因此重建一個DrawCall 的開銷會更大。
因此需要將UI控件分組,將一段時間內(nèi)會發(fā)生變化的控件----比如怪物頭頂?shù)难獥l和傷害跳字放在同一個Panle上,并且這些Panle上只有這些控件,其余基本不變的控件放在別的控件Panle上,這樣兩類控件就隔開到不同的DrawCall在不同的Panle中,當一個控件發(fā)生變化而導致DrawCall重建時,就不需要遍歷那些沒有變化的控件。因為在美術設計上,一段時間內(nèi)在變化的控件總是少數(shù),所以優(yōu)化效果十分明顯,節(jié)省的CPU占用率能達到25%。
?
優(yōu)化錨點內(nèi)部邏輯,使其只在必要時更新
在上一點優(yōu)化了Panel的DrawCall重建效率之后,我們發(fā)現(xiàn)NGUI錨點自身的更新邏輯也會消耗不少CPU開銷。即使是在控件靜止不動的情況下,控件的錨點也會每幀更新(見UIWidget.OnUpdate函數(shù)),而且它的更新是遞歸式的,使CPU占用率更高。因此我們修改了NGUI的內(nèi)部代碼,使錨點只在必要時更新。一般只在控件初始化和屏幕大小發(fā)生變化時更新即可。不過這個優(yōu)化的代價是控件的頂點位置發(fā)生變化的時候(比如控件在運動,或控件大小改變等),上層邏輯需要自己負責更新錨點。
?
降低貼圖分辨率
這一招說白了其實就是減小貼圖素材的尺寸。比如對一張在原畫里尺寸是100x80的貼圖,我們將它導入Unity后會把它縮小到50x40,即縮小兩倍。游戲?qū)嶋H使用的是縮小后的貼圖。不過這一招是必然會顯著降低美術品質(zhì)的,美術立馬會發(fā)現(xiàn)畫面變得更模糊,因此一般不到程序撐不住的時候不會采用。
? 界面的延遲加載和定時卸載
如果一些界面的重要性較低,并且不常被使用,可以等到界面需要打開顯示的時候才從bundle加載資源,并且在關閉時將自己卸載出內(nèi)存,或者等過一段時間再卸載。不過這個方法有兩個代價:一是會影響體驗,玩家要求打開界面時,界面的顯示會有延遲;二是更容易出bug,上層寫邏輯時要考慮異步情況,當程序員要訪問一個界面時,這個界面未必會在內(nèi)存里。因此目前為止我們?nèi)晕磳嵤┰摲桨浮D壳爸皇沁M入一個新場景時,卸載上一個場景用到但新場景不會用到的界面。
? 避免頻繁調(diào)用GameObject.SetActive 我們游戲的某些邏輯會在一幀內(nèi)頻繁調(diào)用GameObject.SetActive,顯示或隱藏一些對象,數(shù)量達到一百多次之多。這類操作的CPU開銷很大(尤其是NGUI的UIWidget在激活的時候會做很多初始化工作),而且會觸發(fā)大量GC。后來我們改變了顯示和隱藏對象的方法——讓對象一直保持激活狀態(tài)(activeInHierarchy為true),而原來的SetActive(false)改為將對象移到屏幕外,SetActive(true)改為將對象移回屏幕內(nèi)。這樣性能就好多了。
?
NGUI性能消耗點匯總
使用LinkedList
BetterList是一個數(shù)組 LinkedList
NGUI節(jié)點查找非常耗時。
?
代碼中非必要的堆分配
1)
我們應避免使用foreach循環(huán) :一般建議是避免使用foreach循環(huán),盡量使用for或者while循環(huán),我在Unity論壇遇到很多人提到這個建議。這背后的原因咋一看似乎是合理的,foreach只是語法封裝,因為編譯器處理代碼的流程大體是下面這樣:
foreach(SomeType s in someList)s.DoSomething();轉(zhuǎn)換為:
using(SomeType.Enumerator enumerator = this.someList.GetEnumerator()){
while(enumerator.MoveNext()){
SomeType s =(SomeType)enumerator.Current;s.DoSomething();} } 每次使用foreach時 都會創(chuàng)建一個enumerator 對象,一個System.Collections.IEnumerator的接口實例。但是創(chuàng)建在堆棧上還是堆上是都可能的 幾乎所有的System.Collections.Genric(list
2)應該避免使用閉包和LINQ嗎?
匿名方法和lambda表達式會引起內(nèi)存泄露嗎?答案是:這取決于C#編譯器,有兩種區(qū)別很大的方式來處理
int result = 0;void Update(){
for(int i = 0;i < 100;i++){
System.Func
現(xiàn)在我們在托管定義方式上做一些小小的改變:
System.Func
通過把“p”替換為“i++”,我們已經(jīng)局部定義方法轉(zhuǎn)變成一個真的閉包(閉包是函數(shù)編程的一大支柱。它把數(shù)據(jù)和函數(shù)聯(lián)系到一起,更準確的說是非局部變量在函數(shù)之外定義。)在myFunc中,p是一個局部變量但i是一個非局部變量,屬于Update()方法。C#編譯器現(xiàn)在不得不將myFunc轉(zhuǎn)換成可訪問、甚至是可修改,包含非局部變量的方法。它通過聲明一個全新的類表示myFunc創(chuàng)建的引用來實現(xiàn)這一功能。For循環(huán)每次執(zhí)行都要分配一個類的實例,瞬間產(chǎn)生大量的內(nèi)存泄露(在我的電腦上每幀26KB)閉包概念在C#3.0 的時候被引入主要原因是LINQ。如果閉包回引起內(nèi)存泄露
3)協(xié)程
通過StartCoroutine()運行一個協(xié)程,會隱式分配Unity Coroutine類(系統(tǒng)上占用21字節(jié))和Enumerator(占用16個字節(jié)),所以在游戲運行時盡量少用StartCoroutine()
4)字符串
C#和Unity內(nèi)存問題必須會提到字符串。從內(nèi)存角度,字符串很奇怪,因為,他們是堆分配且不變的。當你連接兩個字符串時(無論是變量還是常量):運行時不得不分配至少一個新的字符串對象存儲新的結(jié)果。String.Concat()有效地通過調(diào)用FastAllocateString()分配新對象,但是必定會產(chǎn)生多余的堆分配(上面例子在我的系統(tǒng)上占用40字節(jié))。如果你需要在運行時修改或者連接字符串,最好使用 System.Text.StringBuilder
5)裝箱
盡量減少裝箱
6)庫方法
各種庫方法也會隱式分配內(nèi)存。捕捉它們最好的方法是分析。我之前已經(jīng)寫過的 foreach-循環(huán),大多數(shù)標準泛型集合不會導致堆分配。Dictionary
? 查找堆分配的兩種方式 1.使用Unity profiler 2.反編譯自己的代碼
在CIL中查找內(nèi)存分配
CIL代碼的優(yōu)勢在于堆分配代碼不會被隱藏。相反,完全可以在反編譯的代碼中找到堆分配的三種指令。
1)
newobj
2)
newarr <元素類型>:在堆上創(chuàng)建一個數(shù)組。元素類型在參數(shù)中指定。
3)
box <值類型標記>:裝箱(傳遞數(shù)據(jù))專用指令,在第一部分已經(jīng)介紹過。
? Unity腳本執(zhí)行順序和編譯順序 1)腳本執(zhí)行順序
Unity 在后臺會把每個腳本的 Awake、Start、Update、LateUpdate、FixedUpdate 等等,所有的方法合并到一起。然后按照 代碼的執(zhí)行順序進行執(zhí)行。
編譯順序
? 首先從腳本語言類型來看,Unity3d支持3種腳本語言,都會被編譯成CLI的DLL 如果項目中包含有C#腳本,那么Unity3d會產(chǎn)生以Assembly-CSharp為前綴的工程,名字中包含”vs”的是產(chǎn)生給Vistual Studio使用的,不包含”vs”的是產(chǎn)生給MonoDevelop使用的。
? 對于每一種腳本語言,根據(jù)腳本放置的位置(其實也部分根據(jù)腳本的作用,比如編輯器擴展腳本,就必須放在Editor文件夾下),Unity會生成4中后綴的工程。其中的firstpass表示先編譯,Editor表示放在Editor文件夾下的腳本。
Assembly-CSharp-filepass-vs.csproj Assembly-CSharp-Editor-filepass-vs.csproj Assembly-CSharp-vs.csproj Assembly-CSharp-Editor-vs.csproj 根據(jù)官方的解釋,它們的編譯順序如下:
(1)所有在Standard Assets、Pro Standard Assets或者Plugins文件夾中的腳本會產(chǎn)生一個Assembly-CSharp-filepass-vs.csproj文件,并且先編譯;
(2)所有在Standard Assets/Editor、Pro Standard Assets/Editor或者Plugins/Editor文件夾中的腳本產(chǎn)生Assembly-CSharp-Editor-filepass-vs.csproj工程文件,接著編譯;
(3)所有在Assets/Editor外面的,并且不在(1),(2)中的腳本文件(一般這些腳本就是我們自己寫的非編輯器擴展腳本)會產(chǎn)生Assembly-CSharp-vs.csproj工程文件,被編譯;
(4)所有在Assets/Editor中的腳本產(chǎn)生一個Assembly-CSharp-Editor-vs.csproj工程文件,被編譯。
之所以按照這樣建立工程并按此順序編譯,也是因為DLL間存在的依賴關系所決定的。好了,到此為止,我們可以很容易地判斷出上面舉的實例中,腳本的編譯順序(實際上,我已經(jīng)把順序?qū)懺诹四_本的文件名中了)一個Unity3d的工程中,最多可以產(chǎn)生多少個工程文件呢?
4*3*2=24
4個文件 3中編譯器 2種平臺 1 個工程
? IOS平臺崩潰的幾種情況。
1.在協(xié)程中要判斷對象是不是為空(list GameObject)在每次調(diào)用的時候都學要調(diào)用(因 為協(xié)程不能保證即使調(diào)用如果對象已銷毀但是依然使用時會卡死)。
2. Delegate的判斷(IOS 盡量使Event)
3. 如果引用靜態(tài)的static Compent的組件會出現(xiàn)卡死
4. Unity中的OnEnable Start Awake Disable Destory()都回延遲一幀 5. Unity在Ios對反射的支持不完整。
6. Awake 和Start函數(shù)執(zhí)行時機, Awake 函數(shù)在這個腳本在場景中加載時就會調(diào)用,需要注意的是,Start函數(shù)也不是一定立即執(zhí)行的,它是在該腳本第一次調(diào)用Update函數(shù)之前調(diào)用的,也就是說,如果這個腳本一開始的狀態(tài)是disable的,那么直到它變成enable狀態(tài),在Update函數(shù)第一次執(zhí)行前,才會執(zhí)行Start函數(shù)。
7.Linq TO XML
untiy中配置文件需要注意的點:
pc端不區(qū)分文件大小寫。
Andriod不區(qū)分大小寫
Ios移動端區(qū)分文件大小寫。
需要注意文件名稱大小寫。
? 資源優(yōu)化(內(nèi)存優(yōu)化):
1.代碼中申請的內(nèi)存,一般是New 或者Instantiate操作 Instantiate中也是調(diào)用了New 2.及時設置釋放標識符 變量設置為Null 超出變量作用域 Destory()3.及時Gc釋放內(nèi)存 需要注意
Gc時會造成游戲短時間的卡頓,影響游戲體驗 需要選擇合適的時間Gc 4.盡可能的重用資源(貼圖 材質(zhì) 網(wǎng)格)
5.一般圖片資源占用的內(nèi)存最大,優(yōu)化效果最明顯(降低貼圖分辨率,在效果和大小之間找一個平橫點)
6.程序中的內(nèi)存池 對象池 必要時主動釋放內(nèi)存
7.做AssetBundle資源的關系以來打包 動態(tài)加載
卸載
8.C#中Struct數(shù)據(jù)在棧上 Class在堆上 局部數(shù)據(jù)盡量用Struct 減少Gc的頻率 9.按C++ 的思想來管理內(nèi)存,比如使用的內(nèi)存池,對象池 手工卸載 主動Gc 注意在內(nèi)存和幀率之間做好平衡。
10.www 下載時需要注意變量聲明和要注意申請的內(nèi)存堆上的無用內(nèi)存
11.? Unity資源(加載/更新)
1.Resources
-打包集成到.asset文件里面及引用的資源as后se一個文件里面面可讀不可寫無
-只能用WWW類下載
StreamingAssets文件夾也是一個只讀的文件夾,但是它和Resources有點區(qū)別,Resources文件夾下的資源會進行一次壓縮,而且也會加密,不使用點特殊辦法是拿不到原始資源的。但是StreamingAssets文件夾就不一樣了,它下面的所有資源不會被加密,然后是原封不動的打包到發(fā)布包中,這樣很容易就拿到 里面的文件。所以StreamingAssets適合放一些二進制文件,而Resources更適合放一些GameObject和Object文件。StreamingAssets 只能用過www類來讀取。
最后凡是在Hierarchy視圖對象引用過的資源文件也會被無條件打包到發(fā)布包中。如果有一部分文件可能沒有在Resources文件 夾下也沒有在StreamingAssets文件夾下,也沒有被Hierarchy視圖游戲?qū)ο笠茫敲催@類資源是不會被打包到發(fā)布包中的。
3.PersistentDataPath無
-清除手機緩存文件會一并清理這里的東西
-隨意弄,可作為本地目錄讓WWW下載、也可以自己用FileInfo亂整
4.WWW.LoadFromCacheOrDownload
?
Unity常用目錄對應的Android && iOS平臺地址
IOS:
Application.dataPath : Application/xxxxx/xxx.app/Data Application.streamingAssetsPath : Application/xxxxx/xxx.app/Data/Raw Application.persistentDataPath : Application/xxxxx/Documents Application.temporaryCachePath : Application/xxxxx/Library/Caches
Android:
Application.dataPath : /data/app/xxx.xxx.xxx.apk Application.streamingAssetsPath : jar:file:///data/app/xxx.xxx.xxx.apk/!/assets Application.persistentDataPath : /data/data/xxx.xxx.xxx/files Application.temporaryCachePath : /data/data/xxx.xxx.xxx/cache
? Unity的Android和IOS上相關的目錄結(jié)構(gòu)
Android:
-assets 游戲內(nèi)容相關的都在這里了res 圖標之類的
-AndroidManifest.xml Android配置文件resources.arsc Java編譯后的二進制文件
IOS:
-level0/level1… Scene
-sharedassets0/shaedassets1/… Scene相關的東西resources.assets Resources里面的東西-Raw StreamingAssets里面的東西
第二篇:Hamlet --- The unity of controverasal
Hamlet
---The combination of contradiction
As the saying goes, one thousand readers, there are one thousand Hamlets.Others may think he is a soldier, a hero or a thinker.However, in my mind, he is an immature teen-age youth who is the combination of contradictions.Firstly, as a prince, he is an idealist.He lives a luxurious life and is educated by humanism.Without knowing the dark aspects of the society, he is favored by his parents and respected by his people.We can see in the play that he believes the true, the good and the beautiful and he is a real perfectionist, which can also explain why he is so shocked by the things happen on him and doesn’t know how to deal with it perfectly.Experiencing the death of his father, the usurping the throne of his uncle and the remarriage of his mother, Hamlet’s dream turns into bubbles.He falls in to hell from the heaven and goes on the trip of revenge.The prince has to have common people’s feeling, sadness, hatred, disappointment, hypocrisy and so on.Secondly, he is definitely a great thinker but also an ordinary people who hesitates to practice his thought.He begins consider himself and his people after he listen to his dead Father King’s words.He even says “To be or not to be, this is a question: was bear the slings and arrows of outrageous fortune, or to take arms against a sea of troubles world, through the clearing their struggle, these two kinds of behavior, which is a more noble.” He falls in to deep thought and condemns himself.His father is murdered and the ghost of his father urges him to take the revenge.He doesn’t do anything.He wonders: how a coward or a indecent woman I am.He not only thinks of his own fate, but also considers everyone’s existence.There is no doubt that he is the great man of mind.“Now I clearly have reason, have the determination and have the strength, have a way of can start to do what I have to do, but I still in touted said: 'it needs to do.'But never expressed in action…” is the evidence for his hesitation.When his enemy is praying and he plans to kill him, he should consider that killing a man who is praying will allows him to go to haven, which makes him lose the chance to kill his uncle and commit the tragedy.Thirdly, he believes the true, the good and the beautiful, but he doesn’t believe his friends and his lover.It is his behavior that makes Ophelia dead.He pretends to be mad and kill her father by accident.Ophelia can’t bear the reality and goes to the place where she dates with her prince madly… His ignorance of others’ care and arrogance kill other four innocent people.Last but not least, he is the combination of the goodness and evil.On the one hand, he is pious to his parents, his girlfriend and his friends in a way.He bears the responsibility to take revenge on his uncle and to save the ordinary people.He tries his best to satisfy everyone but he also hurts many people.He takes his revenge on his uncle by hook or by crook.He kills Rosencrantz and Guildenstern.He is cold when he kills Polonius and heartless to Ophelia.Not merely does he lead to his own tragedy, but also leads to the whole play’s tragedy.All in all, the dejected prince wants to take revenge on his uncle, but he can’t find a proper way and his ability is not equal to his ambition.He is an idealist who has to face the cruel reality.As a great think who believes the true, the good and the beautiful, he hesitates to take the action and doubt everyone around him.He is the saver and also the destroyer.He is a giant and also an ordinary people.He is a noble prince and also an immature teen-age youth.
第三篇:unity烘焙光照貼圖
引言: 光影烘焙,英文叫Lightmapping 或 light baking。Unity自帶了Lightmapping的功能(是Illuminate Labs出的名為Beast的產(chǎn)品)。本系列教程分為4講: 第一講 光影烘焙 第二講 AreaLight 第三講 Light Probes 第四講 腳本控制
其中第三第四講講解的是動態(tài)物體與烘焙后場景的融合。
光影烘焙
打開方式 Window – Lightmapping 有幾點需要注意:
1.所要烘焙物體的mesh 必須要有合適的lightmapping uv。如果不確定的話,就在導入模型設置中勾選 Generate Lightmap UVs 2.任何Mesh Renderer, Skinned Mesh Renderer 或者 Terrain都要標注為static(lightmap static)
界面一:Object 點擊Bake Scene即開始烘焙
界面2:Bake 烘焙參數(shù)的設置 Mode:(1)Dual Lightmap mode:近景烘焙圖(near lightmaps)和遠景烘焙圖(far lightmaps)都會被烘焙,只有deferred rendering path支持該模式。
(2)Single Lightmap mode:只有遠景烘焙圖(far lightmaps)會被烘焙,(3)Directional Lightmap mode: Use in forward rendering: 一般可以忽略它。針對Dual lightmaps的設定,只在Mode選的是Dual時才會出現(xiàn)。在forward rendering模式下是否激活dual lightmaps,需要自己寫對應的Shader。Quality:
High low 2個選項。決定采集射線的數(shù)量,對比界限,以及反鋸齒等設置。Bounces:
Global Illumination模擬中 light bounces的數(shù)量。0表示只有直接光照會被計算,如果要加入柔軟的,真實的間接光照的話,則至少填1。Sky Light Color:
模擬從天空從所有方向射來的光照。對室外場景很重要。
(注意:RenderSettings里的Ambient Light也參與烘焙,并且會覆蓋Sky Light。所以使用Sky Light的話,則需要關閉Ambient Light,把Ambient調(diào)成(0,0,0,0)即可)Sky Light Intensity:Sky Light的強度。0表示關閉Sky Light.Bounce Boost:加強Bounced light也就是間接光照的效果.Bounce Intensity:間接光照的效果強度。
Final Gather Rays:從所有收集的點發(fā)射的射線的數(shù)量,最高則效果最好。默認為1000 Contrast Threshold: 越高表示光照越平滑同時細節(jié)越低
Interpolation:顏色計算方式。0表示線性插值,1表示基于梯度的高級插值。有時1會產(chǎn)生人工光照的失真效果。
Interpolation Points:越多表示光照越平滑同時細節(jié)越低。
Ambient Occlusion:環(huán)境閉塞(全局閉塞)在烘焙中的量,和光照無關,僅僅基于距離的效果
Lock Atlas:鎖上了,貼圖就不會變化,沒什么用。Resolution:
通常來說 Resolution設置平均每單位面積對應lightmap的多少色素。該值越高代表單位面積的色素越多即越精細。反之越低越粗糙。默認值為50。如果一個10x10的plane,resolution是50的話,在lightmap里該plane就占用500x500像素尺寸。
當然也可以單調(diào)該數(shù)值。選中物體后,在lightmapping界面中會有Scale in lightmap的數(shù)值,表示的是該物體的烘焙信息在lightmap占的大小,1表示正常尺寸。0表示該物體沒有l(wèi)ightmap效果,但會影響其他物體的lightmap運算。2表示正常尺寸的兩倍大小。Padding:在lightmap里,不同物體的烘焙圖的間距,單位為圖素(texel)
界面3:Maps 烘焙好后的map在這里顯示。Compressed: 是否壓縮lightmap Array Size(0~254)lightmaps array的尺寸
Lightmaps array:即下方的4張貼圖,空格會被視為黑圖,指數(shù)即下方的 0,1對應Mesh Renderer及Terrain里的lightmap index。這個會自動計算。
按下烘焙后,會在右下角有進度條顯示。然后你就可以去喝喝咖啡泡泡妹子神馬的,放心,它烘焙好了會有Import asset提示并自動切回Unity的。烘焙好之后,會產(chǎn)生與場景名稱相同的文件夾,一般來說會有兩張.exr貼圖,LightmapFar-0和LightmapNear-0(僅在Dual模式下有near圖),當物體距離攝像機小于Shadow Distance時,使用的是 實時燈 + LightmapNear-0。當大于是使用的是LightmapFar-0,此時燈光對物體不起作用。
(注意:Shadow Distance的設置
(1)如果是編輯器里運行:Lightmap display設置界面里的Shadow Distance,如下方左圖(2)如果實際運行: Quality設置下的Shadow Distance,如下方右圖
Lightmap Display界面里的其他設置: Use Lightmaps:是否使用lightmaps,不勾選的話就沒有任何烘焙的效果了。
Show Resolution:當勾選Show Resolution時,會有下圖所示類似國際象棋黑白相間的格子,一個格子對應lightmap里所占用的一個texel Show Probes:是否顯示light probes,后面會講到。Show Cells:light probes分割形成的空間的數(shù)量。
當物體烘焙好之后,不管是復制物體還是把物體做成prefab,都會繼承烘焙的效果。但是如果縮放的話,烘焙好的光容易出現(xiàn)問題。
被烘焙的物體并不要求特定的材質(zhì)或者Shader。只要物體的Shader使用的是Surface Shader,那么就可以被烘焙。
注意:一個場景只能烘焙一次,如果多次烘焙,效果是最后一次烘焙的效果。
最后推薦ShadowGun里的烘焙配置,如下圖,供大家參考。烘焙時間很短,效果也很好。極力建議大家搜下ShadowGun的demo來參考學習。里面無論是場景布局,光影分配,Godrays運用,及烘焙等等都是極高的水準。
第四篇:unity開發(fā)游戲的優(yōu)缺點
Unity做游戲的幾個優(yōu)勢:
1、跨平臺,平臺相關的功能Unity都已經(jīng)幫你實現(xiàn)好了。即便有些Unity沒有實現(xiàn),也有插件幫你實現(xiàn)。
2、基于Unity的酷炫的粒子光效編輯。Unity本身就是一個功能強大的粒子編輯器。之前我還認為cocos2d-x的粒子系統(tǒng)的功能足夠了,但是跟專業(yè)的編輯器比起來,遠遠不夠。粒子系統(tǒng)要跟粒子特效編輯器配合起來,其功能遠遠不是之配置一個粒子系統(tǒng)的幾個參數(shù)就可以的。cocos2d-x本身的粒子系統(tǒng)是很雞肋的功能,只能拿來做一些簡單的光效,不可能用來做復雜的技能特效。
3、由于框架和架構(gòu)的優(yōu)勢,Unity的游戲可以極大程度避免崩潰和閃退。由于代碼都是c#寫的,并且是組件結(jié)構(gòu),所以即便出了錯誤也只是個異常而已,而不會影響到系統(tǒng)流程。
4、強大的性能分析工具,可以輕易的找到內(nèi)存和cpu的瓶頸。支持Android和iOS的真機運行分析。
5、編輯器可以方便的進行擴展,不需要像傳統(tǒng)游戲公司一樣,有一個專門寫編輯器的部門。無論是場景編輯器還是技能編輯器都可以輕松搞定。如果想玩高科技的話,還可以把技能編輯器做成可拖拽的模塊化結(jié)構(gòu),策劃可以像搭積木一樣來編輯技能。最重要的是,這些都是所見即所得的。
6、方便的資源管理系統(tǒng)。使用Unity,你不用特意維護幾份資源(比如原始資源、打包后的資源、iOS版本資源、Android版本資源等等),只要一份資源,然后Unity里面可以設置它的具體參數(shù),比如使用紋理壓縮、最大限制在512x512大小等等。Unity發(fā)布游戲的時候會自動根據(jù)平臺相關的導出選項導出正確的資源。
7、豐富的插件。有大量的功能我無論拿cocos2d-x還是Unity都不知道怎么實現(xiàn)。比如一些shader特效、物件碎裂的特效、場景破壞和變形的特效等等,這些在Unity插件中都可以找到對應的實現(xiàn)。而且很多Unity的游戲都可以反編譯,無形中又可以學到很多東西。
8、熟悉之后確實感覺Unity很簡單。很多功能都是成體系的自然而然的。比如物理、碰撞檢測、導航尋路、場景管理、場景烘焙。這些無論拿哪個出來都是相當有技術的功能,但是在Unity中幾個按鈕、幾步操作就可以實現(xiàn)對應的功能。
至于缺點也有一些:
1、最主要的,無論是Unity還是插件都是要收費的。(破解版,等賺錢了再考慮回饋)
2、由于iOS平臺的一些限制,Unity很難做動態(tài)代碼更新。而cocos2d-x有l(wèi)ua這個比較成熟的方案。(如果程序穩(wěn)定了,需要頻繁更新代碼的機會不多,更多的是更新配置和資源)
3、可能有些人不熟悉Unity,從而選擇了開源的cocos2d-x。適應Unity的框架、工作方式需要一定的時間。(相信我,不會很長,要知道一個8歲的孩子都能拿Unity來做游戲,并且上架,如果有程序員說搞不定Unity,那干脆轉(zhuǎn)行賣燒餅吧)
4、對應上面的第6點,由于Unity中資源對應的配置有很大的重要性,所以一個Unity功能就是資源+代碼的整合,你很難分出一個資源包。這樣你的Unity項目可能很大。(使用AssetsBundle打包后可能避免這個問題,但是項目初期資源變動大,經(jīng)常打包很不方便)
5、Unity很多設計都是為可視化編輯考慮的,舉個例子,2D的動畫可以方便的拖幾張圖片就可以搞定。但是如果我每張圖片都有一定的偏移,那就麻煩了,需要自己重新實現(xiàn)幀動畫功能,自己加載配置文件來實現(xiàn)。(這個嚴格說來不是引擎的問題,畢竟引擎不是為了一家游戲公司設計的,大眾化的簡易的操作方式是唯一需要考慮的。但是很多時候確實感覺有些不爽)
第五篇:Unity 3D的學習報告
Unity 3D的學習報告
劉卉
數(shù)媒0902班
0305090205 學習總結(jié):
剛開始這門課程的時候,其實心里是比較恐懼的,因為對Unity 3D這樣的軟件完全沒有認知,對于這門課程的學習也處于比較茫然的狀態(tài),可以說是抱著嘗試的心情開始這門課程的學習的。開始使用軟件的時候,不知道從何下手,于是試著對照書本操作,漸漸地,我發(fā)現(xiàn)其實并沒有我想象中那么困難,一般的操作還是能夠在書本上學到的,可能最終完全掌握會有難度,但是對于目前的要求,還是比較易于實現(xiàn)的。在學習并實踐的過程中,可能在腳本游戲的代碼編寫上還是出現(xiàn)最多問題的,有的時候就是照搬書本上的代碼,也會出錯,不僅僅是粗心,也是我對于代碼并不熟悉導致的,在一遍遍的修改中,我對代碼的編寫也更加熟練,相比較之前的生疏,現(xiàn)在算是比較得心應手了。此外,比較困擾我的就是攝像機位置的各方面調(diào)整,有的時候很難調(diào)整到想要的角度,最后只能將就,這點讓我很是糾結(jié)。對于這種情況,我試著各種方法達到理想效果,如果說我改變不了攝像機,那我只能改變我設置的場景、對象的位置了,雖然這樣的方法比較笨,而且可能會比較繁瑣,但是最終也幫助我實現(xiàn)了想要達到的效果。
也許是為了完成這門課的要求,也許是為了交作業(yè),我最終還是自己嘗試著學習了Unity 3D的操作,可能我所做所學的都是基礎的知識,相對簡單的,但是我還是學到了很多,不能說了解但也是熟悉了這個軟件。可能我做的東西不是很理想的,希望我能在日后的學習實踐中一點一點的去完善。
學習日志:
2012年9月20日
今天在電腦上安裝了Unity3D軟件,安裝的過程有點糾結(jié),但最后還是安裝完成了。翻閱《Unity3D游戲開發(fā)》這本書,了解了第一章基礎知識的內(nèi)容。
2012年9月21日
打開Unity3D軟件,跟著書本試著操作。看書上第二章的內(nèi)容,一步步學習:創(chuàng)建工程——創(chuàng)建材質(zhì)——創(chuàng)建游戲?qū)ο蟆x予材質(zhì)——調(diào)節(jié)攝像機位置,初步創(chuàng)建了“正方體”對象。
2012年9月24日
又到了周一,繼續(xù)學習操作啦。今天學習“移動試圖”,通過創(chuàng)建游戲腳本,做了平移、旋轉(zhuǎn)和縮放的調(diào)整,并且編寫代碼,使對象動起來。使用21號做的正方體,最終實現(xiàn)了移動和旋轉(zhuǎn)的效果。
2012年9月27日
今天我照著書中第二章第7小節(jié)的內(nèi)容,完成第一個游戲?qū)嵗km然最終完成了,但實現(xiàn)的過程并不順利,光攝像機位置的調(diào)節(jié)就花了很長時間,然后每個對象位置的調(diào)整、材質(zhì)的顏色還算順利,最后就是創(chuàng)建腳本游戲的時候,按照書上的編寫代碼,卻總是出錯,最后發(fā)現(xiàn)原來是這些原因:代碼位置寫錯、部分首字母小寫卻被我寫成了大寫、空格多加了。
2012年10月9日
放假歸來以后,開始書本第三章以后內(nèi)容的學習。我按照書本的內(nèi)容先將第三章的每一小節(jié)瀏覽了一遍,了解了大概的內(nèi)容。試著對照書本完成了一個GUI控件的腳本實例,其中包括各個控件的設置,代碼的編寫,中間也出現(xiàn)很多錯誤,最終在同學的幫助下,終于運行成功。
2012年10月10日
今天繼續(xù)第三章的內(nèi)容,學習了游戲界面的布局和貼圖的繪制。試著完成“人物移動”的實例,各種問題逐漸顯露出來:代碼出錯、攝像機位置擺不好、人物移動方式不如我愿,總之是在挫敗中結(jié)束了學習。
2012年10月12日
今天又把上次沒完成的“人物移動”拿出來繼續(xù)修改。我回顧了書本第三章的內(nèi)容,重新創(chuàng)建工程,試著完成各項操作。首先我先再次學習了添加與關閉窗口,又開始了貼圖的學習和繪制動畫。將貼圖以材質(zhì)的形式繪制在游戲?qū)ο笾校以赑roject視圖中需要加載的圖片存儲在根目錄“Resources”中。而動畫則是使用程序?qū)赢嬞Y源存儲在動畫數(shù)組中,然后設定動畫的刷新時間,每次刷新動畫時在原有的顯示區(qū)域繪制下一幀圖片,到了最后一幀則從第一幀重復開始,依此類推。相比較而已,這部分會比較有趣的。
2012年10月13日
終于,今天我實現(xiàn)了“人物移動”這個實例。可能是之前太心急,前面部分知識還沒學習,就直接做實例,通過昨天的學習,再加上今天的努力,前天的難題都不再是難題,很快,我就做好了。
2012年10月18日
偷懶了很多天,今天我開始第四章的學習。這次我沒有急著做案例,我認真的研究了書本。
2012年10月22日
學習了第五章的理論知識。知道了地形的參數(shù)包括地形的寬度、高度、長度、分辨率和高度圖等。總之,今天學習了創(chuàng)建地形,地形參數(shù),編輯地形和地形貼圖的內(nèi)容。
2012年10月23日
學習了書中實例“攝像機切換鏡頭”。
2012年10月29日
今天學習了第7章的輸入與控制的鍵盤事件。通過鍵盤的按下事件、抬起事件、任意鍵事件和組合鍵事件等實現(xiàn)交互這樣的功能。這部分的內(nèi)容可能實踐更重要,今天先進行理論知識的學習,明天試著操作一下。除此之外,還學習了鼠標事件、自定義按鍵事件、模型與動畫和GL圖像庫的一部分內(nèi)容。鼠標事件就是鼠標按下事件、抬起事件、長按事件。自定義按鍵是在輸入管理器中配置,自定義按鍵可以設置軸向,按鍵軸的數(shù)值默認為0。另外,我嘗試模型的載入、設置3D動畫和播放動畫等內(nèi)容,可以說忙的不亦樂乎。
2012年10月30日
將昨天所學操作了一下。
2012年11月02日
試著做“運動員踢足球”小游戲,包括場景的構(gòu)建、人物的構(gòu)建和移動、球的移動等等。首先我參考書中第五章內(nèi)容創(chuàng)建地形,添加地形元素,添加天空,導入了3D人物模型,以及創(chuàng)建了一個球形對象。將人物運動控制腳本綁定人物模型,球體運動腳本綁定球。
2012年11月05日
今天將書上8、9、10章沒有閱讀過的部分看了一遍,了解了一些操作的大概原理,試著學習書上的案例操作部分內(nèi)容,完善所學知識。