仿LOL項目開發第六天
by草帽
OK,因為更新模塊已經處理好了,接着開始登陸的編寫。那么我們就需要狀態機的管理。
所謂狀態機就是在哪個狀態執行那個狀態的代碼邏輯:
那么我們開始編寫GameStateManager來管理:
我們先在DefineCommon里面定義游戲狀態類型:
/// <summary> /// 游戲狀態 /// </summary> public enum GameStateType { GS_Continue,//中間狀態,也就是說介於兩個狀態轉換的中間狀態 GS_Login,//登陸狀態 GS_User,//創建用戶狀態 GS_Lobby,//大廳,類似於LOL主界面狀態 GS_Room,//創建房間狀態 GS_Hero,//選擇英雄 GS_Loading,//加載狀態 GS_Play,//對戰狀態 GS_Over,//對戰結束 }
有分這么多個狀態,如果還有其他狀態以后再加:
然后在GameStateManager里面搞個字典緩存這些狀態。這個管理方式和WindowManage十分的相似。
using UnityEngine; using System.Collections.Generic; using Game; using Game.Common; /// <summary> /// 游戲狀態管理器 /// </summary> public class GameStateManager : Singleton<GameStateManager> { public Dictionary<GameStateType, IGameState> m_dicGameStates; IGameState m_oCurrentState; public IGameState CurrentState { get { return this.m_oCurrentState; } } public GameStateManager() { m_dicGameStates = new Dictionary<GameStateType, IGameState>(); m_dicGameStates.Add(GameStateType.GS_Login, new LoginState()); } /// <summary> /// 改變游戲狀態 /// </summary> /// <param name="stateType"></param> public void ChangeGameStateTo(GameStateType stateType) { if (m_oCurrentState != null && m_oCurrentState.GetStateType() != GameStateType.GS_Loading && m_oCurrentState.GetStateType() == stateType) return; if (m_dicGameStates.ContainsKey(stateType)) { if (m_oCurrentState != null) { m_oCurrentState.Exit();//先退出上個狀態 } m_oCurrentState = m_dicGameStates[stateType]; m_oCurrentState.Enter();//進入這個狀態 } } /// <summary> /// 進入默認狀態,默認為登陸狀態 /// </summary> public void EnterDefaultState() { ChangeGameStateTo(GameStateType.GS_Login); } public void FixedUpdate(float fixedDeltaTime) { if (m_oCurrentState != null) { m_oCurrentState.FixedUpdate(fixedDeltaTime); } } public void Update(float fDeltaTime) { GameStateType nextStateType = GameStateType.GS_Continue; if (m_oCurrentState != null) { nextStateType = m_oCurrentState.Update(fDeltaTime); } if (nextStateType > GameStateType.GS_Continue) { ChangeGameStateTo(nextStateType); } } public IGameState getState(GameStateType type) { if (!m_dicGameStates.ContainsKey(type)) { return null; } return m_dicGameStates[type]; } }
我們抽象出所有的狀態公有的方法屬性:IGameState接口:
也符合面向接口編程原則。好處我之前講過了。
IGameState:
using UnityEngine; using System.Collections; using Game.Common; /// <summary> /// 游戲狀態接口 /// </summary> public interface IGameState { GameStateType GetStateType();//獲取實現類的狀態類型 void SetStateTo(GameStateType gsType);//設置實現類的狀態類型(改變狀態) void Enter();//進入實現類的狀態,做主要狀態的邏輯處理 GameStateType Update(float fDeltaTime);//狀態改變,返回改變后的狀態 void FixedUpdate(float fixedDeltaTime);//固定更新狀態 void Exit();//退出該狀態 }
然后編寫實現接口的子實現類,這里我們先寫LoginState:
using UnityEngine; using System.Collections; using Game.Common; /// <summary> /// 登陸游戲狀態 /// </summary> public class LoginState : IGameState { GameStateType m_eStateTo; public LoginState() { } public GameStateType GetStateType() { return GameStateType.GS_Login; } public void SetStateTo(GameStateType stateType) { this.m_eStateTo = stateType; } public void Enter() { SetStateTo(GameStateType.GS_Continue); LoginCtrl.singleton.Enter(); } public void Exit() { LoginCtrl.singleton.Exit(); } public void FixedUpdate(float fixedDeltaTime) { } public GameStateType Update(float fDeltaTime) { return m_eStateTo; } }
然后在GameStateManager的構造方法,添加到緩存字典里面。
OK,這個狀態機,假如說我們調用GameStateManager的ChangeStateTo(你想要的狀態類型),那么就會執行你想要的狀態實現類的Enter方法。
所以我們在LoginState的Enter編寫我們登陸的邏輯,因為LoginState主要是管理狀態改變的,所以我們為了類的單一職責,吧所有登陸邏輯放在:LoginCtrl控制類里面。
public void Enter() { SetStateTo(GameStateType.GS_Continue);//先轉到中間狀態 LoginCtrl.singleton.Enter(); }
LoginCtrl:
OK,寫到這里,我們之后當我知道版本更新完成或者根本不需要更新,就直接彈出登陸UI的用戶名輸入框界面。
那么,我們就得寫個LoginWindow來管理登陸UI,所以先寫LoginWindow:
using UnityEngine; using System.Collections; using Game.Common; using Utility; using System; /// <summary> /// 登陸界面UI /// </summary> public class LoginWindow : BaseWindow { public LoginWindow() { this.mResName = "Guis/LoginWindow"; this.mResident = false; } public override void Init() { EventCenter.AddListener(EGameEvent.eGameEvent_LoginEnter, Show); EventCenter.AddListener(EGameEvent.eGameEvent_LoginExit, Hide); } public override void Realse() { EventCenter.RemoveListener(EGameEvent.eGameEvent_LoginEnter, Show); EventCenter.RemoveListener(EGameEvent.eGameEvent_LoginExit,Hide); } protected override void InitWidget() { } protected override void RealseWidget() { } protected override void OnAddListener() { } protected override void OnRemoveListener() { } public override void OnEnable() { } public override void OnDisable() { } public override void Update(float deltaTime) { base.Update(deltaTime); } }
OK,我們在LoginWindow里面添加顯示登陸界面和隱藏登陸界面事件監聽。
首先,我們知道,玩LOL的時候,當我們登陸成功之后,還要選擇游戲大區服務器。所以我們把選擇服務器歸入到登陸界面來管理。
所以我們還是需要制作一個SelectServer界面,這里我也隨便搞了下界面:
未完待續。。。。。。沒時間以后繼續
OK,終於暑假了,又有時間來寫了,隔了好久的時間,我可能落下很多步驟,如果有不明白的童鞋,歡迎在下方留言。
接着講,我們選擇服務器的界面還沒有制作,所以首先我們先來制作這個界面。
粗略的看下這界面的結構:
1.背景圖片
2.左邊的服務器列表
3.右邊的圖標和各個按鈕
4.藍色的服務器背景
大致就是這些,OK,我們看下Unity中的Hire窗口物體結構:
我們着重來看下ServerList的制作,其他的讀者可以自行理解,然后搭建起來。
首先來看下ServerList:
我將他分為兩個部分,第一個部分是上面的推薦服,第二個部分是下面的電信聯通具體服。
制作好之后,吧他拖到Prefabs文件夾下面,然后拖到我們之前做好的登陸界面當做子物體。
然后把他的Panel設置為不激活狀態。因為我們默認進入到登陸界面只顯示輸入用戶名和密碼,不顯示選擇服務器界面。等到我們正確的驗證密碼之后,然后才進入到選擇服務器界面。
OK,大致的界面講解完成了,我們開始寫代碼。在寫代碼之前,先來分析下看,因為這個服務器動態的,也就是說假如一個服務器進行維護或者繁忙,我們這邊應該實時的知道。
所以,當我們進入到選擇服務器界面的時候,應該接收到服務器發送來的服務器實時的數據信息,然后客戶端才動態加載這些服務器列表。
所以我們代碼怎么寫?怎么樣才能做到動態加載不確定數量的服務器列表。這里NGUI的UITable和UIGrid有點坑,我們如果想實例化一個子物體給UITable,他是不會動態刷新的,所以我決定自己再封裝一層NGUI的代碼,形成自己的一套UI管理。
我們在Window文件夾下面,新建一個UIObject文件夾,里面存放着所以和UI相關的接口和類,如XUISprite.cs實際上就是封裝的NGUi的UISprite腳本。
可以看到我已經封裝了這么多,可能有些童鞋會問了,既然NGui的都可以用,為什么還這么麻煩,自己封裝一層。
這個封裝確實很有必要:
1.方便操作,可以根據我們需要的功能進行擴展。就拿這個UITable來說,如果我們需要實時更新里面的Item,我們每在一處添加,都要得寫好多代碼,如果我們封裝起來,一個方法就搞定。
2.可擴展性強。可以看到我們每個UI都有自己的一個接口,實現了依賴倒置原則。如果我們想要使用UGUi作為UI框架,我們只需要修改下,底層的代碼,高層調用者就不需要改動代碼,如果不使用的話,高層要高到死為止。
好處大致就是這么多。OK,我先來貼貼代碼,我把所有的代碼貼出來:
IXUIObject.cs
using UnityEngine; using System.Collections; /// <summary> /// 所有UI物體公共的接口 /// </summary> public interface IXUIObject { Transform CacheTransform { get; } GameObject CacheGameObject { get; } IXUIObject Parent { get; set; } string Tip { get; set; } object TipParam { get; set; } bool IsVisible(); void SetVisible(bool bVisible); IXUIObject GetUIObject(string strPath); void Highlight(bool bTrue); }
XUIObjectBase.cs:
using UnityEngine; using System.Collections; /// <summary> /// 繼承MOnoBehavior的UI物體 /// </summary> public abstract class XUIObjectBase : MonoBehaviour,IXUIObject { private bool m_bInit = false; public string m_strTipText = ""; protected float m_fAlpha = 1f; private Transform m_cacheTransform; private GameObject m_cacheGameObject; private IXUIObject m_parent; public Transform CacheTransform { get { if (this.m_cacheTransform == null) { this.m_cacheTransform = base.transform; } return this.m_cacheTransform; } } public GameObject CacheGameObject { get { if (this.m_cacheGameObject == null) { this.m_cacheGameObject = base.gameObject; } return this.m_cacheGameObject; } } public object TipParam { get; set; } public string Tip { get { return this.m_strTipText; } set { this.m_strTipText = value; } } public virtual float Alpha { get { return this.m_fAlpha; } set { this.m_fAlpha = value; } } public virtual IXUIObject Parent { get { return this.m_parent; } set { this.m_parent = value; } } public bool IsInited { get { return this.m_bInit; } set { this.m_bInit = value; } } public virtual void Init() { this.m_bInit = true; } public bool IsVisible() { return base.gameObject.activeInHierarchy; } public virtual void SetVisible(bool bVisible) { } public virtual void Highlight(bool bTrue) { } public virtual IXUIObject GetUIObject(string strPath) { return null; } public virtual void OnAwake() { } public virtual void OnStart() { } public virtual void OnUpdate() { } public virtual void _OnClick() { } private void Awake() { OnAwake(); } private void Start() { if (!this.m_bInit) { Init(); } OnStart(); } private void Update() { OnUpdate(); } private void OnClick() { this._OnClick(); } private void OnEnable() { } private void OnDisable() { } }
這個腳本是每個UI必須的,比如NGUi的腳本都是掛在UI物體上的。所以我們自己封裝的腳本也是如此。
注意到沒有中間有用到:
TipParam:這個是提示參數類
using UnityEngine; using System.Collections; using Game.Common; /// <summary> /// 提示參數類 /// </summary> public class TipParam { //提示信息 public string Tip { get; set; } //提示類型,有普通提示(技能裝備等)和標題提示(沒有帶復雜內容,只有一行字) public TipEnumType TipType { get; set; } public TipParam() { TipType = TipEnumType.eTipType_Common; } }
這個主要是處理界面提示用的。
XUIObject.cs:
using UnityEngine; using System.Collections; public abstract class XUIObject : XUIObjectBase { public override void OnAwake() { base.OnAwake(); } public override void OnStart() { base.OnStart(); } public override void OnUpdate() { base.OnUpdate(); } public override void Init() { base.Init(); } public override void SetVisible(bool bVisible) { NGUITools.SetActiveSelf(base.gameObject, bVisible); } }
OK,我們開始寫具體的UI類:先寫UIList和UIListItem也就是Table或者Grid他對應着UIList,他下面的子物體對應着UIListItem。
由於UIListItem可能他的子物體有UISprite和UILabel等等,所以我們在寫他之前先寫UISprite:
因為我們寫程序最好要依賴接口編程,所以寫個IXUISprite接口:
using UnityEngine; using System.Collections; public interface IXUISprite : IXUIObject { Color Color { get; set; } string SpriteName { get; } IXUIAtlas UIAtlas { get; } /// <summary> /// 播放UI動畫 /// </summary> /// <param name="bLoop"></param> /// <returns></returns> bool PlayFlash(bool bLoop); void SetEnable(bool bEnable); /// <summary> /// 設置UISprite /// </summary> /// <param name="strSpriteName"></param> /// <returns></returns> bool SetSprite(string strSpriteName); bool SetSprite(string strSpriteName, string strAtlas); /// <summary> /// 停止UI動畫 /// </summary> /// <returns></returns> bool StopFlash(); }
注意到沒有,我們Sprite可能會用到UIAtlas,所以我們得再寫個UIAtlas:
IXUIAtlas:
using UnityEngine; using System.Collections; public interface IXUIAtlas { UIAtlas Atlas { get; set; } }
XUIAtlas:
using UnityEngine; using System.Collections; public class XUIAtlas : MonoBehaviour,IXUIAtlas { private UIAtlas m_uiAtlas; public UIAtlas Atlas { get { return this.m_uiAtlas; } set { this.m_uiAtlas = value; } } private void Awake() { this.m_uiAtlas = base.GetComponent<UIAtlas>(); if (null == this.m_uiAtlas) { Debug.LogError("null == m_uiAtlas"); } } }
XUISprite:
using UnityEngine; using System.Collections; using Game.Common; [AddComponentMenu("XUI/XUISprite")] public class XUISprite : XUIObject,IXUIObject,IXUISprite { private string m_spriteNameCached = string.Empty; private string m_atlasNameCached = string.Empty; private UISprite m_uiSprite; private UISpriteAnimation m_uiSpriteAnimation; private ResourceUnit m_oAltasUnit; private IXLog m_log = XLog.GetLog<XUISprite>(); public override float Alpha { get { if (null != this.m_uiSprite) { return this.m_uiSprite.alpha; } return 0f; } set { if (null != this.m_uiSprite) { this.m_uiSprite.alpha = value; } } } public Color Color { get { if (this.m_uiSprite != null) { return this.m_uiSprite.color; } return Color.white; } set { if (this.m_uiSprite != null) { this.m_uiSprite.color = value; } } } public string SpriteName { get { if (null != this.m_uiSprite) { return this.m_uiSprite.spriteName; } return null; } } public IXUIAtlas UIAtlas { get { if (null == this.m_uiSprite) { return null; } if (null == this.m_uiSprite.atlas) { return null; } return this.m_uiSprite.atlas.GetComponent<XUIAtlas>(); } } public override void Init() { base.Init(); this.m_uiSprite = base.GetComponent<UISprite>(); if (null == this.m_uiSprite) { Debug.LogError("null == m_uiSprite"); } this.m_uiSpriteAnimation = base.GetComponent<UISpriteAnimation>(); } /// <summary> /// 播放動畫 /// </summary> /// <param name="bLoop"></param> /// <returns></returns> public bool PlayFlash(bool bLoop) { if (null == this.m_uiSpriteAnimation) { return false; } this.m_uiSpriteAnimation.loop = bLoop; this.m_uiSpriteAnimation.ResetToBeginning(); this.m_uiSpriteAnimation.enabled = true; this.m_uiSprite.enabled = true; return true; } /// <summary> /// 停止動畫 /// </summary> /// <returns></returns> public bool StopFlash() { if (null == this.m_uiSpriteAnimation) { return false; } this.m_uiSpriteAnimation.enabled = false; return true; } /// <summary> /// 設置UISprite /// </summary> /// <param name="strSprite"></param> /// <param name="strAltas"></param> /// <returns></returns> public bool SetSprite(string strSprite, string strAltas) { if (null == this.m_uiSprite) { return false; } //如果緩存圖集已經存在了,那么就直接設置 if (this.m_atlasNameCached.Equals(strAltas)) { this.m_spriteNameCached = strSprite; this.m_uiSprite.spriteName = strSprite; this.m_uiSprite.enabled = true; return true; } this.m_spriteNameCached = strSprite; this.m_atlasNameCached = strAltas; this.PrepareAtlas(strAltas, strSprite); return true; } /// <summary> /// 設置默認圖集的UISprite /// </summary> /// <param name="strSpriteName"></param> /// <returns></returns> public bool SetSprite(string strSpriteName) { if (null == this.m_uiSprite) { return false; } if (!string.IsNullOrEmpty(this.m_atlasNameCached)) { this.SetSprite(this.m_atlasNameCached, strSpriteName); } else { this.m_uiSprite.spriteName = strSpriteName; } return true; } public void SetEnable(bool bEnable) { Collider compent = base.GetComponent<Collider>(); if (compent != null) { compent.enabled = bEnable; } } private void OnDestroy() { if (this.m_oAltasUnit != null) { this.m_oAltasUnit.Dispose(); this.m_oAltasUnit = null; } } private void PrepareAtlas(string strAltas, string strSprite) { m_oAltasUnit = ResourceManager.Instance.LoadImmediate(strAltas, ResourceType.PREFAB); GameObject obj = m_oAltasUnit.Asset as GameObject; UIAtlas uiAtals = obj.GetComponent<UIAtlas>(); if (null == uiAtals) { this.m_log.Error("加載圖集的時候出錯!!"); return; } this.m_uiSprite.atlas = uiAtals; this.m_uiSprite.spriteName = strSprite; this.m_uiSprite.enabled = true; } }
可以看到XUISprite提供4個主要接口:
1.SetSprite(string strSpriteName)---->設置Sprite,在默認的Alta中
2.SetSprite(string strSpriteName,string strAtlas)---->設置Sprite,在指定的Atlas中
3.PlayFlash(bool bLoop)---->是否播放UI幀動畫
4.StopFlash()----->停止播放UI幀動畫
寫完Sprite之后,我們寫
IXUIListItem:
using UnityEngine; using System.Collections.Generic; public interface IXUIListItem :IXUIObject { int Id { get; set; } long GUID { get; set; } int Index { get; set; } bool IsSelected { get; set; } Dictionary<string, XUIObjectBase> AllXUIObject { get; } bool SetText(string strId,string strContent); void SetSelected(bool bTrue); void SetEnableSelect(bool bEnable); void SetIconSprite(string strSprite); void SetIconSprite(string strSprite, string strAtlas); void SetIconTexture(string strTexture); void SetColor(Color color); void SetEnable(bool bEnable); void Clear(); }
XUIListItem.cs:
using UnityEngine; using System.Collections.Generic; using UILib; using Game.Common; [AddComponentMenu("XUI/XUIListItem")] public class XUIListItem : XUIObject,IXUIObject,IXUIListItem { private UISprite m_uiSpriteIcon; private UILabel[] m_uiLabels; private UITexture m_uiTextureIcon; private UIButton m_uiButton; private UIToggle m_uiToggle; private UITexture[] m_uiTextures; private UISprite[] m_uiSprites; private XUISprite m_uiSpriteFlash; private Dictionary<string, XUIObjectBase> m_dicId2UIObject = new Dictionary<string, XUIObjectBase>(); protected Collider m_colldier; private Color m_highlightColor = Color.clear; public int m_unId; private int m_unIndex = -1; private long m_GUID; public int Id { get { return this.m_unId; } set { this.m_unId = value; } } public int Index { get { return this.m_unIndex; } set { this.m_unIndex = value; } } public long GUID { get { return this.m_GUID; } set { this.m_GUID = value; } } public XUIList ParentXUIList { get { XUIList xUIlist = this.Parent as XUIList; if (null == xUIlist) { Debug.LogError("null == uiList"); } return xUIlist; } } public bool IsSelected { get { return this.m_uiToggle != null && this.m_uiToggle.value; } set { if (this.m_uiToggle != null && this.m_uiToggle.value != value) { this.m_uiToggle.Set(value); if (value) { this.ParentXUIList.SelectItem(this, false); }else { this.ParentXUIList.UnSelectItem(this, false); } } } } public Dictionary<string, XUIObjectBase> AllXUIObject { get { return this.m_dicId2UIObject; } } public void SetSelected(bool bTrue) { if (this.m_uiToggle != null && this.m_uiToggle.value != bTrue) { this.m_uiToggle.Set(bTrue); } } public void SetEnableSelect(bool bEnable) { if (!bEnable && this.m_uiToggle != null) { this.m_uiToggle.value = false; } this.Highlight(bEnable); if (this.m_uiToggle != null) { this.m_uiToggle.enabled = bEnable; } } private void OnSelectStateChange() { bool bSelected = this.m_uiToggle.value; if (bSelected) { //List選擇該item this.ParentXUIList.OnSelectItem(this); } else { //List不選擇該item this.ParentXUIList.OnUnSelectItem(this); } } public void SetIconSprite(string strSprite) { if (null != this.m_uiSpriteIcon) { this.m_uiSpriteIcon.spriteName = strSprite.Substring(strSprite.LastIndexOf("\\") + 1); this.m_uiSpriteIcon.enabled = true; } XUISprite xUISprite = this.GetUIObject("Sprite_Icon") as XUISprite; if (null != xUISprite) { xUISprite.SetSprite(strSprite); } } public void SetIconSprite(string strSprite, string strAtlas) { XUISprite xUISprite = this.GetUIObject("Sprite_Icon") as XUISprite; if (null != xUISprite) { xUISprite.SetSprite(strSprite, strAtlas); } } public void SetIconTexture(string strTexture) { XUITexture xUITexture = this.GetUIObject("Texture_Icon") as XUITexture; if (xUITexture != null) { xUITexture.SetTexture(strTexture); } } public bool SetText(string strId, string strText) { IXUILabel label = this.GetUIObject(strId) as IXUILabel; if (label != null) { label.SetText(strText); return true; } return false; } public void SetColor(Color color) { if (this.m_uiSpriteIcon != null) { this.m_uiSpriteIcon.color = color; } if (this.m_uiTextureIcon != null) { this.m_uiTextureIcon.color = color; } } public void SetEnable(bool bEnable) { if (this.m_colldier != null) { this.m_colldier.enabled = bEnable; } if (this.m_uiButton != null) { this.m_uiButton.enabled = bEnable; } } public void Clear() { this.m_unId = 0; UILabel[] uiLabels = this.m_uiLabels; for (int i = 0; i < uiLabels.Length; i++) { UILabel uILabel = uiLabels[i]; uILabel.text = string.Empty; } if (null != this.m_uiSpriteIcon) { this.m_uiSpriteIcon.enabled = false; } if (null != this.m_uiTextureIcon) { this.m_uiTextureIcon.enabled = false; } this.Tip = string.Empty; this.TipParam = null; } public override void Init() { base.Init(); WidgetFactory.FindAllUIObjects(base.transform, this, ref m_dicId2UIObject); foreach (var uiObject in this.m_dicId2UIObject.Values) { uiObject.Parent = this; if (!uiObject.IsInited) { uiObject.Init(); } } if (null == this.m_uiSpriteIcon) { Transform tran = base.transform.FindChild("Sprite_Icon"); if (tran != null) { this.m_uiSpriteIcon = tran.GetComponent<UISprite>(); } } if (null == this.m_uiTextureIcon) { Transform tran1 = base.transform.FindChild("Texture_Icon"); if (tran1 != null) { this.m_uiTextureIcon = tran1.GetComponent<UITexture>(); } } this.m_colldier = base.GetComponent<Collider>(); this.m_uiLabels = base.GetComponentsInChildren<UILabel>(); this.m_uiToggle = base.GetComponent<UIToggle>(); this.m_uiButton = base.GetComponent<UIButton>(); this.m_uiSprites = base.GetComponentsInChildren<UISprite>(true); this.m_uiTextures = base.GetComponentsInChildren<UITexture>(true); this.m_uiSpriteFlash = this.GetUIObject("Sprite_Flash") as XUISprite; if (this.m_uiToggle != null) { EventDelegate.Add(this.m_uiToggle.onChange, this.OnSelectStateChange); } this.Highlight(false); } public override IXUIObject GetUIObject(string strPath) { if (strPath == null) { return null; } string key = strPath; int num = strPath.LastIndexOf('/'); if (num >= 0) { key = strPath.Substring(num + 1); } XUIObjectBase result = null; if (this.m_dicId2UIObject.TryGetValue(key, out result)) { return result; } return null; } public override void Highlight(bool bTrue) { base.Highlight(bTrue); if (this.m_uiSpriteFlash != null) { if (!bTrue) { this.m_uiSpriteFlash.StopFlash(); } else { this.m_uiSpriteFlash.PlayFlash(true); } } } public override void _OnClick() { base._OnClick(); this.ParentXUIList._OnClick(this); } }
注意了,細心的童鞋可能看到,這個Item他的子物體假如是Sprite,那么他的命名必須是:
Sprite_Icon
如果子物體是Texture,那么命名必須是:
Texture_Icon
如果子物體是有帶動畫的Sprite,必須命名為:
Sprite_Flash
還有如果這個Item是可以選擇的,必須添加UIToggle腳本,具體讀者自己看代碼。OK,接着我們寫
IXUIList:
using UnityEngine; using System.Collections.Generic; using Game.Common; public interface IXUIList : IXUIObject { int Count { get; } int GetSelectedIndex(); void SetSelectedIndex(int nIndex); void SetSelectedItemByIndex(List<int> listItemIndex); void SetSelectedItemById(int unId); void SetSelectedItemById(List<int> listItemId); IXUIListItem GetSelectedItem(); IXUIListItem[] GetSelectedItems(); IXUIListItem GetItemById(int unId, bool bVisible); IXUIListItem GetItemByGUID(long ulId); IXUIListItem[] GetAllItems(); IXUIListItem GetItemByIndex(int nIndex); IXUIListItem AddListItem(GameObject obj); IXUIListItem AddListItem(); bool DelItemById(int unId); bool DelItemByIndex(int nIndex); bool DelItem(IXUIListItem iUIListItem); void SetEnable(bool bEnable); void SetEnableSelect(bool bEnable); void SetEnableSelect(List<int> listIds); void Highlight(List<int> listIds); void Refresh(); void OnSelectItem(XUIListItem listItem); void SelectItem(XUIListItem listItem, bool bTrigerEvent); void OnUnSelectItem(XUIListItem listItem); void UnSelectItem(XUIListItem listItem, bool bTrigerEvent); void RegisterListOnSelectEventHandler(ListSelectEventHandler handler); void RegisterListOnUnSelectEventHandler(ListSelectEventHandler handler); void RegisterListOnClickEventHandler(ListOnClickEventHandler handler); void Clear(); }
可能會有出錯,因為我們ListSelectEventHandler委托類型還沒有聲明,我們到DefineCommon中定義這兩個委托類型:
public delegate bool ListSelectEventHandler(IXUIListItem listItem); public delegate bool ListOnClickEventHandler(IXUIListItem listItem);
XUIList.cs:
using UnityEngine; using System.Collections.Generic; using System; using Game.Common; [AddComponentMenu("XUI/XUIList")] public class XUIList : XUIObject, IXUIObject,IXUIList { public GameObject m_prefabListItem; public bool m_bMultiSelect; private bool m_bHasAddItem; private List<XUIListItem> m_listXUIListItem = new List<XUIListItem>(); private List<XUIListItem> m_listXUIListItemSelected = new List<XUIListItem>(); private ListSelectEventHandler m_eventhandlerOnSelect; private ListSelectEventHandler m_eventhandlerOnUnSelect; private ListOnClickEventHandler m_eventhandlerOnClick; private UIGrid m_uiGrid; private UITable m_uiTable; public int Count { get { if (null == this.m_listXUIListItem) { return 0; } return this.m_listXUIListItem.Count; } } public override void Init() { base.Init(); this.m_listXUIListItem.Clear(); this.m_listXUIListItemSelected.Clear(); for (int i = 0; i < base.transform.childCount; i++) { Transform child = base.transform.GetChild(i); XUIListItem component = child.GetComponent<XUIListItem>(); if (component == null) { Debug.LogError("null == uiListitem"); } else { component.Parent = this; this.m_listXUIListItem.Add(component); } this.m_listXUIListItem.Sort(new Comparison<XUIListItem>(XUIList.SortByName)); int num = 0; foreach (XUIListItem current in this.m_listXUIListItem) { current.name = string.Format("{0:0000}", num); current.Index = num; current.Id = num; if (!current.IsInited) { current.Init(); } UIToggle component2 = current.GetComponent<UIToggle>(); if (current.IsSelected) { this.m_listXUIListItemSelected.Add(current); } num++; } this.m_uiGrid = base.GetComponent<UIGrid>(); if (null != this.m_uiGrid) { this.m_uiGrid.Reposition(); } this.m_uiTable = base.GetComponent<UITable>(); if (null != this.m_uiTable) { this.m_uiTable.Reposition(); } } } public int GetSelectedIndex() { if (this.m_listXUIListItemSelected.Count > 0) { return this.m_listXUIListItemSelected[0].Index; } return -1; } public void SetSelectedIndex(int nIndex) { XUIListItem selectedItem = this.GetItemByIndex(nIndex) as XUIListItem; this.SetSelectedItem(selectedItem); //this.FocusIndex(nIndex); } public void SetSelectedItemByIndex(List<int> listItemIndex) { if (this.m_bMultiSelect) { this.m_listXUIListItemSelected.Clear(); foreach (XUIListItem current in this.m_listXUIListItem) { if (listItemIndex != null && listItemIndex.Contains(current.Index)) { current.SetSelected(true); this.m_listXUIListItemSelected.Add(current); } else { current.SetSelected(false); } } } else { Debug.LogError("false == m_bMultiSelect"); } } public void SetSelectedItemById(int unId) { XUIListItem selectedItem = this.GetItemById(unId) as XUIListItem; this.SetSelectedItem(selectedItem); } public void SetSelectedItemById(List<int> listItemId) { if (this.m_bMultiSelect) { this.m_listXUIListItemSelected.Clear(); foreach (XUIListItem current in this.m_listXUIListItem) { if (listItemId != null && listItemId.Contains(current.Id)) { current.SetSelected(true); this.m_listXUIListItemSelected.Add(current); } else { current.SetSelected(false); } } } else { Debug.LogError("false == m_bMultiSelect"); } } public void SetSelectedItem(XUIListItem uiListItem) { foreach (XUIListItem current in this.m_listXUIListItemSelected) { current.SetSelected(false); } this.m_listXUIListItemSelected.Clear(); if (null != uiListItem) { uiListItem.SetSelected(true); this.m_listXUIListItemSelected.Add(uiListItem); } } public IXUIListItem GetItemByIndex(int nIndex) { if (this.m_listXUIListItem == null) { return null; } if (0 > nIndex || nIndex >= this.m_listXUIListItem.Count) { return null; } return this.m_listXUIListItem[nIndex]; } public IXUIListItem GetSelectedItem() { if (this.m_listXUIListItemSelected.Count > 0) { return this.m_listXUIListItemSelected[0]; } return null; } public IXUIListItem[] GetSelectedItems() { return this.m_listXUIListItemSelected.ToArray(); } public IXUIListItem GetItemById(int unId) { foreach (XUIListItem current in this.m_listXUIListItem) { if (unId == current.Id) { return current; } } return null; } public IXUIListItem GetItemById(int unId, bool bVisible) { foreach (XUIListItem current in this.m_listXUIListItem) { if (unId == current.Id && current.IsVisible() == bVisible) { return current; } } return null; } public IXUIListItem GetItemByGUID(long ulId) { foreach (XUIListItem current in this.m_listXUIListItem) { if (ulId == current.GUID) { return current; } } return null; } public IXUIListItem[] GetAllItems() { return this.m_listXUIListItem.ToArray(); } public IXUIListItem AddListItem(GameObject obj) { if (null == obj) { return null; } GameObject gameObject = UnityEngine.Object.Instantiate(obj) as GameObject; gameObject.name = string.Format("{0:0000}", this.Count); gameObject.transform.parent = base.transform; gameObject.transform.localPosition = Vector3.zero; gameObject.transform.localScale = Vector3.one; gameObject.transform.localRotation = Quaternion.identity; NGUITools.SetLayer(gameObject, this.CacheGameObject.layer); UIToggle component = gameObject.GetComponent<UIToggle>(); XUIListItem xUIListItem = gameObject.GetComponent<XUIListItem>(); if (null == xUIListItem) { //Debug.LogError("null == uiListItem"); xUIListItem = gameObject.AddComponent<XUIListItem>(); } xUIListItem.Index = this.Count; xUIListItem.Id = xUIListItem.Index; xUIListItem.Parent = this; if (!xUIListItem.IsInited) { xUIListItem.Init(); } this.m_listXUIListItem.Add(xUIListItem); this.m_bHasAddItem = true; this.Refresh(); return xUIListItem; } public IXUIListItem AddListItem() { if (null != this.m_prefabListItem) { return this.AddListItem(this.m_prefabListItem); } return null; } public bool DelItemById(int unId) { IXUIListItem itemById = this.GetItemById(unId); return this.DelItem(itemById); } public bool DelItemByIndex(int nIndex) { IXUIListItem itemByIndex = this.GetItemByIndex(nIndex); return this.DelItem(itemByIndex); } public bool DelItem(IXUIListItem iUIListItem) { XUIListItem xUIListItem = iUIListItem as XUIListItem; if (null == xUIListItem) { return false; } this.m_listXUIListItemSelected.Remove(xUIListItem); int index = xUIListItem.Index; for (int i = index + 1; i < this.Count; i++) { this.m_listXUIListItem[i].name = string.Format("{0:0000}", i - 1); this.m_listXUIListItem[i].Index = i - 1; } this.m_listXUIListItem.Remove(xUIListItem); xUIListItem.gameObject.transform.parent = null; UnityEngine.Object.Destroy(xUIListItem.gameObject); this.Refresh(); return true; } public void Clear() { if (this.m_listXUIListItem == null) { return; } foreach (XUIListItem current in this.m_listXUIListItem) { current.gameObject.transform.parent = null; UnityEngine.Object.Destroy(current.gameObject); } this.m_listXUIListItemSelected.Clear(); this.m_listXUIListItem.Clear(); this.Refresh(); } public void SetEnable(bool bEnable) { foreach (XUIListItem current in this.m_listXUIListItem) { current.SetEnable(bEnable); } } public void SetEnableSelect(bool bEnable) { foreach (XUIListItem current in this.m_listXUIListItem) { current.SetEnableSelect(bEnable); } if (!bEnable) { this.m_listXUIListItemSelected.Clear(); } } public void SetEnableSelect(List<int> listIds) { if (listIds == null) { return; } foreach (XUIListItem current in this.m_listXUIListItem) { if (listIds.Contains(current.Id)) { current.SetEnableSelect(true); } else { current.SetEnableSelect(false); } } this.m_listXUIListItemSelected.RemoveAll((XUIListItem x) => !listIds.Contains(x.Id)); } public override void Highlight(bool bTrue) { foreach (XUIListItem current in this.m_listXUIListItem) { current.Highlight(bTrue); } } public void Highlight(List<int> listIds) { this.Highlight(false); if (listIds == null) { return; } foreach (XUIListItem current in this.m_listXUIListItem) { if (listIds.Contains(current.Id)) { current.Highlight(true); } } } public void Refresh() { if (null != this.m_uiGrid) { this.m_uiGrid.repositionNow = true; } if (null != this.m_uiTable) { this.m_uiTable.repositionNow = true; } this.RefreshAllItemStatus(); } public void OnSelectItem(XUIListItem listItem) { this.SelectItem(listItem, true); } public void SelectItem(XUIListItem listItem, bool bTrigerEvent) { if (null == listItem) { return; } if (this.m_listXUIListItemSelected.Contains(listItem)) { return; } if (!this.m_bMultiSelect) { this.m_listXUIListItemSelected.Clear(); } this.m_listXUIListItemSelected.Add(listItem); //觸發選擇委托 if (bTrigerEvent && this.m_eventhandlerOnSelect != null) { this.m_eventhandlerOnSelect(listItem); } } public void OnUnSelectItem(XUIListItem listItem) { this.UnSelectItem(listItem, true); } public void UnSelectItem(XUIListItem listItem, bool bTrigerEvent) { if (null == listItem) { return; } if (!this.m_listXUIListItemSelected.Contains(listItem)) { return; } this.m_listXUIListItemSelected.Remove(listItem); //不選擇委托 if (bTrigerEvent && this.m_eventhandlerOnUnSelect != null) { this.m_eventhandlerOnUnSelect(listItem); } } public void RegisterListOnSelectEventHandler(ListSelectEventHandler handler) { this.m_eventhandlerOnSelect = handler; } public void RegisterListOnUnSelectEventHandler(ListSelectEventHandler handler) { this.m_eventhandlerOnUnSelect = handler; } public void RegisterListOnClickEventHandler(ListOnClickEventHandler handler) { this.m_eventhandlerOnClick = handler; } public void _OnClick(XUIListItem item) { if (this.GetSelectedIndex() != item.Index) { this.SelectItem(item, false); } if (this.m_eventhandlerOnClick != null) { this.m_eventhandlerOnClick(item); } } public static int SortByName(XUIListItem a, XUIListItem b) { return string.Compare(a.name, b.name); } private void RefreshAllItemStatus() { int num = this.GetSelectedIndex(); if (num < 0) { this.SetSelectedIndex(0); } } }
可以看都XUIList封裝了好多處理Item的方法,具體的讀者可以自行閱讀代碼,這里我們只需要知道怎么用就行了。
OK,封裝好了之后,我們回到UI界面,把我們自己定義的這些組件添加到對應的UI組件中。
這里我們電信的Grid,我添加自己定義的XUIList組件。
然后他的子物體Item,我添加了XUIListItem組件和UIToggle組件。
然后將Item拖到Prefab當成預制物,然后到XUiList中設置Prefab ListItem變量為這個預制物。可以看上圖的XUIList我已經添加了。
這個Prefab ListItem有什么用呢?
這要是我們動態添加item的時候,他就會實例化這個預制物。也就是我們前提設置好要動態添加的item。
OK,其他的組件自己自行添加。
同理,聯通的那個UIGrid也是類似的。講完這個自己封裝的UI框架,我們繼續回到游戲主題。
開始寫LoginWindow.cs
這節一多,下節繼續。。。。。。