通過委託與事件監聽狀態改變來更新UI
阿新 • • 發佈:2019-01-29
該博文涵蓋的知識點
1. C# 委託 2. 如何利用委託監聽事件以此更新顯示所要完成目標
我們剛開始做好的部分UI介面如下圖所示:
觀察左邊的紅色方框,我們先做了例項的姓名,頭像,slider,和Label等,在運行遊戲時候需要更新相應的屬性。
在下面的指令碼中,我們分別更新:左邊方框中的nameLabel(黃曉明),energyLabel(50/100),toughenLabel(32/50)以及levelLabel(89);和右邊的兩個Label(12345678和12345678)。如何更新呢?我們藉助委託註冊事件來監聽屬性的改變,下面不再做解釋,指令碼中註釋說明了一切!!!!
指令碼、Unity相關設定
這裡只使用三個指令碼來學習如何使用委託來註冊事件,以此監聽屬性的變化。如上圖所示,PlayerBar指令碼繫結在player-bar上,PlayerInfo指令碼繫結在GameObject(空的遊戲物體,作為控制)上,TopBar指令碼繫結在top-bar上,分別在這些指令碼中獲取Unity Hierarchy中的相關屬性,然後進行更新。下面分別是三個指令碼:PlayerInfo,PlayerBar以及TopBar
using UnityEngine; using System.Collections; public enum InfoType{ Name, HeadPortrait, Level, Power, Exp, Diamond, Coin, Energy, Toughen, All } public class PlayerInfo : MonoBehaviour { // 建立該類 為單例模式、 public static PlayerInfo _instance; #region property private string _name; private string _headPortrait; private int _level = 1; private int _power = 1; private int _exp = 0; private int _diamond; private int _coin; private int _energy; private int _toughen; #endregion // 體力和歷練的計時器;一分鐘體力加1 private float energyTimer = 0; private float toughenTimer = 0; // ----------------- 委託 ----------------------------------- public delegate void OnPlayerInfoChangedEvent(InfoType type); // 利用委託定義事件,通過事件監聽屬性的更改 public event OnPlayerInfoChangedEvent OnPlayerInfoChanged; #region get set method public string Name{ get{ return _name; } set{ _name = value; } } public string HeadPortrait{ get { return _headPortrait; } set { _headPortrait = value; } } public int Level{ get { return _level; } set { _level = value; } } public int Power{ get { return _power; } set { _power = value; } } public int Exp{ get { return _exp; } set { _exp = value; } } public int Diamond{ get { return _diamond; } set { _diamond = value; } } public int Coin{ get { return _coin; } set { _coin = value; } } public int Energy{ get { return _energy; } set { _energy = value; } } public int Toughen{ get { return _toughen; } set { _toughen = value; } } #endregion void Start(){ Init ();// 初始化 } void Awake(){ _instance = this; } void Update(){ // ------------- 實現體力和歷練的自由增長 ---------------------------- // 每一分鐘體力和歷練增長1,其中體力總數為100,歷練總是為50 // 實現體力的自動增長 if (this.Energy < 100) { energyTimer += Time.deltaTime; if (energyTimer > 60) { Energy += 1; energyTimer -= 60; OnPlayerInfoChanged (InfoType.Energy); } } else { energyTimer = 0; } // 實現歷練的自由增長 if (this.Toughen < 50) { toughenTimer += Time.deltaTime; if (toughenTimer > 60) { Toughen += 1; toughenTimer -= 60; OnPlayerInfoChanged (InfoType.Toughen); } } else { toughenTimer = 0; } // ------------- ----------------------- ---------------------------- } // 初始化屬性 void Init(){ this.Coin = 9870; this.Diamond = 1234; this.Energy = 78; this.Exp = 123; this.HeadPortrait = "頭像底板女性"; this.Level = 12; this.Name = "千頌伊"; this.Power = 1745; this.Toughen = 34; OnPlayerInfoChanged (InfoType.All); } }
using UnityEngine; using System.Collections; /**2016-5-13 By BigoSprite * 設定PlayerBar指令碼的執行順序次於PlayerInfo指令碼 * 步驟如下: * Edit>Project Settings>Script Execution Order * 注意:值小的,先執行 */ public class PlayerBar : MonoBehaviour { // 該指令碼用於更新左上角這一區域的屬性 private UISprite headSprite; private UILabel nameLabel; private UILabel energyLabel; private UISlider energySlider; private UILabel levelLabel; private UILabel toughenLabel; private UISlider toughenSlider; private UIButton energyPlusButton; private UIButton toughenPlusButton; void Awake(){ headSprite = transform.Find ("head-sprite").GetComponent<UISprite> (); nameLabel = transform.Find ("name-label").GetComponent<UILabel> (); energyLabel = transform.Find("energy-progressBar/Label").GetComponent<UILabel> (); energySlider = transform.Find ("energy-progressBar").GetComponent<UISlider> (); levelLabel = transform.Find ("level-label").GetComponent<UILabel> (); toughenLabel = transform.Find ("toughen-progressBar/Label").GetComponent<UILabel> (); toughenSlider = transform.Find ("toughen-progressBar").GetComponent<UISlider> (); energyPlusButton = transform.Find ("energyPlusButton").GetComponent<UIButton> (); toughenPlusButton = transform.Find ("toughenPlusButton").GetComponent<UIButton> (); energyPlusButton = transform.Find ("energyPlusButton").GetComponent<UIButton> (); toughenPlusButton = transform.Find("toughenPlusButton").GetComponent<UIButton> (); // 使用單例模式前,要保證先初始化。因為我們設定PlayerInfo指令碼先執行,後執行PlayerBar指令碼 // 而已經在PlayerInfo指令碼中的Awake方法中初始化了,因此可保證_instance肯定存在。 // ------- 註冊PlayerInfo中的委託事件(+=), PlayerInfo是單例模式,公有的類,所以 ---------- PlayerInfo._instance.OnPlayerInfoChanged += this.OnPlayerInfoChanged; } // 登出事件 -= void OnDestory(){ PlayerInfo._instance.OnPlayerInfoChanged -= this.OnPlayerInfoChanged; } // 當我們的主角資訊發生改變的時候,會觸發這個方法 void OnPlayerInfoChanged(InfoType type){ // 首先判斷角色的哪部分資訊改變了 // 注意這個指令碼(PlayerBar)繫結在PlayerBar身上,即左上角的區域 if(type == InfoType.All ||type == InfoType.Name || type == InfoType.Level || type == InfoType.Energy || type == InfoType.Toughen){ UpdateShow();// 更新資訊的顯示 } } // 更新顯示 // 如何更新資訊的顯示?怎麼確定具體哪一個資訊改變了??? // 這裡管他具體哪個改變了,全部給他更新,哈哈!!! void UpdateShow(){ PlayerInfo info = PlayerInfo._instance;// 初始化一個物件 headSprite.spriteName = info.HeadPortrait;// 頭像 levelLabel.text = info.Level.ToString(); nameLabel.text = info.Name; // 注意: 這裡需要除以100f和50f,得到浮點型;如果除以100和50,slider不會顯示! energySlider.value = info.Energy / 100f;// energy Slider energyLabel.text = info.Energy.ToString () + "/100"; toughenSlider.value = info.Toughen / 50f;// toughen Slider toughenLabel.text = info.Toughen.ToString()+"/50"; } }
using UnityEngine;
using System.Collections;
public class TopBar : MonoBehaviour {
private UILabel coinLabel;
private UILabel diamondLabel;
private UIButton coinPlusButton;
private UIButton diamondPlusButton;
void Awake(){
coinLabel = transform.Find ("coin-bg/Label").GetComponent<UILabel> ();
diamondLabel = transform.Find ("diamond-bg/Label").GetComponent<UILabel> ();
coinPlusButton = transform.Find ("coin-bg/coinPlusButton").GetComponent<UIButton> ();
diamondPlusButton = transform.Find ("diamond-bg/diamondPlusButton").GetComponent<UIButton> ();
// 1. 註冊事件,同樣是在設定指令碼執行次序的前提下
// 加入未設定執行次序,PlayerInfo不先於TopBar執行,會報錯:說
// Object reference not set to an instance of an object.
// 即PlayerInfo指令碼中的_instance = this;次於TopBar指令碼執行,TopBar指令碼使用例項,但例項還未初始化呢?所以需要指定次序。
PlayerInfo._instance.OnPlayerInfoChanged += this.OnPlayerInfoChanged;
}
// 登出事件
void OnDestory(){
PlayerInfo._instance.OnPlayerInfoChanged -= this.OnPlayerInfoChanged;
}
// ---------------------------------------------------------------------
// 1. 註冊和登出事件
// 2. 更新顯示
// 注意:更改指令碼執行順序,PlayerInfo先於TopBar執行
void OnPlayerInfoChanged(InfoType type){
if(type == InfoType.All || type == InfoType.Coin || type == InfoType.Diamond){
UpdateShow ();
}
}
void UpdateShow(){
PlayerInfo info = PlayerInfo._instance;
coinLabel.text = info.Coin.ToString ();
diamondLabel.text = info.Diamond.ToString ();
}
}
其中,設定指令碼執行次序如下圖所示:
執行Unity,效果如下圖所示:
注:本博文參考SIKI老師的《泰斗破壞神》,用於學習