仿LOL项目开发第七天
仿LOL项目开发第七天
by 草帽
不知不觉已经写到了第七篇这种类型的博客,但是回过头看看之前写的,发现都只能我自己能看懂。
我相信在看的童鞋云里雾里的,因为我基本上没怎么详细讲一个脚本怎么用?但是你们可以自己看下代码,很快你就知道怎么用!以后也可以用到自己的项目中。
所以说阅读别人的代码非常重要,因为你们从中发现他们代码的优点和缺点。
OK,废话不多说,我们继续上节课,上节课我们已经封装自己的UI框架,但是还少个没讲,可能有些童鞋也会遇到报错,怎么解决?
在Window下新建一个UILib,然后里面新建一个脚本:
WidgetFactory:
using UnityEngine;
using System.Collections.Generic;
namespace UILib
{
public class WidgetFactory
{
/// <summary>
/// 查找节点下所有的UI组件,缓存到字典里面
/// </summary>
/// <param name="trans"></param>
/// <param name="parent"></param>
/// <param name="dicAllUIObjects"></param>
public static void FindAllUIObjects(Transform trans, IXUIObject parent, ref Dictionary<string, XUIObjectBase> dicAllUIObjects)
{
int i = 0;
while (i < trans.childCount)
{
Transform child = trans.GetChild(i);
XUIObjectBase component = child.GetComponent<XUIObjectBase>();
if (!(null != component))
{
goto IL_85;
}
if (component.GetType().GetInterface("IXUIListItem") == null)
{
if (dicAllUIObjects.ContainsKey(component.name))
{
Debug.Log(component.name);
Debug.LogError("m_dicId2UIObject.ContainsKey:" + WidgetFactory.GetUIObjectId(component));
}
dicAllUIObjects[component.name] = component;
component.Parent = parent;
goto IL_85;
}
else
{
Debug.Log("fdsfd");
}
IL_8F:
i++;
continue;
IL_85:
WidgetFactory.FindAllUIObjects(child, parent, ref dicAllUIObjects);
goto IL_8F;
}
}
/// <summary>
/// 取得该组件所在的id(包含父亲节点的id)
/// </summary>
/// <param name="uiObject"></param>
/// <returns></returns>
public static string GetUIObjectId(IXUIObject uiObject)
{
string result;
if (null == uiObject)
{
result = string.Empty;
}
else
{
string text = uiObject.CacheGameObject.name;
IXUIListItem iXUIListItem = uiObject as IXUIListItem;
if (iXUIListItem != null)
{
text = iXUIListItem.Id.ToString();
}
while (null != uiObject.Parent)
{
uiObject = uiObject.Parent;
string arg = uiObject.CacheGameObject.name;
iXUIListItem = (uiObject as IXUIListItem);
if (null != iXUIListItem)
{
arg = iXUIListItem.Id.ToString();
}
text = string.Format("{0}#{1}", arg, text);
}
result = text;
}
return result;
}
}
}
这个脚本主要是用来找UI的子物体用的。
OK,我们正式进入到LoginWindow的完善。我们知道这个界面分为两块,一个是登陆,一个选择服务器。
我们先来写登陆的逻辑。
可以看到这个界面分为3个组件:
1.用户名输入框
2.密码输入框
3.确认登陆按钮
所以我们在LoginWindow初始化这些组件:
然后在InitWidget()里面初始化这些定义的组件:
这里的名字是我自己去的比如Login/UserNameInput,你们可以自己取自己的名字。
Login是LoginWindow下面的子物体,然后UserNameInput是Login下面的子物体,我们用/来区分紫武器。
OK,当我们点击确认登陆按钮的时候,肯定需要一个登陆事件给这个按钮,所以现在我们来写这个事件监听。
然后我们来编写OnLoginSumbit方法,主要处理一些登陆逻辑的事情。
public void OnLoginSumbit(GameObject go)
{
string username = this.m_Input_UsernameInput.value;
string password = this.m_Input_PasswordInput.value;
//如果用户名或者密码为空的话,就显示提示消息
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
CEvent evt = new CEvent(EGameEvent.eGameEvent_ShowMessage);
evt.AddParam("content", StringConfigManager.GetString("MessageWindow.EMT_SureTip.LoginNullUsernameOrPassword"));
EventCenter.SendEvent<EMessageType, Action<bool>>(evt, EMessageType.EMT_SureTip, (isOk) =>
{
EventCenter.Broadcast(EGameEvent.eGameEvent_HideMessage);
});
}
LoginCtrl.singleton.Login(username, password);
}
可以看到我们搞了一个当确定消息提示,如果用户名和密码为空的话。
然后为了符合类的单一职责,我们把所有的逻辑放在LoginCtrl中。
新建文件夹取名为Controller,然后在里面新建一个LoginCtrl类:(我忘记之前是不是讲过这个类,如果有讲过这个类,因为我太久之前写的,都忘记了,读者自行改过)。
在写这个逻辑之前,我们先来想下我们登陆进去在选择服务器,所以登陆这个验证并没有进入到游戏服务器中,因为我们根本没有选择服务器,怎么能进到服务器中呢?
所以我认为就只是网页简单的验证用户名密码,然后选择服务器之后才真正的进入到游戏服务器。
所以这个登陆的逻辑步骤是:
1.开启协程访问一个网站,这个网站验证用户名和密码。(所以我决定用PHP来写这个验证)
2.如果验证通过之后,然后发送服务器列表给客户端,客户端再进入到选择服务器界面。
3.客户端选择某个服务器,然后进入到这个游戏服务器。
所以首先,我在网站文件夹下面新建一个check.php文件:
这个脚本就是通过数据库连接,然后进行验证,这里我简单一点,我就直接都放回成功。因为我们只是做下测试,不用每步都详细。
所以我这里只是简单放回一个success字符串,然后在LoginCtrl中:
public void Login(string account, string password)
{
this.username = account;
this.password = password;
LOLGameDriver.Instance.StartCoroutine(CheckUserPass());
}
IEnumerator CheckUserPass()
{
if (string.IsNullOrEmpty(this.username) || string.IsNullOrEmpty(this.password))
{
yield break;
}
WWW www = new WWW("http://127.0.0.1/LOLGameDemo/check.php");
bool success = false;
for (int i = 0; i < 10; i++)
{
yield return new WaitForSeconds(0.5f);
if (www.isDone)
{
if (string.IsNullOrEmpty(www.error))
{
if (!string.IsNullOrEmpty(www.text))
{
if (www.text == "success")
{
//加载服务器信息
SystemConfig.LoadServerList();
success = true;
EventCenter.Broadcast(EGameEvent.eGameEvent_ShowSelectServerList);
}
else
{
//登陆失败
}
}
}
else
{
this.m_log.Error(www.error.ToString());
}
break;
}
}
if (www != null)
{
www.Dispose();
www = null;
}
//如果不成功
if (!success)
{ }
yield break;
}
不知读者注意到没有,如果登陆成功的话,我们就开始加载服务器列表。
//加载服务器信息
SystemConfig.LoadServerList();
所以我们回到SystemConfig里面:
/// <summary>
/// 加载服务器列表
/// </summary>
public static void LoadServerList()
{
try
{
List<ServerInfo> servers;
var url = GetCfgInfoUrlByName("ServerList");
string xmlSerList = "";
if (!string.IsNullOrEmpty(url))
{
xmlSerList = DownloadMgr.Instance.DownLoadHtml(url);
}
servers = LoadXMLText<ServerInfo>(xmlSerList);
if (servers.Count != 0)
{
ServerList = servers;
}
for (int i = 0; i < ServerList.Count; i++)
{
if (ServerList[i].id == LocalSetting.SelectedServer)
{
SelectedServerIndex = ServerList[i].id;
break;
}
}
}
catch (Exception e)
{
m_log.Error(e.ToString());
}
}
/// <summary>
/// 根据名字取得服务端配置信息Url
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string GetCfgInfoUrlByName(string name)
{
string result = "";
foreach (var item in CfgInfoList)
{
if (item.name == name)
{
result = item.url;
break;
}
}
return result;
}
然后我们到Cfg.xml文件添加这个url=>id是1,名字是ServerList:
<?xml version="1.0" encoding="utf-8"?>
<root>
<cfg>
<id>0</id>
<name>version</name>
<url>http://127.0.0.1/LOLGameDemo/ServerVersion.xml</url>
</cfg>
<cfg>
<id>1</id>
<name>ServerList</name>
<url>http://127.0.0.1/LOLGameDemo/ServerList.xml</url>
</cfg>
</root>
然后我们添加4个游戏服务器,分别是电信2个(type为0),联通两个(type为1):
<?xml version="1.0" encoding="utf-8"?>
<root>
<list>
<id_i>0</id_i>
<name_s>艾欧尼亚</name_s>
<type_i>0</type_i>
<flag_i>0</flag_i>
<text_s>fe</text_s>
</list>
<list>
<id_i>1</id_i>
<name_s>战争学院</name_s>
<type_i>0</type_i>
<flag_i>0</flag_i>
<text_s>csc</text_s>
</list>
<list>
<id_i>2</id_i>
<name_s>黑色玫瑰</name_s>
<type_i>1</type_i>
<flag_i>0</flag_i>
<text_s>greger</text_s>
</list>
<list>
<id_i>3</id_i>
<name_s>洛克萨斯</name_s>
<type_i>1</type_i>
<flag_i>0</flag_i>
<text_s>greger</text_s>
</list>
</root>
所以我们回到LoginWindow中,添加该事件:
protected override void OnAddListener()
{
EventCenter.AddListener(EGameEvent.eGameEvent_ShowSelectServerList, ShowSelectServer);
}
protected override void OnRemoveListener()
{
EventCenter.RemoveListener(EGameEvent.eGameEvent_ShowSelectServerList, Show);
}
在写ShowSelectServer方法之前,我们得先定义选择服务器界面组件:
#region 选择服务器界面
private UIPanel m_Panel_Select;//选择服务器界面整体Panel
private UIButton m_Button_Select;//确认选择按钮
private UIButton m_Button_LeftButton;
private UIButton m_BUtton_RightButton;
private UIButton m_Button_ServerListButton;//服务器列表按钮
private XUIList m_List_Dianxin;
private XUIList m_List_Wangtong;
private XUISprite m_Sprite_IconBG;
private XUISprite m_Sprite_ServerName;
private XUISprite m_Sprite_Icon;
private XUILabel m_Label_ServerName;
private XUILabel m_Label_NetworkSpeed;//测试速度Label
#endregion
InitWeight:
this.m_Button_ServerListButton = this.mRoot.FindChild("Select/Button/ServerListButton").GetComponent<UIButton>();
this.m_Button_Select = this.mRoot.FindChild("Select/Button/SelectButton").GetComponent<UIButton>();
this.m_Panel_Select = this.mRoot.FindChild("Select").GetComponent<UIPanel>();
this.m_List_Dianxin = this.mRoot.FindChild("Select/ServerList/Table/Dianxin/DianxinGrid").GetComponent<XUIList>();
this.m_List_Wangtong = this.mRoot.FindChild("Select/ServerList/Table/Wangtong/WangtongGrid").GetComponent<XUIList>();
this.m_Sprite_IconBG = this.mRoot.FindChild("Select/Signal/IconBG").GetComponent<XUISprite>();
this.m_Sprite_Icon = this.mRoot.FindChild("Select/Signal/IconAnim").GetComponent<XUISprite>();
this.m_Sprite_ServerName = this.mRoot.FindChild("Select/Signal/Name/ServerNameIcon").GetComponent<XUISprite>();
OK,初始化好界面后,我们回过头写ShowSelectServer:
/// <summary>
/// 显示选择服务器界面
/// </summary>
public void ShowSelectServer()
{
if (this.m_Panel_Select != null)
{
if (this.ShowServerList())
{
//服务器列表按钮的sprite替换
if (this.m_bShowServerList)
{
this.m_Button_ServerListButton.normalSprite = "image 378";
}
else
{
this.m_Button_ServerListButton.normalSprite = "image 383";
}
this.m_Panel_Select.enabled = true;
GameObject serverList = this.m_Panel_Select.transform.FindChild("ServerList").gameObject;
//serverList.
serverList.SetActive(this.m_bShowServerList);
//如果显示服务器列表面板,播放偏移动画
if (this.m_bShowServerList)
{
serverList.transform.localPosition = new Vector3(14, 0, 0);
TweenAlpha.Begin(serverList, 1, 1);
TweenPosition.Begin(serverList, 1, Vector3.zero);
}
}
else
{
Debug.LogError("服务器列表还没有初始化");
}
}
}
/// <summary>
/// 显示服务器列表
/// </summary>
public bool ShowServerList()
{
if (this.m_bHasLoadedServerList)
{
return true;
}
if (SystemConfig.ServerList != null)
{
this.m_selectedServerId = SystemConfig.SelectedServerIndex;
this.m_lastSelectServerId = SystemConfig.SelectedServerIndex;
int indexDianxin = 0;
int indexWangtong = 0;
foreach (var serverInfo in SystemConfig.ServerList)
{
IXUIListItem serverItem;
switch (serverInfo.type)
{
case 0:
if (serverInfo.flag == (int)ServerType.Recommend)
{
this.m_reDianxinServerId = serverInfo.id;
}
if (indexDianxin < this.m_List_Dianxin.Count)
{
serverItem = this.m_List_Dianxin.GetItemByIndex(indexDianxin);
}
else
{
serverItem = this.m_List_Dianxin.AddListItem();
}
if (serverItem != null)
{
serverItem.SetText("ServerName",serverInfo.name);
serverItem.SetVisible(true);
serverItem.TipParam = new TipParam
{
Tip = serverItem.Tip
};
serverItem.Id = serverInfo.id;
}
else
{
serverItem.SetVisible(false);
}
indexDianxin++;
break;
case 1:
if (serverInfo.flag == (int)ServerType.Recommend)
{
this.m_reWangtongServerId = serverInfo.id;
}
if (indexWangtong < this.m_List_Wangtong.Count)
{
serverItem = this.m_List_Wangtong.GetItemByIndex(indexWangtong);
}
else
{
serverItem = this.m_List_Wangtong.AddListItem();
}
if (serverItem != null)
{
serverItem.SetText("ServerName", serverInfo.name);
serverItem.SetVisible(true);
serverItem.TipParam = new TipParam
{
Tip = serverItem.Tip
};
serverItem.Id = serverInfo.id;
}
else
{
serverItem.SetVisible(false);
}
indexWangtong++;
break;
}
}
this.m_bHasLoadedServerList = true;
return true;
}
else
{
return false;
}
}
#region 变量定义
private bool m_bShowServerList = false;//是否显示服务器列表
private bool m_bHasLoadedServerList = false;//是否已经加载过服务器列表
private int m_selectedServerId = -1;
private int m_lastSelectServerId = SystemConfig.SelectedServerIndex;
private int m_reDianxinServerId = -1;//电信推荐服务器id
private int m_reWangtongServerId = -1;//网通推荐服务器idn
#endregion
然后在InitWeight中,让m_Button_ServerListButton监听显示服务器列表和不显示的事件监听:
UIEventListener.Get(this.m_Button_ServerListButton.gameObject).onClick = (x) => { this.m_bShowServerList = !this.m_bShowServerList; ShowSelectServer(); };
还有我们点击某个服务器,得把那个服务器的id,记录下来,所以我们还是注册一个事件:
this.m_List_Dianxin.RegisterListOnClickEventHandler(new ListOnClickEventHandler(this.OnServerListItemClick));
/// <summary>
/// 服务器某个被点击
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
private bool OnServerListItemClick(IXUIListItem item)
{
if (null == item)
{
return false;
}
this.m_selectedServerId = item.Id;
ServerInfo info = SystemConfig.GetServerInfoById(this.m_selectedServerId);
bool active = true;
if (info.flag == (int)ServerType.Close || info.flag == (int)ServerType.Maintain)
{
active = false;
}
ShowServerSignal(active, info);
return true;
}
/// <summary>
/// 播放动画
/// </summary>
/// <param name="bActive"></param>
/// <param name="info"></param>
private void ShowServerSignal(bool bActive,ServerInfo info)
{
if (bActive)
{
if (info.id == 0)
{
this.m_Sprite_Icon.SetSprite("image 967", "Atlas/SelectAtlas/SelectServerAtlas");
this.m_Sprite_ServerName.SetSprite("image 975");
}
else
{
this.m_Sprite_Icon.SetSprite("image 1015", "Atlas/SelectAtlas/SelectServerAtlas");
this.m_Sprite_ServerName.SetSprite("image 1012");
}
if (this.m_Sprite_IconBG != null)
{
this.m_Sprite_IconBG.PlayFlash(false);
this.m_Sprite_ServerName.Alpha = 0f;
this.m_Sprite_Icon.Alpha = 0f;
TweenAlpha.Begin(this.m_Sprite_ServerName.gameObject, 0.8f, 1f);
TweenAlpha.Begin(this.m_Sprite_Icon.gameObject, 0.8f, 1f);
}
}
}
OK,大致就是这么多的代码,具体步骤:
1.如果选择服务器Panel不激活的话,就显示服务器列表,然后激活。
2.注册一些按钮的事件
3.记录下来选择的服务器id
然后我们点击选择按钮,就发送这个服务器id给游戏网关服务器,网关服务器就把用户连接到这个游戏服务器中。
下节课,我们就开始进入游戏服务器连接,当然这里就涉及到NetworkManager的编写,主要是TCp的连接。
仿LOL项目开发第七天的更多相关文章
- 仿LOL项目开发第九天
仿LOL项目开发第九天 by 草帽 OK,今天我们完全换了一种风格,抛弃了Unity3d的c#语法,我们来写写java的项目. 说到java服务器,当然有些人可能鄙视java的服务器速度太慢,但是相对 ...
- 仿LOL项目开发第八天
仿LOL项目开发第八天 by 草帽 这节我们继续上节所讲的内容,上节我们初始化好了LoginWindow,当我们点击确认选择服务器按钮的时候,就发送服务器id给游戏服务器. 这里就开始涉及到客户端需要 ...
- 仿LOL项目开发第六天
仿LOL项目开发第六天 by草帽 OK,因为更新模块已经处理好了,接着开始登陆的编写.那么我们就需要状态机的管理. 所谓状态机就是在哪个状态执行那个状态的代码逻辑: 那么我们开始编写GameState ...
- 仿LOL项目开发第五天
仿LOL项目开发第五天 by草帽 今天呢,我们看下能开发什么内容,首先上节我们已经讲了UI框架的搭建,上节还遗留下很多问题,比如说消息的字符是代码里面自己赋值的. 那么就比较死板,按照正常的逻辑,那些 ...
- 仿LOL项目开发第四天
---恢复内容开始--- 仿LOL项目开发第四天 by草帽 上节讲了几乎所有的更新版本的逻辑,那么这节课我们来补充界面框架的搭建的讲解. 我们知道游戏中的每个界面都有自己的一个类型:比如登陆界面,创建 ...
- 仿LOL项目开发第三天
仿LOL项目开发第二天 by草帽 昨个我们已经实现了下载功能,但是发现没有,下载的包是压缩的,没有解压开,那么Unity是识别不了的. 所以今个我们来讲讲如何实现解压文件. 还记得吗,我们在Downl ...
- 仿LOL项目开发第二天
仿LOL项目开发第二天 by草帽 接着上节来讲,上节更新还没开始写代码逻辑,今天我们补充完整. 我们找到VersionManager脚本里面的CheckVersion方法: 首先我们想到检测版本,需要 ...
- 仿LOL项目开发第一天
---恢复内容开始--- 仿LOL项目开发第一天 by---草帽 项目源码研究群:539117825 最近看了一个类似LOL的源码,颇有心得,所以今天呢,我们就来自己开发一个类似于LOL的游戏demo ...
- 第七章 企业项目开发--本地缓存guava cache
1.在实际项目开发中,会使用到很多缓存技术,而且数据库的设计一般也会依赖于有缓存的情况下设计. 常用的缓存分两种:本地缓存和分布式缓存. 常用的本地缓存是guava cache,本章主要介绍guava ...
随机推荐
- linux kernel.shmall shemax shemin解释
Linux X86-64操作系统,Oracle 10g数据库,由8G加到16G,把kernel.shmmax参数改到17179869184(16G)后,发现只要修改sga_max_size和s ...
- hdoj1050 Moving Tables(贪心)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1050 题意 有一条走廊,走廊两边各有200个房间,一边的房间编号是奇数,另一边是偶数.现在有n个箱子需 ...
- Wannafly挑战赛9 D - 造一造
链接:https://www.nowcoder.com/acm/contest/71/D来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...
- (四)静态断言(上),assert,NDEBUG, 以及通过宏定义处理文件包含关系
一.断言:运行时与预处理时 断言(assertion)是一种编程常用的手段.想必大家都见过 assert 吧.今天我们就来了解一下它. 通常情况下,断言就是将一个返回值总是需要为真的判别式放在语句中, ...
- Linux-CentOs7-svn安装及钩子配置
做个svn的教程 首先进入test目录下,新建一个svn目录,准备做svn测试cd /testmkdir svncd svn然后使用yum安装svn,这里就不使用编译安装了,这玩意只要能用就行,版本无 ...
- Error after SQL Server 2012 installation: Login Failure for "SQL Server Integration Services 11.0" SSIS service
When you install SQL Server 2012 and you try to connect to SSIS services, you cannot due to that the ...
- 支撑大规模公有云的Kubernetes改进与优化 (3)
这一篇我们来讲网易为支撑大规模公有云对于Kubernetes的定制化. 一.总体架构 网易的Kubernetes集群是基于网易云IaaS平台OpenStack上面进行部署的,在外面封装了一个容器平台的 ...
- android 安全退出 activity
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 定义一个 活动 的基础类, 每次打开一个 活动,就记录下来. 退出时,关闭每一个 活动. ...
- [xsy3466]见面会
题意:有$n$个区间,把它们划分成若干段,如果一段$k$个区间的交长度$\geq2$,那么会产生$\binom k2$的贡献,最大化贡献 对每个$i$用单调栈预处理出$l_i$表示最小的$j$使得$j ...
- LNMP一键安装包如何重装Nginx
LNMP一键安装包安装好后,相应的Mysql,Nginx及PHP都会安装配置完成. 由于某些特殊情况的需要,如何更换Nginx的版本呢? nginx升级脚本可以完成. 1. 手动编译方法:/usr/l ...