Unity3d項目入門之Rolling Ball

  下面經過分析製做一個簡單的收集特定物體的滾球遊戲來入門unity,包括操做面板和C#腳本的編寫導入,建立Game Object和給Object添加組件等等。html

  一 初始設置架構

  在Assert下建立主場景MainScene。往場景中添加一3D Obj - 「平面」 Plane,rename 爲Ground,編輯器

  

  建立玩家 Player 對象(Sphere),選中球以此點擊「Edit」->「Frame Select」或者快捷鍵「F」,可聚焦到當前所選的obj。設置0.5個unity單位讓球脫離地面。ide

  

  新增Materials材質文件夾,給Ground對象設置顏色。設置Albedo(反射率,直接影響反射光照)的RGB爲(0,32,64),而後把「衣服」材質拖到Ground上。函數

  二 移動玩家ui

  玩家移動須要接收鍵盤輸入,同時碰到邊緣須要停下來,所以給玩家添加一物理剛體 - 「Rigibody」spa

           (能夠經過up和down調整組件的順序).net

  由於要接收鍵盤輸入,故給玩家添加一C#腳本,命名爲PlayerController3d

       

  注意,經過組件的方式添加腳本會生成在項目根目錄下,咱們能夠新建一Scripts文件夾保持項目的組織架構的清晰,把相關的腳本都拖到這個腳本文件夾中。 本例中腳本代碼以下:code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    //目的是每一幀都檢測一下用戶的輸入,而後每一幀都把輸入應用到遊戲對象上
    private void FixedUpdate()
    {
        //得到用戶輸入
        float moveHorization = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        //注意y方向是上下移動,則這裏只需x,z
        Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical);
        rb.AddForce(movement);
    }
}

  每幀檢測有兩種方法:①Update每一幀展現以前被調用;②Fixed Update:進行任何的物理計算以前被調用,物理代碼在這裏執行。 對剛體施加力的做用使球移動起來,是物理系統,則本例在Fixed Update裏添加代碼。

  運行Play遊戲,發現有兩個問題:一是太慢;二是移動一會就脫離視野看不到了。

public class PlayerController : MonoBehaviour {
    //只有public變量纔會出現Inspector面板
    public float speed;

    ... ...

    private void FixedUpdate()
    {
        ... ...
        rb.AddForce(movement* speed);
    }
}

  

  運行遊戲,能夠手動調節移動的速度了。

  三 移動攝像機

  上述的問題,顯然由於攝像機不會移動致使看到的視野頗有限,這就須要將攝像機和玩家角色綁定。 首先沿y軸向上95單位,再沿x軸旋轉45度,

  

  而後把攝像機當作是玩家角色的子對象,這就是所謂的「第三人稱視角」。 但僅僅簡單綁定到玩家對象上,會發現攝像機的x,y,z值在瘋狂無規律變化,轉得眼花繚亂,顯然不正確。其實攝像機不須要隨着玩家對象一直翻滾,因此直接綁定是不正確的。  回想一下打CF的FTS遊戲時,能夠發現攝像頭和爆頭槍始終保持在一個相同的距離和角度的參數。 故給Camera添加腳本CameraController控制以下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour {
    //跟隨對象
    public GameObject player;
    private Vector3 offset;

    void Start () {
        //第一幀開始計算好攝像機和玩家角色對象的偏移
        offset = transform.position - player.transform.position;
    }
    
    void LateUpdate () {
        //每幀保持恆定間隔 從而每幀顯示以前先移動到跟角色相關的新的位置
        transform.position = player.transform.position + offset;
    }
}

  注意!:上述代碼每幀更新的方法最好使用LateUpdate。 LateUpdate和Update同樣都是每幀都會執行,但它執行在全部的東西都Update以後。這樣就能肯定玩家角色在這一幀內已經移動完成,緊接着的攝像機作的運算是最新的。

  運行遊戲,發現遊戲是不會跟着動的?what!  別忘了把當前玩家即那個球拖動到player的變量賦值,正常,實現了第三人稱視角。

  四 設置遊戲場地

  這節要解決的問題主要有兩點,一是圍欄阻擋的添加,二是計分物的增長。建立一Empty Object,命名爲Wall,做爲父空對象。而後建立一Cube方格,命名爲WestWall,reset重置到原點。將WestWall做爲Wall的子對象。 快捷鍵F聚焦得下圖:

  

  設置尺寸爲寬x:0.5,高y:2,長z:10,設置x位置爲-5。同理建立另外三面牆體的Game Object,

  

  由於新建的Cube有Box Collider,則會和玩家剛體發生碰撞檢測,

  

  五 建立收集物

  新建一Cube,命名爲PickUp,同理重置reset位置。爲取消Player對象的視覺阻擋,可取消選擇Name屬性,實質是遊戲對象的Active勾選框取消選擇會讓該遊戲對象在場景中不可見

  

  縮小並沿各個軸旋轉45度,而後添加腳本Rotator控制持續的轉動,根據unity官方文檔可知旋轉和移動都有對應的公用方法接口,以下:

  

    

     

   

     

  腳本代碼以下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Rotator : MonoBehaviour {
    void Update () {
        //注意旋轉接口函數是類對象的公共方法,因此須要經過對象來調用,故必須小寫t開頭transform
        transform.Rotate(new Vector3(15,30,45) * Time.deltaTime);//爲使旋轉更平滑乘以deltaTime
    }
}

  運行遊戲,能看到收集物每幀實時更新旋轉角度。 接下來,就須要在場景中添加多個相似的這種拾取物,這裏有個很重要的概念點:預設體prefab),指一個資源,它包含一個遊戲對象或對象組的模板或原型。prefab的做用在於,對一個預設的實例作變動改變預設資源自己,則場景中全部的這個預設對象(如此例中的拾取物對象)都會作一樣的變動!  所謂的「分身」做用,這裏的收集物顯然可作成預設體:

  (根目錄新建Prefabs目錄裝預設體)

  將某個對象 A 拖到Prefabs文件夾,能發現對象A的Name變藍,表示成爲了預設體,以下圖:

  

  建立一空對象做爲父節點,單獨裝載全部預設體實例instance。這裏要注意一點,即每一個instance實例對象座標系的選擇,主要有兩種:一是Local本地座標系,  是伴隨對象自身變換而改變的座標系,以下:

  

  二是Global世界座標系, 不會因對象旋轉變換而改變座標系,以下:

  

  本例中爲了保持各個拾取物都處於同一個水平面,故應該切換成Global模式,

  (y軸方向不拖動便能保持同一水平面)

  爲了更突出,可更改預設體的材質顏色,直接複用上面的一個材質,而後把材質應用到預設體上。 這裏有個方法:

  ①直接替換材質到預設體基類上。以下圖:

      

  ②替換材質到某一個預設體instance實例上,但必需要記得點擊「Apply」才能應用到預設體及其全部實例對象,以下:

       

  六 展現分數和文本

  顯然須要兩部分實現本例內容,一是展現分數,二是計算統計分值。在PlayerController中添加一count私有變量用來存儲當前分數,初始值爲0;每次發生碰撞時自增1,而後傳遞給UI控件顯示。

  1)右鍵選UI部分往場景添加一個Text控件,法線畫布Canvas和事件系統EventSystem也隨之建立(UI控件內容都是放置在一畫布中,規定全部的UI元素都是畫布Canvas的子元素)。

  

  和Game Object不一樣的是,Transform變量變成了Rect Transform,可見UI元素可設置錨點和軸心等因素:

     

  如這裏把錨定至畫布左上角,同時把軸心設置在了左上角,設置x = 10,y = -10設置邊間距。到此UI相關設置完畢,下面要在腳本中獲取這個UI控件:

  注意!:UI箱中的全部UI元素的詳細信息都在一個叫「UI」的namespace命名空間中,和腳本代碼中已有的 「using UnityEngine;」 和 「using System.Collections;」等同樣的道理,所以在腳本開頭加上:

  using UnityEngine.UI;

  或者在VS編輯器跳轉到定義能看到命名空間中對應UI類的定義,

  

  接下來就能在下面編寫UI代碼,先定義一個public變量來引用保存UI文本組件,而後再初始化UI文本顯示值。代碼以下:

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour {
    public Text CountText_;
    private int count;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        count = 10;
        CountText_.text = "Count Text:" + count.ToString();
    }
    ... ... ...
}

  2)簡單說,就是和拾取物發生碰撞時,通知玩家對象對count變量自增並更新UI顯示;同時把被碰撞的拾取物隱藏不可見。  總結兩點:

  ①隱藏不可見用SetActive,但要先獲取實體類對象gameObject再調用; 銷燬對象用Destroy

  ②碰撞事件監聽OnTriggerEnter

  

  這裏注意一點,就是要對發生碰撞的類型過濾下,由於此例中和圍欄發生碰撞也會進入這個事件通知,代碼以下:

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("fuck"))
        {
            count = count + 1;
            CountText_.text = "Count Text:" + count.ToString();
        }
    }

  運行遊戲,發現發生碰撞的時候並無響應事件更新顯示控件。oh My God! 查閱資料,發現有一重要點忽略了,就是「trigger開關」! 接收碰撞物體的是Collider,有一 Is Trigger屬性,以下:

  

  默認不勾選的,則會有碰撞中止的物理效果。當勾選激活此項時,會調用碰撞雙方的腳本 OnTrigger***, 反之,腳本方面沒有任何反應。 但激活帶來的反作用就是不會再有物理效果,如本例中若把player的Collider激活會發現球直接穿牆出去,同時自由落體掉下去了。 故這裏只把拾取物的prefab的trigger開關所有打開接收碰撞響應(由於拾取物沒有RigidBody剛體),整體代碼以下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour {
    public float speed;
    private Rigidbody rb;
    public Text CountText_;
    private int count;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        count = 0;
        CountText_.text = "Count Text:" + count.ToString();
    }

    private void FixedUpdate()
    {
        float moveHorization = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical);
        rb.AddForce(movement* speed);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("fuck"))
        {
            other.gameObject.SetActive(false);
            count = count + 1;
            CountText_.text = "Count Text:" + count.ToString();
        }
    }
}

  運行遊戲,正常運行!

  參考資料連接:

  http://www.javashuo.com/article/p-flijmgxi-mg.html (Unity3D碰撞檢測)

  https://www.cnblogs.com/zengbinsi/p/zengbinsi_unity3d_004.html (【Unity入門】碰撞檢測與觸發檢測)

  七 編譯發佈

  (或快捷鍵 Ctrl + Shift + B)

  選擇不一樣的平臺,

  

  

  把須要編譯的場景添加至Build Settings窗口,能夠經過「Add Open Scenes」來添加當前場景,或者從項目視圖中拖拽任意場景到Build Settings窗口的頂部區域。注意,咱們無需包含項目中的每一個場景,只包含須要的場景便可。 甚至窗口中沒有添加任何場景也能編譯,由於Unity會選擇當前正在打開編輯的場景。 最後點擊build按鈕,開始編譯。

  

  PS.編譯過程須要Android SDK,若沒有安裝則會編譯失敗。

  參考資料連接:

  《unity3d-配置Android環境,打包發佈Apk流程詳解

相關文章
相關標籤/搜索