仿LOL项目开发第五天
仿LOL项目开发第五天
by草帽
今天呢,我们看下能开发什么内容,首先上节我们已经讲了UI框架的搭建,上节还遗留下很多问题,比如说消息的字符是代码里面自己赋值的。
那么就比较死板,按照正常的逻辑,那些字符我们得从配置文件中获取,然后赋值给消息提示。
所以呢,我们创建一个StringConfigManager来统一管理这些字符串。
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 | using UnityEngine; using System.Collections.Generic; using System.Xml; using Game; using Utility; /// <summary> /// 字符串管理器 /// </summary> public class StringConfigManager : Singleton<StringConfigManager> { //所有字符缓存字典 private Dictionary< string , string > m_oDicAllStringData; public StringConfigManager() { this .m_oDicAllStringData = new Dictionary< string , string >(); } public void Init() { this .m_oDicAllStringData.Clear(); XmlDocument doc = XmlResAdapter.GetXmlDocument(UnityTools.LoadFileText(SystemConfig.StringPath)); OnLoadStringFinishedEventHandler(doc); } /// <summary> /// 根据字符id取得字符串内容 /// </summary> /// <param name="id"></param> public static string GetString( string id) { return StringConfigManager.singleton.TryGetString(id); } private void OnLoadStringFinishedEventHandler(XmlDocument doc) { if (doc != null ) { XmlNode root = doc.SelectSingleNode( "root" ); XmlNodeList tableList = root.ChildNodes; foreach ( var node in tableList) { XmlElement ele = (XmlElement)node; string id = ele.GetAttribute( "id" ); string content = ele.InnerText; bool flag = this .m_oDicAllStringData.ContainsKey(id); if (flag) { Debug.Log( "字符字典已经包含该字符id" ); } this .m_oDicAllStringData[id] = content; } } } private string TryGetString( string id) { if ( this .m_oDicAllStringData.ContainsKey(id)) { return this .m_oDicAllStringData[id]; } else { return id; } } } |
然后创建string.xml文件,存放在Resources/Config文件夹下面:
1 2 3 4 5 6 7 | <?xml version= "1.0" encoding= "utf-8" ?> <root> <ele id= "MessageWindow.EMT_NetTryAgain.Title" >网络错误</ele> <ele id= "MessageWindow.EMT_NetTryAgain.Content" >您的网络无法连接上服务器,请检查下网络是否良好。</ele> <ele id= "MessageWindow.EMT_NetTryAgain.TryAgainButton" >image 168</ele> <ele id= "MessageWindow.EMT_NetTryAgain.QuitButton" >image 172</ele> </root> |
更改MessageWindow里面的代码,将StringConfigManager里面用上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //根据不同的消息类型,显示不同的提示消息 switch ( this .m_eMessageType) { //如果是重试消息的话 case EMessageType.EMT_NetTryAgain: this .m_firstButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.TryAgainButton" ); this .m_secondButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.QuitButton" ); this .m_title.text = StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.Title" ); this .m_content.text = StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.Content" ); break ; case EMessageType.EMT_ReConnect: break ; case EMessageType.EMT_None: break ; } |
对了,在用StringConfigManager之前得先初始化,那么在LOLGameDriver里面初始化。
1 2 3 4 5 | void Init() { WindowManager.singleton.Init(); //界面UI初始化 StringConfigManager.singleton.Init(); //字符管理器初始化 } |
Ok,大功告成,我们运行程序。
与之前的一模一样,但是我们现在只要改下配置文件里面的字符,程序中的字符也会改变。
OK,我们接着做,更新消息提示框,还是在MessageWindow里面,我们只需要再添加一个消息类型:EWT_UpdateTip和EWT_UpdateDownload:
然后再修改MessageWindow里面的代码:
未完待续。。。。。。
时隔几日,终于才有时间来写博客。这几日,当然我也没有闲着,也修改了好多代码。所以如果代码中有些步骤错过的话,可以留言给我。
OK,我们这几日试着发现这样的消息类型,要定到死为止,所以我定了一个总的消息类型:
1 2 3 4 5 6 7 8 9 10 11 | /// <summary> /// 消息类型 /// </summary> public enum EMessageType { EMT_None = -1, EMT_UpdateDownload, //更新下载提示 EMT_Double, //两个按钮 EMT_Tip, //提示 EMT_SureTip //确定提示 } |
确定提示:
两个按钮:
仅仅提示:
还有比较特殊的更新界面提示(其实就是double+多字符Label):
OK,已经知道了这么多的消息类型,那么我们就实现这些类型的表现:在MessageWindow的ShowMessage里面:
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 | public void ShowMessage(CEvent evt,EMessageType type,Action< bool > callback = null ) { //如果已经显示了,就直接返回 if (mVisible && evt.GetParamCount() == 0) { return ; } this .m_eMessageType = type; this .m_actCallBack = callback; Show(); //根据不同的消息类型,显示不同的提示消息 switch ( this .m_eMessageType) { //如果是重试消息的话 case EMessageType.EMT_Double: this .m_firstButton.gameObject.SetActive( true ); this .m_secondButton.gameObject.SetActive( true ); this .m_centerButton.gameObject.SetActive( false ); this .m_firstButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_Double.TryAgainButton" ); this .m_secondButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_Double.QuitButton" ); this .m_title.text = evt.GetParam( "title" ) as string ; //StringConfigManager.GetString("MessageWindow.EMT_NetTryAgain.Title"); this .m_content.text = evt.GetParam( "content" ) as string ; //StringConfigManager.GetString("MessageWindow.EMT_NetTryAgain.Content"); break ; case EMessageType.EMT_Tip: this .m_frame.spriteName = StringConfigManager.GetString( "EMessageType.EMT_Tip.Frame" ); this .m_firstButton.gameObject.SetActive( false ); this .m_secondButton.gameObject.SetActive( false ); this .m_centerButton.gameObject.SetActive( false ); this .m_title.gameObject.SetActive( false ); this .m_content.alignment = NGUIText.Alignment.Center; this .m_content.text = evt.GetParam( "content" ) as string ; //StringConfigManager.GetString("EMessageType.EMT_UpdateTip.Content1"); break ; case EMessageType.EMT_SureTip: this .m_frame.spriteName = StringConfigManager.GetString( "EMessageType.EMT_Tip.Frame" ); this .m_firstButton.gameObject.SetActive( false ); this .m_secondButton.gameObject.SetActive( false ); this .m_centerButton.gameObject.SetActive( true ); this .m_title.gameObject.SetActive( false ); this .m_content.alignment = NGUIText.Alignment.Center; this .m_content.text = evt.GetParam( "content" ) as string ; break ; case EMessageType.EMT_UpdateDownload: this .m_frame.spriteName = StringConfigManager.GetString( "EMessageType.EMT_UpdateTip.Frame" ); this .m_firstButton.gameObject.SetActive( true ); this .m_secondButton.gameObject.SetActive( true ); this .m_firstButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_UpdateDownload.LookNewButton" ); this .m_secondButton.normalSprite = StringConfigManager.GetString( "MessageWindow.EMT_Double.TryAgainButton" ); this .m_title.gameObject.SetActive( false ); this .m_content.alignment = NGUIText.Alignment.Center; this .m_content.text = string .Format(StringConfigManager.GetString( "EMessageType.EMT_UpdateDownload.Content" ), evt.GetParam( "index" ), evt.GetParam( "total" ), evt.GetParam( "fileName" )); break ; case EMessageType.EMT_None: break ; } |
因为我们消息改了,所以有些组件也需要添加进去,我们重新制作消息UI界面,我们新增一个centerButton:
1 | private UIButton m_centerButton; //中间按钮 |
然后在InitWeight里面添加事件监听:
1 2 3 4 | this .m_centerButton = this .mRoot.FindChild( "Frame/CenterButton" ).GetComponent<UIButton>(); EventDelegate.Add( this .m_firstButton.onClick, OnFirstBtn); EventDelegate.Add( this .m_secondButton.onClick, OnSecondBtn); EventDelegate.Add( this .m_centerButton.onClick, OnFirstBtn); |
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 | public void OnFirstBtn() { switch ( this .m_eMessageType) { //如果是重试消息的话 case EMessageType.EMT_Double: this .m_actCallBack( true ); Hide(); break ; case EMessageType.EMT_None: break ; } } public void OnSecondBtn() { switch ( this .m_eMessageType) { //如果是重试消息的话 case EMessageType.EMT_Double: this .m_actCallBack( false ); Hide(); break ; case EMessageType.EMT_None: break ; } } |
这里我只写double类型的,以后再来扩充。
可能有些童鞋发现了,那么消息的内容不是都是不一样吗,我们不能写死了,所以我们要在其他地方传入到这个方法里面赋值。
那么我们直接用EventCenter.Broadcast是不支持传递参数的,所以我们在ShowMessage传入一个Cevent类的实例,这个类主要是传递值的。也就是在两个类之间传递数值。
我已经在ShowMessage传入了Cevent类型,所以我们需要到EventCenter里面改下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static public void SendEvent(CEvent evt) { Broadcast<CEvent>(evt.GetEventId(), evt); } static public void SendEvent<T>(CEvent evt, T arg2) { Broadcast<CEvent, T>(evt.GetEventId(), evt, arg2); } static public void SendEvent<T,U>(CEvent evt, T arg2,U arg3) { Broadcast<CEvent, T, U>(evt.GetEventId(), evt, arg2,arg3); } static public void SendEvent<T, U,V>(CEvent evt, T arg2, U arg3,V arg4) { Broadcast<CEvent, T, U,V>(evt.GetEventId(), evt, arg2, arg3,arg4); } |
修改SendEvent方法能带更多的泛型参数。
OK,那么我们怎么使用,我们先修改下MessageWindow的错误:
到Init()修改下参数错误:
1 2 3 4 | public override void Init() { EventCenter.AddListener<CEvent,EMessageType,Action< bool >>(EGameEvent.eGameEvent_ShowMessage, ShowMessage); } |
你们全部修改完成之后,我们回到LOLGameDriver修改下:
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 | checkTimeout.AsynIsNetworkTimeout((result) => { //网络良好 if (result) { //开始更新检测 DoInit(); } else //说明网络错误 { Debug.Log( "网络错误" ); //开始消息提示框,重试和退出 CEvent evt = new CEvent(EGameEvent.eGameEvent_ShowMessage); evt.AddParam( "title" , StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.Title" )); evt.AddParam( "content" , StringConfigManager.GetString( "MessageWindow.EMT_NetTryAgain.Content" )); EventCenter.SendEvent<EMessageType, Action< bool >>(evt, EMessageType.EMT_Double, (isOk) => { if (isOk) { TryInit(); //重试 } else { Application.Quit(); //退出 } }); } }); |
先new一个CEvent实例,然后在其中添加两个参数,也就是我们消息的标题和内容。然后调用SendEvent方法。OK,我们在MessageWindow接收到CEvent传递的“title”和“content”两个参数的值,初始化消息框的Label的值。
OK,我们接着制作其他消息提示框,其实大致步骤是一样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Action< bool > fileDecompress = (finish) => { LOLGameDriver.Invoke(() => { EventCenter.Broadcast(EGameEvent.eGameEvent_HideMessage); if (finish) { CEvent evt = new CEvent(EGameEvent.eGameEvent_ShowMessage); evt.AddParam( "content" , StringConfigManager.GetString( "EMessageType.EMT_UpdateTip.Content2" )); EventCenter.SendEvent<EMessageType, Action< bool >>(evt, EMessageType.EMT_Tip, null ); Debug.Log( "正在更新本地文件" ); } else { CEvent evt = new CEvent(EGameEvent.eGameEvent_ShowMessage); evt.AddParam( "content" , StringConfigManager.GetString( "EMessageType.EMT_UpdateTip.Content3" )); EventCenter.SendEvent<EMessageType, Action< bool >>(evt, EMessageType.EMT_Tip, null ); Debug.Log( "数据读取中" ); } }); }; |
我们重点看看更新消息提示框(其实也一样,那就不重点看看了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Action< int , int , string > taskProgress = (total, index, fileName) => { LOLGameDriver.Invoke(() => { //正在下载更新文件 Debug.Log( string .Format( "正在下载更新文件({0}/{1}:{2})" , index + 1, total, fileName)); CEvent evt = new CEvent(EGameEvent.eGameEvent_ShowMessage); evt.AddParam( "index" , index + 1); evt.AddParam( "total" , total); evt.AddParam( "fileName" , fileName); EventCenter.SendEvent<EMessageType, Action< bool >>(evt, EMessageType.EMT_UpdateDownload, (isOk) => { if (isOk) { Application.OpenURL( "http://www.baidu.com" ); } else { } }); }); }; |
OK,既然我们能让一个消息界面显示,那么我也需要自动让他消息,那么我们就再加个消息不显示的事件类型,在AddListener里面,直接添加WindowBase父类的Hide方法:
1 2 3 4 5 6 7 8 | protected override void OnAddListener() { EventCenter.AddListener(EGameEvent.eGameEvent_HideMessage, Hide); } protected override void OnRemoveListener() { EventCenter.RemoveListener(EGameEvent.eGameEvent_HideMessage, Hide); } |
然后在适当的时机调用隐藏消息提示框。
OK,我这里又要改下,在CheckVersion里面,如果不需要更新的话,就添加执行finished的委托,我忘记加了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public void CheckVersion(Action< bool > fileDecompress,Action< int , int , string > taskProgress,Action< int , long , long > progress,Action finished,Action<Exception> error) { BeforeCheck((result) => { if (result) { //需要更新 Debug.Log( "需要更新" ); EventCenter.Broadcast(EGameEvent.eGameEvent_HideMessage); CheckAndDownload(fileDecompress, taskProgress, progress, finished, error); } else { EventCenter.Broadcast(EGameEvent.eGameEvent_HideMessage); //不需要更新 Debug.Log( "不需要更新" ); if (finished != null ) { finished(); } } }, () => { error( new Exception( "下载版本文件超时!" )); }); } |
OK,消息界面已经搞一个段落,我们下节开始登陆的逻辑编程,这里就涉及游戏状态机的管理。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法