字幕列表 影片播放 列印所有字幕 列印翻譯字幕 列印英文字幕 In Unity 4.3 we're launching our first set of 2D features. Unity 4.3 我們發佈了第一階段的2D工具 To compliment this we have constructed a 為此,我們用這個工具做了一個2D範例 demo project with these tools. 這個2D範例叫做"鐵橋塔防" Our 2D platformer is nicknamed 'Tower Bridge Defence' 描述倫敦鐵橋被外星人入侵的故事 It depicts London's Tower Bridge in the midst 範例完全用2D圖片和物理來呈現 讓你了解這些元素如何在Unity裡組合 of an alien invasion. 影片會說明範例裡的背景、前景、角色、特效 鏡頭追跡、動作和腳本程式是如何製作的 It's a completely sprite-based, physics driven 開始之前,先來聊聊基本的Unity 2D工作 2D sample level that we hope will help you 首先,當要製作2D專案,你應該先設定工作環境為2D understand how 2D games are put together in Unity. 可以在建立新專案時在下拉選單設定 This video will discuss the background and 或是在開發中到Edit - Project Settings - Editor調整 foreground construction, characters, effects, 這代表預設情況下,輸入的材質會 被視為2D圖片,場景視圖也會預設為2D camera tracking, animation and scripting 這個新的2D模式會採用完全的 正視圖視角來呈現你的2D遊戲 used in the demo. 同時也會把右上角的3D小圖示都隱藏 讓工作空間更大 To begin with, let's discuss the basics 除此之外,Unity 2D的工作流程 是和現有的3D流程整合在一起的 of working in 2D in Unity. 如果你已經會操作原本的Unity 那Unity 2D會很好上手 Firstly, when working in 2D, you should set the 值得一提的是,你也可以混搭2D和3D共用 Editor Behaviour Mode to 2D 所以如果你想要有3D元素在你的2D遊戲裡 或2D元素在3D遊戲裡都沒有問題 for various settings. 現在來看看範例如何建立一個關卡 This can be done when making a new project 我們一開始勾勒關卡設計雛形 然後到Photoshop裡面去把每個圖層做出來 using the drop-down on the project wizard 然後輸出這些圖層 成為新的Sprite類型導入Unity or during a project by choosing 為了呈現出背景的視差,我們做了一些 背景元素在Sorting Layer裡 Edit - Project Settings - Editor from the top menu. 這是一個2D工具的新功能 This means that by default textures 當所有背景指定到這一層後 我們可以在圖片著色器的圖層排序它們 will be imported as sprites and the 調好位置之後也可以把圖層鎖定不能編輯 Scene View will default to 2D mode. 這樣的話我們編輯前景元素的時候 就不用擔心會不小心動到背景元素 This new mode gives you a completely orthographic 可以從介面右上方的圖層選單來設定 view in which to construct 2D games. 由於背景只是裝飾用的,所以 並不需要在圖片上放任何元件 It also hides the usual 3D gizmo 將它們放到一個空的物件裡 in the top right of the view, giving you more space 並放入一個叫做叫做 BackgroundParallax的腳本來處裡視差 to work in. Aside from these settings the work 更多的細節可以詳查這個已經註解的腳本 flows for 2D have been designed to mirror 接下來製作角色活動的前景空間 existing Unity approaches to 3D game creation. 我們設計了倫敦鐵橋和降落在中間的飛碟 So if you already know a little about Unity 主角處於一個敵人從天而降並到處亂竄的環境 you'll be in a great position to start making 因此,每一個前景元素都需要 碰撞體(Collider)來讓主角在上面行走 2D games right away. 大多數環境用方體碰撞就可以 除了外型比較複雜的飛碟 It's worth noting at this stage that you can Unity提供多邊形碰撞體(Polygon Collider) 可以根據圖片外型自動產生多邊形碰撞體 still mix 2D and 3D in Unity, 甚至可以調整碰撞體的外型 so if you want to add 3D elements to your 2D game 你可以新增、移動或刪除節點 調整到更適合行走的外型 or vice versa you can do that with no worries. 為了排序前景元素我們建立了前景層 設定顯示在背景之前 Let's take a look at the demo project itself, 接下來看看主角 and how we built it up one stage at a time. 我們的主角也是在Photoshop裡面設計的 一個四肢獨立類似卡通主角雷曼的角色 We began by sketching out the level design 另外一個2D工具的新功能 for this sample level and then went about 是一個以圖表化的動畫工具 可以在Photoshop裡繪製每一節點的圖 recreating the layout in Photoshop. 後面我們會介紹如何用這方法 製造我們的天鵝 Creating and exporting the layers, 因為身體部位分開比較好控制動畫 因此我們希望獨立每個身體部位 we were able to import these in to Unity 所以我們將身體部位獨立切開 好讓Unity在輸入時容易拆離它們 using the new Sprite type. 這代表我們可以為圖片單獨製作動作 In order to create parallaxing in our background later, 把這些部位放入建好的角色層 然後改變Z軸深度來改變前後順序 we kept some of the background elements separate 把這些圖片都放入一個有控制腳本 碰撞體、物理設定等等的物件 and placed them on to a Background Sorting Layer. 一旦做到這裡,就可以到動畫視窗給予圖片動作 建立待機、跑、跳、射擊和死亡的動畫 Yet another new feature of 2D development in Unity. 使用動畫視窗裡新的分鏡表功能 就可以簡單製作動作 Having assigned all of our backgrounds to this layer, 我們在父物件建立一個動畫元件 然後針對每一個子物件建立影格 we could then use the Order In Layer property 移動指標到想要的影格後調整角色部位 就會自動把變量錄到影格上 of the Sprite Renderer to sort them. 可隨時切換分鏡表和動畫曲線 使得它更容易調整設計 Once we were happy with their positions 這些動作建立好之後我們可以 幫我們的角色設計控制狀態 we could lock the Background Sorting Layer 讓我們用程式呼叫角色執行各種動作 so that when we added foreground elements 因為不是驅動3D骨架,所以取消打勾Root Motion we didn't need to worry about accidentally 也可以打勾Animate Physics如果 動畫要和物理行為相互作用 dragging background elements around. 為了在場景走動,主角腳上有圓形碰撞體 和一個包覆整個身體的方形碰撞體 This is done using the Layers pull-down in the 這樣他可以平順地行走和跳下場景 跳起來的時候頭部也可以判定撞到 top right of the interface. 為了控制角色動作,我們寫了 一個腳本透過2D物理引擎來移動 Because the background elements are purely decorative 這代表在遊戲裡面可以指定主角和敵人 讓遊戲動態更豐富的物理行為 we did not require any additional components 我們用PlayerControl腳本來判斷角色的輸入 on the sprite game object. 我們在此指定物理移動速度 同時也把輸入的值送到動畫控制器 They were parented to an empty game object 判定播放哪些動畫以及 順暢的播放分鏡表上圖片的轉變 that has a simple script to handle parallaxing 使用動畫控制建立圖片動態最大的好處是 called BackgroundParallax. 可以調整動畫速度用來搭配物理速度 不需要額外再作任何判定 For more information you'll find this script FixedUpdate函式會檢查每一步物理運算 fully commented in the Scripts folder. 在這裡我們第一件要做的事情是 把輸入的水平值傳給動畫的速度參數 Next up came the creation of the foreground elements 在我們的狀態設定裡 待機狀態到跑動需要速度參數大於0.1 that our characters would actually traverse. 當值成立時,動畫就會從待機切到跑步 We designed London's Tower Bridge with a UFO 要讓角色移動,讓它有Rigidbody2D元件 就可以為它加力道移動 landed in the centre. 同時我們也根據輸入的水平值是 大於0或小於0來處理角色面朝的方向 The character has the run of the environment 這是因為在Unity裡,按住左鍵會傳回-1 而按住右鍵會傳回+1 as enemies spawn from the skies and begin 根據輸入值呼叫一個簡單的翻轉函數 來翻轉角色的X軸縮放,讓角色面向反方向 to navigate around the level. 為了判定角色是否著地 我們新增了一個Ground圖層 As such, each piece of the foreground required 並指定給全部可行走的前景物件 a collider for characters to walk upon. 然後使用2D裡面的Linecast函數 檢查Ground圖層是否和角色的腳接觸 For most of the environment we used 2D 為了讓製作更容易,我們建立了 一個空白的物件當作檢查地面的標準點 box colliders for efficiency, 在該物件上增加一個小圖示 我們就可以控制角色到地面的距離 but the UFO itself has a more complex shape. 就遊戲角度來看 角色在地面時只能做跳的動作 Unity's Polygon Collider allowed us to 更多關於角色控制的資訊 可以查看範例腳本裡面的說明 automate creation of the collider itself 影片稍後也會討論角色的武器 based on the shape of the sprite. 接下來看看相機如何追蹤角色 It even meant that we could tweak the shape of 跟3D遊戲一樣,在2D遊戲裡 鏡頭運鏡也左右著遊戲體驗 the collider later. 要呈現經典的2D遊戲運鏡 我們參考了2D遊戲經典大作 Moving, adding or subtracting points 任天堂或超任的超級瑪莉歐的鏡頭運作 of the collider shape to make it more 在超級瑪莉歐世界裡鏡頭會水平移動 除了封閉的空間或關卡邊緣 appropriate to walk over. 在這兩類區域裡角色小幅移動 鏡頭不會追蹤 To sort these foregrounds we created a 一旦角色移出區域 鏡頭又會開始追蹤角色 Foregrounds Sorting Layer, which was drawn 超級瑪莉歐的相機 用特定高度來進行垂直判定 above the backgrounds in the Tags And Layers manager. 但我們的遊戲沒有往上的長度 比較像動作平台,所以不需要這類設定 Next, let's take a look at our hero. 因此我們的相機在垂直判定 採用了和水平一樣的方法 Our player character was yet again designed 請看看主相機裡的CameraFollow腳本 了解鏡頭追蹤更完整的寫法和註解 in Photoshop, and for this demo 遊戲中有許多特效 但最重要的是主角殺死外星人的能力 we chose to make a character with independent 主角會發射一個具有 反作用力動畫的火箭筒 limbs and features in the style of 這個動畫由幾個部分組成 2D hits such as Rayman. 首先檢查輸入,當按下Fire鍵時 產生一個火箭,播放音效並觸發火箭動畫播放 Our other option would have been to design 讓我們進一步分解這些步驟 a sprite sheet-based animation and design each 為了可以播放其他動畫(跑步)時同時播放火箭發射 我們在動畫控制器建立了Shooting的動畫層 each frame in Photoshop, 將Weight屬性設為1,可以 完全覆蓋基本層(Base Layer)所有的動作 an approach we use later for the background Swan, 我們可以從任何狀態中用程式 觸發Shoot參數發射動畫 which we'll discuss later in the video. 來看看負責這工作的Gun腳本 Because our character had independent elements 你可以看到我們寫了驅動事件 觸發Shoot為True that we wish to animate we finalised the design 觸發後會打開,在下一格重置為關 就可以重複使用,對於射擊動作最好用 and then moved his bodily elements in to separate 除了設定動畫,我們也從腳本中發射火箭 spaces on our canvas to allow Unity to isolate them 播放音效後根據角色的方向 產生火箭並給它一個X軸的正或負速度 as separate sprites in the Importer. 這個Gun腳本被放在主角身上的空物件 This meant that we could then arrange all of 像這樣將腳本放到一個空物件上 可以輕易的定位火箭發射位置 our sprites as separate elements to be animated. 我們將物件放到火箭筒發射口 然後以他自己的座標當作發射點 We placed these on to a new Character Sorting Layer 火箭本身有2D剛體 我們給它一個速度讓它移動 that we created, and then used Z values in the 它也有火焰噴射動畫和粒子系統做的煙霧 transform to sort their rendering depth. 粒子系統也接受新的Sprite圖片 All of these sprites are then arranged under an 所以可以將煙霧的圖片切好後加到材質 並指定到粒子系統的Texture Sheet Animation empty game object, which has all of our 就有煙霧特效讓粒子系統發射 controls scripting, colliders, physics, excetera attached to it. 當火箭命中敵人或環境時 火箭本身會引起爆炸並被摧毀 Once we'd done this we were able to use the newly 爆炸是我們製作的爆炸動畫物件 upgraded Animation window to create 排序位置在前景的最後面 Idle, Run, Jump, Shoot and Death animations 要建立這類動畫,可以從專案點選圖片 然後在屬性Sprite Mode選擇Multiple by animating each of the character's sprites over time. 這功能允許我們編輯圖片 手動或是自動裁切圖片大小 With the new Dopesheet View in the Animation window 一旦完成裁切後 this is easier than ever. 只需要點擊Apply Unity會自動產生圖片並作為子物件 We simply add animation to the parent object 這就是火箭製作過程 and then create keyframes for any of the child objects. 稍後我們將在影片中討論 殺死敵人的動畫技法 Moving the playhead to where we want 現在先讓我們回到主角 看看如何處理血條補血和扣血 and then moving the various parts of the character 血條被定義為一個浮點數(Float) 每次碰到敵人就會呼叫TakeDamage函式 to automatically keyframe the animation. 為了避免觸發太快造成死亡 我們用repeatDamagePeriod來間隔觸發時間 The ability to switch between Curve and Dopesheet 為了讓角色顯示受傷 並容易從敵人手中逃脫 representation of our animation makes it easier than 我們建立了受傷的動作 並在物理上彈飛主角 ever to adjust timing and design. 要做到這點,TakeDamage函式 會阻止角色跳躍 With these animations created we can 並從主角與敵人之間找到一個向量位置 then design a state machine for our character 指定一個物理力量往指定方向擊退 so that when called upon in code, differing animations hurtForce是一個全域變數,可以隨時從介面調整 而不用從腳本裡調整 could be played. 除了擊退主角之外,我們同時 也扣掉角色的血量並更新血條 the animator controller for the character is 為了呈現扣血,我們把血條的寬度縮減 用一個公式計算讓綠色轉變到紅色 not driving a 3D biped, so we simply deselect 透過當下的血量和總量算出一個百分比 Apply Root Motion and select Animate Physics 血條是由兩個圖片組成 一個顯示血量,另一個顯示外框 in order to drive our animations in time with 這也是在Photoshop裡做的 然後輸出兩個單獨的圖片 the physics engine. 導入圖形的時候,設定圖形軸心在左邊 所以當它按比例減少時,就會往左縮 In order to traverse the environment our hero has a 這兩個圖片放在一個空物件底下 給予一個簡單腳本,讓它顯示在角色頭上 circle collider at his feet and a box collider 將血條位置設定與角色相同 to cover the rest of his body outline. 並加上偏移用的全域變數 好在檢視介面進行調整 This means he can smoothly walk up and down hills 當主角血量為0時,設定碰撞體的isTrigger = true 主角就會往下跌到水上 and when he jumps his head will hit the ceiling. 同時將主角排序推到UI層上 主角會移到畫面最上層 In order to control the character and it's animations UI層是我們製作的層 是用來表示像UI的前面的物件 we wrote a script that moves him via 2D physics forces. 當腳色死亡時,我們有兩個動畫 This means that we can apply physics to him 一個叫Death,會失去帽子和槍 另外一個叫Falling and the enemies during the game for more 用Exit Time當作動畫的切換條件 一旦Death播完就會切到Falling動畫 dynamic game play. 最後,在播放死亡動畫時 為了阻止玩家移動角色或射擊 In our PlayerControl script for the character 我們會禁用PlayerControl和Gun腳本 we check for player input. 由於Die函式是全域可以從任何地方呼叫 例如玩家掉入水中 We use this to apply physics forces 要在主角接觸水面時重置遊戲,我們 用一個由觸發器和腳本組成的KillTrigger物件 for movement and also send the value of the input 在大多的情況下 Remover腳本移除掉入河中的敵人 to the animator, which in turn defines which 並播放一個水花動畫和音效 animation should be playing and smoothly transitions 但如果是主角被觸發器偵測到時 between the different animation clips that 就會呼叫PlayerHealth腳本裡的Die函式 we've created as states. 並禁用CameraTracking同時將角色移出螢幕 並呼叫co-routiene函數(停止2秒) The great thing about using the animator to 然後重生在出生點 create states from animation clips is 接下來焦點轉移到角色生存 that we can go and tweak speeds of animation 來看看它是如何生存 和我們給予它甚麼生存工具 to match our physics velocities 遊戲中有兩種幫助玩家的補給箱 一種箱子是炸彈,另一種可以補血 without having to reanimate anything 補給箱由箱子和降落傘兩個部分組成 The FixedUpdate function evaluates with 這兩個元素放入一個空白物件 我們就可以一起觸發動畫 each physics step, and the first thing we 我們定位這兩個圖片 降落傘的軸心位於父物件的中心 do with this is to feed the value of Horizontal 這樣動畫可以左右搖擺 讓降落傘是浮在空中的感覺 input in to the Speed parameter of our animator. 然後增加一個剛體讓它有重力往下掉 The transition between Idle and Run 箱子增加碰撞體用來探測它的著陸時機 和玩家撿起的時機 in our simple state machine requires 著陸之後 播放第二段動畫讓降落傘消失 that the Speed parameter is above 0.1. 跟遊戲其他地方一樣 動畫器控制物件的狀態 When it is, the animator blends from Idle 我們可以看到預設的情況下 它會播放FloatDown動畫 in to the Run state. 然後當Land = True時會切換到著陸狀態 We then go on to add forces to the player's 在腳本裡,我們使用onTriggerEnter函數 透過標記來檢測是否碰到地面 2D physics component, the rigidbody2D, 我們也將補給箱從父物件中分離 並給它一個剛體 in order to move him around. 它就可以和環境互動 比如降落在一個斜坡上就會斜停在坡上 We also handle which direction the character is facing 接下來看看炸彈 based on the value of Horizontal input, 撿起炸彈箱的動作是箱子上的 BombPickup腳本處理的 checking whether it is above or below 0. 透過角色身上的LayBombs腳本 增減主角擁有的炸彈數量 This is because in Unity, holding the left input key LayBombs腳本負責檢查是否攜帶著炸彈 並負責產生並放置炸彈 returns a value of -1, where right returns positive 1. 炸彈設有定時裝置,在爆炸之前 透過BombDetonation裡的yield倒數計時 Depending on input, we then call a simple flip function, 爆炸函式執行幾個動作 which reverses the X scale of the character, 它會重置bombLaid參數 允許產生另外一個炸彈箱 giving him the appearance of facing the opposite direction. 它會通知產生器補充新的炸彈箱 並炸死範圍內的敵人 To decide whether the player is grounded 來看看最後一部分怎麼運作的 we added a layer in Unity called Ground 因為炸彈對敵人來說是致命的 不管他們的生命值剩下多少 and applied it to all of our walkable foreground surfaces. 我們用Physics.OverlapCircleAll方法收集 在爆炸範圍內所有標記為敵人的對象 We then used the Linecast function in 2D 然後為每一個敵人執行迴圈 to check whether something on the Ground layer 設定他們的血量為0 從爆炸地點到敵人算出一個向量並施加外力 is below the character's feet. 一旦迴圈跑完,就可以播放視覺效果 To customise this more easily we created 播放一段音效同時摧毀炸彈 an empty game object to use as a point 爆炸視覺效果有兩部分 at which to check for the ground. 主要部份是一個簡單的圓形 短暫的出現後摧毀 By adding a gizmo to this empty object 第二部分是星星狀的粒子系統 重複用相同圖片呈現火箭爆炸 we are able to manipulate how far below 效率上我們保持粒子系統持續在場景中 需要時我們用程式移動到指定位置播放 the character we'll check for the ground. 這樣可以讓粒子系統存在記憶體裡 使遊戲比較有效率 From a gameplay perspective this means that 這麼做主要是因為這個範例 同時只會有一個爆炸在場景中 the character can only jump when grounded. 因為玩家只能一次丟一個炸彈 Check out the rest of the comments in the script for more 這就是為什麼將粒子系統保持在場景中 並重複播放的原因,比起建立後移除有效率 information on the control of the player. 但如果是火箭爆炸,因為可以重複發射 因此需要建立後移除 We will discuss the player's weapon 讓我們看看主角殺死敵人 怎麼計算分數 later in this video. 這分為兩個部分,動畫顯示獲得100分 以及增加UI的分數計算 Next, let's take a look at how the camera 分數動畫由1和0兩個數字組成 tracks the player in our demo. 將它們放到場景中的空白物件 In 2D games, much like 3D, the motion of 給予一個簡單的得分動畫 並用程式讓它們在動畫完成後消失 the camera tracking the action can make 我們放置摧毀腳本在動畫事件尾端 or break your game. ScoreUI單純是個GUI文字元件 帶有管理玩家分數的腳本 For a classic 2D platformer, we looked at the mechanics Score是全域變數,代表隨時可以 檢查當敵人被殺死時增加100分 of one of the most interesting camera in 2D gaming history, 說到敵人,讓我們仔細看看他們 the camera from Super Mario World on the Super Nintendo 在我們的遊戲裡,有兩種類型外星敵人 or Super Famicom. 一種是綠皮膚的鼻涕蟲 In Super Mario world the camera tracks 另一種是會搭著飛船保護自己 的智慧型外星怪物 horizontally, but uses a dead zone 這些角色會共用一種腳本 or margin in the centre of the viewport 因為他們行為相似 in which the character can move a little 我們可以檢視它們的全域變數 並設定不同的移動速度和生命 without the camera tracking. 每個敵人都有自己的移動動畫 Once the character moved beyond this margin 鼻涕蟲有一個可以活動的尾巴 飛船內的敵人會前後搖擺移動 the camera tracks back toward the player. 對鼻涕蟲來說,我們匯入圖形 並把尾巴切為獨立圖形 The Super Mario World camera used particular heights 這樣我們就可以單獨縮放它 不會影響到整個圖片 to snap to vertically, but we didn't need this 軸心設定到右邊 我們可以漂亮的伸展收縮尾巴 kind of detail for our game as we 上下移動眼瞼 do not have a long level in the X axis 然後使用Z軸來排序 眼睛就會在眼瞼底下了 but more of a stage on which the action takes place. 就可以製作眨眼動畫 For this reason our camera employs 第二個外星人的動畫要簡單的多 我們只需要前後轉動它 similar tracking vertically as it does horizontally. 關於這些敵人的移動技術 我們透過改變剛體的速率來移動它們 Take a look at the CameraFollow script on the 當它們遇到一個牆壁這樣的障礙物時 會呼叫Physics.OverlapPoint函式來檢測 mainCamera game object to see comments 檢查是否有重疊到像是 牆壁和兩邊的塔被標記的障礙物 on how it achieves this effect. 當函式偵測到時,就會呼叫Flip函式 There are several effects in the game, 函式會翻轉敵人的X軸縮放 讓它轉到不同方向 but most important is our heroes ability 要殺死敵人,當敵人和火箭相撞時 在撞擊時會呼叫Hurt函式 to slay the alien onslaught he's faced with. 這個函式我們從敵人身上扣1點血 Our hero shoots a bazooka which has animated recoil. 並持續呼叫函式保持敵人持續扣血 This action is made up of several parts. 如果血條降到0,就會呼叫死亡函式 First we listen for key input and when the Fire key is 當他們死後,就會執行一些函式 pressed we instantiate a rocket, 會先停用所有的圖形渲染 因為2D角色大多都有動畫 play an audio clip and trigger an animation state to play. 這是為了把動畫物件換成單張死亡圖片 Let's break this down even further. 我們在圖形渲染器將圖片改為deadEnemy in order to play the Shoot animation while other 然後我們幫Score全域變數增加100 animations such as Run are playing we 然後增加扭轉讓他們死亡時扭曲 created a separate layer within our animator 因此我們要讓這些敵人死後 掉入環境的河中 called Shooting. 我們找到物件上所有碰撞體 並設定IsTrigger = True By setting the Weight property to 1 here 這樣他們就會穿過所有環境往下掉 we can totally override motion in the base layer 然後播放死亡音效之後展示一個分數動畫 on any parts of our character that are animated 要將已死亡的敵人從場景中移除 by clips on the shooting layer. 我們使用killTregger物件 In this layer we switch to the Shoot animation 和前面所說的一樣 from any state, when the Shoot trigger 當任何角色接觸它時 parameter is called from code. 將會引起一個水花動畫,並移除該物件 Let's take a look at the Gun script in charge of this. 它們撞擊水面並播放 一段附在水花動畫的音效 Here you can see that we address the animator 所以當我們產生水花動畫時 同時也聽到音效 and set that trigger to True. 要完成遊戲關卡 我們也用一些移動背景來裝飾 Triggers simply act as a switch and reset themselves to false 為了讓遊戲環境更顯動態 on the next frame so that they can be called again, 我們添加了一些飛翔的天鵝 以及沿著河岸開的公車和計程車 which is perfect for actions such as shooting. 首先是天鵝,它是在Photoshop裡面畫好後 用Multiple Sprite導入圖片 In addition to setting the animation we fire the Unity會自動裁切天鵝的每個圖片 rockets themselves from this script, 分為不同的圖導入 並把原圖當作父物件放在底下 playing an audio clip and dependent upon 因為這是個動畫組合,可以將所有的圖片 一起拖到場景中,讓Unity幫我們生成動畫 the direction that the player is facing 瞧,天鵝的動畫已經準備好了 we instantiate a rocket and give it a velocity 然後給天鵝一個剛體 讓我們可以控制速度飛過螢幕 that's positive or negative in the X axis. 和公車和計程車一樣,天鵝已被存為預製物件 This script is attached to the Gun empty game object 公車和計程車作法只需要 在匯入圖形時分開車身和車輪 in the hero's hierarchy. 並製作一個簡單的擺動動畫 We place code like this on to an empty game object 相同指定2D剛體到車子上 就能夠驅動他們在螢幕上跑 as it allows us to easily position 公車、計程車和天鵝這三個物件 我們用一個重複執行的腳本來製造它們 where the rockets are created. BackgroundPropsSpawner腳本 同時也處理出生位置,出生頻率並給予速度 We do this by placing the empty object 代表我們可以用這個腳本應用在三種對象 預設出生點和屬性 at the end of the barrel of the bazooka 要了解更多的細節,可以查看腳本中的說明 and then we use it's own position as the 最後,要了解更多的背景動態 我們使用了移動的雲朵、流動的河水和煙霧 point at which to spawn the rockets. 我們在空白物件下放兩個背景圖片 並使這些圖片緩慢飛過螢幕 The rocket itself has a 2D rigidbody 因為這是個無限循環 所以動畫永遠不會停 and we assign a velocity to that in order 這就是我們遊戲的製作過程 to make it move. 我們希望這個教學讓你 對如何用Unity開發2D遊戲有一定了解 It has a sprite swap flame exhaust 未來我們也會製作更簡單的教學 plus a particle system for smoke. 也期待你們對於Unity4.3的反應 迫不及待想看看你們的2D產品 The particle system also accepts the new sprite type of graphics 謝謝觀看 so by adding a sprite sheet of smoke puffs to a material we can assign it to the texture sheet animation module of the particle system and we get instant animation of our sprites for the particle emission. When our rockets hit an enemy or part of the environment the rocket itself is destroyed and an explosion is spawned. The explosion is simply a sprite game object that animates through a sprite sheet that we have created. Yet again using sorting layers to render this at the lowest layer order of our foreground objects. When adding sprite-based animation like this we setup the sprites themselves by selecting the file in our Project Panel and choosing the Sprite Mode Multiple. This gives us access to the sprite editor which allows us to slice manually or automatically. Once happy with the selection of sprites from our file we simply hit Apply and Unity generates the sprites as children of that file to be used in our project. So that's our rocket in a nutshell. We will discuss the mechanics of killing the enemies later in this video in the section about enemies. Let's return to the player character now and look at how we handle health and taking damage. Health is stored as a float and with each interaction with a tagged enemy we call the TakeDamage function. This is only allowed to occur after the repeatDamagePeriod has passed to avoid the player being killed very quickly. To allow the player to escape enemies more easily and to show the player that they are being hurt we make the act of taking damage repel the character physically. To achieve this the TakeDamage function briefly stops the player from jumping and finds a vector from the enemy to the player and repels him in that direction by adding a physics force. The hurtForce variable is exposed in the Inspector as public so that it can be tweaked to adjust this element of game play without returning to the script. In addition to repelling the player, we of course subtract from the player's health. and update the player's health bar. To signify the decrease in health we subtract from the width of the bar and use a colour lerp to transition it's colour between green and red, both by finding the percentage that the current health is of the full health amount. The health bar simply comprises of two sprites, one for the outline of the bar and the other for the bar itself. This was again designed in Photoshop and then the two separate elements were exported. In the import settings for these sprites we set their pivot to the middle left of the graphic so that when it scales down it shrinks towards the left. These two sprites are placed under an empty parent game object which has a simple script on it which makes it follow the player. We do this by setting the position to the same as the player object's position plus an offset that we've made public to allow for adjustment in the Inspector. When the player has 0 health remaining we allow him to fall through the level by setting his colliders to triggers, and we move him to the very front of rendering by placing his sprite renderers on the UI Sorting layer, one we've made to render in front of everything in the game. We have 2 animations for when the player dies. 1 called Death, where he loses his hat and gun and another called Falling. We naturally transition in to Falling once the Death animation completes by using the Exit Time as our transition condition in the animator. Finally, to stop the player moving the character or shooting during the Death sequence we disable the PlayerControl and Gun scripts. Because the Die function is made as public we can call it from elsewhere, such as if the player falls in to the water. To reset the game once the player does hit the water we have a KillTrigger object, which simply comprises of a trigger collider and a script. For most of the game the purpose of the Remover script is to remove our enemy objects that fall in to the river, and instantiate a splash animation and sound effect. However, when the player is detected by this trigger we call the Die function in the PlayerHealth script and also disable CameraTracking whilst moving the player off screen and calling a co-routiene that pauses for 2 seconds and then reloads the level. But let's not dwell on the death of the player, let's look at his survival and the tools that we give him to do that. Our game features 2 airdropped crates that assist the player, 1 containing a bomb, the other a med kit to boost health. These crate drops are made up of 2 parts. The crate itself and a parachute. These 2 elements are nested beneath an empty parent object to allow us to animate them as a group. We position the 2 sprites so that the parachute's centre is at the centre of the parent. This way the animation can swing left and right as if the entire parachuting crate is floating to the ground. We then simply add a rigidbody to cause gravity to pull the object down and add colliders to the crate so that we can detect when it lands and when the player picks up the crate. Upon landing we transition to a second animation state which scales the parachute down. Like other parts of our game, the animator handles the states of the object. We can see that by default it plays the floatDown animation state but then switches to a landing state when the trigger Land is set to true. In our script we do this using an onTriggerEnter function, which detects the ground via a tag. We also detatch the crate itself from the parent object and give it a rigidbody of it's own so that it can interact with the environment resting realistically on a slope if it lands on one. Let's focus on the bomb first of all. Picking up the bomb crate is handled on the BombPickup script, attached to the crate. We pickup the crate by destroying it and adding to the count of bombs that the player has in the script attached to the player called LayBombs The LayBombs script simply checks if the player is carrying a bomb and then instantiates an instance of the Bomb prefab. The Bomb prefab has a timed fuse which waits by using an yield within the BombDetonation co-routiene before calling the Explode function. The Explode function performs several actions. First it resets the bombLaid variable to allow another bomb to be deployed, it tells the pickup spawner it is allowed to spawn a new crate drop and kills enemies within a defined blast radian. Let's take a look at how this last part works. Because bombs are lethal to enemies regardless of their remaining hit points we use the Physics.OverlapCircleAll to collect all objects tagged Enemy within a certain radius of the bomb. We then run a foreach loop for every enemy found setting their health to 0 finding a vector from where the bomb was to where the enemy is, in order to apply a force in the direction of that vector. Once the foreach loop is complete we play and instantiate visual effects, play an audio clip for the explosion and of course destroy the bomb itself. The visual of the explosion is twofold. The main part is a simple circle that appears briefly and is then destroyed and the second part is a particle system of stars that reuses the same sprites as our rocket explosion. For efficiency we keep this particle system in the scene at all times and when it is required we use code to move the system to the desired position and play it. This keeps the particle system in memory and makes the game more efficient. It's worth noting that we can do this because we know we will only have 1 single explosion in the scene at any one time as the player can only throw 1 bomb at a time. This is why keeping our particle system in the scene and replaying it is more efficient than creating instances and then removing them. With the rocket explosion however, we can have many at once so we do need to spawn and remove them. Now let's take a look at what happens when our player kills an enemy and scores points. This is done in 2 parts, a scoring animation that plays showing 100 points earned and the score UI at the top of the screen that increments. The score animation is made up to 2 number sprites, a 1 and a 0. We place this in the scene under an empty parent object and animated them using a simple destroyer script to remove them from the scene when the animation is complete. We call the destroyer function in the script by placing an animation event at the end of the timeline. The ScoreUI itself is a simple GUI text component with a custom font and script that manages the score for the player. The Score variable is public, meaning that we can address it from the Enemy script when they are killed and add 100 points to the value. Speaking of the enemies, let's take a look at them more in depth now. In our game we have 2 types of alien enemy, a green slug-like monster and a smarter alien that brought his ship with him for protection during the invasion. These characters share the same script as the behaviour is very similar and we allow for differing movement speeds and amounts of hit points by setting these as public variables in the Inspector. Each enemy has it's own Walk animation. The slug has a moving tail, whist the ship-based enemy rocks back and forth as it approaches. For the slug we used the sprite importer to define the tail section of the graphic as a separate sprite element, meaning that we could animate it individually and avoid having to scale the entire sprite. By setting the pivot to the right we are able to animate the tail expanding and contracting from that point. For added character we then move the eyelid up and down and we use the Z value to sort the sprites amongst one another, the eye being below the eyelid so that we could animate it over the top. The second enemy's animation was much simpler and just meant that we rotated it back and forth. For the mechanics of moving the enemies we drive them by setting the velocity of the rigidbody. When they encounter an obstacle such as a wall they detect this by using a Physics.OverlapPoint function, which checks for a point in space overlapping a collider. Our walls, the towers at each side of the level, are tagged as obstacles. When this function detects them it calls the Flip function, it reverses the X scale of the enemy sending them moving in a different direction. To kill the enemies, each time a rocket collides with them it's script calls the Hurt function on the particular enemy that it's hit. In this function we subtract 1 from the hit points of the particular enemy. We then keep tabs on the enemy's health inside the fixed update function. If it drops to 0 we call the Death function. When they die we perform a number of functions. Firstly we disable all sprite renderers as our 2D characters are made up of a number of sprite objects that are animated. This is because we simply want to swap out the animated elements for a single sprite of the dead character We do this with the main sprite renderer by setting it to use the sprite assigned to the deadEnemy variable. We then add to the score using the public variable in the Score script and we add some visual flare to the enemy's death by adding torque to spin them as they die. Because we need the enemies to fall through the environment and land in the river when they die we find all colliders on the object and set their IsTrigger parameter to true. This means that they will pass through the environment colliders. We then choose from an array of death audio clips and play one of them back, before creating an instance of the Score animation we showed you earlier. To remove the dead enemy from the scene we rely on the killTrigger object It performs the same function as discussed earlier as any non-player object touching it will cause a splash animation and remove that object. The sound effect of them hitting the water is an audio clip attached to the animated splash which plays on awake so that when we create an instance of the animated object we hear the sound right away. To finish the game level re decorated the background with a number of moving props in order to make our game environment feel more dynamic. We added flying swans, plus buses and taxis that drive along the river bank. First was the swan, which was created from a sprite sheet, drawn in Photoshop and imported using the Multiple Sprite Mode import setting in the Inspector. By choosing this approach Unity automates choosing each frame in the sheet and importing it as a separate sprite under the parent hierarchy of the asset. Because this is a linear set of animation frames we could simply drag all of these sprites in to the scene to let Unity animate them for us. Et voila, our animated swan is ready to add as a background element. The swan was then given a rigidbody2D so that we can use velocity to send it across the screen. As with the bus and the cab, the swan is saved as a prefab. For the bus and taxi prefabs we simply separated the bodies and wheels of the vehicles in the sprite importer and made a simple bobbing animation. Applying a 2d rigidbody to these as well, we were able to drive them across the screen using velocity. For all 3 props, the bus, taxi and the swan we created a script we could reuse which is in charge of spawning them. The BackgroundPropsSpawner script also handles the frequency, a speed to give them and where on screen to spawn them. This meant that we could make 3 creator objects with the same script on. Changing which prefab will be spawned and what properties to give it. Take a look at the comments in the script to learn more. Finally, for more background dynamism, we added rolling clouds, panning river details and fog. We did this by adding 2 instances of the background sprite to a parent object and simply used animation to slowly pan them across the screen. Because this animation loops our animation will continue indefinitely. And that's how we made our game. We hope this overview has given you some idea of how we create 2D games in Unity, and we'll be creating more simply projects and tutorials in the future. We look forward to your feedback on Unity4.3 and we can't wait to see the great 2D titles that you'll come up with. Thanks for watching.
B2 中高級 中文 英國腔 動畫 腳本 物件 敵人 圖片 角色 Unity 4.3 - 2D遊戲開發演練 (Unity 4.3 - 2D Game Development Walkthrough) 321 11 朱瑛 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字