仿LOL项目开发第六天
仿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
这节一多,下节继续。。。。。。