仿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
這節一多,下節繼續。。。。。。
