search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

實戰教程:手把手教你做一款《憤怒的小鳥》

今天為大家分享一篇Unity 2D教程,使用Unity 2D功能來實現一款類似《憤怒的小鳥》的遊戲。其中用到的背景圖片、石頭、小鳥等資源均來自Asset Store資源商店的2D Sprites Pack,涉及到的功能包括2D物理、2D碰撞器及LineRenderer等。

該遊戲最終運行效果如下:

溫馨提示,學習本教程需要了解Unity編輯器基本操作及腳本編程概念。本文先為大家分享上半部分,示例工程使用Unity5.6.1f1,實現內容包括設置背景、地面、彈弓及其與彈子之間的物理交互。

準備工作

可以進入進入Unity官方中文社區,下載遊戲所需的圖片資源。

新建Unity2D項目,並將下載的圖片資源導入該項目。將Sprites文件夾下的SkySprite圖片拖拽至層級視圖作為遊戲背景,並將其重命名為「Background」。然後在層級視圖新建空遊戲對象命名為Floor,將GrassThinSprite圖片拖拽至其下方成為子節點並重命名為「Floor1」,調整草地坐標讓其位於屏幕下方區域。

為「Floor1」添加Edge Collider 2D組件,調整碰撞器的坐標讓其位於草皮與地面交界處,如下圖所示:

在層級視圖中選中「Floor1」對象,按下快捷鍵Ctrl/Cmd + D根據需要複製多個草地對象,並依次調整各自的坐標讓這些草地鋪滿整個屏幕下方。效果如下:

添加彈弓

選中Sprites文件夾下的CatapultSprite圖片,將其切割為左右兩部分,並分別將切割后的圖片錨點移動至彈弓的皮筋所在位置,以便於後面繪製皮筋紋理。

切割完畢后將兩張圖片分別添加至場景,放置於草地上的合適位置。然後為場景添加彈子,也就是Sprites文件夾下的AsteroidSprite圖片,並將其縮放為合適的大小。

為彈子添加Rigidbody2D組件,這裡希望彈子在空中飛行時不受重力的影響,所以將Rigidbody 2D組件的Body Type設為Kinematic。然後為彈子添加Circle Collider 2D組件,以便於進行物理檢測。

這裡希望彈子在落地後會慢慢停止而非不停朝前運動,所以要為草皮使用物理材質,讓草皮擁有一點摩擦力,以阻止彈子前進。新建Physical Material 2D物理材質,並將其Friction設為5。然後將新建的物理材質綁定到所有草地對象的Edge Collider 2D組件中。

添加拉弓效果

新建空遊戲對象Slingshot作為彈弓的父節點,將之前的兩部分彈弓移到該對象下成為其子節點。然後新建兩個LineRenderer對象作為彈弓左右兩條弓,並新建三個空遊戲對象分別標記彈弓兩邊節點與彈子起始位置。Slingshot對象結構如下圖:

新建C#腳本Slingshot添加到Scripts文件夾下,Slingshot腳本的作用是處理彈子與彈弓之間的物理交互,生成彈弓被彈子拉扯的軌跡,並將彈子飛出。在Start方法中設置所有Line Renderer的Sorting Layer,並計算彈弓兩邊節點的中點位置。Start方法代碼如下:

Update方式實現了一個簡易的遊戲狀態機,當彈弓為空閑狀態時,玩家點擊屏幕會將彈子放置到待發射位置,並繪製彈弓兩邊的弦。如果玩家點擊並拖拽彈子,則改變彈弓狀態為UserPulling。代碼如下:

當彈弓處於UserPulling狀態時,就表示玩家正在拉扯彈弓。此時要計算彈子與彈弓中點之間的距離,如果距離大到一定程度就不允許玩家使勁了,同時繪製出彈弓的兩條弦。將允許的最大距離設為1.5f,代碼如下:

控制彈弓最遠拉拽距離的原理如下圖,其中B為彈弓兩個節點的中點,C為玩家拖拽彈子的位置(超過了設置的最大值1.5f),A是彈子最終可以到達的位置:

用笛卡爾坐標系來表示上圖,則三者之間的坐標關係如下:

此時可以根據數學公式算出點A的坐標,所以可以得出可以拖拽的最遠坐標值為:

varmaxPosition = (location - SlingshotMiddleVector).normalized * 1.5f +SlingshotMiddleVector;

當玩家鬆開彈弓后,需要檢測玩家拉拽彈弓的力量,如果力量夠大,則彈子起飛,否則彈子將回到起始位置。代碼如下:

其中ThrowBird函數用來讓彈子起飛,計算彈子起飛的加速度,並再飛行後為其添加重力作用,最後拋出事件通知腳本彈子已起飛。ThrowBird函數代碼如下:

DisplaySlingshotLineRenderers函數用來繪製彈弓的兩條弓,SetSlingshotLineRenderersActive則用於設置兩條弓是否可見。兩個函數代碼如下:

DisplayTrajectoryLineRenderer函數則用於繪製彈子飛行方向的軌跡,根據拋物線原理進行計算。代碼如下:

到此彈子與彈弓的交互工程就完成了,此時運行場景,效果如下:

在上半部分解決了最棘手的彈弓與彈子之間的物理交互問題,我們實現了彈弓與彈子之間的物理交互。後面我們將講解,為彈子添加拖尾效果,加入彈子與障礙物的交互,加入相機跟隨效果及遊戲勝負判定。

添加彈子拖尾效果

在層級視圖選中彈子對象,在檢視視圖中為其添加Trail Renderer組件:

新建C#腳本命名為Bird,將該腳本添加到彈子對象上。在Start函數中設置彈子的初始狀態,放大彈子的碰撞器以方便玩家點擊,並控制拖尾效果是否顯示。BirdState是用來標誌彈子狀態的枚舉,共有飛行前及飛行中兩種狀態。Start函數代碼如下:

在腳本中添加FixedUpdate函數,來檢測彈子是否已被彈弓射出,如果已被射出且彈子速度非常小,就表示彈子已經落地。落地兩秒后從場景中移除彈子對象。代碼如下:

最後是供彈弓腳本調用的OnThrow函數,在彈子被射出時將其碰撞器設為原始大小,為其加上重力作用並顯示拖尾效果。代碼如下:

彈子射出后的拖尾效果如下:

顯示彈子飛行軌跡

在層級視圖中選中彈弓對象,為其新建空遊戲對象命名為trajectoryLineRenderer,並將該對象賦給SlingShot腳本的TrajectoryLineRenderer欄位。在trajectoryLineRenderer對象上添加LinerRenderer組件。現在彈弓對象的層級結構如下:

SlingShot腳本中的DisplayTrajectoryLineRenderer函數用於繪製彈子飛行軌跡。拉拽彈弓時,會預先顯示彈子的飛行軌跡,效果如下:

添加障礙物

新建空遊戲對象作為障礙物父節點,然後將Sprites文件夾下的PlankSprite拖拽至該對象下方,設置Tag為「Brick」,並為該圖片添加BoxCollider 2D及Rigidbody 2D組件。新建C#腳本命名為Brick,該腳本用於檢測彈子與障礙物的碰撞,並在碰撞發生后減去相應的生命值,減至0時從場景中移除障礙物。腳本代碼如下:

將新建的Brick腳本添加到障礙物子對象上,並在層級視圖中複製多個障礙物,調整各個障礙物的坐標。擺成如下圖的形式:

添加目標

障礙物建好之後,下面來添加射擊目標。將Sprites文件夾下的BirdEnemyIdleSprite添加到障礙物父節點下,與障礙物為同一層級,將遊戲對象重命名為Pig,設置其Tag為「Pig」。並為其添加Circle Collider 2D與Rigidbody 2D組件。新建Pig腳本用於檢測碰撞,如果目標與彈子發生碰撞,則直接死亡。如果目標是與其它對象發生碰撞,則計算傷害,並在傷害減至0時從場景中移除目標。腳本代碼如下:

將Pig腳本添加到目標對象上,然後複製兩個目標,調整目標的坐標位置如下:

將Sprites文件夾下的BirdEnemyDeathSprite圖片分別賦給3個Pig腳本的SpriteShowWhenHurt欄位,在目標被射中時會更換圖標表示受傷。

設定遊戲邊界

在場景中新建3個Quad對象,分別作為遊戲的左、右及上方邊界,位於背景圖後面。將其材質設置為半透明,並為其添加Box Collider 2D組件,勾選碰撞器的Is Trigger屬性。

新建腳本Destroyer用於在任意對象碰撞到邊界時銷毀對象,腳本代碼如下:

當彈子飛出邊界後會被直接銷毀。

添加相機跟隨

新建腳本CameraFollow,用於跟隨彈子射出時移動相機,並限定相機移動範圍,以避免移出遊戲邊界。將該腳本添加到場景中的主相機上,腳本代碼如下:

添加遊戲勝負判定

用遊戲管理器來管理遊戲狀態,控制彈弓狀態,觸發彈弓發射事件,並更改相機是否跟隨的狀態,最後負責遊戲勝負的判定。在Start函數中,遊戲管理器會獲取所有類型的對象,並設置遊戲與彈弓的初始狀態。新建腳本GameManager,代碼如下:

在Update函數中管理遊戲狀態,控制遊戲開始、進行中與遊戲結束后的操作。遊戲開始前,玩家點擊屏幕後將第一個彈子移動到彈弓初始位置就位,然後等待玩家拉拽彈弓后射出彈子。Update函數代碼如下:

AllPigsDestroyed函數用於檢測是否所有目標都被銷毀,代碼如下:

AnimateCameraToStartPosition函數用於移動相機位置,相機在跟隨射出的彈子移動到屏幕右側后,對目標進行判斷,如果所有目標被摧毀,則玩家勝利且遊戲結束。否則就將相機移動至起始位置,繼續下一次射擊。如果沒有可供射擊的彈子,則玩家失敗。函數代碼如下:

AnimateBirdToSlingshot函數用於將彈子移動到彈弓的起始拉拽位置,彈子就位后將彈弓改為激活狀態,可以繪製彈弓兩邊的弦。代碼如下:

Slingshot_BirdThrown是BirdThrown事件的回調函數,用於告訴相機需要跟隨的彈子。函數代碼如下:

最後的OnGUI函數用於在遊戲界面上顯示一些遊戲狀態相關的文字信息,代碼如下:

最後是項目中定義的常量與枚舉,常量主要包括彈子的最小速度、彈子的最小及最大半徑,這些也可以直接在Bird腳本中定義。單獨列出來以方便後面進行維護,新建Constants腳本,代碼如下:

枚舉則用來定義彈弓狀態、彈子狀態以及遊戲狀態,新建Enums腳本,代碼如下:

到此整個教程就結束了,在場景中另外添加兩個彈子。運行遊戲,效果如下:

結語

本教程為大家介紹了如何在Unity中實現一款類似《憤怒的小鳥》的簡單遊戲,設計了一個關卡,添加了勝負判斷條件。大家還可以在此基礎上繼續完善,設計多個不同的關卡,為目標受傷添加音效,添加關卡時間限制等等。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦