日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转载unity

發(fā)布時(shí)間:2023/12/14 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转载unity 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原創(chuàng)

Unity基礎(chǔ)知識(shí)匯總

2018-05-12 17:02:37 levosam 閱讀數(shù) 3870 分類專欄: 編程 版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。 本文鏈接:https://blog.csdn.net/levosam/article/details/80292989

2.Unity相關(guān)知識(shí)

2.1 Unity介紹

Unity成為一款可以輕松創(chuàng)建游戲和三維互動(dòng)的開發(fā)工具,是一個(gè)專業(yè)跨平臺(tái)游戲引擎

Unity操作快捷鍵

?

Ctrl

?

N

New Scene 新建場景

Ctrl

?

O

Open Scene 打開場景

Ctrl

?

S

Save Scene 保存

Ctrl

Shift

S

Save Scene as 保存場景為

Ctrl

Shift

B

Build Settings... 編譯設(shè)置...

Ctrl

?

B

Build and run 編譯并運(yùn)行

Edit 編輯

Ctrl

?

Z

Undo 撤消

Ctrl

?

Y

Redo 重做

Ctrl

?

X

Cut 剪切

Ctrl

?

C

Copy 拷貝

Ctrl

?

V

Paste 粘貼

Ctrl

?

D

Duplicate 復(fù)制

Shift

?

Del

Delete 刪除

?

?

F

Frame? selected 選擇的幀

Ctrl

?

F

Find 查找

Ctrl

?

A

Select All 全選

Ctrl

?

P

Play 播放

Ctrl

Shift

P

Pause 暫停

Ctrl

Alt

P

Step 停止

?

2.2 腳本基礎(chǔ)開發(fā)

Unity面向組件開發(fā),游戲物體想要實(shí)現(xiàn)什么樣的功能,只需要添加相對應(yīng)的組件就可以了,此時(shí)會(huì)在屬性面板上顯示出來。可以像添加組件一樣把腳本添加到游戲物體上。

腳本生命周期:

1.Awake

最早執(zhí)行,在GameObejct對象的數(shù)據(jù)和狀態(tài)的初始化后執(zhí)行,只會(huì)觸發(fā)一次。

tips:GameObject實(shí)例化到場景中后在激活的狀態(tài)下才會(huì)初始化,如果GameObject從來未激活,它的腳本上的Awake永遠(yuǎn)不會(huì)被調(diào)用。

即時(shí)觸發(fā),GameObject第一次active的時(shí)候調(diào)用。

2.Start

在腳本第一次調(diào)用Update之前調(diào)用,只會(huì)觸發(fā)一次。

3.OnEnable

在腳本狀態(tài)由disabled變?yōu)閑nabled狀態(tài)是觸發(fā)一次,Unity內(nèi)部可能將腳本初始置為diabled,所以如果我們實(shí)例化一個(gè)激活的GameObject,并且在掛上一個(gè)enabled了的腳本后把它加入場景會(huì)調(diào)用一次OnEnable,并且早于Start。

4.OnDisable

在腳本由enabled狀態(tài)變?yōu)閐isabled狀態(tài)的時(shí)候會(huì)調(diào)用。

tips:OnEnable和OnDisable事件的觸發(fā)是即時(shí)的,并且這兩個(gè)事件是綜合考慮GameObject的active狀態(tài)和腳本的enabled狀態(tài)的。所以不要在OnEnable里面把腳本設(shè)置為disabled同時(shí)在OnDisable中把腳本設(shè)置為enabled,會(huì)導(dǎo)致死循環(huán)!!!

5.Update

在每一幀調(diào)用,用于實(shí)現(xiàn)各種行為邏輯

6.LateUpdate

在每一幀調(diào)用,但是是在Update之后觸發(fā)。常用的一種情況是相機(jī)跟隨移動(dòng)角色:角色移動(dòng)邏輯在Update里面實(shí)現(xiàn),相機(jī)跟隨邏輯在LateUpdate里面實(shí)現(xiàn)。

7.OnDestroy

在組件被銷毀時(shí)調(diào)用,只有GameObject被激活過才會(huì)觸發(fā)。

腳本常用類:

1.Component類

2.GameObject類

3.Transform類

4. Vector3類

1.?Quaternion

Identity:該四元素?zé)o旋轉(zhuǎn)。

LookRotation:創(chuàng)建一個(gè)旋轉(zhuǎn),沿著forward(Z軸)并且頭部沿著Y軸的約束注釋

2.?Time

3.?Mathf

預(yù)設(shè)體

組件的集合體 , 預(yù)制物體可以實(shí)例化成游戲?qū)ο?

創(chuàng)建預(yù)設(shè)體的作用: 可以重復(fù)的創(chuàng)建具有相同結(jié)構(gòu)的游戲?qū)ο蟆?/p>

在腳本中,使用instantiate函數(shù)來進(jìn)行預(yù)設(shè)體的實(shí)例化

Object tmpObj = Instantiate(prefabs, pos , Quaternion.identity);

?

?

2.3 物理引擎

1.鍵盤輸入常用方法

GetKey:按鍵按下期間返回true

GetKeyDown:按鍵按下的第一幀返回true

GetKeyUp:按鍵松開的第一幀返回True

Input類簡介

虛擬按鍵

具體代碼和實(shí)現(xiàn)方式如下:

Float hor = Input.GetAxis(“Horizontal”);

鼠標(biāo)事件

常用的鼠標(biāo)屬性和方法

?

碰撞器組件:

當(dāng)我們在場景當(dāng)中創(chuàng)建出來一個(gè)游戲物體的方式后,引擎會(huì)自動(dòng)為這個(gè)游戲物體添加碰撞器組件,其主要功能是進(jìn)行碰撞檢測。

發(fā)生碰撞的條件:1、相對運(yùn)動(dòng),2、兩個(gè)碰撞器,2、一個(gè)剛體

?

剛體組件

剛體組件能受到你的作用,比如:重力,反作用力,阻力,外加力,爆炸力等等

以下是剛體組件的一些屬性和常用方法

觸發(fā)器:

發(fā)生觸發(fā)的條件:1、兩個(gè)碰撞器 2、一個(gè)觸發(fā)器 3、一個(gè)剛體

?

射線

Unity提供了涉嫌集資:通過虛擬射線檢測所碰撞到的物體

Ray ray = new Ray();

Bool Raycast(Ray ray,out RaycastHit hitInfo);

Rayray=Camera.main.ScreenPointToRay(Input.mousePostion);

從主攝像機(jī)到鼠標(biāo)點(diǎn)擊位置創(chuàng)建一條射線。

?

2.4 Unity2D和精靈

精靈:

圖片精靈的意思(Flash引擎里也有圖片精靈對象),將導(dǎo)入的圖片類型設(shè)置為Sprite即可拖到場景面板里,帶有隨屏幕大小自動(dòng)縮放功能,還可以加Collider進(jìn)行射線檢測,簡單實(shí)用。圖片精靈是用來繪制圖集的控件,精靈可以在一張大圖中去截取一部分(大圖就是整體圖像集合(Atlas),而截取的小圖就是一個(gè)精靈),然后給精靈命名,使用時(shí)通過精靈的名稱就能直接繪制,并且精靈還可以用來制作動(dòng)畫。

圖層排序:2D游戲當(dāng)中的圖片之鍵沒有深度關(guān)系,都處于同一個(gè)平面上,但在實(shí)際游戲當(dāng)中需要為他們排序,按視覺上的空間先后順序顯示。

2D物理組件與3D物理引擎在功能上基本相似,當(dāng)我們給精靈添加了個(gè)剛體之后,他就會(huì)受到2D物理引擎的控制。

2D碰撞和觸發(fā)回調(diào)方法:

?

?

2D開發(fā)常用類:

創(chuàng)建序列幀動(dòng)畫,按Ctrl+F6打開Animation的編輯窗口,點(diǎn)擊后可以添加屬性,如果要更改動(dòng)畫中某一幀的位置、旋轉(zhuǎn)和縮放,只需要點(diǎn)擊+號(hào)即可,在Animation編輯窗口,在關(guān)鍵幀點(diǎn)擊天津愛時(shí)間,此時(shí)可以選擇腳本中的方法,但是該方法必須是public ,可訪問狀態(tài)

?

?

2.6 UGUI

UGUI的特點(diǎn):靈活,快速和可視化,對于開發(fā)者而言,效率高,易于使用和擴(kuò)展以及對Unity的兼容性高。

UGUI與GUI插件NGUI相比:

1. 由NGUI創(chuàng)始人參與開發(fā)

2. 與Unity結(jié)合更加密切

3. 自適應(yīng)系統(tǒng)更加完善

4. 更方便的深度處理

5. 省去Altas,直接使用Sprite Pa

UGUI畫布:是所有UI控件的根類,所有的UI控件補(bǔ)習(xí)都在畫布上面。EventSystem是事件系統(tǒng),負(fù)責(zé)監(jiān)聽用戶的輸入,創(chuàng)建UI控件是,當(dāng)層級試圖當(dāng)中沒有CANVAS和EventSystem,系統(tǒng)會(huì)幫我們自動(dòng)創(chuàng)建。

畫布的三種渲染模式模式:

1、Screen Space-Overlay:不需要UI攝像機(jī),畫布會(huì)一直出現(xiàn)在攝像機(jī)最前面

2、Screen Space-Camera:需要一個(gè)UICamera,支持U前方顯示3D模型和粒子系統(tǒng)

3、World Space:UI控件成為3D場景中的一部分

LayoutGroup組件:對子控件進(jìn)行布局,上面只能有一種布局組件,布局組件有以下三種:

1.Horizontal Layout Group (水平布局)

2.Ver tical Layout Group(垂直布局)

3.Grid Layout Group(網(wǎng)格布局)

1. UGUI畫布也稱為Canvas,UGUI是所有控件的父類

2. 所有UGUI控件都必須繪制在畫布上面

3. 當(dāng)創(chuàng)建UGUI控件工程當(dāng)中沒有Canvas的時(shí)候會(huì)自動(dòng)創(chuàng)建

Canvas與EventSystem

Text控件是用來顯示文本的文本控件

Text的屬性可以在Inspector當(dāng)中通過Text組件進(jìn)行設(shè)置,也可以在代碼當(dāng)中進(jìn)行動(dòng)態(tài)設(shè)置。給Canvas掛載腳本UGUISetting

Image控件主要是用來顯示圖片,顯示圖片的格式是Sprite

當(dāng)我們給Image選擇一張貼圖之后會(huì)出現(xiàn)ImageType選項(xiàng),如下圖所示。ImageType總共有四種選項(xiàng):simple顯示單個(gè)會(huì)拉伸;Tilled平鋪顯示,圖片按照原始顯示;Sliced按照九宮格顯示,拉伸區(qū)域只會(huì)在九宮格中間;Filled填充顯示,可以根據(jù)不同的填充方式模擬技能冷卻的

按鈕添加監(jiān)聽事件:

Button btn;

void Star t () {

//獲取到按鈕

btn = GameObject.Find(“Button”).GetComponent<Button> ();

//給按鈕添加監(jiān)聽事件

btn.onClick .AddListener (BtnClick);

}

void BtnClick(){//按鈕響應(yīng)事件

Debug.Log (“btn.onClick .AddListener ()”);

}?????

Slider是滑動(dòng)條,Slider的屬性如圖所示:

Slider slider ;

void Star t () {

//獲取到Slider組件

slider = GameObject.Find(“Slider ”).GetComponent<Slider> ();

//添加監(jiān)聽事件

slider.onValueChanged.AddListener(SliderValueChange);

}

//? 事件響應(yīng)

public voidSliderValueChange (float value){

Debug.Log (“value = “+value);

}

InputField創(chuàng)建出來如下圖所示,InputField層級視圖當(dāng)中包含Placeholder與Text,Placeholder用于顯示占位符,即輸入框沒有輸入文本時(shí)顯示的文本,例如下圖的“Enter text”,Text用于顯示輸入的內(nèi)容。

RectTransform的作用用來計(jì)算UI的位置和大小,RectTransform繼承于Transform,具有Transform的所有特診,通過RectTransform能夠?qū)崿F(xiàn)基本的布局和層級控制。

如圖所示,箭頭所指即為錨點(diǎn),錨點(diǎn)表示的是相對于父級矩形的子矩形區(qū)域。如圖所示錨點(diǎn)為四邊形,錨點(diǎn)有多種擺放方式,可以為矩形,點(diǎn)狀或是為線狀。錨點(diǎn)移動(dòng)范圍僅限于父級視圖當(dāng)中。

按下T鍵選中某一個(gè)UI控件即可看到UI控件的中心點(diǎn),中心點(diǎn)也叫中心軸,當(dāng)鼠標(biāo)拖動(dòng)UI控件進(jìn)行旋轉(zhuǎn)的時(shí)候會(huì)圍繞中心點(diǎn)旋轉(zhuǎn)。中心點(diǎn)為矩形的一部分。0對應(yīng)左下角,1對應(yīng)右上角

UGUI回調(diào)方法

輸入模塊StandaloneModule和TouchInputModule兩個(gè)組件會(huì)檢測到用戶的一些輸入事件,并且以事件的方式通知目標(biāo)對象。實(shí)現(xiàn)這些回調(diào)方法需要實(shí)現(xiàn)相應(yīng)的接口。常用的回調(diào)事件如下所示

CanvasGroup的作用:當(dāng)一個(gè)控件蓋到另外一個(gè)控件上的時(shí)候,下面的控件默認(rèn)是檢測不的,為了可以透過當(dāng)前控件檢測到下面的控件,可以給該組件添CanvasGroup組件,其屬性blocksRaycasts設(shè)置為false時(shí)表示可以穿透該控件檢測到下面的控件,如果為true表示不能穿透,下方的控件檢測不到.

在Unity中,所有與應(yīng)用程序相關(guān)的方法都寫在Application 類中。

主要功能:獲取或設(shè)置當(dāng)前應(yīng)用程序的一些屬性

? 加載游戲關(guān)卡場景

? 獲取資源文件路徑

? 退出當(dāng)前游戲程序

? 獲取當(dāng)前游戲平臺(tái)

? 獲取數(shù)據(jù)文件夾路徑

同步加載場景的方式分為兩種:

讀取新關(guān)卡后立即切換,其參數(shù)為所讀取新關(guān)卡的名稱或索引

SceneManager.LoadScene("Scene2");?????????

加載一個(gè)新的場景,當(dāng)前場景不會(huì)被銷毀。

SceneManager.LoadScene("Scene2",LoadSceneMode.Additive);

異步加載新游戲場景,當(dāng)新場景加載完成后進(jìn)入新場景并且銷毀之前的場景。

SceneManager.LoadSceneAsync("Scene2");

同樣異步加載新場景,新場景加載完畢后,保留之前場景并且進(jìn)入新場景。

SceneManager.LoadSceneAsync("Scene2",LoadSceneMode.Additive);

?

2.7 Unity 動(dòng)畫系統(tǒng)基礎(chǔ)

Mecanim 功能強(qiáng)大的動(dòng)畫系統(tǒng)

方便的實(shí)現(xiàn)人型動(dòng)畫的設(shè)置和重用方便的實(shí)現(xiàn)動(dòng)畫剪輯的設(shè)置

可視化的動(dòng)畫控制界面

對動(dòng)畫播放的精確控制

動(dòng)畫類型分為四種

None:無任何動(dòng)畫

Legacy:舊版Animation動(dòng)畫

Generic:一般動(dòng)畫(非人形動(dòng)畫)

Humanoid:人形動(dòng)畫

設(shè)置Avatat,Avatat是Mecanim系統(tǒng)中極為重要的模塊,因此為模型資源正確的設(shè)置Avatar也至關(guān)重要,不管Avatar自動(dòng)創(chuàng)建過程是否成功,用戶都需要進(jìn)入

根動(dòng)作設(shè)置包括旋轉(zhuǎn)、Y 軸水平位置和 XZ 平面位置Bake Into Pose:烘焙進(jìn)姿勢

loop match:當(dāng)需要讓一個(gè)動(dòng)作重復(fù)時(shí),后面的圓點(diǎn)顏色就代表重復(fù)質(zhì)量。綠色表示該動(dòng)畫的第一幀和最

后一幀角色的姿勢相似,黃色次之,紅色質(zhì)量最差。Based Upon:定根動(dòng)作的參考點(diǎn)

Offset:偏移量用來設(shè)置指定根動(dòng)作,在運(yùn)動(dòng)時(shí)的偏移量

動(dòng)畫間的過渡需要使用狀態(tài)機(jī)和狀態(tài)參數(shù)實(shí)現(xiàn),目前支持的參數(shù)類型有4種。

Animator常用方法:

改變 Float 類型狀態(tài)參數(shù)的值

animator.SetFloat(speedFloat, 2.0f );

改變 Bool 類型狀態(tài)參數(shù)的值

animator.SetFloat(deadBool, true);

BlendTree: 融合樹的功能是將兩個(gè)或多個(gè)相似的動(dòng)作進(jìn)行融合,可以使用多個(gè)或者一個(gè)參數(shù)來控制融合狀態(tài)。

在 Unity 中可以使用動(dòng)畫層來管理不同類型的動(dòng)畫分層處理。動(dòng)畫層遮罩能夠在本層動(dòng)畫中,身體的特定部分選擇性的激活或禁用在 Project面板下創(chuàng)建一個(gè) Avatar Mask。身體遮罩包括頭部、左手臂、右手臂、左手、右手、左腿、右腿和根部,還可以選擇給手和腿添加 IK,這將決定 IK 曲線是否會(huì)包含在動(dòng)畫融合中,點(diǎn)擊身體部分可以激活或禁用對應(yīng)部位的動(dòng)畫。

大多數(shù)動(dòng)畫是由旋轉(zhuǎn)關(guān)節(jié)角度的骨架來預(yù)先確定的值。子關(guān)節(jié)的位置變化根據(jù)父節(jié)點(diǎn)的旋轉(zhuǎn),因此關(guān)節(jié)鏈的最終位置會(huì)根據(jù)角度和它所包含的各個(gè)關(guān)節(jié)的相對位置來確定。這種方法構(gòu)成的骨架被稱為正運(yùn)動(dòng)學(xué)。

IK動(dòng)畫全名是Inverse Kinematics 意思是反向動(dòng)力學(xué),就是子骨骼節(jié)點(diǎn)帶動(dòng)父骨骼節(jié)點(diǎn)運(yùn)動(dòng)。比如跳街舞的少年用手撐著身體在地上轉(zhuǎn)圈,手就是子骨骼,胳膊身體就是它的父骨骼,這時(shí)運(yùn)動(dòng)手就需要帶動(dòng)胳膊身體來移動(dòng)。我們需要從一個(gè)正確配置的Avatar的人形Mecanim角色開始,接下來創(chuàng)建一個(gè)動(dòng)畫控制器,包含至少一個(gè)動(dòng)畫人物。然后在動(dòng)畫窗口的圖層面板中,單擊圖層的齒輪設(shè)置圖標(biāo),并在彈出的菜單中選中IK復(fù)選框。

animator.SetIKPositionWeight(AvatarIKGoal.RightHand,1);

animator.SetIKRotationWeight(AvatarIKGoal.RightHand,1);

if (ikActive) {

animator.SetIKPosition(AvatarIKGoal.RightHand,rightHandObj.position);animator.SetIKRotation(AvatarIKGoal.RightHand,rightHandObj.rotation);

} else{

animator.SetIKPositionWeight(AvatarIKGoal.RightHand,0);

animator.SetIKRotationWeight(AvatarIKGoal.RightHand,0);

}

當(dāng)你需要在角色動(dòng)畫播放到某一幀的時(shí)候需要做其他處理時(shí),這時(shí)可以使用動(dòng)畫事件

2.8 Unity 導(dǎo)航系統(tǒng)

導(dǎo)航在游戲當(dāng)中的概念就是從一點(diǎn)走到另外一點(diǎn)的過程,在該過程中需要考慮:阻擋,路徑選擇,可走地形,地形特點(diǎn)以及擬人化等多方面因素。在游戲當(dāng)中導(dǎo)航分為兩種:

(1)ai角色:基于計(jì)算機(jī)本身控制的純導(dǎo)航

(2)主角:基于UI交互下的導(dǎo)航

導(dǎo)航實(shí)現(xiàn)方式

(1) A*算法

導(dǎo)航當(dāng)中常用的算法是A*算法,它是一種從起點(diǎn)到終點(diǎn)探測代價(jià)最小路徑的廣度優(yōu)先搜索方式,廣泛應(yīng)用于2D格子型地圖。

? (2)NavigationMesh

在Unity當(dāng)中采用的是基于Navigation Mesh的尋路算法原理, 是A*算法的變種,將A*算法當(dāng)中的格子變成三角形或多邊形, 可以方便的從二維擴(kuò)展到三維空間,是3D游戲當(dāng)中的主流尋路算法。

NavMesh(導(dǎo)航網(wǎng)格)是3D游戲世界中用于實(shí)現(xiàn)動(dòng)態(tài)物體自動(dòng)尋路的一種技術(shù),將游戲中復(fù)雜的結(jié)構(gòu)組織關(guān)系簡化為帶有一定信息的網(wǎng)格,在這些網(wǎng)格的基礎(chǔ)上通過一系列的計(jì)算來實(shí)現(xiàn)自動(dòng)尋路。

NavMeshAgent常見的屬性和方法:

分離路面導(dǎo)航:

在兩個(gè)不連通的尋路網(wǎng)格間,如果角色想在這兩個(gè)網(wǎng)格間行走就需要添

加跳躍的鏈接Off MeshLink

分層烘焙路面:

實(shí)現(xiàn)分層路面導(dǎo)航主要分為以下步驟:

(1)自定義Area層

(2)設(shè)置場景中不同區(qū)域烘焙為不同的層

(3)設(shè)置角色可以在導(dǎo)航網(wǎng)格中哪些層移動(dòng)

設(shè)置不同區(qū)域在導(dǎo)航網(wǎng)格中為不同的層主要是控制角色有選擇的行走某些區(qū)域。設(shè)置好烘焙出來不同區(qū)域在場景當(dāng)中呈現(xiàn)不同顏色,接下來通過角色自身掛載的NavMeshAgent組件里的AreaMask屬性設(shè)置代理可以在導(dǎo)航網(wǎng)格中的哪些區(qū)域移動(dòng)。默認(rèn)為Everything

動(dòng)態(tài)障礙:

Nav Mesh Obstacle有兩種模式,一種是普通的模式,通過設(shè)置半徑與高度來確定一個(gè)范圍,阻擋代理的移動(dòng)。另一種是Car ve模式,會(huì)根據(jù)模型大小界定該區(qū)域無法參與導(dǎo)航網(wǎng)格計(jì)算

?

2.9 Unity 特效渲染

粒子特效:

Unity中一個(gè)典型的粒子系統(tǒng)是一個(gè)對象,它包含了一個(gè)粒子發(fā)射器,一個(gè)粒子動(dòng)畫和一個(gè)粒子渲染器。粒子發(fā)射器產(chǎn)生粒子,粒子動(dòng)畫器則隨時(shí)間移動(dòng)粒子,粒子渲染器則將它們渲染到屏幕中

粒子系統(tǒng)相關(guān)參數(shù):

拖尾渲染:

TrailRenderer

拖尾渲染組件屬于特效當(dāng)中的一種,給一個(gè)物體添加拖尾渲染組件的方式

線性渲染:

LineRenderer常用方法

?

2.10 Unity 數(shù)據(jù)庫與存儲(chǔ)

PlayerPrefs存儲(chǔ)數(shù)據(jù)

適用范圍

1. 適用設(shè)備:Mac OSX、Linux、Windows、

Windows Store Apps、Windows Phone 8、Web players

2. 存儲(chǔ)機(jī)制:Key-Value

3. 可存儲(chǔ)變量類型:int、float、string

PlayerPrefs數(shù)據(jù)存儲(chǔ)路徑

1. Mac OSX:~/Library/Preferences

2.Windows:HKCU\Software\[company name]\[product name]

3.Linux:~/.config/unity3d/[CompanyName]/[ProductName]

4. Windows StoreApps:%userprofile%\AppData\Local\Packages\

[ProductPackageId]>\LocalState\playerprefs.dat

5. WebPlayer

6. Mac OS X:~/Library/Preferences/Unity/WebPlayerPrefs

7. Windows:%APPDATA%\Unity\WebPlayerPrefs

PlayerPrefs常用方法;

void Example() {

PlayerPrefs.SetFloat("PlayerScore", 10.0F);

print(PlayerPrefs.GetFloat("PlayerScore"));

?

XML數(shù)據(jù)生成和解析

1. XML 指可擴(kuò)展標(biāo)記語言(EXtensible Markup Language)

2. XML 是一種標(biāo)記語言,很類似 HTML

3. XML 的設(shè)計(jì)宗旨是傳輸數(shù)據(jù),而非顯示數(shù)據(jù)

XML結(jié)構(gòu)

每個(gè)標(biāo)簽內(nèi)部可以有多個(gè)屬性。標(biāo)簽可以層層嵌套,形成一個(gè)樹形

結(jié)構(gòu)。

例如:

<position name=“player”>

<x>18</x>

<y>5</y>

<z>30</z>

</position>

以上Alarm(元素節(jié)點(diǎn)),lock(屬性節(jié)點(diǎn)),Time(元素節(jié)點(diǎn)), StringValue(文本節(jié)點(diǎn))都是節(jié)點(diǎn)(Node),

但是只有<Alarm>……</Alarm>

和<Time>StringValue</Time>是元素(Element)

XML常用的類

1. XmlDocument——XML文件類2. XmlNode——XML節(jié)點(diǎn)類

3. XmlAttribute——XML屬性類4. XmlElement——XML元素類

XmlNode

?

?

?

?

?

?

?

?

XmlDocument

XmlElement

Xml數(shù)據(jù)生成步驟

在Unity引擎中如何生成本地XML數(shù)據(jù)?

第一步:引用C#的命名空間 System.Xml

第二步:生成XML文檔(XmlDocument 類)

第三步:生成根元素(XmlElement類)添加給文檔對象第四步:循環(huán)生成子元素添加給父元素

第五步:將生成的XML文檔保存

Xml數(shù)據(jù)生成示例

//創(chuàng)建xml文件對象

XmlDocument doc = newXmlDocument();

//創(chuàng)建xml頭

XmlNode xmldct =doc.CreateXmlDeclaration ("1.0", "utf-8", null);

//添加xml頭

doc.AppendChild (xmldct);

//創(chuàng)建xml根節(jié)點(diǎn)(元素屬于節(jié)點(diǎn))users

XmlNode root =doc.CreateElement("users");

//添加xml根節(jié)點(diǎn)

doc.AppendChild (root);

//創(chuàng)建子節(jié)點(diǎn)

XmlNode xn_element =doc.CreateNode (XmlNodeType.Element, "name", null); //設(shè)置子節(jié)點(diǎn)的值

xn element.InnerText ="Albert";

//創(chuàng)建屬性

XmlAttribute xa =doc.CreateAttribute ("no");

//設(shè)置屬性值

xa.Value ="1234";

//獲取元素的docment

XmlDocument xd = xnelement.OwnerDocument;

_

//設(shè)置元素屬性

xnelement.Attributes.SetNamedItem (xa);

_

//添加子節(jié)點(diǎn)到root節(jié)點(diǎn)

root.AppendChild (xn_element);

//保存xml

doc.Save(Application.dataPath+ "/test.xml");

Xml序列化

序列化是將對象狀態(tài)轉(zhuǎn)換為可保持或傳輸?shù)母袷降倪^程。

我們可以把對象序列化為不同的格式,比如說,Json序列化、XML序列化、二進(jìn)制序列化等,以上這些不同的格式也都是為了適應(yīng)具體的業(yè)務(wù)需求。

public class BaseInfo {

//BaseInfo對象中保存Person對象

? List<Person> perList = newList<Person>(); //創(chuàng)建元素節(jié)點(diǎn)

[XmlElement(ElementName="Perosn")]publicList<Person> PerList

{

get

{

return perList;

}

set

{

perList = value;

}

}

}

//用于將信息寫入字符串

StringWriter sw = newStringWriter();

//指定 Xml序列化名字空間

XmlSerializerNamespacesns = new XmlSerializerNamespaces();ns.Add("", "");

//聲明Xml序列化對象實(shí)例serializer,對BaseInfo類 進(jìn)行序列化

XmlSerializer serializer= new XmlSerializer(typeof(BaseInfo));

//使用 StringWriter 和指定的名字空間 將BaseInfo 對象寫入Xml文件

serializer.Serialize(sw,baseInfo, ns);

sw.Close();

反序列化示例

//根據(jù)指定路徑讀取,實(shí)例化FileStream對象

FileStream fs = newFileStream(Application.dataPath +

"/Practise5/test.xml",FileMode.Open,FileAccess.Read);

//指定反序列化的類型

XmlSerializer serializer= new XmlSerializer(typeof(BaseInfo));BaseInfo baseInfo =(BaseInfo)serializer.Deserialize(fs);

fs.Close();

//遍歷baseinfo對象中的信息,輸出到控制臺(tái)

for (int i = 0; i <baseInfo.PerList.Count; i++)

{

Person per =baseInfo.PerList[i];

Debug.Log("名字: "+ per.Name +", 年齡:"+per.Age );

for (int j = 0; j <per.BooksList.Count; j++)

{

Books books =per.BooksList[ j];

for (int k = 0; k <books.BookList.Count; k++)

{

Book book =books.BookList[k];

Debug.Log("書名: "+book.Title+", 價(jià)格:"+book.Price);

}

}

}

?

JSON數(shù)據(jù)生成和解析

System.Json

?

1. JSON 是純文本

2. JSON 是一種輕量級的數(shù)據(jù)交換格式3. JSON 具有層級結(jié)構(gòu)(值中存在值)

1. 數(shù)據(jù)在鍵值對

2. 數(shù)據(jù)由逗號(hào)分隔3. 花括號(hào)保存對象4. 方括號(hào)保存數(shù)組

LitJson.JsonMapper

1. 把對象轉(zhuǎn)化成 JSON格式字符串: JsonMapper.ToJson

2. 把JSON格式字符串轉(zhuǎn)化成對象: JsonMapper.ToObject

什么是SQLite

1. SQLite是一款輕型的數(shù)據(jù)庫

2. SQLite的設(shè)計(jì)目標(biāo)是嵌入式的

3. SQLite占用資源非常的低

4. SQLite能夠支持Windows/Linux/Unix等等主流的操作系統(tǒng)

作用:INSERT INTO 語句用于向表格中插入新的行。

語法1:INSERT INTO 表名稱 VALUES (值1, 值2,....)

語法2:INSERT INTO table name (列1, 列2,...) VALUES (值1, 值2,....)

作用:DELETE 語句用于刪除表中的行。

語法:DELETE FROMPerson WHERE LastName = 'Wilson'

作用:Update 語句用于修改表中的數(shù)據(jù)。

語法:UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值

作用:SELECT 語句用于從表中選取數(shù)據(jù)。

語法:SELECT 列名稱 FROM 表名稱

Unity當(dāng)中使用SQLite:

導(dǎo)入mono.data.sqlite.dll到Assets文件夾代碼添加庫:using Mono.Data.Sqlite;

使用SQLiteConnection對象,進(jìn)行數(shù)據(jù)庫連接,此操作可以創(chuàng)建空的數(shù)據(jù)庫

具體代碼如下:

//數(shù)據(jù)庫連接路徑

string path = "data source="+ Application.streamingAssetsPath +

"/UserDatabase.sqlite";

void OpenDataBase(stringconnectionString)

{

try

{

conn = newSqliteConnection(connectionString);

conn.Open();

}

catch (System.Exceptionexc)

{

Debug.Log(exc);

}

}

使用SqliteCommand數(shù)據(jù)指令,對象進(jìn)行數(shù)據(jù)庫操作

//判斷數(shù)據(jù)庫中是否有UserTable這個(gè)表SqliteCommand cmd =conn.CreateCommand();

cmd.CommandText ="select count(*) from sqlite master where

_

type = 'table' and name ='UserTable'";

SqliteDataReader reader =cmd.ExecuteReader();

使用SqliteDataReader 數(shù)據(jù)讀取對象,進(jìn)行數(shù)據(jù)庫內(nèi)容讀取

//判斷數(shù)據(jù)庫中是否存在這張表

bool isExit = false;

while (reader.Read())

{

for (int i = 0; i <reader.FieldCount; i++)

{

if(reader.GetValue(i).ToString() == "1")

{

isExit = true;

}

}

}

數(shù)據(jù)庫操作完成之后要將數(shù)據(jù)庫關(guān)閉

//如果表不存在則建表

reader.Dispose();

reader.Close();

reader = null;

if (!isExit)

{

Debug.Log("表不存在,建表");

cmd.CommandText ="Create Table UserTable(uname text,pwd

text)";

cmd.ExecuteNonQuery();

}

cmd.Dispose();cmd =null;CloseDataBase();

執(zhí)行SQL語句的三種方式

1、int ExecuteNonQuery()

返回受影響的行數(shù)(常用于執(zhí)行增刪改操作)

2、object ExecuteScalar()

返回查詢到的第一個(gè)值(常用于只查詢一個(gè)結(jié)果時(shí))3、SqliteDataReader ExecuteReader()

返回所有查詢的結(jié)果(SqliteDataReader對象)

?

數(shù)據(jù)庫封裝:

為何要封裝?

1. 方便項(xiàng)目管理

2. 方便開發(fā)人員的快捷的使用

3. 防止高度保密數(shù)據(jù)外泄

1. 連接數(shù)據(jù)庫

2. 通過Sql語句查詢數(shù)據(jù)

3. 通過表名查詢?nèi)頂?shù)據(jù)

4. 關(guān)閉數(shù)據(jù)庫連接,釋放資源

平臺(tái)選擇不同的存儲(chǔ)路徑:

在直接使用Application.dataPath來讀取文件進(jìn)行操作,移動(dòng)端是沒有訪問權(quán)

限的。

Application.streamingAssetsPath

直接使用Application.streamingAssetsPath來讀取文件進(jìn)行操作,此方法在pc/Mac電腦中可實(shí)現(xiàn)對文件實(shí)施“增刪查改”等操作,但在移動(dòng)端只支持讀取操作。

使用Application.persistentDataPath來操作文件,該文件存在手機(jī)沙盒中,因?yàn)椴荒苤苯哟娣盼募?/p>

1.通過服務(wù)器直接下載保存到該位置,也可以通過Md5碼比對下載更新新的資源

2.沒有服務(wù)器的,只有間接通過文件流的方式從本地讀取并寫入

Application.persistentDataPath文件下,然后再通過

Application.persistentDataPath來讀取操作。

注:

在Pc/Mac電腦以及android跟Ipad、ipone都可對文件進(jìn)行任意操作,

另外在IOS上該目錄下的東西可以被iCloud自動(dòng)備份。

發(fā)布到安卓端需要經(jīng)過特殊處理

同樣需要上述的三個(gè)類庫和libsqlite.so文件,但不需要重新建表和重新

插入數(shù)據(jù)內(nèi)容。當(dāng)Android端安裝應(yīng)用程序時(shí),需要一個(gè)*.apk的安裝文件,此文件內(nèi)保存著我們從Unity開發(fā)平臺(tái)導(dǎo)入的*.sqlite文件,所以我們可以通過www來下載該sqlite文件,從而通過IO流寫入到Android本地的persistentDataPath沙盒路徑。該文件保存著所有表格和數(shù)據(jù),無需再次創(chuàng)建和插入,通常使用的都是這種方式,較為便捷。

Android端連接本地?cái)?shù)據(jù)庫:

注意:

? 二進(jìn)制文件需要放在Plugins->Android->assets中,然后根據(jù)下面的路徑就可以在Android中讀取。

string Path =jar:file://” + Application.dataPath + “!/assets/” +

“你的文件“;

?

2.11 WWW類與協(xié)程

什么是協(xié)程?

1. Unity的協(xié)程系統(tǒng)是基于C#的一個(gè)簡單而強(qiáng)大的接口

2. 簡單講,協(xié)程就是可以把一個(gè)方法拆分成多次執(zhí)行的一種接口

IEnumerator ShowTime()

{

Debug.Log("FirstFrame");//第一幀執(zhí)行

yield return 0;//等待下一幀

Debug.Log("SecondFrame");//第二幀執(zhí)行

yield return 0;//等待下一幀

Debug.Log("ThirdFrame");//第三幀執(zhí)行

}

開啟協(xié)程

//通過傳入方法開啟協(xié)程

StartCoroutine(ShowTime());

//通過傳入字符串類型的方法名稱開啟協(xié)程

StartCoroutine("ShowTime");

停止協(xié)程

StartCoroutine(“ShowTime");

//停止協(xié)程

StopCoroutine(“ShowTime”);

注意:StopCoroutine只能停止以字符串方式開啟的協(xié)程

當(dāng)你“yield”一個(gè)方法時(shí),你相當(dāng)于說,“現(xiàn)在停止這個(gè)方法,然后在下一幀中從這里繼續(xù)開始!”。

2. 用0或者null來yield的意思是告訴協(xié)程

等待下一幀,直到繼續(xù)執(zhí)行為止。

協(xié)程注意事項(xiàng)

1. 在程序中調(diào)用StopCoroutine()方法只能終止以字符串形式啟動(dòng)(開始)的協(xié)程。

2. 多個(gè)協(xié)程可以同時(shí)運(yùn)行,它們會(huì)根據(jù)各自的啟動(dòng)順序來更新。

3. 協(xié)程可以嵌套任意多層。

4. 協(xié)程不是多線程(盡管它們看上去是這樣的),它們運(yùn)行在同一線程中,跟普通的腳本一樣。

5. IEnumerator類型的方法不能帶ref或者out型的參數(shù),但可以帶被傳遞的引用。

協(xié)程,線程的區(qū)別

1. 線程擁有自己獨(dú)立的棧和共享的堆,共享堆,不共享?xiàng)?#xff0c;線程亦由操作系統(tǒng)調(diào)度(標(biāo)準(zhǔn)線程是的)。

2. 協(xié)程和線程一樣共享堆,不共享?xiàng)?#xff0c;協(xié)程由程序員在協(xié)程的代碼里顯示調(diào)度。

3. 協(xié)程避免了無意義的調(diào)度,由此可以提高性能,但也因此,程序員必須自己承擔(dān)調(diào)度的責(zé)任,同時(shí),協(xié)程也失去了標(biāo)準(zhǔn)線程使用多CPU的能力。

協(xié)程優(yōu)點(diǎn):

1. 跨平臺(tái)

2. 跨體系架構(gòu)

3. 無需線程上下文切換的開銷

4. 無需原子操作鎖定及同步的開銷

5. 方便切換控制流,簡化編程模型

6. 高并發(fā)+高擴(kuò)展性+低成本:一個(gè)CPU支持上萬的協(xié)程都不是問題。所以很適合用于高并發(fā)處理。

缺點(diǎn):

1. 無法利用多核資源:協(xié)程的本質(zhì)是個(gè)單線程,它不能同時(shí)將 單個(gè)CPU的多個(gè)核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)行在多CPU上.當(dāng)然我們?nèi)粘K帉懙慕^大部分應(yīng)用都沒有這個(gè)必要,除非是cpu密集型應(yīng)用。

2. 進(jìn)行阻塞(Blocking)操作(如IO時(shí))會(huì)阻塞掉整個(gè)程序:這一點(diǎn)和事件驅(qū)動(dòng)一樣,可以使用異步IO操作來解決。

什么是AssetBundle。?
AssetBundle是從unity項(xiàng)目中打包出來的資源文件,可用于資源的更新等。AssetBundle支持3中格式的壓縮選擇,分別是LZMA,LZ4,無壓縮。默認(rèn)是LZMA格式的壓縮,但是這樣雖然可以使資源文件大小大大縮小,利于下載,但是也有不利的一面,在使用時(shí)會(huì)先解壓再使用,所以會(huì)造成加載時(shí)間過長。?
不壓縮格式資源包會(huì)比較大,但是加載時(shí)不需要解壓,所以加載時(shí)會(huì)更快。

WWW類:

1. 可以簡單的訪問web頁面;

2. 這是一個(gè)小工具模塊檢索url的內(nèi)容;

3. 你開始在后臺(tái)下載通過調(diào)用WWW(url),返回一個(gè)新的WWW對象;

4. 你可以檢查isDone屬性來查看是否已經(jīng)下載完成,或者yield自動(dòng)等待下載物體,直到它被下載完成(不會(huì)影響游戲的其余部分)。

WWW類常用屬性:

?

2.12 網(wǎng)絡(luò)基礎(chǔ)

?

網(wǎng)絡(luò)協(xié)議即網(wǎng)絡(luò)中傳遞、管理信息的一些規(guī)范,在計(jì)算機(jī)之間的相互通信需要共同遵守一定的規(guī)則,這些規(guī)則就稱為網(wǎng)絡(luò)協(xié)議。

TCP/IP不是一個(gè)協(xié)議,而是一個(gè)協(xié)議簇的統(tǒng)稱,里面包含TCP協(xié)議IP協(xié)議, UDP協(xié)議,及http、FTP等。之所以命名為TCP/IP協(xié)議,因?yàn)門CP,IP協(xié)議是兩個(gè)很重要的協(xié)議,所以以TCP/IP命名。

TCP/IP協(xié)議的四層參考模型

應(yīng)用層:

應(yīng)用程序間溝通的層,如簡單電子郵件傳輸(SMTP)、文件傳輸協(xié)議(FTP)、網(wǎng)絡(luò)遠(yuǎn)程訪問協(xié)議

(Telnet),以及超文本傳輸協(xié)議(http) 等。

傳輸層:

在此層中,它提供了節(jié)點(diǎn)間的數(shù)據(jù)傳送服務(wù),如傳輸控制協(xié)議(TCP)、用戶數(shù)據(jù)報(bào)協(xié)議(UDP)等,TCP和UDP給數(shù)據(jù)包加入傳輸數(shù)據(jù)并把它傳輸?shù)较乱粚又?#xff0c;這一層負(fù)責(zé)傳送數(shù)據(jù),并且確定數(shù)據(jù)已被送達(dá)并接收。

互連網(wǎng)絡(luò)層:

負(fù)責(zé)提供基本的數(shù)據(jù)封包傳送功能,讓每一塊數(shù)據(jù)包都能夠到達(dá)目的主機(jī)(但不檢查是否被正確接收),如網(wǎng)際協(xié)議(IP)。

網(wǎng)絡(luò)接口層:

對實(shí)際的網(wǎng)絡(luò)媒體的管理,定義如何使用實(shí)際網(wǎng)絡(luò)來傳送數(shù)據(jù)。

長連接:

是客戶端與服務(wù)器建立連接后,進(jìn)行業(yè)務(wù)報(bào)文的收發(fā),始終保持連接狀態(tài),在沒有報(bào)文收發(fā)的情況下,可以使用心跳包來確認(rèn)連接狀態(tài)的保持,很多移動(dòng)端游戲類型都采用長連接,例如RPG,SLG, ACT等需要即時(shí)交互的游戲類型,使用TCP長連接協(xié)議。

短連接:

是客戶端與服務(wù)器需要進(jìn)行報(bào)文交互時(shí)進(jìn)行連接,交互完畢后斷開連接。例如在某種推圖游戲?qū)?zhàn)回合中,進(jìn)行不聯(lián)網(wǎng)的單機(jī)計(jì)算,當(dāng)在本關(guān)卡結(jié)束時(shí)再聯(lián)機(jī)交互結(jié)算報(bào)文,所以例如卡牌,回合制還有例如頁游等使用http短連接協(xié)議。

TCP協(xié)議和UDP協(xié)議對比:

TCP(Transmission Control Protocol,傳輸控制協(xié)議)是面向連接的協(xié)議, 在收發(fā)數(shù)據(jù)前,必須和

對方建立可靠的連接。

客戶端主機(jī)和服務(wù)器經(jīng)過三次握手進(jìn)行鏈接簡單描述如下:

第一次,客戶端向服務(wù)器發(fā)送連接請求。

第二次 服務(wù)器做出收到請求和允許發(fā)送數(shù)據(jù)的應(yīng)答。

第三次客戶端再次送一個(gè)確認(rèn)應(yīng)答,表示現(xiàn)在開始傳輸數(shù)據(jù)了。

UDP協(xié)議使用IP層提供的服務(wù)把從應(yīng)用層得到的數(shù)據(jù)從一臺(tái)主機(jī)的某個(gè)應(yīng)用程序傳給網(wǎng)絡(luò)上另一臺(tái)主機(jī)上的某一個(gè)應(yīng)用程序UDP協(xié)議有如下的特點(diǎn):

1、UDP傳送數(shù)據(jù)前并不與對方建立連接,即UDP是無連接的,在傳輸數(shù)據(jù)前,發(fā)送方和接收方相互交換信息使雙方同步。

2、UDP不對收到的數(shù)據(jù)進(jìn)行排序,在UDP報(bào)文的頭中并沒有關(guān)于數(shù)據(jù)順序的信息(如TCP所采用的

序號(hào)),而且報(bào)文不一定按順序到達(dá)的,所以接收端無從排起。

3、UDP對接收到的數(shù)據(jù)報(bào)不發(fā)送確認(rèn)信號(hào),發(fā)送端不知道數(shù)據(jù)是否被正確接收,也不會(huì)重發(fā)數(shù)據(jù)。

4、UDP傳送數(shù)據(jù)較TCP快速,系統(tǒng)開銷也少。

總結(jié):

從以上特點(diǎn)可知,UDP提供的是無連接的、不可靠的數(shù)據(jù)傳送方式,是一種盡力而為的數(shù)據(jù)交互服務(wù),而TCP是長連接,較可靠的網(wǎng)絡(luò)協(xié)議。

Socket本質(zhì)是對TCP/IP封裝的編程接口(API),使得程序員更方便地使用TCP/IP協(xié)議。Socket類提供了各種網(wǎng)絡(luò)連接,接收數(shù)據(jù),發(fā)送數(shù)據(jù)等相關(guān)方法給程序開發(fā)人員使用。

Socket類常用方法

?

BeginConnect()?? 開始一個(gè)對遠(yuǎn)程主機(jī)連接的異步請求

BeginReceive()?? 開始異步接收數(shù)據(jù)

BeginSend()????? 開始異步發(fā)送數(shù)據(jù)

Connect()??????? 建立與遠(yuǎn)程主機(jī)的連接

Send()??????????? 將數(shù)據(jù)發(fā)送到連接

Receive()??????? 接收數(shù)據(jù)到緩沖區(qū)

EndConnect()???? 結(jié)束異步連接請求

EndReceive()???? 結(jié)束異步接收

EndSeed()??????? 結(jié)束異步發(fā)送

Close()????????? 關(guān)閉socket連接和釋放所有關(guān)聯(lián)

?

protocolbuffer也叫Googlebuffer,protobuf,它是谷歌的數(shù)據(jù)交換格式,獨(dú)立于語言,原生支持Java,c++ ,python 等語言,一種高效率和優(yōu)秀兼容性的二進(jìn)制數(shù)據(jù)傳輸格式,使用第三方工具可以良好支持C#語言,由于它獨(dú)立于語言和平臺(tái),可以在unity客戶端和c++服務(wù)器,或python服務(wù)器之間進(jìn)行良好交互,故而是目前unity移動(dòng)端網(wǎng)絡(luò)游戲開發(fā)的主流數(shù)據(jù)交互協(xié)議。

?

基本語法

定義消息 message 關(guān)鍵字:message c2s login game request

{

required string account =1;required string password = 2;

}

1,2是分配標(biāo)識(shí)號(hào)

基本語法

字段關(guān)鍵字:

Package:包定義,名空間。

required:表示該值是必須要設(shè)置的。

optional:可選字段,消息格式中該字段可以有0個(gè)或1個(gè)值(不超過1個(gè))。

repeated:重復(fù)的值的順序會(huì)被保留,表示該值是一個(gè)集合。

注釋:

Proto文件可以使用//注釋不需要編譯的內(nèi)容。

?

序列化proto數(shù)據(jù)參考代碼:

public static byte[]Serialize(IExtensible msg)

{

byte[] result;

using (var stream = new MemoryStream())

{

Serializer.Serialize(stream,msg);result = stream.ToArray();

}

return result;

}

反序列化參考代碼:

public static TDeserialize<T>(byte[] message)

{

T result;

using (var stream = newMemoryStream(message))

{

result =Serializer.Deserialize<T>(stream);

}

return result;

}

?

2.13 性能優(yōu)化

程序性能的分析

程序性能的分析主要是對Profiler的講解。Profiler工具是Unity3D提供的一套用于實(shí)時(shí)監(jiān)控資源消耗的工具,通過使用該工具,我們可以直觀地查看程序運(yùn)行時(shí)各個(gè)方面資源的占用情況,并勻速找到影響程序性能的線程和函數(shù),再針對性的優(yōu)化

我們可以使用快捷鍵Ctrl+7快捷鍵或依次點(diǎn)擊“Window->Profiler”命令來調(diào)出Profiler窗口。

下方是Profiler工具中各項(xiàng)參數(shù)的意義:

CPUUsage

???GC Alloc?- 記錄了游戲運(yùn)行時(shí)代碼產(chǎn)生的堆內(nèi)存分配。這會(huì)導(dǎo)致ManagedHeap增大,加速GC的到來。我們要盡可能避免不必要的堆內(nèi)存分配,同時(shí)注意:1、檢測任何一次性內(nèi)存分配大于2KB的選項(xiàng);2、檢測每幀都具有20B以上內(nèi)存分配的選項(xiàng)。

??WaitForTargetFPS?-VSync功能所致,即顯示的是當(dāng)前幀的CPU等待時(shí)間。

??Overhead?-表示Profiler總體時(shí)間,即所有單項(xiàng)的記錄時(shí)間總和。用于記錄尚不明確的時(shí)間消耗,以幫助進(jìn)一步完善Profiler的統(tǒng)計(jì)。(一般出現(xiàn)在移動(dòng)設(shè)備,鋸齒狀為Vsync所致)

??Physics.Simulate?-當(dāng)前幀物理模擬的CPU占用量。

??Camera.Render?-相機(jī)渲染準(zhǔn)備工作的CPU占用量。

??RenderTexture.SetActive?-設(shè)置RenderTexture操作。比對當(dāng)前幀與前一幀的ColorSurface和DepthSurface,如果一致則不生成新的RT,否則生成新的RT,并設(shè)置與之對應(yīng)的Viewport和空間轉(zhuǎn)換矩陣。

??Monobehaviour.OnMouse_?-用于檢測鼠標(biāo)的輸入消息接收和反饋,主要包括 SendMouseEvents和DoSendMouseEvents。

??HandleUtility.SetViewInfo?-僅用于Editor中,作用是將GUI在Editor中的顯示看起來與發(fā)布版本上的顯示一致。

???GUI.Repaint?- GUI的重繪(盡可能避免使用Unity內(nèi)建GUI)。

??Event.Internal_MakeMasterEventCurrent?-負(fù)責(zé)GUI的消息傳送。

??CleanupUnused Cached Data?- 清空無用的緩存數(shù)據(jù),主要包括RenderBuffer 的垃圾回收和TextRendering的垃圾回收。

??RenderTexture.GarbageCollectTemporary?-存在于RenderBuffer的垃圾回收中,清除臨時(shí)的FreeTexture。

??TextRendering.Cleanup?-TextMesh的垃圾回收操作。

??Application.IntegrateAssets in Background?- 遍歷預(yù)加載的線程隊(duì)列并完成加載,同時(shí)完成紋理的加載、Substance的Update等。

??Application.LoadLevelAsyncIntegrate?- 加載場景的CPU占用。

??UnloadScene?-卸載場景中的GameObjects、Component和GameManager,一般用在切換場景時(shí)。

??CollectGameObjects?-將場景中的GameObject和Component聚集到一個(gè)Array 中。

??Destroy?-刪除GameObject或Component的CPU占用。

??AssetBundle.LoadAsyncIntegrate?- 多線程加載AwakeQueue中的內(nèi)容,即多線程執(zhí)行資源的AwakeFormLoad函數(shù)。

??Loading.AwakeFormLoad?-在資源被加載后調(diào)用,對每種資源進(jìn)行與其對應(yīng)的處理。

??StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace()?- 一般是由Debug.Log或類似API造成,游戲發(fā)布后需將Debug API進(jìn)行屏蔽。

??GC.Collect?-系統(tǒng)啟動(dòng)的垃圾回收操作。當(dāng)代碼分配內(nèi)存過量或一定時(shí)間間隔后觸發(fā),與現(xiàn)有的Garbage size及剩余內(nèi)存使用粒度相關(guān)。

???GarbageCollectAssetsProfile?-引擎在執(zhí)行UnloadUnusedAssets操作。

GPUUsage?

??Device.Present?-device.PresentFrame的耗時(shí)顯示,該選項(xiàng)出現(xiàn)在發(fā)布版本中。關(guān)于該參數(shù)有如下幾個(gè)常見問題:1、GPU的presentdevice確實(shí)非常耗時(shí),一般出現(xiàn)在使用了非常復(fù)雜的Shader等;2、GPU運(yùn)行是非常快的,而由于Vsync的原因,使得它需要等待較長時(shí)間;3、同樣是Vsync的原因,若其他線程非常耗時(shí),會(huì)導(dǎo)致該項(xiàng)等待時(shí)間很長,比如過量的AssetBundle加載時(shí)容易出現(xiàn)該問題。

??Graphics.PresentAndSync?-GPU上的顯示和垂直同步耗時(shí),該選項(xiàng)出現(xiàn)在發(fā)布版本中。

??Mesh.DrawVBO?-GPU中關(guān)于Mesh的Vertex Buffer Object的渲染耗時(shí)。

??Shader.Parse?-?資源加入后引擎對Shader的解析過程。

??Shader.CreateGPUProgram?-根據(jù)當(dāng)前設(shè)備支持的圖形庫信息來建立GPU工程。

Memory?

???GameObjects in Scene?- 當(dāng)前幀場景中的GameObject數(shù)量。

??otalObjects in Scene?- 當(dāng)前幀場景中的Object數(shù)量(除了GameObject外,還有Component等)。

??TotalObject Count?- Object數(shù)量 + Asset數(shù)量。

??SceneMemory?- 記錄當(dāng)前幀場景中各方面的內(nèi)存占用情況,包括GameObject、所有資源、各種組件及GameManager等。

?

幀調(diào)試器(FrameDebugger)的應(yīng)用

一個(gè)針對渲染的調(diào)試器。與其他的調(diào)試工具的復(fù)雜性相比,Unity原生的幀調(diào)試器非常的簡單便捷。我們可以使用它來看到游戲圖像的某一幀是如何一步步渲染出來的

需要使用幀調(diào)試器,我們首先需要在Window->Frame Debugger中打開幀調(diào)試器窗口。

GPU優(yōu)化分為四個(gè)部分:

1、DrawCall:Unity每次再準(zhǔn)備數(shù)據(jù)并通知GPU渲染的過程被稱為一次DrawCall。

優(yōu)化方案:批處理(接下來我們會(huì)做詳細(xì)的講解)

2、物理組件的使用

優(yōu)化方案:

? <1>設(shè)置一個(gè)合適的FixedTimestep

? <2>不要使用MeshCollider(從優(yōu)化的角度上來說,我們盡量減少使用物理組建)

3、GC(Garbage Collection垃圾回收)

優(yōu)化方案:減少對CPU的調(diào)用(稍后做講解)

4、代碼質(zhì)量

Unity中有兩種批處理方式:

動(dòng)態(tài)批處理

好處:一切處理都是自動(dòng)的,不需要我們自己做任何操作,而且物體是可以移動(dòng)的。

壞處:限制很多,可能一不小心我們就會(huì)破壞了這種機(jī)制,導(dǎo)致Unity無法批處理一些使用了相同材質(zhì)的物體。

靜態(tài)批處理

好處:自由度很高,限制很少。

壞處:可能會(huì)占用更多的內(nèi)存,而且經(jīng)過靜態(tài)批處理后的所有物體都不可以再移動(dòng)了。

GPU優(yōu)化

1、減少繪制的數(shù)目

解決方案:模型的LOD技術(shù)、遮擋剔除技術(shù)

2、優(yōu)化顯存的帶寬

模型的LOD技術(shù)

LOD(Level of Detail)技術(shù)。這種技術(shù)的原理是,當(dāng)另一個(gè)物體離攝像機(jī)很遠(yuǎn)時(shí),模型上的很多細(xì)節(jié)是無法被察覺到的。因此,LOD允許當(dāng)前對象逐漸原理攝像機(jī)時(shí),減少模型上的面片數(shù)量,從而提高性能。

在Unity中,我們可以使用LODGrounp組件來為一個(gè)物體構(gòu)建一個(gè)LOD。我們需要為同一個(gè)對象準(zhǔn)備多個(gè)包含不同細(xì)節(jié)程序的模型,然后把它們賦給LODGroup組件中的不同等級,Unity就會(huì)自動(dòng)判斷當(dāng)前位置上需要使用哪個(gè)等級的模型。

同樣它的缺點(diǎn)同樣是需要占用更多的內(nèi)存,而且如果沒有調(diào)整好距離的話,可能會(huì)造成模擬的突變。

遮擋剔除技術(shù)

實(shí)際開發(fā)過程中,每一個(gè)場景往往伴隨著大量的對象,其中相當(dāng)一部分對象是不在攝像機(jī)拍攝范圍內(nèi)的,進(jìn)行著一部分對象的繪制是完全沒有必要的。強(qiáng)大的Unity3D引擎提供了非常實(shí)用的遮擋剔除技術(shù),使不被拍攝到的點(diǎn)或面不送入渲染管線繪制。

1、Resource資源不用的要?jiǎng)h除,紋理、網(wǎng)格、音頻等等;

2、在CPU壓力不是特別大的時(shí)候,重置GameObject、組件等占用的內(nèi)存;

3、在打包AssetBundle的時(shí)候,可以考慮bundle的壓縮。

總結(jié)

以上是生活随笔為你收集整理的转载unity的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。