仿LOL项目开发第六天
仿LOL项目开发第六天
by草帽
OK,因为更新模块已经处理好了,接着开始登陆的编写。那么我们就需要状态机的管理。
所谓状态机就是在哪个状态执行那个状态的代码逻辑:
那么我们开始编写GameStateManager来管理:
我们先在DefineCommon里面定义游戏状态类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /// <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十分的相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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控制类里面。
1 2 3 4 5 | public void Enter() { SetStateTo(GameStateType.GS_Continue); //先转到中间状态 LoginCtrl.singleton.Enter(); } |
LoginCtrl:
OK,写到这里,我们之后当我知道版本更新完成或者根本不需要更新,就直接弹出登陆UI的用户名输入框界面。
那么,我们就得写个LoginWindow来管理登陆UI,所以先写LoginWindow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 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:这个是提示参数类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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:
1 2 3 4 5 6 7 8 9 10 | using UnityEngine; using System.Collections; public interface IXUIAtlas { UIAtlas Atlas { get ; set ; } } |
XUIAtlas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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中定义这两个委托类型:
1 2 | public delegate bool ListSelectEventHandler(IXUIListItem listItem); public delegate bool ListOnClickEventHandler(IXUIListItem listItem); |
XUIList.cs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | 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
这节一多,下节继续。。。。。。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步