同步玩家狀態是多人連線中一個重要的概念。
這次的教學中,我們將在子彈碰撞到玩家物件時,讓玩家的血量數值減少,而當前血量也屬於玩家狀態之一,所以我們也要對血量數值做同步。
新增子彈碰撞
讓子彈能影響目標物的第一步是新增能處理碰撞的元件,在本範例中,我們會在子彈碰到其他碰撞體時,將子彈銷毀。
這次的教學中,我們將在子彈碰撞到玩家物件時,讓玩家的血量數值減少,而當前血量也屬於玩家狀態之一,所以我們也要對血量數值做同步。
新增子彈碰撞
讓子彈能影響目標物的第一步是新增能處理碰撞的元件,在本範例中,我們會在子彈碰到其他碰撞體時,將子彈銷毀。
- 在Bullet物件下新增名為Bullet的腳本
- 開啟此腳本,並刪除所有內容
- 新增碰撞時的處理函式,內容是碰到其他碰撞體時,將自己銷毀
using UnityEngine; using System.Collections; public class Bullet : MonoBehaviour { void OnCollisionEnter() { Destroy(gameObject); } }編譯過Bullet腳本後,可以做第一次的測試,測試連線時結果的方法點我。
現在當子彈會在碰撞時銷毀,而且子彈被NetworkManager管理,當子彈在伺服器中被銷毀時,所有用戶端看到的那顆子彈也會被銷毀。
玩家血量
要新增單機版本的血量,我們需要一個新的腳本來追蹤並顯示當前的血量。
- 在Player prefab下新增名為Health的腳本
- 開啟此腳本,並刪除所有內容
- 新增以下內容,最大血量maxHealth,當前血量currentHealth,以及受到攻擊的函式TakeDamage
using UnityEngine; public class Health : MonoBehaviour { public const int maxHealth = 100; public int currentHealth = maxHealth; public void TakeDamage(int amount) { currentHealth -= amount; if (currentHealth <= 0) { currentHealth = 0; Debug.Log("Dead!"); } } }在Bullet物件碰撞到玩家物件時,需要呼叫TakeDamage,因此我們要對Bullet腳本做更新,在碰撞呼叫OnCollisionEnter時,需要一個collision變數存取那一個被子彈碰到的對象,之後要呼叫該對象Health腳本中的TakeDamage。
using UnityEngine; using System.Collections; public class Bullet : MonoBehaviour { void OnCollisionEnter(Collision collision) { GameObject hit = collision.gameObject; Health health = hit.GetComponent<Health>(); if (health != null) { health.TakeDamage(10); } Destroy(gameObject); } }現在子彈能對玩家的生命值造成傷害,但並不會顯示在畫面上,因此接下來我們要在玩家物件上新增簡易的血條。
新增簡易血條
為了做到此功能,我們需要新增簡單的UI物件,要注意的是,接下來的方法並不是一個好做法,但可以讓本範例在簡單的幾個步驟內就完成此功能。
- 新增UI->Image(同時也會新增Canvas和EventSystem)
- 將Canvas重新命名為HealthbarCanvas
- 將Image重新命名為Background
- 設定Background的數值...
- RectTransform下的Width為100
- RectTransform下的Height為10
- Image下的Source Image設為InputFieldBackground
- Image下的Color為紅色
- 複製貼上一個Background並重新命名為Foreground
- 讓Foreground成為Background的子物件
- 將Player prefab拖曳至Hierchy
- 讓HealthbarCanvas成為Player的子物件,最後會像這樣:
- 選取Foreground,將Image下的Color設為綠色
- 開啟Anchor Presets將Pivot和Position設為Middle Left
- 接著選取HealthbarCanvas...
- 將Render Mode預設的Overlay改為World Space
- 點選RectTransform的齒輪reset數值
- 將RectTransform的Scale設為(0.01, 0.01, 0.01)
- 將RectTransform的Position設為(0.0, 1.5, 0.0)
現在要將HealthbarCanvas與前面的血量和損傷做連結,我們需要從Health腳本中改變血條圖來顯示當前血量。
開啟Health腳本,新增命名空間UnityEngine.UI,新增healthBar變數用來參照Foreground的RectTranform,最後在TakeDamage中血量減少後,將當前血量currentHealth作為healthBar的Width,如此一來就可以顯示血量減少的結果。
using UnityEngine; using UnityEngine.UI; public class Health : MonoBehaviour { public const int maxHealth = 100; public int currentHealth = maxHealth; public RectTransform healthBar; public void TakeDamage(int amount) { currentHealth -= amount; if (currentHealth <= 0) { currentHealth = 0; Debug.Log("Dead!"); } healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y); } }
- 回到Hierarchy視窗中的Player物件,將Foreground拖曳到Healthbar變數上
- 點選Player的apply更新Player prefab
- 刪除Hierarchy視窗中的Player物件
最後我們需要讓血條能一直朝向攝影機。
- 找到Player prefab下的HealthbarCanvas
- 新增名為Billboard的腳本
- 開啟Billboard,在Update中新增transform.LookAt(Camera.main.transform);
現在我們可以再一次測試結果,測試連線時結果的方法點我。
目前,玩家物件的修改可以獨立運作於所有用戶端和伺服器上,當一名玩家射擊另一名玩家時,Bullet和Health腳本在本機上執行,並不會產生同步。
Bullet物件由NetworkManager管理,所以在碰撞產生時,會把伺服器和所有用戶端的該顆子彈給銷毀。子彈和玩家發生碰撞,玩家可能會造成傷害,但也有可能因為延遲或其他原因,在造成傷害這個判斷在發生前子彈就被銷毀,子彈同步但玩家血量狀態不同步,這個問題可能會造成各用戶端看到的當前血量完全不同,所以下一篇我們將同步玩家的血量狀態。
上一篇:新增多人連線時的射擊功能
下一篇:連線時的玩家血量
您绝对熟悉开发人员用于开发项目的最佳编码语言 C#,并且他们可以正确回答所有查询,例如“oncollisionenter 已声明但从未使用”。
回覆刪除