第一篇:unity開發游戲的優缺點
Unity做游戲的幾個優勢:
1、跨平臺,平臺相關的功能Unity都已經幫你實現好了。即便有些Unity沒有實現,也有插件幫你實現。
2、基于Unity的酷炫的粒子光效編輯。Unity本身就是一個功能強大的粒子編輯器。之前我還認為cocos2d-x的粒子系統的功能足夠了,但是跟專業的編輯器比起來,遠遠不夠。粒子系統要跟粒子特效編輯器配合起來,其功能遠遠不是之配置一個粒子系統的幾個參數就可以的。cocos2d-x本身的粒子系統是很雞肋的功能,只能拿來做一些簡單的光效,不可能用來做復雜的技能特效。
3、由于框架和架構的優勢,Unity的游戲可以極大程度避免崩潰和閃退。由于代碼都是c#寫的,并且是組件結構,所以即便出了錯誤也只是個異常而已,而不會影響到系統流程。
4、強大的性能分析工具,可以輕易的找到內存和cpu的瓶頸。支持Android和iOS的真機運行分析。
5、編輯器可以方便的進行擴展,不需要像傳統游戲公司一樣,有一個專門寫編輯器的部門。無論是場景編輯器還是技能編輯器都可以輕松搞定。如果想玩高科技的話,還可以把技能編輯器做成可拖拽的模塊化結構,策劃可以像搭積木一樣來編輯技能。最重要的是,這些都是所見即所得的。
6、方便的資源管理系統。使用Unity,你不用特意維護幾份資源(比如原始資源、打包后的資源、iOS版本資源、Android版本資源等等),只要一份資源,然后Unity里面可以設置它的具體參數,比如使用紋理壓縮、最大限制在512x512大小等等。Unity發布游戲的時候會自動根據平臺相關的導出選項導出正確的資源。
7、豐富的插件。有大量的功能我無論拿cocos2d-x還是Unity都不知道怎么實現。比如一些shader特效、物件碎裂的特效、場景破壞和變形的特效等等,這些在Unity插件中都可以找到對應的實現。而且很多Unity的游戲都可以反編譯,無形中又可以學到很多東西。
8、熟悉之后確實感覺Unity很簡單。很多功能都是成體系的自然而然的。比如物理、碰撞檢測、導航尋路、場景管理、場景烘焙。這些無論拿哪個出來都是相當有技術的功能,但是在Unity中幾個按鈕、幾步操作就可以實現對應的功能。
至于缺點也有一些:
1、最主要的,無論是Unity還是插件都是要收費的。(破解版,等賺錢了再考慮回饋)
2、由于iOS平臺的一些限制,Unity很難做動態代碼更新。而cocos2d-x有lua這個比較成熟的方案。(如果程序穩定了,需要頻繁更新代碼的機會不多,更多的是更新配置和資源)
3、可能有些人不熟悉Unity,從而選擇了開源的cocos2d-x。適應Unity的框架、工作方式需要一定的時間。(相信我,不會很長,要知道一個8歲的孩子都能拿Unity來做游戲,并且上架,如果有程序員說搞不定Unity,那干脆轉行賣燒餅吧)
4、對應上面的第6點,由于Unity中資源對應的配置有很大的重要性,所以一個Unity功能就是資源+代碼的整合,你很難分出一個資源包。這樣你的Unity項目可能很大。(使用AssetsBundle打包后可能避免這個問題,但是項目初期資源變動大,經常打包很不方便)
5、Unity很多設計都是為可視化編輯考慮的,舉個例子,2D的動畫可以方便的拖幾張圖片就可以搞定。但是如果我每張圖片都有一定的偏移,那就麻煩了,需要自己重新實現幀動畫功能,自己加載配置文件來實現。(這個嚴格說來不是引擎的問題,畢竟引擎不是為了一家游戲公司設計的,大眾化的簡易的操作方式是唯一需要考慮的。但是很多時候確實感覺有些不爽)
第二篇:IT部開發優缺點分析
IT部內部開發的優缺點對比
優點:
1內部溝通;內部員工溝通比較方便,順暢;
2熟悉公司業務情況;內部開發IT部開發人員較為熟悉公司業務情況,能夠減少調研時間;
3持續優化方便;知根知底的工作,如果業務或者管理模式發生變化,那么公司可以較好的應對這些變化;
4核心數據和架構不受牽制于其他企業,易整合;
缺點:
1IT部開發人員較少,項目任務較多;開發進度較為緩慢,影響進度;
2缺少制度化管理;內部做需求管理,由于沒有設計到精確的成本計算,所以用戶會輕易不停的修改需求,產生無數變更,這明顯會使項目周期延長;
3工作繁忙,技能培訓較少:IT部工作量大,內部人員經常加班,較少時間能進行技能培訓,接觸到更先進的技術方便用到工作之中;
4內部結算較為麻煩;流程較多,沒有外部結算方便;
第三篇:Unity之工作總結
圖片格式
----------1 DrawCall
-----------2
? 圖片格式:
NGUI生成的圖集的圖片格式是PNG格式,但是無論是什么格式的圖片 Unity都會自己生成一套格式,并且打包的時候不會用文件夾下面的格式,而是Unity自己格式。
如果你用的UITexture 你可以對每一張圖來修改格式,比如顏色數比較少的圖片可以使用16bit,如果沒有透明,可以使用pvr或者etc 這樣圖片會小很多。如果是UISprite 只要有透明的 就必須使用RGBA32 要不然UI會很難看。
除去 UITextuer和Atlas的圖片之外(因為有透明),其余的貼圖必須是2的冪次方。因為只有2的冪次方圖片,并且沒有透明通道的才會被壓縮。Ios會被壓縮成pvr格式,Andriod會壓縮成etc格式。壓縮之后會小很多。
人物貼圖 場景題圖 特效貼圖 一定要是2的冪次方。
貼圖透明通道分離,壓縮格式設為ETC/PVRTC 最初我們使用了DXT5作為貼圖壓縮格式,希望能減小貼圖的內存占用,但很快發現移動平臺的顯卡是不支持硬件解壓DXT5的。因此對于一張1024x1024大小的RGBA32貼圖,雖然DXT5可將它從4MB壓縮到1MB,但系統將它送進顯卡之前,會先用CPU在內存里將它解壓成4MB的RGBA32格式(軟件解壓),然后再將這4MB送進顯存。于是在這段時間里,這張貼圖就占用了5MB內存和4MB顯存;而移動平臺往往沒有獨立顯存,需要從內存里摳一塊作為顯存,于是原以為只占1MB內存的貼圖實際卻占了9MB!
所有不支持硬件壓縮格式都有相同的問題。解決方案:
現在Andriod硬件最廣泛支持的時Etc ,IOS上支持的時PVRTC。但這兩種格式都是不帶透明(Alpha)通道的,因此我們需要將每張原始貼圖的透明通道分離出來,寫進另一張貼圖的紅色通道里,這兩張特圖都采用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)。它們渲染時的內存占用則是2x0.5+2x0.5=2MB。
? DrawCall 當兩個renderQueue相鄰的DrawCall使用了相同的貼圖、材質和shader實例時,這兩個DrawCall就可以合并。但需要注意的是DrawCall合并不見得會提高性能,有時反而會降低性能
如果是UIGeometry為了渲染繪制準備數據,那么UIDrawCall其實是定義了渲染繪制需要的基本組件。這里拿煮菜做個比喻幫助理 解:UIGeometry好比為煮菜準備食材,UIDrawCall好比是煮菜的工具(鍋,爐子等),UIPanel就是大廚了決定著什么時候該煮 菜,UIWidget(UILabel,UISprite和UITexture)是這道菜怎么樣的最終呈現。
UIWidget分別用UpdateGeometry和WriteToBuffers對UIGeometry的ApplyTransform和 WriteToBuffers進行封裝調用,ApplyTransform是根據UIPanel的坐標調整Vertices的坐 標,WriteToBuffers將UIGeometry的Vertices,UVs和Colors添加進UIPanel的Vertices,UVs和 Colors的BetterList中。
這里還有一個細節就是:UIGeometry中的Vertices,UVs和Colors的BetterList的buffer什么時候得到,因為這些都 是UIWidget或其子類的信息,所以在UIWidget的子類UILabel,UISprite和UITexture中OnFill函數生成 UIGeometry的BetterList的buffer。
UIWidget這個腳本中的兩個函數:WriteToBuffers,OnFill,UpdateGeometry。
WriteToBuffers和OnFill這兩個函數都是將Vertices,UVs和Colors等add進參數的List中去,查看 WriteToBuffers的調用出發現其參數是UIPanel的Vertices,UVs和Colors,而OnFill的參數是 UIGeometry的Vertices,UVs和Colors。
WriteToBuffers只是對UIGeometry的封裝調用,也就是說將UIGeometry的Vertices,UVs和Colors等信息add進UIPanel的對應List中。
UIGeometry的腳本,一直有一個疑問:UIGeometry的Vertices,UVs和Colors的List沒有看到add方法的執行,只有在WriteToBuffers被add。直到看到了OnFill才恍然大悟,雖然UIWidget的OnFill是虛函數,沒有具體實現,看了下 UISprite重寫的OnFill函數,就是把Vertices,UVs和Colors 添加到UIGeometry的Vertices,UVs和Colors中。所有UI組件的Vertices,UVs和Colors都匯集到UIPanel的Vertices,UVs和Colors去了,然后 UIPanel指定給UIDrawCall渲染就行了
UIWidget的一些實現細節,MakePixelPerfect():對gameObject的localPosition和locaScale進行微調和糾正。SetDirty():調用UIPanel的SetDirty()對組件的變更進行重建(rebuilt)。Uiwidge UIGeometry& UIDrawCall 的關系:
UIWidget 中有兩個變量UiDrawCall mDrawcall 和UIGeometry mGeo 的verts uvs cols 的BetterList,然后UiWidget 的UpdateGeometry函數對UIGeometry 的ApplyTransform()和WriteToBuffer()調用進行更新.每一個UIwidget都有一個UIGeometry 但是不都有一個UIDrawCall,而是通過Batch合并達到減少DrawCall的數量,UiDrawCall是有UiPanel生成的。
DrawCall的數量優化
根據上述描述可以得出一個結論:使用相同material的連續的Uiwidget(UILable UiSprite)公用一個UIDrawcall。通過這個結論我們可以得到一個解決DrawCall過多的問題,UIPanel生成DrawCall時是Fill()方法。Fill 方法對UiWidget.list進行檢測把使用相同Material的連續的Uiwidget合并生成一個DrawCall ,UIWidget.List 的排序是根據UiWidget的Depth進行的。所以解決方案有兩種:
1.修改UiWidget(UiLable UIwidget)的Depth,限定UIwidget.List的排序 2.重寫Uiwidget的CompareFunc()方法。(重寫UIWidget的CompareFunc也是可以的,按照Material的name優先排序,只有當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越大,越靠前)。當然現在只有增加一 個DrawCall(如多使用一個UIPanel或用另外一個Material)來做到Material的夾層效果。
特效層級:
粒子系統的渲染順序列默認為3000 而NGUI的渲染順序默認是從3000開始,當有嵌套的Panel或者Deoth更高的panel時,NGUI的渲染順序會高于3000
解決方案:
1.修改Ngui中的panel腳本中的默認RenderQueue 調整到3000以下,這樣就不會擋住粒子特效。當窗口顯示在特效上面時把窗口的RenderQueue調整到3000以上,就解決了。
2.使用另外一個攝像機顯示特效,但是Ui窗口切換時不太好控制
3.修改例子特效的shader中的RenderQueue的值(需要考慮特效中的層級關系)一級界面 二級界面..浮動窗口
1.不同圖集
項目中做到復雜一些的界面,經常會用到多個圖集,以技能界面為例,項目中常用的圖片放到共用圖集中,這是一個圖集,技能界面本身獨有的元素,比如跟技能職業相關的背景,算作第二個圖集,還有一些技能圖標,圖標單獨歸類到一個圖集中,再一個就是字體的圖集。基本一個界面如此分法,最多需要4個圖集。NGUI的圖集之間的 處理,默認是靠調整控件的Z值來區分的,但是這里他可以調整同一個圖集每個一個控件的Z值,其實不是很好。經常會出現圖層相互遮擋的情況,尤其對于控件比較多的界面,一段時間回過來再修改界面的時候,整個要崩潰。
解決方案:在UIPanel中,為每一個Material添加一個layer的變量,當同一圖層靠depth來決定前后關系,不同圖層靠 layer來決定前后關系,在繪制UIDrawCall的時候,根據layer對跟節點做一定偏移。這樣就能從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為參考,屏幕分辨率的高度值不同于此設置值時,則根據其比例(即Screen Height / Manual Height)對整棵UI樹的進行“等比”縮放(寬度的縮放比也是此比例值)。
注釋:如果設置FixedSize,UIWidget.height(以UiRoot默認值進行高度縮放)是不會改變的,不管實際屏幕分辨率的像素是多少,Anchor Stretch的背景圖片高度始終是manualHeight.UIRoot下的UIWidget的height參數一直都是實際的值
UIRoot 是基于高度進行縮放的如何做以寬度適配。
UIRoot是基于高度放縮的,即放縮的比例是以高度為參考的,所以UIRoot有一個manualHeight的參數。那么對于橫版游戲顯然不行,要是 能實現基于寬度放縮。所以可以通過設置一個“manualWidth”的參數來做。比如我們項目中使用的是 1024 作為UI的寬屏尺寸,通過換算設置manualHeight的值:
int height = Mathf.Max(2, Screen.height);manualHeight = Screen.height * 1024 / Screen.width;//基于寬度的屏幕分辨率自適應
注釋:UIRoot其實就做了一件事情:根據Screen.height和UIRoot.activeHeight的比例來調整UIRoot的 loaclScal,從而保證UIWidget(UISprite,UILabel)可以按照其本身的大小進行設置,而不用經過復雜的換算過程。
? 資源分離打包與加載
資源分離打包與加載是最有效的減小安裝包體積與運行時內存占用的手段。一般打包粒度越細,這兩個指標就越小。但打包粒度也并不是越細就越好。如果運行時要同時加載大量小bundle,那么加載速度將會非常慢——時間都浪費在協程之間的調度和多批次的小I/O上了。此需要有策略地控制打包粒度。一般只分離字體和貼圖這種體積較大的公用資源。
? 關閉貼圖的讀寫選項
Unity中導入的每張貼圖都有一個啟用可讀可寫(Read/Write Enable)的開關,對應的參數是TextureImporter.isReadable。選中貼圖后可在Import Setting選項卡中看到這個開關。只有打開這個開關才可以對貼圖使用Textuer2D.GetPixel,讀取或改寫貼圖資源的像素,但這就需要系統在內存中保留一份貼圖的拷貝,以供Cpu訪問,但是一般游戲運行過程中不會有這樣的需求,因此我們對所有貼圖都關閉這個開關,只在中做貼圖導入后處理(比如對原始提貼圖分離透明通道)時需要打開這個選項。這樣,上文提到的1024x1024大小的貼圖,其運行時的2MB內存占用又可以少一半,減小到1MB。Texture圖片空間和內存占用分析
紋理大小影響:
可以將其他(非二的冪-“NPOT”)紋理大小用于 Unity非二的冪紋理大小通常占用的內存稍多一點,由 GPU 進行讀取的速度可能較慢,因此考慮到性能,最好盡可能使用二的冪大小。如果平臺或 GPU 不支持 NPOT 紋理大小,則 Unity 會縮放紋理并將其填補為下一個二的冪大小,這甚至會使用更多內存并使加載更慢
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次方大小的圖片會得到引擎更大的支持,包括壓縮比率,內存消耗 打包壓縮大小,而且支持的力度非常大。
2.減小圖片的占用大小和內存方式有:圖片大小變化(Maxsize),色彩位數變化(16位色 32位色),壓縮PVRC格式
3.U3D對于圖片的格式是自己生成的,而并不是你給它什么它用什么格式。一張1024*1024圖在無壓縮的格式下,他會被U3D無壓縮文件像是存放,也就是說U3D 里的Texture Perview 里顯示的占用大小**M 不只是內存占用的大小,還是空間占用大小。
Unity 圖片壓縮格式介紹:
U3D 的內部機制為自動生成圖片類型來替代我們的圖片在圖片的壓縮方式需要進行謹慎的選擇。幾種比較主要的壓縮格式:
RGBA32 BIT/AutomaticTurecolor(256*256 256k)
格式為無壓縮最保真格式,最消耗內存和空間的格式。RGBA16 BIT/
格式為無壓縮16位格式,比32位節省一半的空間和內存,與Automatic16 相同。RGBA Compressed PVRTC 4bits格式為PVRTC 圖片格式,它相當于把圖片更改了壓縮方式新生成了一個圖片來替換原來的圖片格式
貼圖格式:
3D游戲中貼圖的的分類:
UI貼圖
ui是按照 1280*853比例出的圖
3D場景貼圖 主要是因為多重采樣的緣故。3D游戲一般來說都是受攝像機遠近大小改變而采取不同的采樣大小,如果不設置多重采樣的話,在遠處有非常多的白色噪點。
2D游戲
所有都不需要勾選多重采樣,具有3D性質的貼圖,我們都需要勾選上GENERATE MIP MAPS,這樣會使貼圖大小增加25%這樣。
正方貼圖與非正方貼圖也要區分: 非正方貼圖只有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的貼圖來實現透明效果。
非正方形:
一般采用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所有圖片的壓縮格式都會以另一種方式存儲,不會以你給的方式存儲,只有你指定了某種格式,他才會轉換成你要的格式。而且在Andriod 里的并不一定有效,因為Andriod的機型多,GPU的渲染方式也不一樣,RGBA16 適應于所有機型
? GameObject數量
場景中GameObject的數量也是衡量性能的重要指標,頻繁的創建 和銷毀GameObjec 是非常耗時,場景中存在的GameObject會占用內存,如果GameObject上掛有物體的話,每個GameOject的腳本都需要實力化。
? 整理圖集
整理圖集的主要目的是節省運行時內存(雖然有時也能起到合并DrawCall的作用)。從這個角度講,顯示一個界面時送進顯存的圖集尺寸之和是越小越好。一般有如下方法可以幫助我們做到這點: 1)在界面設計上,盡量讓美術控件設計成九宮格拉伸,即UiSprite的類型是Sliced.這樣美術素材可以切出一張很小的圖片在unity中做拉伸。當然一個九宮格也就意味著其定點數量會從4個增加到16個(如果九宮格的中心格子采用Tiled做平鋪類型的話,定點數會更多),構建DrawCall的開銷會更大。但一般只要DrawCall安排合理就不會出問題 2)同樣在界面設計上 盡量設計成對稱的形式,這樣在切圖的時候美術切圖的時候就可以只切一部分,我們在Untiy中將完整的圖案拼出來,比如一個圓形圖案我們可以只切四分之一,不過與上述第一點類似這樣會增加定點個數,同時也會增加場景中GameObject的個數,因為GameObject的數量增多時會占用跟多的內存,所以只對尺寸較大的圖案采用這種方法。3)4)確保不要讓不必要的貼圖素材駐留內存,更不要在渲染時將無關的貼圖素材送進顯存。為此需要將圖集按照界面分開,按模塊劃分圖集,一個界面中的UISprite也不要使用別的界面的圖集。數量龐大 且數量不固定的物品不要使用圖集 要采用UITexture 減少圖集中的空白地方。完全透明的像素和不透明的像素所占用的空間是一樣的,因此在像素量不變的情況下,要盡量減少圖集中的空白。比如有時一張1024x1024的圖集中,素材所占的面積還沒超過一半,這時可以考慮將這張圖集切成兩張512x512的圖集。(可能有人會問為什么不能做成一張1024x512的圖集,這是因為iOS平臺似乎要求送進顯存的貼圖一定是方形。)當然,兩張不同圖集的DrawCall是無法合并的,但這并不是什么問題。5)
? 根據各個UI控件的設計安放Panle,隔開DrawCall 在合并DrawCall時需要注意,如果將會移動變化的UI控件和一個靜止不變的UI控件的DrawCall合在一起,當其中一個UI控件(UiWeight)的位置 大小 或顏色等屬性發生變化時,UIPanle就需要重建這個Panle上的所有DrawCall。有時重建一個DrawCall會消耗不少的CPU,它需要計算這個DrawCall上的所有頂點信息,包括頂點位置 UV和顏色等,如果很多的控件都集中在同一個DrawCall上,那么其中一個控件上有一點點變化,這個DrawCall上的所有的頂點就都需要遍歷一遍。而如果我們的UI又大量的采用九宮格拉伸,使控件的頂點數量就會變得更多。因此重建一個DrawCall 的開銷會更大。
因此需要將UI控件分組,將一段時間內會發生變化的控件----比如怪物頭頂的血條和傷害跳字放在同一個Panle上,并且這些Panle上只有這些控件,其余基本不變的控件放在別的控件Panle上,這樣兩類控件就隔開到不同的DrawCall在不同的Panle中,當一個控件發生變化而導致DrawCall重建時,就不需要遍歷那些沒有變化的控件。因為在美術設計上,一段時間內在變化的控件總是少數,所以優化效果十分明顯,節省的CPU占用率能達到25%。
?
優化錨點內部邏輯,使其只在必要時更新
在上一點優化了Panel的DrawCall重建效率之后,我們發現NGUI錨點自身的更新邏輯也會消耗不少CPU開銷。即使是在控件靜止不動的情況下,控件的錨點也會每幀更新(見UIWidget.OnUpdate函數),而且它的更新是遞歸式的,使CPU占用率更高。因此我們修改了NGUI的內部代碼,使錨點只在必要時更新。一般只在控件初始化和屏幕大小發生變化時更新即可。不過這個優化的代價是控件的頂點位置發生變化的時候(比如控件在運動,或控件大小改變等),上層邏輯需要自己負責更新錨點。
?
降低貼圖分辨率
這一招說白了其實就是減小貼圖素材的尺寸。比如對一張在原畫里尺寸是100x80的貼圖,我們將它導入Unity后會把它縮小到50x40,即縮小兩倍。游戲實際使用的是縮小后的貼圖。不過這一招是必然會顯著降低美術品質的,美術立馬會發現畫面變得更模糊,因此一般不到程序撐不住的時候不會采用。
? 界面的延遲加載和定時卸載
如果一些界面的重要性較低,并且不常被使用,可以等到界面需要打開顯示的時候才從bundle加載資源,并且在關閉時將自己卸載出內存,或者等過一段時間再卸載。不過這個方法有兩個代價:一是會影響體驗,玩家要求打開界面時,界面的顯示會有延遲;二是更容易出bug,上層寫邏輯時要考慮異步情況,當程序員要訪問一個界面時,這個界面未必會在內存里。因此目前為止我們仍未實施該方案。目前只是進入一個新場景時,卸載上一個場景用到但新場景不會用到的界面。
? 避免頻繁調用GameObject.SetActive 我們游戲的某些邏輯會在一幀內頻繁調用GameObject.SetActive,顯示或隱藏一些對象,數量達到一百多次之多。這類操作的CPU開銷很大(尤其是NGUI的UIWidget在激活的時候會做很多初始化工作),而且會觸發大量GC。后來我們改變了顯示和隱藏對象的方法——讓對象一直保持激活狀態(activeInHierarchy為true),而原來的SetActive(false)改為將對象移到屏幕外,SetActive(true)改為將對象移回屏幕內。這樣性能就好多了。
?
NGUI性能消耗點匯總
使用LinkedList
BetterList是一個數組 LinkedList
NGUI節點查找非常耗時。
?
代碼中非必要的堆分配
1)
我們應避免使用foreach循環 :一般建議是避免使用foreach循環,盡量使用for或者while循環,我在Unity論壇遇到很多人提到這個建議。這背后的原因咋一看似乎是合理的,foreach只是語法封裝,因為編譯器處理代碼的流程大體是下面這樣:
foreach(SomeType s in someList)s.DoSomething();轉換為:
using(SomeType.Enumerator enumerator = this.someList.GetEnumerator()){
while(enumerator.MoveNext()){
SomeType s =(SomeType)enumerator.Current;s.DoSomething();} } 每次使用foreach時 都會創建一個enumerator 對象,一個System.Collections.IEnumerator的接口實例。但是創建在堆棧上還是堆上是都可能的 幾乎所有的System.Collections.Genric(list
2)應該避免使用閉包和LINQ嗎?
匿名方法和lambda表達式會引起內存泄露嗎?答案是:這取決于C#編譯器,有兩種區別很大的方式來處理
int result = 0;void Update(){
for(int i = 0;i < 100;i++){
System.Func
現在我們在托管定義方式上做一些小小的改變:
System.Func
通過把“p”替換為“i++”,我們已經局部定義方法轉變成一個真的閉包(閉包是函數編程的一大支柱。它把數據和函數聯系到一起,更準確的說是非局部變量在函數之外定義。)在myFunc中,p是一個局部變量但i是一個非局部變量,屬于Update()方法。C#編譯器現在不得不將myFunc轉換成可訪問、甚至是可修改,包含非局部變量的方法。它通過聲明一個全新的類表示myFunc創建的引用來實現這一功能。For循環每次執行都要分配一個類的實例,瞬間產生大量的內存泄露(在我的電腦上每幀26KB)閉包概念在C#3.0 的時候被引入主要原因是LINQ。如果閉包回引起內存泄露
3)協程
通過StartCoroutine()運行一個協程,會隱式分配Unity Coroutine類(系統上占用21字節)和Enumerator(占用16個字節),所以在游戲運行時盡量少用StartCoroutine()
4)字符串
C#和Unity內存問題必須會提到字符串。從內存角度,字符串很奇怪,因為,他們是堆分配且不變的。當你連接兩個字符串時(無論是變量還是常量):運行時不得不分配至少一個新的字符串對象存儲新的結果。String.Concat()有效地通過調用FastAllocateString()分配新對象,但是必定會產生多余的堆分配(上面例子在我的系統上占用40字節)。如果你需要在運行時修改或者連接字符串,最好使用 System.Text.StringBuilder
5)裝箱
盡量減少裝箱
6)庫方法
各種庫方法也會隱式分配內存。捕捉它們最好的方法是分析。我之前已經寫過的 foreach-循環,大多數標準泛型集合不會導致堆分配。Dictionary
? 查找堆分配的兩種方式 1.使用Unity profiler 2.反編譯自己的代碼
在CIL中查找內存分配
CIL代碼的優勢在于堆分配代碼不會被隱藏。相反,完全可以在反編譯的代碼中找到堆分配的三種指令。
1)
newobj
2)
newarr <元素類型>:在堆上創建一個數組。元素類型在參數中指定。
3)
box <值類型標記>:裝箱(傳遞數據)專用指令,在第一部分已經介紹過。
? Unity腳本執行順序和編譯順序 1)腳本執行順序
Unity 在后臺會把每個腳本的 Awake、Start、Update、LateUpdate、FixedUpdate 等等,所有的方法合并到一起。然后按照 代碼的執行順序進行執行。
編譯順序
? 首先從腳本語言類型來看,Unity3d支持3種腳本語言,都會被編譯成CLI的DLL 如果項目中包含有C#腳本,那么Unity3d會產生以Assembly-CSharp為前綴的工程,名字中包含”vs”的是產生給Vistual Studio使用的,不包含”vs”的是產生給MonoDevelop使用的。
? 對于每一種腳本語言,根據腳本放置的位置(其實也部分根據腳本的作用,比如編輯器擴展腳本,就必須放在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 根據官方的解釋,它們的編譯順序如下:
(1)所有在Standard Assets、Pro Standard Assets或者Plugins文件夾中的腳本會產生一個Assembly-CSharp-filepass-vs.csproj文件,并且先編譯;
(2)所有在Standard Assets/Editor、Pro Standard Assets/Editor或者Plugins/Editor文件夾中的腳本產生Assembly-CSharp-Editor-filepass-vs.csproj工程文件,接著編譯;
(3)所有在Assets/Editor外面的,并且不在(1),(2)中的腳本文件(一般這些腳本就是我們自己寫的非編輯器擴展腳本)會產生Assembly-CSharp-vs.csproj工程文件,被編譯;
(4)所有在Assets/Editor中的腳本產生一個Assembly-CSharp-Editor-vs.csproj工程文件,被編譯。
之所以按照這樣建立工程并按此順序編譯,也是因為DLL間存在的依賴關系所決定的。好了,到此為止,我們可以很容易地判斷出上面舉的實例中,腳本的編譯順序(實際上,我已經把順序寫在了腳本的文件名中了)一個Unity3d的工程中,最多可以產生多少個工程文件呢?
4*3*2=24
4個文件 3中編譯器 2種平臺 1 個工程
? IOS平臺崩潰的幾種情況。
1.在協程中要判斷對象是不是為空(list GameObject)在每次調用的時候都學要調用(因 為協程不能保證即使調用如果對象已銷毀但是依然使用時會卡死)。
2. Delegate的判斷(IOS 盡量使Event)
3. 如果引用靜態的static Compent的組件會出現卡死
4. Unity中的OnEnable Start Awake Disable Destory()都回延遲一幀 5. Unity在Ios對反射的支持不完整。
6. Awake 和Start函數執行時機, Awake 函數在這個腳本在場景中加載時就會調用,需要注意的是,Start函數也不是一定立即執行的,它是在該腳本第一次調用Update函數之前調用的,也就是說,如果這個腳本一開始的狀態是disable的,那么直到它變成enable狀態,在Update函數第一次執行前,才會執行Start函數。
7.Linq TO XML
untiy中配置文件需要注意的點:
pc端不區分文件大小寫。
Andriod不區分大小寫
Ios移動端區分文件大小寫。
需要注意文件名稱大小寫。
? 資源優化(內存優化):
1.代碼中申請的內存,一般是New 或者Instantiate操作 Instantiate中也是調用了New 2.及時設置釋放標識符 變量設置為Null 超出變量作用域 Destory()3.及時Gc釋放內存 需要注意
Gc時會造成游戲短時間的卡頓,影響游戲體驗 需要選擇合適的時間Gc 4.盡可能的重用資源(貼圖 材質 網格)
5.一般圖片資源占用的內存最大,優化效果最明顯(降低貼圖分辨率,在效果和大小之間找一個平橫點)
6.程序中的內存池 對象池 必要時主動釋放內存
7.做AssetBundle資源的關系以來打包 動態加載
卸載
8.C#中Struct數據在棧上 Class在堆上 局部數據盡量用Struct 減少Gc的頻率 9.按C++ 的思想來管理內存,比如使用的內存池,對象池 手工卸載 主動Gc 注意在內存和幀率之間做好平衡。
10.www 下載時需要注意變量聲明和要注意申請的內存堆上的無用內存
11.? Unity資源(加載/更新)
1.Resources
-打包集成到.asset文件里面及引用的資源as后se一個文件里面面可讀不可寫無
-只能用WWW類下載
StreamingAssets文件夾也是一個只讀的文件夾,但是它和Resources有點區別,Resources文件夾下的資源會進行一次壓縮,而且也會加密,不使用點特殊辦法是拿不到原始資源的。但是StreamingAssets文件夾就不一樣了,它下面的所有資源不會被加密,然后是原封不動的打包到發布包中,這樣很容易就拿到 里面的文件。所以StreamingAssets適合放一些二進制文件,而Resources更適合放一些GameObject和Object文件。StreamingAssets 只能用過www類來讀取。
最后凡是在Hierarchy視圖對象引用過的資源文件也會被無條件打包到發布包中。如果有一部分文件可能沒有在Resources文件 夾下也沒有在StreamingAssets文件夾下,也沒有被Hierarchy視圖游戲對象引用,那么這類資源是不會被打包到發布包中的。
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上相關的目錄結構
Android:
-assets 游戲內容相關的都在這里了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.
第五篇:管理信息系統五種開發方法優缺點評析
管理信息系統的五種常見開發方法及其優缺點闡述
1.把系統的建立看作是一種生命物種的成長過程。由6個開發階段組成:系統定義-> 需求分析-> 系統設計-> 編寫代碼-> 安裝調試-> 系統維護 優點:
這種開發方法把管理信息系統開發的全過程按其生存周期分成若干階段,每個階段有相對獨立的任務,然后逐步完成各個階段的任務。在每一階段的開始與結束都規定了嚴格的標準。前一個階段的結束標準就是后—階段開始的標準,而每個階段任務相對獨立而且比較簡單,便于不同人員分工協作,從而降低了整個軟件工程開發的困難程度。在軟件生命周期的每個階段都采用科學管理和良好的技術方法,而且在每個階段結束之前都從技術與管理兩個角度進行嚴格審查,合格之后才開始下一階段工作。這就使得軟件開發全過程以一種有條不紊的方式進行,保證了軟件質量,提高了軟件的可維護性。這樣不僅可以大大提高軟件開發的成功率,軟件開發的生產率也會明顯地提高。且簡單明了,結構清晰。
同時把文檔資料作為每個階段的產品之一,而且加以標準化,作為每個階段結束的重要標準。它保證了在系統開發結束時有一個完整準確的軟件配置交付使用。文檔資料是通訊的工具,它清楚地說明了到這個時候為止關于該項工程已經知道或做了什么,同時確定了下一步的工作基礎。文檔資料也起著備忘錄的作用,如果文檔不完整或與上一階段的文檔不相銜接則一定在工作上有不完整的地方。文檔資料另一重要作用是有利于與用戶交流,檢查錯誤,用戶評價。文檔資料也是系統維護的依據,通過每一階段生成的文檔資料,使得開發人員和用戶易于使用維護。不足:
這種開發方法的不足具體表現在以下幾方面
第一,階段回溯不可避免,延長系統開發的時間。結構化生命周期法并沒有解決軟件開發研制時間過長的嚴重危機,在計算機硬軟件技術相通訊技術日新月異發展的時代,很容易使剛建立起來的管理信息系統迅速變得陳舊,生命周期很短,所以系統開發周期過長將導致系統運行時間變短。
第二,使用過程化語言,沒有以根本上改變個體手工編程的工作方式。
第三,專業開發人員開發用戶使用的系統開發模式,開發人員與用戶都要化時間去掌握對方專業領域的知識以期產生共同語言,導致用戶系統分析不充分,理解不透徹,或表達的二義性,造成軟件生命周期中越早潛入的錯誤發現越晚,系統分析時引入的錯誤往往要到運行時才發現,其修正的代價是相當昂貴的。
第四,用戶熱情沒有自始至終調動,不能從根本上解決讓用戶參加系統開發的問題。系統維護就十分困難。且文檔資料缺乏實用價值,特別是早期的系統規格說明——專業知識的缺乏使得用戶難以理解文檔的內容,文檔資料沒有起到應有的作用,反而延長了開發時間。
2.:
快速地創建出管理信息系統的測試版(可用來演示和評估),借助這種測試版本挖掘用戶的需求,然后在此版本的基本上進修改、增強。由4個開發階段組成: 確認基本需求-> 開發原型系統-> 使用原型系統 <-> 修改增強原型 優點:
快速原型法突出一個“快”字,采用結構化生命周期法作系統分析時要反復和用戶討論,這種討論費時費力,而且終究是“紙上談兵”,原型法則是“真槍實彈”,能夠使用戶立刻與想象中的目標系統作出比較。開發人員向用戶提供一個“樣品”,用戶迅速向開發人員作出反饋,提高系統的質量,快速原型法要求在獲得一組基本的用戶需求后,快速地實現新系統的一個“原型”,可以說是以用戶需求為中心,又不完全依賴于用戶需求,它對用戶需求的定義采用啟發的方式,引導用戶在對系統逐漸加深理解的過程中作出響應,鼓勵用戶參與到系
統的設定與開發中去,更加便于系統的維護和使用。不足:
快速原型法,雖然能夠積極調動用戶參與到系統開發與設計中去,但起局限性在于,只能適用于中小型企業的管理信息系統開發,而大型企業,管理信息系統本身十分復雜,各種不確定性因素多變,對那些簡單的數據操作和記錄管理的應用比較適合用原型法開發。而對那些批處理或大量計算和有著復雜過程邏輯的系統一般不適合用原型法處理。原型法更適合較小的應用開發,對大型系統就須分成幾部分,一部分一部分地分別建立原型。如果缺乏用傳統方法進行透徹的需求分析,就無法對大型系統進行劃分,因為一開始很難分辨系統各部分之間存在哪些相互的影響。如果冒昧使用快速原型法,會導致管理信息系統出現漏洞。
3.應用軟件包法:
通過購買商品化軟件包并在此基本上進行系統的開發方法。由4個階段組成:系統分析-> 系統設計-> 系統修正->系統維護 優點:
從軟件包開發者手中直接購買企業需要的應用軟件包,市場出售的應用軟件包非常多而且應用范圍廣,可以給企業管理者更多的選擇,使用商業化的應用軟件包就不必自己再編寫程序或者只需寫少量的程序,因此可以說省時又省力,且效果立竿見影。不足:
應用軟件包法雖然方便,但是同樣需要系統分析,設計,測試,轉換和維護等開發過程,而且由于此種方法是購買商業軟件包,因此導致企業內部專業人員無法參與到系統開發中去,容易受制于軟件開發者,它不是一個完全獨立的系統,不易維護,不易更新,更不易于修改。而且軟件包是基于商業化開發的,軟件包不可能滿足一個組織的全部需求,相對來說,它更適用于所有組織中比較通用的一些需求。為了使其市場最有吸引力,軟件包力求滿足所有組織最共同的需求。勢必不能完全適應于企業方方面面的實際情況。企業如想進一步改進系統,需要投入一部分的額外資金培養人才。
用戶自己采用開發工具開發自己需要的各種系統。由3個階段組成一個循環開發過程: 系統分析-> 系統開發-> 系統維護->回到系統分析 優點:
這種方法的優點在于克服了應用軟件包法開發系統時企業無法自主的不足,由企業的開發人員根據企業的實際需要去開發和維護管理信息系統,可以適應企業的實際情況,用戶對自己設計和開發的系統更容易接受并樂于使用,對應變突發事件有好處,同時通過重復分析、開發 維護、再分析的幾個步驟,可以加深企業工作人員對管理信息系統的認識和理解,這樣有利于系統的開發和維護。而且由于開發系統的責任由信息系統專業人員轉給了最終用戶,所以用戶開發的系統有助于減少應用系統后備資源。不足:
第一,由于缺乏規范的信息系統分析,用戶開發的應用系統就缺乏獨立的外部評審,缺乏獨立的問題分析或可選方案的來源,用戶就很難完整并全面地說明其需求。
第二,由企業內部人員自主開發管理信息系統,由于企業從業人員的專業水平參差不齊,且開發的系統常常快速地建立,沒有一套正規的開發方法,這類系統往往缺乏適當的標準、控制和質量保障過程,可能也沒有用于測試和提交文檔的規范。用戶開發的系統還可能缺乏對輸入和更新審計記錄的完整性及合法性的控制,缺乏操作控制、目標控制和各子系統之間穩定的接口標準的控制。
第三,數據難以控制。
第四,用戶能用開發工具建立自己專用的“私用”信息系統,這類系統可對組織的其他成員隱蔽一些信息。一旦系統的開發者離開其崗位,這種非文檔化的私用系統將無法容易地移交
給他人使用。
5.將所需要的系統,委托企業外部的人員或組織進行開發。它只是一種信 息系統開發策略,這些開發依然要選擇如何使用前面4種開發方法。由3個階段組成:用戶需求-> 外包信息系統-> 最終系統 優點:
在經濟方面,由于負責系統開發服務的外部開發商是信息系統服務和技術方面的專家,所以靠專業化和規模經濟,他們能以低于內部成本的費用向組織提供同樣的服務和價值。服務質量方面,因為一旦外部開發商提供的服務不夠滿意,那么他將會失去自己的客戶,所以企業對外部開發商的影響比對自己員工的影響更大。從而使企業能以較低的成本從開發商那里獲得高質量的服務。再一點,由于企業與外部開發商事先針對不同層次的服務所對應的費用進行了簽約,因此可大大減少成本的不確定性。外包信息系統具備一定的靈活性,在組織的信息系統基礎設施不發生重大變化的情況下,能適應業務量的增長。當信息技術滲透整個企業價值鏈時,由于成本和性能可按變化的需求不斷進行調整,所以外部開發商可提供較強的業務控制和適應能力。外包信息系統同時也可以解放人力資源,將較少且昂貴的高層次人才集中到具有較高價值和回報的活動中。不足:
第一,失控:當一個企業將開發、運行其信息系統的責任承包給另一個組織時,它可能失去對信息系統職能的控制。如果開發商成為企業運行和開發信息系統的惟一選擇,那么企業將不得不接受開發商所提供的任何技術,這種從屬關系最終將導致產生較高的成本,并可能失去對技術管理的控制。
第二,戰略信息易損:由于企業信息系統由外部人員運行、開發,所以商業秘密或業主信息可能會泄漏給競爭對手;若允許外部開發者開發或操作使企業具有競爭優勢的應用系統,那將更有害。
第三,依賴性:企業會隨開發商對企業信息系統的開發、運作而變得對開發商的生存能力更加依賴,那么開發商的財政問題或服務上的衰減都可能對企業產生嚴重的影響。