Unity 4.3 2D 教程:新手上路
?
如果你嘗試用更早版本的Unity來制作2D游戲,那當(dāng)然沒問題,但你也知道必須先解決一些問題。
可能你通過給quad應(yīng)用紋理,使用腳本調(diào)整紋理參數(shù)來實(shí)現(xiàn)一些動畫。由于它們在3D環(huán)境,如果添加物理效果,你需要保證它們在同樣的深度才能互相作用,同時還要確保它們沒有意外的繞x或y軸旋轉(zhuǎn)。再者,你可能添加Unity的Asset Store中各種各樣的元件,例如2D Toolkit或者Orthello 2D Framework,它們都擁有一些很棒的特性,但還是需要你來控制。
現(xiàn)在Unity 4.3本地包提供了一個新的維度,你可以工作在2維環(huán)境,同時原先的一切仍然可用。
這是探索Unity2D系類教程的第一篇,通過這一系列教程,你將學(xué)會制作一個名叫Zombie Conga的游戲,這是一個2D卷軸游戲,其中有一個逍遙自在只想跳舞的僵尸,一個想在來世變成僵尸的貓,和一個想阻止它們的老處女。
學(xué)習(xí)怎樣在Unity 4.3中使用新的內(nèi)置2D toolset制作一個2D游戲!
這個Unity 4.3 3D的教程重點(diǎn)放在Unity的新類型——Sprite,所有關(guān)于它你需要知道的知識,你都將學(xué)到,而且,之后你會學(xué)到如何使用Unity的 Animators 控制動畫,你也會了解到Unity的新2D物理支持。
還有很長的路要走,你應(yīng)該起航了。
Note:這個教程假定你至少有一些Unity的經(jīng)驗(yàn),你應(yīng)該知道Unity的基本操作界面,GameObjects 和 Components,而且你也應(yīng)該知道一些操作,比方說:
“通過從 Project browser 拖一個貓到 Hierarchy 來添加到你的場景”
如果你覺得它聽起想胡扯,或者你想讓你拖動這只貓的時候有一個更好的心態(tài),你可能要先閱讀一下Unity的基本簡介,比如這個。
最后,注意這個教程是面向OS X的,如果你在Windows下工作,不用擔(dān)心,因?yàn)閁nity中大多數(shù)操作都是相同的,可能會有一點(diǎn)點(diǎn)不同(比方使用Windows Explorer來代替Finder),但我相信你能搞定,或者你干脆你和我一樣用OS X也行。
推開大門
Unity在4.3版引入了本地2D工具包(免費(fèi)和專業(yè)版都有),所以確保你安裝的是最新版本,你能在Unity的官網(wǎng)下載到。
你也需要一些素材來制作2D游戲,幸運(yùn)的是,Mike Berg制作了一些很酷的圖片為Zombie Conga,下載Mike的作品,解壓它到某個方便的地方。
Note:你可以使用這個教程提供的素材,音樂和音效在你想做的游戲中,但是必須注明來源在你的游戲中:“Artwork/sounds: from iOS Game by Tutorials book, available at http://www.raywenderlich.com”
創(chuàng)建你的游戲
打開Unity通過選擇 File\New Project…. 點(diǎn)擊出現(xiàn)的 Project Wizard 對話框中的 Create new Project 選項(xiàng)卡中的 Set… 創(chuàng)建一個新的工程。
命名為ZombieConga,選擇一個文件來創(chuàng)建它,點(diǎn)擊 Save。
最后,選擇名稱為 Set up defaults for: 組合框中的2D,就像下面這樣,然后點(diǎn)擊 Create Project。
上面提到的組合框是第一個與2D有關(guān)的特性,它允許改變你項(xiàng)目的默認(rèn)素材資源輸入設(shè)置,但是到目前為止,我們還沒有它正常工作。好在你可以在工程中輕松改變這個設(shè)置。
為了確保這個設(shè)置正確,同時讓你知道在哪里修改這個設(shè)置,選擇 Edit\Project Settings\Editor 來在 Inspector 打開 Editor Setting。在 Default Behavior Mode 段,把 Mode 的值選擇為2D,就像這樣。
這個 Default Behavior Mode 定義了你項(xiàng)目的默認(rèn)素材資源輸入設(shè)置,當(dāng)設(shè)置為3D時,Unity假設(shè)你想將圖像文件導(dǎo)入為 Texture (例如PNG文件),當(dāng)設(shè)置為2D時,Unity假定你想將圖像文件導(dǎo)入為? Sprite,貫穿這套教程,你將了解到關(guān)于 Sprite 資源和輸入設(shè)置的更多細(xì)節(jié)。
2D場景視圖
你將面對的下一個2D特性是 2D 開關(guān)按鈕在 Scene 視圖的控制條上。
點(diǎn)擊 2D開關(guān)按鈕 來切換到2D模式,就想這樣:
這個按鈕控制 Scene 視圖 camera 在透視投影和正交投影中切換,它們之間有什么不同?
當(dāng)使用透視投影時,物體對 camera 呈現(xiàn)近大遠(yuǎn)小,就像在真實(shí)世界用眼睛觀察中一樣。然而,當(dāng)使用正交投影時,物體距離 camera 的并距離不影響它的大小。因此在2D模式,一個物體從距離 camera 遠(yuǎn)處移動到近處,它的大小不會因?yàn)槲恢枚?/p>
接下來的圖片展示出兩種 Sence 視圖的不同,它們都是從相同的位置觀察相同的立方體,上面這幅是使用2D模式,下面的不是。
這個截圖也顯示出2D模式隱藏了讓你改變 camera 透視投影和正交投影的 Scene Gizmo。使用2D模式,上方是y軸正方向,右方是x軸正方向。
Important:開關(guān)的設(shè)置不影響你游戲最終運(yùn)行的結(jié)果,只是在 Scene 改變 camera 的呈現(xiàn)方式,但它仍然在我們框選物體時非常有用。當(dāng)你制作2D游戲的時候你可能在兩種模式中來回切換,甚至有時制作3D游戲也需要,但是這個教程的插圖全部都是截取自2D模式。
Question:跟著截圖一步步做感覺還好嗎?你完全可以自己安排Unity的界面布局使你操作更輕松,試試吧。
Sprites,使這一切變得容易
看看下面的動畫就能發(fā)現(xiàn),用Unity的新特性添加 sprite 到場景中的過程極其容易。
步驟 1:拖動 cat.png 從你的文件夾窗口到 Scene 視圖,就想這個演示一樣。
步驟 2:使用你所省下的時間給Unity的開發(fā)人員發(fā)一份感謝信。
啊!那很棘手!如果你失敗了,不要難過,只要重新閱讀這段教程,再試一次。
Note:想知道為什么動畫下方有兩只貓?不要著急,待我慢慢道來。
依賴Uniyt的默認(rèn)輸入設(shè)置使這個操作變得十分簡單,你不用時常的更正你的圖片設(shè)置。無論如何,這說明Unity的新特性使在2D環(huán)境工作驚人的輕松!在接下來的教程將覆蓋所有你在Unity2D模式工作的需要知道的知識。
Sprite 資源
在 Hierarchy 選擇 cat,同時目光轉(zhuǎn)向 Inspector,你的 Inspector 中非常有可能坐標(biāo)和下面這張截圖不同,但是不用在意它。你要注意的是,Unity為了在 Scene 顯示這只貓,為這個 GameObject 添加了一個 Sprite Render 組件。
同時不易察覺到的是,Unity也創(chuàng)建了一個幾何圖形為這個對象,在Unity免費(fèi)版中,每個 Sprite 獲得一個簡單的矩形,但Unity專業(yè)版為每個 Sprite 創(chuàng)建一個簡易的 mesh 來適應(yīng)圖片不清晰的像素邊界。注意在Unity專業(yè)版中僵尸身上藍(lán)色的 mesh。
通過創(chuàng)建一個這樣的 mesh 而不是應(yīng)用你的 Sprites 作為紋理在一個 quad 上,Unity可以改進(jìn) Scene 的渲染效率,意味著他將產(chǎn)生更少的像素,并且當(dāng)使用Unity專業(yè)版的 Sprite Packer 時,它能把這些紋理打包的更緊密。你將在教程的尾部了解它。
Note:別被這突然出現(xiàn)的僵尸嚇著了,我用僵尸當(dāng)例子只是因?yàn)樗?mesh 比貓的更有趣。
你將學(xué)習(xí)關(guān)于 Sprite Render 的屬性貫穿這個教程,但現(xiàn)在,看這個 Sprite 屬性。這里顯示了分配給Sprite Render 的 Sprite 資源的名字,一次只能分配一個,但在后面你會學(xué)到如何通過更新這個屬性來實(shí)現(xiàn)動畫。
在下面這個圖片中,正如你所見的那樣,這個 cat GameObject 有一個 Sprite 屬性,同時有一個名叫 cat 的資源分配給了這個渲染器。
保持 Prioject 可視,然后點(diǎn)擊 Inspector 中的 Sprite 屬性內(nèi)部,來定位和高亮這個 Sprite 資源在 Project browser,就像這樣:
Note:這個高亮框在幾秒后漸漸消失,所以如果你沒注意到,就再點(diǎn)一下,當(dāng)然,我們的的工程中只有這一只貓,你不太可能沒看到。
就像剛才的截圖中的一樣,Unity在 Project browser 中高亮的項(xiàng)目名叫 cat,而且它還有一個子對象也叫 cat。我們有兩只貓?沒錯,可能有點(diǎn)迷惑。我來解釋下:
- 父 cat 是一個紋理資源,它與你的源素材文件一致(cat.png),用來創(chuàng)建 Sprite 從這個素材,你可以看到它的縮略圖。
- 子 cat 是一個當(dāng)導(dǎo)入 cat.png 時由Unity創(chuàng)建的 Sprite 資源,在我們的例子中,它只有一個,因?yàn)閁nity僅僅從這個文件創(chuàng)建了一個 Sprite,但是在后面幾章,你將了解到如何從一個圖像文件創(chuàng)建多個 Sprite。
Note:我們清楚Unity渲染的是 Sprite 對象,Sprite 類實(shí)際上僅僅包含一個需要被訪問的 Texture2D 對象的信息,就是我們儲存的真正圖像數(shù)據(jù)。如果你想在運(yùn)行時刻生成 Sprite,你可以動態(tài)創(chuàng)建你自己的 Texture2D 對象,但關(guān)于這些的討論將在未來的教程中。
你可以通過從電腦中拖拽素材到你的 Scene 視圖(或者Hierarchy,如果你喜歡)來添加 Sprite。但是通常,將素材添加進(jìn)工程總是在添加進(jìn) Scene之前。
把你下載的剩下的圖片添加到你的工程中:background.png, enemy.png, zombie.png。
通過拖動 Project browser 中的 enemy 到 Hierarchy 來添加一個敵人到你的 Scene 中。
就想貓一樣,Project browser 中有兩個名叫 enemy,但不要緊,隨便拖哪個都行,因?yàn)橥蟿?Sprite asset(子對象)時,總會使用這個 Sprite,而拖動 Texture asset(父對象)時,會使用第一個子對象,在我們現(xiàn)在的情況,其實(shí)都一樣。
在 Hierarchy 中選擇 enemy,設(shè)置它的 Transform 組件中的 Position 為(2,0,0),如圖。
在你的場景變亂之前,在 Hierarchy 中選擇 cat,設(shè)置它的 Postition 為 (0,2,0),如圖。
你的場景現(xiàn)在看起來可能是這樣的。
最后拖動 background 從 project browser 到 Hierarchy,同時設(shè)置它的 Position 為(0,0,0),如圖。
我們等會調(diào)整底圖的質(zhì)量,所以先不要在意它現(xiàn)在看起來不是很清晰(悄悄告訴你,添加 background.png 是Unity默認(rèn)設(shè)置不正確的地方之一),你的 Scene 視圖現(xiàn)在看起來是這樣的:
不要被因?yàn)槟銢]在 Sence 視圖中看到貓和老處女而報警。他們只不過被埋在了沙灘下,你很快就會把他們挖出來。在你挖出他們之前,我們要開始分尸!不對,是僵尸的 Sprite,就在那!
切割 Sprite Sheets
你已經(jīng)導(dǎo)入了 zombie.png 到你的項(xiàng)目,但是這個文件和別的文件不同,它不是只有一只僵尸,它有好幾個僵尸,如圖。
這樣的文件常常被叫做 Sprite Sheet,你會想讓Unity為每個圖中的獨(dú)立個體創(chuàng)建一個單獨(dú)的 Sprite。
在 Project browser 中展開 zombie,如圖。Unity只創(chuàng)建了一個子對象——一個 Sprite 包含了全部的圖像,這不是我們想要的結(jié)果。
好在,Unity提供了解決的辦法,你可以用來對付這種 Sprite Sheet,在 Project browser 中選擇頂層的 zombie 打開 Import Setting 在Inspector。
設(shè)置 Sprite Mode 為 Multiple(如圖),點(diǎn)擊 Apply。
選擇這個選項(xiàng)會顯示一個 Sprite Editor 按鈕,同時 Pivot 屬性消失。
因?yàn)槊總€獨(dú)立的 Sprite 將在其他地方定義他們各自的 pivot point(軸心點(diǎn))。
注意 Project browser 這個 zombie 紋理已經(jīng)沒有了子對象(如下圖),它的右邊也沒有了小箭頭。
在這種狀態(tài)下,zombie 紋理是不可用的,如果你嘗試把它拖動到 Hierarchy,會有一個消息告訴它沒有 Sprite。這是因?yàn)槟阈枰嬖VUnity,你將如何分割這個 sprite sheet。
保持 Project browser 里的 zombie 選中,點(diǎn)擊 Inspector 里的 Sprite Editor 來打開下面的窗口。
這個 Sprite Editor 視圖可以讓你把這個圖片分割為互相獨(dú)立的 sprite。點(diǎn)擊窗口左上角的 Slice 按鈕,開始分割 sprite,就如下圖。
Unity可以自動找到你圖片中的 sprite,但你仍可以調(diào)整它的結(jié)果。現(xiàn)在我們使用默認(rèn)設(shè)置,點(diǎn)擊 Slice。如圖。
Unity使用透明的邊框圈定出圖片中可能存在的每個 sprite,它發(fā)現(xiàn)了四個 spites。
經(jīng)過我的測試,當(dāng)每個個體直接有明確的空白的時候,Unity的自動分割效果最好。注意Untiy在下面這個圖片中只找到了微笑的表情,但之后的圖片中找到了三個 sprite。
Unity沒有找到所有的 sprite,因?yàn)樗荒苁褂脹]有交集的邊界框出每個元素
Unity找到了所有的 sprite,因?yàn)樗芸虺雒總€元素
上面的圖片說明,你應(yīng)該恰當(dāng)?shù)陌才拍愕?sprite sheets,它也說明,為什么Mike要這樣畫這張圖。
點(diǎn)擊隨便一個Unity圈出的 sprite 來編輯它的詳細(xì)屬性,包括它的名字,坐標(biāo),邊界,和軸心點(diǎn)。當(dāng)選擇了第二個 sprite 時,會出現(xiàn)下面這張圖的樣子。
你可以在這個窗口里修改這些設(shè)置,比如直接在圖片上調(diào)整邊界,設(shè)置軸心點(diǎn)。
通常,在你修改完成后,你要點(diǎn)擊 Sprite Editor 視圖右上角的 Apply 或 Revert 來保存和恢復(fù)它。
雖然Unity自動做的很好,但我們不并不想用它自動的配置。這個 zonbie.png 中的每個元素范圍都是等大的矩形,在Unity中有方法可以處理這種情況。
點(diǎn)擊 Sprite Editor 視圖左上角的 Slice 按鈕再次打開分割設(shè)置,但是這次,把 Type 設(shè)置為 Grid,這時它會變成下圖這樣。
左上角彈出的小視圖中,Pixel size 屬性可以讓你指定網(wǎng)格的大小,X是每個格子的寬度,Y是高度。Unity 將使用這些數(shù)值來等距分割你提供的圖片。把X設(shè)置為157,Y設(shè)置為102。如圖。
點(diǎn)擊 Slice,Unity找到了四個 sprite。
你仍然可以選擇其中的一個就像剛才那樣設(shè)置它們的詳細(xì)屬性,但目前,這不重要。
點(diǎn)擊 Sprite Editor 右上角的 Apply 按鈕,應(yīng)用你的操作。注意 Project browser 視圖內(nèi) zombie 發(fā)什么了什么變化。它現(xiàn)在擁有了四個子對象,分別名叫 zombie_0,zombie_1 等,就像下圖這樣。
雖然 zombie 紋理被分割成為了多個 sprite,但把他們添加進(jìn)場景的方法沒什么不同,你仍然可以把他們直接拖到 Hierarchy 來創(chuàng)建你的 GameObject。這里告訴你一個新的方法。
通過選擇 GameObject\CreateEmpty 創(chuàng)建一個新的敵人 GameObject。重命名為 zombie,設(shè)置 Position 為 (-2,0,0),如圖。
在 Hierarchy 中保持 zombie 選中。點(diǎn)擊 Inspector 中的 Add Component,在出現(xiàn)的菜單中選擇 Rendering,然后選擇 Sprite Render 來添加一個 Sprite Render 組件,如圖。
點(diǎn)擊 Sprite Render 的 sprite 屬性旁的那個小圓圈圖標(biāo),打開 Select Sprite 對話框。那個圖標(biāo)是這樣的:
這個出現(xiàn)的對話框有兩個選項(xiàng)卡,分別是 Assets 和 Scene,分別包括所有你項(xiàng)目中和現(xiàn)在場景中的所有 sprite。
切換到 Assets 分頁,選擇 zombie_0 分配給這個屬性來讓 Sprite Render 組件渲染,如圖。
在場景視圖,你就能看到一個僵尸悠閑的站在沙灘上,此刻,沙灘下的某處埋著老處女和她的貓。哈哈。
所有需要的元素都已經(jīng)導(dǎo)入場景。是時候來解決一些問題了。
配置你的 Game 視圖
Zombie Conga 的所有素材是為了制作iPhone游戲,意味著它在特殊的分辨率下看起來才會更好。為了適應(yīng)iPhone的環(huán)境,把 Game 視圖的分辨率大小設(shè)置為 1136x640。
修改 Game 視圖的寬高比或者分辨率都是使用 Game 視圖的控制條的那個下拉菜單,就是圖中高亮的地方。
點(diǎn)開這個菜單,里面是幾個默認(rèn)提供的設(shè)置,如果里面已經(jīng)有了 1136x640,選擇它就行了。如果沒有,點(diǎn)擊菜單底部的 + 按鈕,如圖。
創(chuàng)建一個新的分辨率設(shè)置,將 Type 設(shè)置為 Fixed Resolution,設(shè)置寬度和高度分別為1136和640。如圖。
點(diǎn)擊 OK,在菜單中選擇這個新的設(shè)置。
你的 Game 視圖現(xiàn)在看起來應(yīng)該是這樣:
Note:可能你的視圖看起來和這個截圖不是完全一樣,因?yàn)閁nity重新按照你設(shè)置的寬高比調(diào)整了視圖的大小,但你仍可以在視圖中看到相同的內(nèi)容。
顯然,它不是很正確,你在這里已經(jīng)看到了三個不同問題,你將一一更正它。
首先開始修正第一個問題。
修正你的 Camera 的屬性
在2D游戲中,你通常想使用正交投影而不是透視投影。你在之前的章節(jié)已經(jīng)知道了這兩個 Scene 視圖的屬性,但你可能沒意識到,Unity可能會默認(rèn)設(shè)置你的攝像機(jī)為透視投影。
在 Hierarchy 中選擇 Main Camera,然后,在 Camera 的組件中,確保 Projection 已經(jīng)設(shè)置到了 Orthographic。
通過設(shè)置它的 Transform 組件的 Position 為(0,0,-10),來將攝像機(jī)面朝場景中心垂直放置。你的 Inspector 面板現(xiàn)在應(yīng)該看起來是這樣:
同時你的 Game 視圖現(xiàn)在看起來應(yīng)該是這樣:
現(xiàn)在看看,這和使用透視投影的設(shè)置看起來沒什么太大的不同。如果 sprite 不會隨著它距離攝像機(jī)的距離而改變大小,那要如何放大這個底圖讓它鋪滿整個屏幕呢?你可以試試縮放你的 GameObject,但這里有一個更好的解決辦法——改變攝像機(jī)的 Size 到適當(dāng)?shù)闹怠?/p>
攝像機(jī)的 Size 定義了它視野的基本尺寸。這個數(shù)字的大小是從視圖中心到頂邊的距離。換句話說,就是視圖高度的一半。而寬度是在運(yùn)行時由寬高比計算出來的。如圖。
在這個例子中,你想底圖完美填滿整個屏幕從上到下,同時允許水平滾動。底圖的高度是640像素,所以一半就是320像素。這不就是我們要的數(shù)值嗎?
還沒完。
在 Project browser 中選擇父 background 來在 Inspector 查看它的 Import Settings。
看這個 Sprite 渲染器的 Pixels to Units 屬性。它現(xiàn)在使用的是默認(rèn)的100,如圖。
在Unity中,單位不是很重要,相當(dāng)于屏幕的像素。反而你更經(jīng)常使用相對大小。可能假設(shè)一個單位長度是一米。對于 Sprites,Unity使用 Pixel to Units 來定義除去比例后的大小。
例如,想象導(dǎo)入了一個500像素寬的 Sprite,下面這個表展示了為 Pixels to Units 使用不同的值時候,你的 GameObject 在x軸上渲染出的寬度。
background.png 的高度是640像素,并且它的 Pixel to Unity 屬性的值是100,所以 background 對象在 Hierarchy 將為6.4個單位長度高,然而,這個正交攝像機(jī)的 Size 屬性是它視野范圍高度的一半,所以應(yīng)該把它設(shè)置為 background 對象高度的一半,即為 3.2個單位長度。
在 Hierarchy 中選擇 Main Camera,設(shè)置 Camera 組件中的 Size 屬性為 3.2,如下圖。
現(xiàn)在,你的背景圖片完美的適應(yīng)了整個視野,如下圖。
這時,你會發(fā)現(xiàn)一些圖像質(zhì)量上的問題。下面這兩張圖指出了一些地方,對比它們應(yīng)當(dāng)顯示的樣子,看看我們的圖片。
我們現(xiàn)在的海灘
期望得到的海灘
上面的圖片顯示的問題是由于底圖紋理的壓縮設(shè)置,你可以通過修改這個文件的 Import Setting 來修正它。
修正你的 Import Setting
選擇 Project browser 中的父 background 對象,再次打開它的 Import Setting,但這次,看到 Inspector 底部的 Preview 面板了嗎?
Preview 面板顯示了導(dǎo)入的紋理,連同紋理的大小,顏色,信息,和內(nèi)存使用量。你可以看下面這個截圖,這個 background 紋理現(xiàn)在的大小是 1024x320 像素,但 background.png 的大小是 2048*640 像素!這說明Unity把原始如圖縮小了一半,為了把他放在 1024*1024 的紋理中。
為了修正你的紋理,看到那個 Import Settings 下方的選擇夾里的 Max Size 和 Fortmat 屬性了嗎?如圖。
Max Size 定義了紋理的最大大小,是一個正方形,它的默認(rèn)大小是1024像素,同時,Format 指定了色彩深度,它的默認(rèn)值是 Compressed。
你可以為每種平臺設(shè)置不同的值,(例如:IOS,Web,Android),但對于我們這個應(yīng)用,只用考慮 Default 選項(xiàng)卡就行了。
在 Default 選項(xiàng)卡中,修改 Max Size 為 2048,之后點(diǎn)擊 Apply。你的設(shè)置看起來應(yīng)該是這樣。
立刻,你會注意到 Scene 和 Game 視圖都更棒了,因?yàn)?background 壓縮減少了。下面這張圖顯示了 Game 視圖的樣子。
注意在 Inspector 面板的 Preview 區(qū)域顯示了這個 background 紋理現(xiàn)在是 0.6MB,之前它是 160KB。
增加紋理的大小使它的內(nèi)存使用量BMW之前的四倍(大致估計)。
對于有些紋理,你可能想調(diào)整它的 Format 值來提高它的色彩質(zhì)量,但那將進(jìn)一步增加它的大小。例如,如果你把 background 的 Format 改為 16bit,你會發(fā)現(xiàn)紋理的大小增長到了 2.5MB,當(dāng)改為 Truecolor 時它為 3.8MB。
然而,如果你看下面這兩個版本的 background,你會發(fā)現(xiàn)壓縮過的圖片和真彩色的圖片幾乎一樣好。
壓縮過的紋理
真彩色紋理
因?yàn)閴嚎s過的圖片看起來足夠好,而且占用內(nèi)存少,所以允許 Format 的值為 Compressed。當(dāng)你自己制作游戲的時候,盡量對這些設(shè)置嘗試不同的組合,選擇一個占用內(nèi)存最少,還能達(dá)到你預(yù)期效果的設(shè)置。
那么,攝像機(jī)部署就位,底圖看起來清晰。現(xiàn)在是時候從沙灘挖出那個老處女和她的小貓咪了!
控制渲染順序
你仍然不能看到老處女和貓是因?yàn)閳鼍鞍阉麄儺嬙诘讏D之后,你可以調(diào)整游戲?qū)ο蟮腪軸坐標(biāo)讓它更接近攝像機(jī)從而顯示在前面。事實(shí)上,這種方法可以完美的解決這個問題。但對于渲染順序的問題,現(xiàn)在Unity里有一個很棒的特性,你應(yīng)該試試:Sorting Layers。
在 Hierarchy 選擇 cat,可以看到的 Sprite Render 的 Sorting Layer 屬性被設(shè)置為 Default。如圖。
點(diǎn)擊 Sorting Layer 的下拉框,你會看到你的項(xiàng)目中定義了一個排序?qū)?#xff0c;我們現(xiàn)在選擇的正是其中的 Default。
你也會看到一個名叫 Add Sorting Layer… 的選項(xiàng),點(diǎn)擊它。
這會帶你來到 Tags&Layer 編輯器,你可以從Unity的很多地方來到這個地方。只展開 Sorting Layer 的分組,如圖:
點(diǎn)擊 Sorting Layer 分組中的 + 來創(chuàng)建一個新的名叫 Cats 的排序?qū)印M瑯拥姆椒?#xff0c;再創(chuàng)建兩個層分別叫做 Enemies 和 Zombie。你的編輯器現(xiàn)在會看起來像這樣:
這些層定義了渲染的順序,名叫 Defalut 的 Layer0 在最底層,名叫 Cat 的 Layer 1,在它之上,以此類推。
目前,所有你添加的游戲?qū)ο蠖际鞘褂玫?Default 的排序?qū)印τ?background 對象這沒問題,因?yàn)槲覀兙褪窍胨谒性睾竺?#xff0c;但你需要改變其他對象的排序?qū)訉傩浴?/p>
在 Hierarchy 中選擇 cat,設(shè)置它的 Sorting Layer 為 Cats,你立刻會注意到那只貓?jiān)?Scene 和 Game 視圖都可以看到了。
當(dāng)貓的排序?qū)颖桓臑?Cat …
…立即就能看到貓了
在 Hierarchy 中選擇 enemy,設(shè)置它的 Sorting Layer 為 Enemies。這樣,老處女和她的貓一起在沙灘上散步,誰知道呢,或許他們在度假?
最后在 Hierarchy 中選擇 zombie,設(shè)置它的 Sorting Layer 為 Zombie 確保你的游戲?qū)ο笤陧敳?#xff0c;你的 Game 視圖現(xiàn)在會看起來像這樣:
Note:Sprite Renderer 也有一個 Order in Layer,你可以使用它來為游戲?qū)ο笾付ㄅ判蝽樞颉?/p>
但你不會用到它,因?yàn)?Zombie Conga 沒有任何 Z軸的戰(zhàn)斗的問題,看起來Unity是按照被添加進(jìn) Scene 中的順序來渲染對象的,所以最新添加的對象總是在最頂層,對象不會在這幀在另一個對象的前面而下一幀又到它后面,這個特性對我們的游戲很有用。
給 Sprite 使用腳本
你已經(jīng)把這些 sprite 放在沙灘上了,但他們什么都不能做。通過這章,你將編寫兩個小腳本:一個是僵尸擁有的動畫,另一個可以讓玩家控制僵尸移動。你將在這一系列剩下的教程中逐漸完善這個游戲。
Note:你將編寫C#(讀作see-sharp)腳本的代碼,如果你更喜歡 JaveScript,你可以很輕松的轉(zhuǎn)換過去。如果你需要什么幫助,可以在評論區(qū)自由發(fā)言。(我從沒用過Unity支持的Boo腳本語言,這都看你喜好)
讓 Sprite 動起來!
首先你要添加一個簡單的僵尸動畫腳本。選擇 Hierarchy 中的 zombie,點(diǎn)擊 Inspector 中的 Add Component,在彈出的菜單中選擇 New Script,將這個腳本命名為 ZombieAnimator,Language 選擇為 CSharp,點(diǎn)擊 Create And Add。操作步驟如圖。
Note:你在這系列教材的第二部分會使用Unity的 Animator 來代替這個基本的動畫腳本。但是這個例子可以讓你了解到如何在腳本中訪問 SpriteRenderer。
使用 MonoDevelop 打開 ZomebieAnimator.cs。這是Untiy自帶的代碼編輯器。打開腳本有好幾種方法,但無論何時,最簡單的是雙擊 ZombieAnimator,或者保持 zombie 選中,在 Inspector 或 Project browser,如圖。
Inspector 中的腳本動畫腳本
Project browser 中的腳本動畫腳本
在 Zombie Conga 中你的僵尸只是簡單愚蠢的走路,就像你想象中的好僵尸。為了實(shí)現(xiàn)這個簡單的動畫,你需要一個 Sprite 數(shù)組,和一個循環(huán)播放它的速度。為了儲存這些信息,給 ZombieAnimator 添加下面這兩個共有變量。
public Sprite[] sprites; public float framesPerSecond;Note:在C#中,你可以把這些代碼放置在類定義的花括號之內(nèi),并且在函數(shù)定義的外部的任何地方,技術(shù)上沒有問題。但通常良好的做法是放置類定義中第一個函數(shù)之前。
Public 變量會暴露在Unity的編輯器中,你可以使用Unity的操作界面直接修改它的值而不用修改代碼,甚至運(yùn)行的時候也是。你等下會知道這是多么容易。
你將通過設(shè)置不同的 Sprite 給你的 GameObject 的 SpriteRenderer 組件制作一個動畫。為了代替在每次 Update里獲取 Component,你將在腳本第一次運(yùn)行的時候緩存它。
添加這樣一個私有變量給你的 ZombieAnimator 腳本:
private SpriteRenderer spriteRenderer;私有變量不會暴露在Unity的編輯器中,在這個例子中,你要初始化這個變量,添加下面的代碼到你的 Start 函數(shù)。
spriteRenderer = renderer as SpriteRenderer;你的腳本繼承自 MonoBehaviour,它會讓你能夠訪問一個名叫 renderer 的變量。對于顯示的 GamObject,renderer 就是 SpriteRenderer 組件。因此在給變量賦值之前你需要把 renderer 類型轉(zhuǎn)換到 SpriteRenderer。
Note:為了更佳的游戲性能,這些優(yōu)化是非常有必要的。緩存一些頻繁使用的對象是最常用到的優(yōu)化方法。常見的例子是 GameObject 的 Transform,場景的 Main Camera,或者別的什么,其他的使用 GameObject.Find 來訪問。保持一切簡單明了,這是教程中你唯一緩存對象的地方。這種情況下,這樣做是有意義的。
為了完成這個腳本,添加這幾行代碼到 Updata:
int index = (int)(Time.timeSinceLevelLoad * framesPerSecond); index = index % sprites.Length; spriteRenderer.sprite = sprites[ index ];它使用自從本關(guān)開始到目前為止的秒數(shù)(更多信息請查閱 Time 的類文檔)乘上每秒渲染的幀數(shù),如果這些幀儲存在一個無限長的數(shù)組中,那你會得到現(xiàn)在需要顯示的幀的索引。
但沒那么美好,因?yàn)槟阒罃?shù)組不可能是無限的,你需要在到達(dá)末尾的時候回到數(shù)組的開始,執(zhí)行求余操作,得到兩個整數(shù)相除的余數(shù)。
換句話說,你得到的所有數(shù)值都在0到比數(shù)組長度小1的范圍內(nèi),那會是一個 Sprite 數(shù)組的有效索引(當(dāng)然假設(shè)數(shù)組的長度不為0)。
你在 MonoDevelop 中寫完后,保存腳本(File\Save)回到Unity中。
Note:Unity會自動編譯你的腳本,如果在 Console 中有什么錯誤,先改正它再繼續(xù)。
在 Hierarchy 中選擇 zombie,留心它的 Zombie Animator(Script) 組件,那個區(qū)域展示了你的兩個共有變量。謝謝,Unity!
現(xiàn)在,Sprite 數(shù)組(Unity使用在詞之間添加了空格的變量名)沒有項(xiàng)目。你的 Sprite 資源名叫 zombie_0 到 zombie_3。這些是打算按順序設(shè)置的圖片,所以需要它們放到 Sprite 數(shù)組里來制作一個永遠(yuǎn)循環(huán)的動畫。
為了定義這個循環(huán)的動畫,你需要添加下面這六個元素到 Sprite 數(shù)組:zombie_0,zombie_1,zombie_2,zombie_3,zombie_2,zombie_1。有幾種不同的方式來實(shí)現(xiàn),看你喜歡哪個。
保持 Hierarchy 中的 zombie 選中,點(diǎn)擊 Inspector 右上角的 lock 按鈕,鎖定這個視圖。如圖。
即便你選擇了其他的對象,都會保持顯示現(xiàn)在的 Inspector 信息。在這種情況下,這是個十分有用的功能。
在 Project browser 中展開你的 zombie 紋理,左鍵點(diǎn)擊 zombie_0 來選中它,然后 shift+左鍵點(diǎn)擊 zombie_3,就能選擇四個僵尸 Sprite。
現(xiàn)在拖動你選中的對象到 Inspector,懸浮在 Zombie Animator(Script) 組件的 Sprites 那一行,當(dāng)你鼠標(biāo)移動到正確位置的時候,你會看到你的光標(biāo)下方出現(xiàn)了一個綠色的添加圖標(biāo)。如圖。
釋放鼠標(biāo),Unity會自動添加這些對象到你的數(shù)組里。
Note:拖放的時候無論 Sprites 是否展開都不要緊,上面的截圖僅僅演示了展開狀態(tài),因?yàn)閁nity會自動在拖放時展開你鼠標(biāo)懸浮位置的項(xiàng)目。如果這個時候截屏的話,就會像我這樣。
你的 Zombie Animator(Script) 組件現(xiàn)在看起來是這樣。
現(xiàn)在只選擇 Project browser 中的 zombie_2,用相同的方法添加到數(shù)組里,Unity會自動修改 Sprite 數(shù)組的大小來放入你新加入的元素。
再一次添加 zombie_1,你的數(shù)組現(xiàn)在就有6個順序正確的元素了,就像這樣:
在你結(jié)束這些操作的時候,記得再次點(diǎn)擊 Inspector 視圖右上角的按鈕來解鎖 Inspector 視圖。
如果你忘記怎么做了,之后你可能會為Unity為什么不自動跟隨你選擇的對象切換 Inspector 的信息而摔杯子。
最后,把 Frames Per Second 設(shè)置為 10,如圖這樣:
把游戲跑起來,現(xiàn)在對著這個拖著腳走的僵尸驚訝去吧。
Note:在游戲運(yùn)行的時候,你可以調(diào)節(jié) Frames Per Second 屬性來找到一個你喜歡的速度,但是Unity會在你停止游戲的時候恢復(fù)這些數(shù)值。因此,你需要記住你喜歡的數(shù)值,然后在游戲停止的狀態(tài)下修改它。
現(xiàn)在,你已經(jīng)使這個僵尸動了起來(或者說這是復(fù)活術(shù)?)。它看起來正要去一個聚會,下一章將帶你創(chuàng)建一個簡單的腳本,你可以為他指出正確的方向。
控制這只僵尸
在 Hierarchy 選擇 zombie,為它添加一個新的名叫 ZombieController 的C#腳本。就像剛才你添加 ZombieAnimator腳本一樣。
你是喜歡緩緩移動的僵尸還是奔跑的?都沒問題,如果想在游戲運(yùn)行中調(diào)節(jié)僵尸的移動速度,就需要定義一個共有變量在這個腳本中。
在 MonoDevelop 中打開 ZombieController.cs,添加這個變量。
public float moveSpeed;moveSpeed 會儲存僵尸每秒移動的長度,不是像素,是Unity中的單位。因?yàn)槟愕?Sprite 大小是1單位/100像素,你可能想把這個數(shù)值設(shè)置的相當(dāng)?shù)汀?/p>
正如你在動畫中所見的,你將制作一個僵尸在 Zombie Conga 游戲中直線移動。始終走向鼠標(biāo)最新點(diǎn)擊的位置。(或者是當(dāng)玩家按住鼠標(biāo)鍵時候鼠標(biāo)最新的位置)
僵尸走向你鼠標(biāo)點(diǎn)擊的方向,然后走過。“這里,僵尸!不,是這里!”
僵尸跟隨鼠標(biāo)就像它被拖著。
“哪只小僵尸想吃一口美味的光標(biāo)?你!沒錯,就是你!”
你可能不會在每一幀都有一個鼠標(biāo)的輸入事件,所以你需要在目的地改變的時候保存僵尸前進(jìn)的方向。為了實(shí)現(xiàn)這個,你要計算一個單位向量(一個長度為1的向量)從僵尸指向輸入的坐標(biāo)。
添加下面的變量到 ZombieController:
private Vector3 moveDirection;你正在制作的2D游戲,但要知道Unity仍然工作在三維坐標(biāo)系系統(tǒng)中。比如 Transorm 儲存的 Vector3 的類型。因?yàn)槟阒澜┦肋h(yuǎn)不會在z軸上運(yùn)動,所以你可以在這里使用 Vector2。但你的僵尸運(yùn)動方向是 Vector3 類型的,你不得不在這兩個類型之間不斷轉(zhuǎn)換。這全看個人喜好。
添加下面的代碼到 Update,為了在所有受到輸入事件的時候更新 moveDirection。
// 1 Vector3 currentPosition = transform.position; // 2 if( Input.GetButton("Fire1") ) {// 3Vector3 moveToward = Camera.main.ScreenToWorldPoint( Input.mousePosition );// 4moveDirection = moveToward - currentPosition;moveDirection.z = 0; moveDirection.Normalize(); }這些代碼主要實(shí)現(xiàn)了這幾個功能:
Note:你使用 Input 通用類的方法去獲取信息。工程默認(rèn)中定義了很多輸入方式,叫做 axes,比如 Horizontal,Vertical,和 Jump.Horizontal 用來監(jiān)視搖桿的x坐標(biāo)。同樣包括鍵盤上左右光標(biāo)鍵的狀態(tài),如果你想知道游戲受到的水平移動信息,只要簡單的訪問 Horizontal 軸就可以,不用關(guān)心它的輸入源(鍵盤/手柄/搖桿)。
默認(rèn)定義的 Fire1 是虛擬按鈕之一,它監(jiān)視了鼠標(biāo)或搖桿上的0號按鈕以及鍵盤上的左crtl鍵。當(dāng)指定鍵被按下的時候 Input.Getbutton 返回 true。所以你寫的代碼在每一幀中在按鈕按下的時候更新 moveDirection(不只是最初按下,包括按住),是的,這也說明只要你控制好鼠標(biāo),你可以通過按下左ctrl鍵改變僵尸的方向。
如果你想查看或者定制你工程的輸入設(shè)置,你可以點(diǎn)擊 Edit\Project Setting\Input,在 Inspector 中打開 InputManager 的設(shè)置。
現(xiàn)在在 Update 中添加這些代碼讓僵尸走起來吧!
Vector3 target = moveDirection * moveSpeed + currentPosition; transform.position = Vector3.Lerp( currentPosition, target, Time.deltaTime );第一行計算出了使用設(shè)定速度離開現(xiàn)在位置的目的位置。目標(biāo)位置就是從現(xiàn)在的位置開始運(yùn)動一秒后的位置。
第二行使用了 Vector3.Lerp 來定義僵尸的在現(xiàn)在位置到目標(biāo)位置之間的新位置。Lerp 是一個在兩個三維坐標(biāo)之間插值的簡單方法。Lerp 中的第三個參數(shù)是一個0到1的值,是全程的百分比,意思是當(dāng)這個值為0的時候,會返回 currentPosition,當(dāng)它為1的時候,會返回 target,而當(dāng)它為0.5時候會返回中點(diǎn)坐標(biāo)。
在這個例子中,我們使用 Time.deltaTime 作為第三個參數(shù),因?yàn)檫@是一秒的一小部分,肯定遠(yuǎn)遠(yuǎn)小于1。它會給你一些路徑上的點(diǎn),因?yàn)?Time.deltaTime 接近1,這樣做所以僵尸會永遠(yuǎn)平穩(wěn)的走下去。
保持腳本,返回Unity。
運(yùn)行游戲,隨便點(diǎn)擊一個地方讓僵尸走去。如果僵尸沒動,是因?yàn)?ZombieController 腳本的 moveSpeed 還沒設(shè)置,所以僵尸的移動速度是0!
游戲運(yùn)行的時候,在 Hierarchy 中選中 zombie 在 Inspector 面板中找到 Zonmie Controller(Script) 組件,把 Move Speed 設(shè)置為2,點(diǎn)擊沙灘,你的僵尸就上路了!
在 Inspector 面板調(diào)整到你喜歡的速度,根據(jù)你調(diào)整的速度,你也要調(diào)整一下 Zombie Animator(Script) 腳本組件中的 Frames Per Second,不然僵尸的動作會和速度不匹配。
當(dāng)你嘗試出你希望的值的時候,記住他們。停止游戲,再次重新在 Inspector 中修改好,這樣下次運(yùn)行就會如你所愿了。
當(dāng)你快樂的牽著它到處游蕩的時候,你可能會發(fā)現(xiàn)僵尸身上的幾個問題。
你將在這系列的未來篇目修正它走出屏幕的問題,所以現(xiàn)在不要管它。如果它走出了屏幕,簡單的再點(diǎn)一下沙灘,把它牽回來就行了。僵尸很聽話的。
在 MonoDevelop 中回到 ZombieController.cs。
這個腳本在移動僵尸的時候使用了 moveDirection,但你只在輸入事件里改變了它的值。為了控制僵尸的方向,你需要在游戲開始的時候初始化 moveDirection 指向它的右邊。
添加下面這一行到 Start:
moveDirection = Vector3.right;這會指向x軸的正方向,換句話說,會指向屏幕右端。
保存 ZombieController.cs,再次運(yùn)行你的游戲,現(xiàn)在僵尸直接就開始走了,它的也面朝它走的方向,所以它沒絆倒。
返回 ZombieController.cs,添加一個公有變量,以便你可以控制僵尸的轉(zhuǎn)向的速度。
public float turnSpeed;你會使用 trunSpeed 來控制僵尸轉(zhuǎn)到新的方向的速度。
Unity內(nèi)部使用 quaternion 來代表旋轉(zhuǎn),如果你對它數(shù)學(xué)上的定義感興趣,可以看看這。在你理清了你的思維后,放輕松,制作2D游戲你不需要知道多少關(guān)于 quaternion 的知識。
因?yàn)?Quaternion.Euler 方法可以讓你從歐拉角創(chuàng)建一個 Quaternion 對象。大多數(shù)人都習(xí)慣使用的就是歐拉角,包括獨(dú)立的旋轉(zhuǎn)的x,y,z軸,但它不適合在3D環(huán)境下使用,因?yàn)樗鼤a(chǎn)生一些問題,比如萬向節(jié)死鎖。歐拉角只適用于你只想沿著z軸旋轉(zhuǎn)的2D游戲,
Note:想學(xué)習(xí)有關(guān) Quaternion 的知識,可以去OpenGL ES Transformations with Gestures教程。
添加下面的代碼到 Updata:
float targetAngle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg; transform.rotation = Quaternion.Slerp( transform.rotation, Quaternion.Euler( 0, 0, targetAngle ), turnSpeed * Time.deltaTime );首先使用 Mathf.Atan2 來確定x軸與 moveDirection 之間的角度。Mathf.Atan2 返回一個弧度制的角,所以你通過乘以 Mathf.Rad2Deg 來轉(zhuǎn)換它。
使用 Quaternion.Slerp 來平滑的轉(zhuǎn)到目標(biāo)的角。Quaternion.Slep 可以在你指定的兩個角之間進(jìn)行球面線性插值。這和你剛才看到的 Vector3.Lerp 很像,只是用旋轉(zhuǎn)信息代替了坐標(biāo)信息。
之前,當(dāng)你使用 Vector3.Lerp 的時候,你使用了 moveSpeed 來調(diào)節(jié)僵尸移動的速度,這次,我們使用 trunSpeed 做相似的事情。這個值越大,僵尸轉(zhuǎn)到目標(biāo)地點(diǎn)越快。
Note:肯定會有一部分讀者說,“啊!我想讓僵尸在轉(zhuǎn)向的時候使用最短的路線,就算我數(shù)學(xué)爛的像一坨屎,也可以肯定只用反正切是無法做到的,你在騙我!”
對于這些問題,我建議你先冷靜下來做一套廣播體操并且在飲食中多吃些蔬菜。我要告訴你 Quarternion.Slerp 很強(qiáng)大,它總是會在兩個角之間使用最近的路線來內(nèi)插值。
現(xiàn)在保存 ZombieController.cs,回到Unity。
在 Hierarchy 中選擇 zombie,設(shè)置 Turn Speed 為 5,如圖。
運(yùn)行游戲,無論你多么辛苦的在沙灘上點(diǎn)擊,僵尸都不會感到眩暈。
這就是你在本節(jié)教程中制作的 Zombie Conga。通過點(diǎn)擊 File\Save Scene as… 保存你的 Scene,就把它叫做 CongaScene吧,點(diǎn)擊保存。
下一章會講述Unity2D專業(yè)版中一些很有用的特性。對于我們制作 Zombie Conga 不是非常重要,但你可能會想了解它——Sprite Packing。
Sprite Packing – For Professionals Only (Sort of)
譯者:這章內(nèi)容是關(guān)于打包 Sprite 紋理的一些描述,因?yàn)槲沂褂玫娜匀皇菬o需付費(fèi)的Unity版本,這段的翻譯就放下了。有興趣的同學(xué)請去原文閱讀。
至此,何去何從?
我希望你能喜歡這套Unity 4.3 2D 教程,如果你不喜歡,我希望你最少能學(xué)到點(diǎn)東西。如果你什么都沒學(xué)到,可能你想和我們接觸一下,或者給我們一些建議。
你可以從這里下載完整的工程。
現(xiàn)在雖然 Zombie Conga 還沒完成,事實(shí)上你已經(jīng)充分了解了如何編寫一個2D游戲,去第二部分學(xué)習(xí)如何使用Unity的內(nèi)建動畫系統(tǒng)吧。在這系列的第三部分,你會有很多創(chuàng)建動畫剪輯的練習(xí),你也會學(xué)到如何回放這些動畫,或者給它們之間添加過渡效果。在本系列最后一章,你將完成 Zombie Conga,同時了解Unity2D的物理引擎和更多的腳本。
當(dāng)你學(xué)習(xí)Unity2D工具的時候,記得Unity的網(wǎng)站上有豐富的資源供你去探索,包括:
- 詳細(xì)高質(zhì)量的文檔。
- 視頻教程。大多數(shù)不是關(guān)于2D的,但是他們最近在添加一個新的 2D章節(jié)。
- 培訓(xùn)課程。幾乎每周都有,也有很多過去的課程存檔。
- 一個活躍的交流社區(qū)。
和往常一樣,你可以在評論區(qū)暢所欲言!
轉(zhuǎn)載于:https://www.cnblogs.com/wangzexi/p/3870423.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Unity 4.3 2D 教程:新手上路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 龙眼为什么叫龙眼 揭秘龙眼的命名由来?
- 下一篇: Android 图片合成:添加蒙板效果