欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Unity3D開發(fā)教程:憤怒的小鳥

 更新時間:2021年06月23日 16:38:00   作者:恬靜的小魔龍  
這篇文章詳細的講解了如何從0開發(fā)出一個Unity3D的小游戲憤怒的小鳥,本文包含大量的圖片與文字描述,也含有大量的源代碼,可以讓你快速入手,希望本篇文章對你有所幫助

一、前言

“憤怒的小鳥”在2009年12月發(fā)布,由于它的高度上癮的游戲,它很快成為有史以來最成功的移動游戲。

在本教程中,我們將在“Unity”中實現(xiàn)“憤怒的小鳥”翻版。游戲中最復(fù)雜的部分是物理系統(tǒng),但是多虧了Unity,我們就不用擔(dān)心太多了。

像往常一樣,一切都會盡可能簡單地解釋,這樣每個人都能理解它。

以下是項目的預(yù)覽

在這里插入圖片描述

二、源碼

UI資源:
http://xiazai.jb51.net/202106/yuanma/picturezy_jb51.rar

源代碼:
http://xiazai.jb51.net/202106/yuanma/Game_AngryBirds_jb51.rar

三、正文 項目版本

Unity5.0.0f4

1.設(shè)置相機

點擊Main Cameras,在Hierarchy面板設(shè)置背景色以友好的藍色色調(diào)(紅色=187, 綠色=238, 藍色=255)并調(diào)整大小而位置如下圖所示:

在這里插入圖片描述

2.地面設(shè)置

地面貼圖設(shè)置
為了防止版權(quán)問題,我們不能在本教程中使用原“憤怒的小鳥”圖形。相反,我們將畫我們自己的Sprite,使他們看起來像原來的游戲。

讓我們從用我們選擇的繪圖工具開始:

在這里插入圖片描述

將其保存到我們的項目中后,我們可以在項目區(qū)可以看到:

在這里插入圖片描述

然后在Inspector修改導(dǎo)入設(shè)置:

在這里插入圖片描述

注:Pixels Per Unit像素轉(zhuǎn)到單位價值16這意味著16x16像素將適合在游戲世界的一個單位。我們將使用這個值作為我們所有的紋理。我們選擇16,因為鳥的大小將有一個16x16像素后,我們希望在游戲世界它有一個單位的大小。

好了,現(xiàn)在我們可以將圖片從項目區(qū)拖入到場景中:

在這里插入圖片描述

讓我們看看Inspector把地面定位在(0, -2),所以作為不為y=0的都不是地面的一部分:

在這里插入圖片描述

地面物體設(shè)置
現(xiàn)在地面只是一幅圖像,僅此而已。它不是物理世界的一部分,事物不會與它相撞,也不會站在它上面。我們需要添加一個Collider讓它成為物理世界的一部分,這意味著事物將能夠站在它的頂端,而不是掉進它的正中。

添加BoxCollider2D組件:

在這里插入圖片描述

3.邊界設(shè)置

創(chuàng)建空對象,命名為borders

在這里插入圖片描述

位置歸零:

在這里插入圖片描述

現(xiàn)在,我們將在我們的水平的左邊、右邊和頂部添加某種不可見的區(qū)域。每當(dāng)有東西進入那個區(qū)域,它就應(yīng)該被摧毀。此類行為可以通過Trigger,這幾乎只是一個Trigger它接收到碰撞信息,但不會與任何東西發(fā)生沖突。

添加碰撞器:

在這里插入圖片描述

勾選

Is Trigger

之后,我們可以為級別的右側(cè)和頂部再添加兩個triggers :

在這里插入圖片描述

如果我們看看場景然后,我們可以看到觸發(fā)器是如何與我們的背景很好地對齊的:

在這里插入圖片描述

現(xiàn)在我們?nèi)匀槐仨毚_保任何進入邊界的東西都會立即被銷毀。此類行為可以通過腳本Borders:

創(chuàng)建腳本Borders.cs:

在這里插入圖片描述

將其添加到邊界對象物體上面:

在這里插入圖片描述

讓我們也將腳本移動到一個新的Scripts文件夾,只是為了保持清潔:

在這里插入圖片描述

編輯Borders.cs腳本:

using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
我們不需要啟動或者更新函數(shù),所以讓我們移除它們。相反,我們將使用OnTriggerEnter2D函數(shù),每當(dāng)有東西進入其中一個邊界觸發(fā)器時,統(tǒng)一將自動調(diào)用該函數(shù):
using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    void OnTriggerEnter2D(Collider2D co) {

    }
}
在這個函數(shù)中,無論什么東西進入Triggers,我們都將Destroy這個物體:
using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    void OnTriggerEnter2D(Collider2D co) {
        Destroy(co.gameObject);
    }
}
保存腳本后,我們的邊界就完成了。我們稍后會看到,如果我們試圖將一只鳥射出水平之外,它就會消失。

4.云彩設(shè)置

我們將花幾分鐘額外添加云到背景,以使水平看起來更好。像往常一樣,我們首先畫一個:

在這里插入圖片描述

讓我們在項目區(qū),然后在Inspector修改云的導(dǎo)入設(shè)置:

在這里插入圖片描述

現(xiàn)在我們要做的就是把它從項目區(qū)進入場景幾次,將每一片云放置在我們想要的位置:

在這里插入圖片描述

注意:只要使用一些重復(fù)的模式和一些非常顏色,我們可以使水平看起來相當(dāng)好,無需付出很大的努力。

5.彈弓設(shè)計

彈弓圖片

在這里插入圖片描述

一個飛彈將產(chǎn)生新的鳥類,并允許用戶發(fā)射到水平。和往常一樣,我們將從畫Sprites開始:
這里是導(dǎo)入設(shè)置:

在這里插入圖片描述

稍后,我們將創(chuàng)建一個腳本,在彈弓的位置生成一只新的鳥,或者確切地說是在彈弓的Pivot位置生成一只鳥。
我們想要在彈弓頂部而不是中間處出現(xiàn),這就是為什么我們要在“導(dǎo)入設(shè)置”中設(shè)置Pivot在頂部。

下面的圖像顯示了中心和頂:

在這里插入圖片描述

*注意:如果我們將數(shù)據(jù)透視設(shè)置為中心然后變換位置是彈弓中心的點。如果我們把Pivot 設(shè)為頂,然后變換位置是彈弓頂端的點。

好了,現(xiàn)在我們可以將彈弓拖到場景中去了(-22, 3):

在這里插入圖片描述

生成鳥腳本
如前所述,我們的彈弓應(yīng)該是生成鳥。確切地說,它應(yīng)該在一開始就生成一個,然后等待用戶啟動它,然后在所有的物理計算完成之后再生成另一個。(當(dāng)什么都不動的時候).

我們可以通過腳本來實現(xiàn)這樣的行為。
添加腳本Spawn.cs:

在這里插入圖片描述

我們可以雙擊腳本來打開它:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
這個啟動函數(shù)在開始游戲時由Unity自動調(diào)用。這個更新函數(shù)被一次又一次地自動調(diào)用,大約每秒60次。我們不需要它們中的任何一個,這樣我們就可以從腳本中刪除它們。

還有另一種類型的更新函數(shù),它被稱為FixedUpdate…它也被一次又一次的調(diào)用,但是是在單位物理完全相同的時間間隔內(nèi)計算的,所以在做物理工作的時候使用FixedUpdate是一個好主意(我們很快就會這么做).

下面是修改后的腳本FixedUpdate腳本:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {

    void FixedUpdate() {

    }
}
好的,讓我們添加一個變量,允許我們稍后指定BirdPrefab(我們想生的鳥):
using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {
    // Bird Prefab that will be spawned
    public GameObject birdPrefab;

    void FixedUpdate() {

    }
}
以下是我們?nèi)绾紊伤姆椒ǎ?/pre>
void spawnNext() {
    // Spawn a Bird at current position with default rotation
    Instantiate(birdPrefab,transform.position,Quaternion.identity);
}
生成的觸發(fā)區(qū)域

現(xiàn)在我們不能只生一只又一只鳥。相反,我們將不得不生成一個,然后等待它被發(fā)射。有幾種方法可以實現(xiàn)這一點,但最簡單的方法是使用Triggers.

Trigger是一個簡單的Collider ,接收碰撞信息,但實際上并不是物理世界的一部分。所以如果我們添加一個Trigger然后,每當(dāng)有東西進入Trigger、留在Trigger中或離開Trigger時,我們都會收到通知。然而,由于它只是一個Trigger,事情不會像普通Collider 那樣與它相撞(這很快就更有意義了).

我們可以將Trigger添加到彈弓中,方法是在Hierarchy面板中,然后點擊添加組件Circle Collider 2D,給它一個合適的半徑和中心然后啟用觸發(fā):

Is Trigger

在這里插入圖片描述

我們還可以在場景中查看:

在這里插入圖片描述

在添加觸發(fā)器之后,每當(dāng)有東西進入時,我們都會收到通知。(OnTriggerEnter2D),停留(OnTriggerStay2D)或離開(OnTriggerExit2D)上面那個綠色的圓圈。

現(xiàn)在,我們可以通過創(chuàng)建一個使用中變量,然后將其設(shè)置為bool值,當(dāng)生下一只鳥的時候為false,當(dāng)它離開觸發(fā)器時為true:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {
    // Bird Prefab that will be spawned
    public GameObject birdPrefab;

    // Is there a Bird in the Trigger Area?
    bool occupied = false;

    void FixedUpdate() {

    }

    void spawnNext() {
        // Spawn a Bird at current position with default rotation
        Instantiate(birdPrefab, transform.position, Quaternion.identity);
        occupied = true;
    }

    void OnTriggerExit2D(Collider2D co) {
        // Bird left the Spawn
        occupied = false;
    }
}
之后我們可以修改我們的FixedUpdate函數(shù),因此每當(dāng)觸發(fā)區(qū)域不再被占用時,它總是生成一只鳥:
void FixedUpdate() {
    // Bird not in Trigger Area anymore?
    if (!occupied)
        spawnNext();
}
注:!occupied意思是還沒有被占用…我們也可以用if(occupied==false).

我們的生成腳本現(xiàn)在可以正常工作了,但是讓我們再添加一個特性。在射殺一只鳥之后,會有很多東西相互碰撞,墜落,滾來滾去,甚至爆炸。在最初的“憤怒的小鳥”游戲中,只有在水平上的所有東西停止移動之后,才會產(chǎn)生一只新的鳥。

我們可以很容易地創(chuàng)建一個sceneMoving函數(shù),該函數(shù)查找場景中是否有任何對象仍在移動,而不僅僅是一點點:

bool sceneMoving() {
    // Find all Rigidbodies, see if any is still moving a lot
    Rigidbody2D[] bodies = FindObjectsOfType(typeof(Rigidbody2D)) as Rigidbody2D[];
    foreach (Rigidbody2D rb in bodies)
        if (rb.velocity.sqrMagnitude > 5)
            return true;
    return false;
}
注意:我們使用了FindObjectsOfType找到所有帶有剛體的物體,之后我們會檢查每個物體的velocity,如果這個剛體的sqrMagnitude大于5,說明這個剛體還在移動就返回True,沒有就返回false

使用這個整潔的小腳本,我們可以輕松地修改FixedUpdate功能,因此只有在沒有任何移動的情況下才會產(chǎn)生新的鳥:

void FixedUpdate() {
    // Bird not in Trigger Area anymore? And nothing is moving?
    if (!occupied && !sceneMoving())
        spawnNext();
}
現(xiàn)在我們已經(jīng)完成了生成鳥的腳本,我們可以在Inspector面板看到彈弓上面掛載的腳本:

在這里插入圖片描述

注意:我們還不能在沒有鳥的情況下測試生成鳥腳本,但是它確實工作得很好,我們將在創(chuàng)建鳥之后看到這一點。

6.鳥的設(shè)置

鳥的圖片
讓我們開始更有趣的事情:鳥。我們首先畫一個16 x 16一只大圓身軀和一些小小的翅膀和眼睛的鳥的像素圖像:

在這里插入圖片描述

我們將使用以下方法導(dǎo)入設(shè)置為此:

在這里插入圖片描述

讓我們從項目區(qū)進入場景若要從其中創(chuàng)建游戲?qū)ο?,請?zhí)行以下操作:

在這里插入圖片描述

鳥的物理

讓我們?yōu)轼B添加碰撞器Circe Collider 2D:

在這里插入圖片描述

現(xiàn)在有一個Physics Material 2D對撞機的縫隙,讓我們可以給鳥一些特殊的物理特性。在“Unity憤怒的小鳥”教程中,物理材料將是非常有用的,因為現(xiàn)在,如果這只鳥掉在地上,它看起來會是這樣的:

在這里插入圖片描述

看起來有點不自然。相反,我們想讓這只鳥從下面的東西中跳出來:

在這里插入圖片描述

要在第二張圖片中創(chuàng)建彈跳效果,我們所要做的就是在項目區(qū)并選擇Create>Physics2D Material,說出來鳥類材料把它變成一個新的物理材料文件夾:

在這里插入圖片描述

一旦被選中,我們就可以修改Inspector:

在這里插入圖片描述

注:Bounciness值越大,鳥就越會反彈。

最后,我們可以再次選擇鳥,然后拖動鳥類材料從項目區(qū)進入Collider Material插槽:

在這里插入圖片描述

這只鳥也應(yīng)該四處走動。剛體負責(zé)物體的重力、速度和其他使物體運動的力。根據(jù)經(jīng)驗法則,在物理世界里,所有應(yīng)該移動的東西都需要一個剛體.:

在這里插入圖片描述

注意:我們設(shè)置了Gravity Scale到4因為它能讓鳥飛得更快。

如果我們按下Play現(xiàn)在我們可以看到鳥從地上掉下來并彈跳起來:

在這里插入圖片描述

我們的鳥類物理已經(jīng)完成了,但是有一個小的調(diào)整是我們必須在這里進行的?,F(xiàn)在,如果我們在彈弓中生成的話,由于它的剛體引力,它會立即墜落到地面。我們只希望用戶一開火,鳥就會受到重力的影響,所以讓我們現(xiàn)在啟用Is Kinematic,然后在腳本中禁用它:

在這里插入圖片描述

現(xiàn)在,剛體是運動學(xué)的,這意味著它不受重力或速度的影響,因此不會立即墜落。

注意:為了更清楚地說明這一點,任何像英雄、汽車或鳥之類的東西都應(yīng)該有一個剛體,它是運動學(xué)的。我們只使能只要鳥還在彈弓里就能運動。

鳥預(yù)制體
如前所述,這只鳥從一開始就不應(yīng)該出現(xiàn)在場景中。相反,彈弓應(yīng)該在需要的時候生成出一只新的鳥。為了使彈弓能夠生成鳥,我們必須創(chuàng)建一個預(yù)制件 (換句話說,我們必須在我們的項目區(qū)有鳥的資源).

要創(chuàng)建預(yù)制件,我們所要做的就是在hierarchy面板,將物體拖入到項目區(qū)的Prefabs文件夾中:

在這里插入圖片描述

現(xiàn)在,我們可以在任何時候?qū)ⅧB加載到場景中,這意味著我們現(xiàn)在也可以從Hierarchy中刪除這個對象:

在這里插入圖片描述

生成鳥
讓我們將預(yù)制體bird拖到到我們的Spawn.cs的腳本中的BirdPrefab插槽中:

在這里插入圖片描述

如果我們按下Play現(xiàn)在我們可以看到彈弓是如何生出一只鳥的:

在這里插入圖片描述

拉and釋放腳本
用戶應(yīng)該能夠把鳥在彈弓周圍,然后釋放它,以便把它射向所希望的方向。

我們將創(chuàng)造一個新的C#腳本給它起個名字PullAndRelease :

using UnityEngine;
using System.Collections;

public class PullAndRelease : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
用戶將能夠拖動鳥繞一個圓圈。每個圓都需要一個中心,在我們的例子中,它是鳥的生成位置,所以讓我們確保將它保存在一個變量中:
using UnityEngine;
using System.Collections;

public class PullAndRelease : MonoBehaviour {
    // The default Position
    Vector2 startPos;

    // Use this for initialization
    void Start () {
        startPos = transform.position;
    }
}
*注意:我們還刪除了更新函數(shù)因為我們不需要它。

好的,為了讓用戶把鳥拖曳成一個圓圈,我們必須找出這只鳥是否被點擊了。(確切地說:拖著)…我們還需要知道用戶是否釋放了鼠標,在這種情況下,我們必須在我們目標方向發(fā)射鳥。

當(dāng)然,如果沒有這方面的功能,那就不是Unity了。Unity自動調(diào)用Onmouseup和OnmouseDrag函數(shù),當(dāng)我們用鼠標拖動游戲?qū)ο蠡螂S后釋放鼠標時:

*注:鼠標拖動,意思是用戶在GameObject上按住鼠標按鈕,然后移動鼠標。

移動鳥真的很容易。我們所要做的就是將當(dāng)前的鼠標位置轉(zhuǎn)換到游戲世界的某個點,然后將鳥移到那里。當(dāng)然,只有在一定半徑內(nèi):

void OnMouseDrag() {    // Convert mouse position to world position    Vector2 p= Camera.main.ScreenToWorldPoint(Input.mousePosition);    // Keep it in a certain radius    float radius = 1.8f;    Vector2 dir = p - startPos;    if (dir.sqrMagnitude > radius)        dir = dir.normalized * radius;    // Set the Position    transform.position = startPos + dir;}

*注意:我們可以使用ScreenToWorldPoint獲取到手指點擊的位置,但是這個位置是不固定的,在找到手指點擊的位置p之后,我們只需要計算從startPos到p的距離,如果這個距離太長dir.sqrMagnitude > radius,就讓這個位置等于一個最大值dir = dir.normalized * radius

如果我們按下Play然后我們可以把鳥繞個圈:

在這里插入圖片描述

把鳥射向一個方向也同樣容易。我們可以用我們的Onmouseup函數(shù)來知道鼠標何時釋放。然后,我們將計算出從鳥到startPos然后使用rigidbody的AddForce在那里啟動它的功能:

// The Force added upon releasepublic float force = 1300;void OnMouseUp() {    // Disable isKinematic    GetComponent<Rigidbody2D>().isKinematic = false;    // Add the Force    Vector2 dir = startPos - (Vector2)transform.position;    GetComponent<Rigidbody2D>().AddForce(dir * force);    // Remove the Script (not the gameObject)    Destroy(this);}

*注意:如前所述,我們也將禁用運動學(xué)等使剛體再次受到重力和速度的影響。我們只需將當(dāng)前位置減去startPos…最后,我們刪除這個對象,這樣它就不能再被發(fā)射了。

如果我們按下Play然后我們就可以拉著這只鳥開火了:

在這里插入圖片描述

Feather Particle Effect羽毛的粒子效果
讓我們通過增加鳥的碰撞效果來使游戲更加流暢。一旦它第一次落地,它就應(yīng)該像這樣在自己周圍隨意地長出羽毛:

在這里插入圖片描述

當(dāng)我們需要隨機粒子產(chǎn)生、旋轉(zhuǎn)和向某個方向移動時,就會使用粒子系統(tǒng)。粒子系統(tǒng)的一個簡單的例子是煙霧,它產(chǎn)生灰色紋理,然后以錐狀向上移動。

我們將修改我們的粒子系統(tǒng),使其不是使粒子向上飛,而是使它們飛向四面八方。我們還將修改一些更具體的東西,如大小,速度和旋轉(zhuǎn)。我們的羽毛沒有正確或錯誤的粒子系統(tǒng),所以你可以隨意使用它,直到它看起來像你想讓它看起來那樣。以下是我們得出的結(jié)論:

在這里插入圖片描述

這是我們用來做這件事的圖像:

在這里插入圖片描述

*注意:右擊圖像,選擇另存為.。并將其保存在項目的Assets/Sprites文件夾。

導(dǎo)入設(shè)置:

在這里插入圖片描述

之后,我們可以從項目區(qū)進入我們粒子系統(tǒng)所以它使用圖像對所有的粒子。

現(xiàn)在我們可以將場景中的羽毛對象拖入到我們項目區(qū)的Prefabs文件夾,做成一個預(yù)制體:

在這里插入圖片描述

然后我們可以在Hierarchy中刪除羽毛游戲?qū)ο?/p>

最后一件事是給我們的鳥添加一個腳本,這樣羽毛粒子系統(tǒng)就會在發(fā)生碰撞時產(chǎn)生。讓我們在項目區(qū)然后創(chuàng)建新腳本…我們給它起個名字CollisionSpawnOnce。我們也會把它移到我們的Sprits文件夾,然后雙擊它以打開它:

using UnityEngine;
using System.Collections;

public class CollisionSpawnOnce : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
我們不需要啟動或更新函數(shù)。相反,我們將使用OnCollisionEnter2D函數(shù)和effect公共游戲?qū)ο髴?yīng)生成的預(yù)制件的變量:
using UnityEngine;
using System.Collections;

public class CollisionSpawnOnce : MonoBehaviour {
    // Whatever should be spawned (Particles etc.)
    public GameObject effect;

    void OnCollisionEnter2D(Collision2D coll) {
        // Spawn Effect, then remove Script
        Instantiate(effect,transform.position,Quaternion.identity);
        Destroy(this);
    }
}
*注意:為了確保只產(chǎn)生一次效果,我們將從Destroy(this)(這只會關(guān)閉腳本,而不是整只鳥)。

保存腳本后,我們可以看到Effect插槽…現(xiàn)在我們可以拖著羽毛粒子系統(tǒng)預(yù)制件項目區(qū)進入Effect插槽:

在這里插入圖片描述

如果我們按下Play然后把這只鳥發(fā)射到地上,然后我們就可以看到它周圍的羽毛在生成:

在這里插入圖片描述

路徑
我們還會給我們的鳥添加另一個效果,讓它看起來更流暢:一條白點的軌跡,顯示鳥的軌跡:

在這里插入圖片描述

首先,我們需要一些大小不同的跟蹤圖像:

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

我們會用同樣的導(dǎo)入設(shè)置對于每一幅圖像:

在這里插入圖片描述

我們希望能夠在我們想要的任何時候產(chǎn)生軌跡部分,這意味著我們將需要三個預(yù)制件。因此,讓我們選擇三個圖像并將其拖到場景中,然后拖回到Prefabs文件夾。直到我們有三個預(yù)制體:

在這里插入圖片描述

現(xiàn)在我們只需要一個腳本來生成一個又一個的TRAIL元素,大約每秒鐘一次。讓我們創(chuàng)建一個新的C#腳本給它起個名字Trail :

using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
我們可以移除更新因為我們不需要它。讓我們添加一個public GameObject[]保存所有跟蹤元素的變量。我們將使用Array,這意味著它不僅僅是一個GameObject:
using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;

    // Use this for initialization
    void Start () {

    }
}
我們還需要一個函數(shù)來生成下一條線索。例如,它應(yīng)該產(chǎn)生第一個TRAIL元素,然后下一次應(yīng)該生成第二個,然后是第三個,然后是第一個。這可以通過使用實例化有一個額外的計數(shù)器變量:
using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;
    int next = 0;

    // Use this for initialization
    void Start () {

    }

    void spawnTrail() {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}
我們將其設(shè)置為0,這意味著trails spawnTrail中的第一個元素被調(diào)用。然后使用next+1來增加next。為了保持它在trails數(shù)組的范圍內(nèi),我們還將使用% trails.Length,它使用模(%)運算。對于那些不了解模的人,這里有一個更明顯的版本:
void spawnTrail() {
    Instantiate(trails[next], transform.position, Quaternion.identity);
    next = next + 1;
    if (next == trails.Length) next = 0;
}
現(xiàn)在我們有了一個生成軌跡函數(shù),我們可以使用它生成一個新的trail 元素通過使用InvokeRepeting函數(shù)100 ms生成一個:
using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;
    int next = 0;

    // Use this for initialization
    void Start () {
        // Spawn a new Trail every 100 ms
        InvokeRepeating("spawnTrail", 0.1f, 0.1f);
    }

    void spawnTrail() {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}
現(xiàn)在,小徑元素會一直生成,甚至當(dāng)鳥不飛的時候也是如此。讓我們添加一個小小的修改,只在鳥飛得足夠快的情況下才會產(chǎn)生軌跡:
void spawnTrail() {
    // Spawn Trail if moving fast enough
    if (GetComponent<Rigidbody2D>().velocity.sqrMagnitude > 25) {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}
好的,讓我們保存腳本。在這里,我們將從我們的三條小徑預(yù)制體中拖到插槽中:

在這里插入圖片描述

如果我們按下Play然后我們就可以看到這只鳥射擊后的蹤跡:

在這里插入圖片描述

7.木片

讓我們添加一些結(jié)構(gòu),如石頭,冰和木材,我們的Unity2D憤怒的小鳥游戲更加豐富。

我們先畫一塊木片:

在這里插入圖片描述

注意:右擊圖像,選擇另存為。并將其保存在項目的Assetes/Sprits文件夾。

這里是導(dǎo)入設(shè)置:

在這里插入圖片描述

現(xiàn)在我們可以把它拖到場景把它放在地上的某個地方:

在這里插入圖片描述

木片應(yīng)該是物理世界的一部分,所以我們將一如既往地在添加Box Collider 2D組件:

在這里插入圖片描述

木片也應(yīng)該能夠四處移動?,F(xiàn)在它不會自己移動,但是如果鳥飛進它,它就會移動。它也應(yīng)該受到重力的影響,所以我們需要的是剛體…我們可以通過選擇添加組件->物理二維->Rigidbody 2D…我們也會增加Mass到4所以它更重了一點:

在這里插入圖片描述

現(xiàn)在我們有一塊木頭,它是物理世界的一部分!

對于這個略有不同的木片,我們將重復(fù)相同的工作流程:

在這里插入圖片描述

這是我們的游戲如何看待添加第二塊木材和旋轉(zhuǎn)第一個90°:

在這里插入圖片描述

8.石頭

為了在我們的游戲中有幾種不同的結(jié)構(gòu),我們還將添加兩種不同類型的石頭:

在這里插入圖片描述

在這里插入圖片描述

操作流程和以前一樣,這次我們將Mass設(shè)置為10:

在這里插入圖片描述

下面是我們的游戲中有一些石頭的樣子:

在這里插入圖片描述

注:我們再次實現(xiàn)了一些體面的外觀與基本的形狀,只有少數(shù)顏色和抖動。

9.冰

冰的圖片
我們將為我們的游戲增加一個結(jié)構(gòu):冰。不過,這一次會更有趣一些。

像往常一樣,我們首先畫一塊冰:

在這里插入圖片描述

這個導(dǎo)入設(shè)置與以往相同:

在這里插入圖片描述

冰物理
添加 Boxcollider2D組件 剛體組件:

在這里插入圖片描述

冰應(yīng)該很滑,所以讓我們右擊項目區(qū)并選擇創(chuàng)造->物理二維材料給它起個名字冰IceMaterial:

在這里插入圖片描述

設(shè)置參數(shù):

在這里插入圖片描述

之后,我們可以在Hierarchy面板中選擇冰然后將IceMaterial從項目區(qū)拖入到BoxCollider2D>Material插槽:

在這里插入圖片描述

撞擊時摧毀冰
如果被足夠的力量撞擊,我們也希望冰層被摧毀,因為這就是冰的自然作用。我們添加腳本BreakOnImpact.cs腳本:

using UnityEngine;
using System.Collections;

public class BreakOnImpact : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
我們不需要啟動或者更新函數(shù),所以讓我們移除這兩個函數(shù)。我們需要一種方法來估計碰撞的力量。我們將保持簡單,并將速度與質(zhì)量相乘:
float collisionForce(Collision2D coll) {
    // Estimate a collision's force (speed * mass)
    float speed = coll.relativeVelocity.sqrMagnitude;
    if (coll.collider.GetComponent<Rigidbody2D>())
        return speed * coll.collider.GetComponent<Rigidbody2D>().mass;
    return speed;
}
*注:Collision2D繼承OnCollisionEnter2D功能,我們將獲取一個估計碰撞的力量,它包含方向與速度相乘。如果我們只關(guān)心速度,那么我們可以使用coll.relativeVelocity.sqrMagnitude…現(xiàn)在,如果造成碰撞的對象有剛體然后我們把速度乘以剛體的質(zhì)量…否則我們只返回速度。

好了,現(xiàn)在我們可以用OnCollisionEnter2D函數(shù)以獲得有關(guān)碰撞的通知。然后,我們將比較碰撞的力量和一個可配置的變量。如果它比力大,那么冰就會破裂:

using UnityEngine;
using System.Collections;

public class BreakOnImpact : MonoBehaviour {
    public float forceNeeded = 1000;

    float collisionForce(Collision2D coll) {
        // Estimate a collision's force (speed * mass)
        float speed = coll.relativeVelocity.sqrMagnitude;
        if (coll.collider.GetComponent<Rigidbody2D>())
            return speed * coll.collider.GetComponent<Rigidbody2D>().mass;
        return speed;
    }

    void OnCollisionEnter2D(Collision2D coll) {
        if (collisionForce(coll) >= forceNeeded)
            Destroy(gameObject);
    }
}
如果我們保存腳本,請按Play把鳥碰撞冰層,然后它就會破裂:

在這里插入圖片描述

現(xiàn)在,我們可以花幾分鐘來復(fù)制這些結(jié)構(gòu),并將它們放在一起,這樣我們就可以在它們之間添加豬了:

在這里插入圖片描述

10.綠豬

鳥兒想要消滅所有的豬,所以讓我們把一些豬加入到我們的游戲中,這樣鳥兒就不會覺得無聊了。

我們首先畫一個:

在這里插入圖片描述

導(dǎo)入設(shè)置:

在這里插入圖片描述

添加碰撞器和剛體:

在這里插入圖片描述

如果有足夠大的力量襲擊豬,豬就會死。幸運的是,我們已經(jīng)有了一個腳本。給我們的pig物體添加腳本BreakOnImpact.cs,并且設(shè)置Force Needed的值:

在這里插入圖片描述

*注意:能夠重用這樣的腳本是基于組件的開發(fā)。

現(xiàn)在我們可以復(fù)制這頭豬并把它移到一些結(jié)構(gòu)之間:

在這里插入圖片描述

如果我們按下Play然后我們就可以試著消滅豬了:

在這里插入圖片描述

11.橡膠

我們將為我們的游戲添加最后一個功能:彈弓橡膠,所以拖拽和釋放鳥看起來要好得多:

在這里插入圖片描述

我們首先畫一半的橡膠,這幾乎只是一條粗線:

在這里插入圖片描述

這里是導(dǎo)入設(shè)置:

在這里插入圖片描述

*注意:這次我們設(shè)置了Pivot到右(邊),正確的讓一些旋轉(zhuǎn)變得更容易。

現(xiàn)在我們可以從項目區(qū)進入場景兩次,說出其中一個左橡膠,另一個右橡膠把它們放在彈弓的上部:

在這里插入圖片描述

我們要確保左邊的那個總是畫出來的。后面彈弓和右彈弓總是被拉進去的。前面其中的一部分。我們可以再加兩個分類層對于我們的游戲,但我們將保持簡單,只需更改層序到-1左邊的橡膠和1右邊的橡膠:

在這里插入圖片描述

在這里插入圖片描述

現(xiàn)在橡膠看起來就像在外彈弓:

在這里插入圖片描述

在開始編寫腳本之前,讓我們在Hierarchy然后將這兩個對象設(shè)置為slingshot的子對象:

在這里插入圖片描述

*注意:每當(dāng)我們移動彈弓時,橡膠部件就會隨之移動。

讓我們創(chuàng)建一個新的C#腳本給它起個名字Rubber:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
這個腳本的目的是讓兩個橡膠部分跟隨鳥,直到它離開生成鳥的觸發(fā)圈。

我們需要兩個變量leftRubber 和rightRubber,讓我們在以后指定橡膠。我們不需要啟動或者更新函數(shù),讓我們刪除掉它們:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {
    // The Rubber objects
    public Transform leftRubber;
    public Transform rightRubber;
}
現(xiàn)在,有一些稍微復(fù)雜一些的功能。我們將需要一個功能,定位橡膠在彈弓和鳥的位置,我們必須先將橡膠旋轉(zhuǎn)到鳥的方向,然后根據(jù)鳥的距離使橡膠變成或變短:
void adjustRubber(Transform bird, Transform rubber) {
    // Rotation
    Vector2 dir = rubber.position - bird.position;
    float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
    rubber.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

    // Length
    float dist = Vector3.Distance(bird.position, rubber.position);
    dist += bird.GetComponent<Collider2D>().bounds.extents.x;
    rubber.localScale = new Vector2(dist, 1);
}
注意:首先我們計算從鳥到橡膠的距離,然后計算這個方向的角度。然后我們,通過Quaternion.AngleAxis(angle, Vector3.forward)將橡膠旋轉(zhuǎn)到這個角度。最后,我們計算從鳥到橡膠的距離,之后,我們將橡膠的縮放設(shè)置為這個距離加上碰撞器的x的長度既dist += bird.GetComponent().bounds.extents.x

這個OnTriggerStay2D功能將通知我們,每當(dāng)鳥改變它的位置時,它還在彈弓。我們可以使用這個函數(shù)來調(diào)整左右橡皮筋:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {
    // The Rubber objects
    public Transform leftRubber;
    public Transform rightRubber;

    void adjustRubber(Transform bird, Transform rubber) {
        // Rotation
        Vector2 dir = rubber.position - bird.position;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        rubber.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

        // Length
        float dist = Vector3.Distance(bird.position, rubber.position);
        dist += bird.GetComponent<Collider2D>().bounds.extents.x;
        rubber.localScale = new Vector2(dist, 1);
    }

    void OnTriggerStay2D(Collider2D coll) {
        // Stretch the Rubber between bird and slingshot
        adjustRubber(coll.transform, leftRubber);
        adjustRubber(coll.transform, rightRubber);
    }
}
快好了。我們將再增加一個離開時候觸發(fā)的事件,使橡皮筋在發(fā)射后變短:
void OnTriggerExit2D(Collider2D coll) {
    // Make the Rubber shorter
    leftRubber.localScale = new Vector2(0, 1);
    rightRubber.localScale = new Vector2(0, 1);
}
現(xiàn)在,我們可以通過首先選擇彈弓對象中的游戲?qū)ο?。層次性然后點擊添加組件->Scitps->Rubber…我們亦會把這兩個橡膠拖到相應(yīng)的槽內(nèi):

在這里插入圖片描述

如果我們按下Play現(xiàn)在我們可以看到小鳥和彈弓之間的橡皮筋:

在這里插入圖片描述

當(dāng)然,現(xiàn)在我們也可以玩一輪憤怒的小鳥了:

在這里插入圖片描述

總結(jié)

到這里本篇文章就結(jié)束了,我們剛剛創(chuàng)建了一個小游戲憤怒的小鳥翻版,使用簡單的形狀與顏色來達到一個良好的效果,廣泛的使用了Unity的2D物理引擎,添加了許多的效果

相關(guān)文章

  • c# 如何使用 My 命名空間

    c# 如何使用 My 命名空間

    這篇文章主要介紹了c# 如何使用 My 命名空間,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-10-10
  • C#監(jiān)控文件夾并自動給圖片文件打水印的方法

    C#監(jiān)控文件夾并自動給圖片文件打水印的方法

    這篇文章主要介紹了C#監(jiān)控文件夾并自動給圖片文件打水印的方法,涉及C#針對文件夾及圖片操作的相關(guān)技巧,非常具有實用價值,需要的朋友可以參考下
    2015-05-05
  • 深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組

    深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組

    這篇文章主要介紹了深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組,隱式類型的數(shù)組通常與匿名類型以及對象初始值設(shè)定項和集合初始值設(shè)定項一起使用,需要的朋友可以參考下
    2016-01-01
  • 在C#中如何使用Dapper詳解(譯)

    在C#中如何使用Dapper詳解(譯)

    這篇文章主要給大家介紹了關(guān)于在C#中如何使用Dapper的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2018-09-09
  • Unity快速生成常用文件夾的方法

    Unity快速生成常用文件夾的方法

    這篇文章主要介紹了Unity快速生成常用文件夾的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C#圖表算法之有向圖

    C#圖表算法之有向圖

    這篇文章介紹了C#圖表算法之有向圖,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • C#圖像識別 微信跳一跳機器人

    C#圖像識別 微信跳一跳機器人

    這篇文章主要為大家詳細介紹了C#圖像識別,微信跳一跳機器人,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • c#與mysql的連接

    c#與mysql的連接

    c#與mysql的連接...
    2007-03-03
  • C#實現(xiàn)聊天消息渲染與圖文混排詳解

    C#實現(xiàn)聊天消息渲染與圖文混排詳解

    在實現(xiàn)聊天軟件時,渲染文字表情圖文混排是一項非常繁瑣的工作,再加上還要支持GIF動圖、引用消息、撤回消息、名片等不同樣式的消息渲染時,就更加麻煩了。本文就來和大家分享一下具體實現(xiàn)方法,希望對大家有所幫助
    2023-02-02
  • C# 并發(fā)控制框架之單線程環(huán)境下實現(xiàn)每秒百萬級調(diào)度

    C# 并發(fā)控制框架之單線程環(huán)境下實現(xiàn)每秒百萬級調(diào)度

    本文介紹了一款專為工業(yè)自動化及機器視覺開發(fā)的C#并發(fā)流程控制框架,通過模仿Go語言并發(fā)模式設(shè)計,支持高頻調(diào)度及復(fù)雜任務(wù)處理,已在多個項目中驗證其穩(wěn)定性和可靠性
    2024-10-10

最新評論