UNET連線遊戲(五){死神之眼我看的見你的名子,HUD_UI}

本篇使用的是5.3版後有UNET的UNITY
目標:基本連線遊戲機制+敵方玩家血條(UI)
1.延續前篇(UNET連線遊戲(四){我快死了,HP_UI})

  • 為了區分連線的玩家ID和自己的ID,需要在HUD增加一個Text的UI重新命名為PLAYER_ID,並參考下列設定
    結構:
    unet-hit-025
    效果預覽:
    unet-hit-026unet-hit-027

  • 隨後在玩家身上掛載一隻程式PlayerID.cs
    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    using UnityEngine.UI;
    public class PlayerID : NetworkBehaviour {
    	void Start () {
    		GetNetIdentity ();
    	}
    	// Update is called once per frame
    	void Update () {
    	}
    	void GetNetIdentity(){
    		this.gameObject.name = "PLAYER_" + GetComponent<NetworkIdentity> ().netId.ToString();
    		if (isLocalPlayer) {
    			GameObject player = GameObject.Find ("PLAYER_ID");
    			player.GetComponent<Text> ().text = ID ();
    		}
    	}
    	public string ID(){
    		return this.gameObject.name;
    	}
    }

    透過GetNetIdentity()的功能去取得每個PLAER在網路上獨一的netId,那通常是一個流水號,所以透過this.gameObject.name = “PLAYER_” +這個流水號重新命名這個PLAYER,以便我們之後識別其他玩家。

  • 物件確實被重新命名後接下來就需要在畫面上顯示,這部分一樣透過UGUI來呈現。比較不同的是這個UI要動態產生;因此我們先從畫面上編輯再將它製成預製物件。
    效果預覽:
    unet-hit-017
  • 這個UI由兩個部分組成:血條(命名為HP_ENEMY)+ID文字(命名為ID)
    unet-hit-019
    這個血條跟製作自己的HP一樣的方式只是要的是比較小的版本。先在HUD的UI畫布下加入一個Image並放入1PX的白點,(做法可以參考前篇),需求若為長寬10:1的BAR可以先依照下圖的參數設定
    unet-hit-018
  • 子物件加入一個Text的UI,並寫以左下角對其的方式貼齊血條。參數設定可以參考下圖
    unet-hit-021
    把HP_ENEMY拖入Resources資料夾製成預製物,刪除場景上的HP_ENEMY
  • 接下來需要的就是人物進場時,要將這個物建置入HUD內
    跟之前的GunController.cs生成子彈一樣的方式來生成這個血條,差別在這個血條是由非玩家的人物產生,我們撰寫一條EnemyHP.cs來控制他

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    using UnityEngine.UI;
    public class EnemyHP : NetworkBehaviour {
    	private GameObject HudBar;
    	// Use this for initialization
    	void Start () {
    		if(!isLocalPlayer)SpawnHpBar ();
    	}
    	// Update is called once per frame
    	void Update () {
    	}
    	void SpawnHpBar ()
    	{
    		HudBar = Instantiate (Resources.Load ("HP_ENEMY")) as GameObject;
    		HudBar.name = "PLAYER_" + GetComponent<NetworkIdentity>().netId.ToString();
    		HudBar.transform.parent = GameObject.Find ("HUD").transform;
    		HudBar.GetComponent<UIReset> ().playerName = this.gameObject;
    	}
    }

     

  • 執行後發現跟我們原來的設計不太相同,雖然所屬UI跟著PLAYER改變名子了但在畫面上的位置還有大小不太正常
    unet-hit-022 unet-hit-023
    原因在於原來的UI物件是在HUD的子物件條件下設置的,離開場景外後參數會有所變化,所以重新置入的時候我們需手動將這些數值重置。
    unet-hit-024
    包括:Left、Top、Right、Bottom以及Scale的X、Y、Z縮放
  • 在HP_ENEMY預製物加入一個UIReset.cs將UI歸零重置
    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    public class UIReset : MonoBehaviour {
    	RectTransform UISET;
    	// Use this for initialization
    	void Start () {
    		Reset ();
    	}
    	// Update is called once per frame
    	void Update () {
    	}
    	void Reset(){
    		UISET = this.transform.GetComponent<RectTransform> ();
    		UISET.localScale = new Vector3 (1, 1, 1);
    		UISET.offsetMin = new Vector2 (0,0);
    		UISET.offsetMax = new Vector2 (0,0);
    		transform.FindChild ("ID").GetComponent<Text> ().text = this.gameObject.name;
    	}
    }

    UISET.localScale重置縮放比為1
    offsetMin、offsetMax重置XY的最小最大位置,讓UI與邊界距離為0
    並透過transform.FindChild (“ID”)順手將文字替換為角色ID

  • 剩下的問題則是位置,目前雖然生成UI在HUD內,但他不會跟著角色人物移動,因此我們繼續強化剛剛UIReset.cs的程式,增添UIpos()方法在Update裡反覆取得人物的位置並且換算UI的正確位置。
    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    public class UIReset : MonoBehaviour {
    	RectTransform UISET;
    	public GameObject playerName;
    	GameObject playerCamera;
    	Vector3 pos;
    	Vector3 pos_scr;
    	// Use this for initialization
    	void Start () {
    		Reset ();
    	}
    	void Update () {
    		if (playerName) {
    			UIpos ();
    		} else
    			Destroy (this.gameObject);
    	}
    	void Reset(){
    		UISET = this.transform.GetComponent<RectTransform> ();
    		UISET.localScale = new Vector3 (1, 1, 1);
    		UISET.offsetMin = new Vector2 (0,0);
    		UISET.offsetMax = new Vector2 (0,0);
    		transform.FindChild ("ID").GetComponent<Text> ().text = this.gameObject.name;
    		playerCamera = GameObject.FindWithTag ("LocalCamera");
    	}
    	void UIpos(){
    		pos = new Vector3 (playerName.transform.position.x , playerName.transform.position.y + playerName.GetComponent<Collider>().bounds.size.y*0.75f, playerName.transform.position.z);
    		pos_scr = playerCamera.GetComponent<Camera>().WorldToScreenPoint (pos);
    		//Debug.Log (pos_scr);
    		if (pos_scr.z > 0 ) {
    			UISET.anchorMin = new Vector2 (pos_scr.x / Screen.width - 0.05f, pos_scr.y / Screen.height - 0.01f);
    			UISET.anchorMax = new Vector2 (pos_scr.x / Screen.width + 0.05f, pos_scr.y / Screen.height);
    		} else {
    			UISET.anchorMin = new Vector2 (1, 1);
    		}
    	}
    }
    

    但是由於UI是以玩家本身的攝影機作為基準來設定的,29行用尋找物件標籤的方式找到本地玩家的攝影機,因此除了在標籤列表增加LocalCamera的標籤以外,很早之前的PlayerController.cs裡也要加上一些判斷,來幫本地玩家的攝影機掛上這個標籤,如下: 29-32的else{…}

    using UnityEngine;
    using UnityStandardAssets.Characters.FirstPerson;
    using UnityEngine.Networking;
    public class PlayerController: NetworkBehaviour
    {
    	private FirstPersonController fpsController;
    	private Transform playerCameraTransform;
    	private Camera playerCamera;
    	private AudioListener playerAudioListener;
    	void Start()
    	{
    		if (!isLocalPlayer) {
    			fpsController = GetComponent<FirstPersonController> ();
    			playerCameraTransform = transform.FindChild ("FirstPersonCharacter");
    			playerCamera = playerCameraTransform.GetComponent<Camera> ();
    			playerAudioListener = playerCameraTransform.GetComponent<AudioListener> ();
    			if (fpsController) {
    				fpsController.enabled = false;
    			}
    			if (playerCamera) {
    				playerCamera.enabled = false;
    			}
    			if (playerAudioListener) {
    				playerAudioListener.enabled = false;
    			}
    		} else {
    			playerCameraTransform = transform.FindChild ("FirstPersonCharacter");
    			playerCameraTransform.tag = "LocalCamera";
    		}
    	}
    }

     

  • 連線執行就可以看到對方的ID和HP跟著跑啦
    unet-hit-028

下期預告:UNET連線遊戲(六){你快掛囉,HUD_UI續}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *