仿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项目开发第七天的更多相关文章

  1. 仿LOL项目开发第九天

    仿LOL项目开发第九天 by 草帽 OK,今天我们完全换了一种风格,抛弃了Unity3d的c#语法,我们来写写java的项目. 说到java服务器,当然有些人可能鄙视java的服务器速度太慢,但是相对 ...

  2. 仿LOL项目开发第八天

    仿LOL项目开发第八天 by 草帽 这节我们继续上节所讲的内容,上节我们初始化好了LoginWindow,当我们点击确认选择服务器按钮的时候,就发送服务器id给游戏服务器. 这里就开始涉及到客户端需要 ...

  3. 仿LOL项目开发第六天

    仿LOL项目开发第六天 by草帽 OK,因为更新模块已经处理好了,接着开始登陆的编写.那么我们就需要状态机的管理. 所谓状态机就是在哪个状态执行那个状态的代码逻辑: 那么我们开始编写GameState ...

  4. 仿LOL项目开发第五天

    仿LOL项目开发第五天 by草帽 今天呢,我们看下能开发什么内容,首先上节我们已经讲了UI框架的搭建,上节还遗留下很多问题,比如说消息的字符是代码里面自己赋值的. 那么就比较死板,按照正常的逻辑,那些 ...

  5. 仿LOL项目开发第四天

    ---恢复内容开始--- 仿LOL项目开发第四天 by草帽 上节讲了几乎所有的更新版本的逻辑,那么这节课我们来补充界面框架的搭建的讲解. 我们知道游戏中的每个界面都有自己的一个类型:比如登陆界面,创建 ...

  6. 仿LOL项目开发第三天

    仿LOL项目开发第二天 by草帽 昨个我们已经实现了下载功能,但是发现没有,下载的包是压缩的,没有解压开,那么Unity是识别不了的. 所以今个我们来讲讲如何实现解压文件. 还记得吗,我们在Downl ...

  7. 仿LOL项目开发第二天

    仿LOL项目开发第二天 by草帽 接着上节来讲,上节更新还没开始写代码逻辑,今天我们补充完整. 我们找到VersionManager脚本里面的CheckVersion方法: 首先我们想到检测版本,需要 ...

  8. 仿LOL项目开发第一天

    ---恢复内容开始--- 仿LOL项目开发第一天 by---草帽 项目源码研究群:539117825 最近看了一个类似LOL的源码,颇有心得,所以今天呢,我们就来自己开发一个类似于LOL的游戏demo ...

  9. 第七章 企业项目开发--本地缓存guava cache

    1.在实际项目开发中,会使用到很多缓存技术,而且数据库的设计一般也会依赖于有缓存的情况下设计. 常用的缓存分两种:本地缓存和分布式缓存. 常用的本地缓存是guava cache,本章主要介绍guava ...

随机推荐

  1. drools7 (一、最简单的例子)

    切记!!! 必须使用jdk1.8 工程目录 引入依赖包,pom.xml <?xml version="1.0" encoding="UTF-8"?> ...

  2. 【51nod】1851 俄罗斯方块

    题解 最近一遇到神仙题一卡就好久--做点水题滋养一下自己吧= = 显然我们发现放一个方块的奇偶性不会改变,所以格子如果黑格子是奇数,那么就是No 我们发现每个2 × 3的方格里的2 × 1的黑格子都可 ...

  3. Spring的配置文件ApplicationContext.xml配置头文件解析

    Spring的配置文件ApplicationContext.xml配置头文件解析 原创 2016年12月16日 14:22:43 标签: spring配置文件 5446 spring中的applica ...

  4. CI框架中site_url()和base_url()的区别

    背景:在使用CI框架的使用经常碰到跳转和路径方面的问题,site_url()和base_url()很容易混淆,下面来说说他们的区别! 假如你config文件里面的base_url和index_page ...

  5. 机器学习之路:python线性回归分类器 LogisticRegression SGDClassifier 进行良恶性肿瘤分类预测

    使用python3 学习了线性回归的api 分别使用逻辑斯蒂回归  和   随机参数估计回归 对良恶性肿瘤进行预测 我把数据集下载到了本地,可以来我的git下载源代码和数据集:https://gith ...

  6. codevs 2596 售货员的难题

    2596 售货员的难题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货 ...

  7. [CEOI2008]order --- 最小割

    [CEOI2008]order 题目描述: 有N个任务,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成. 现在给出这些参数, ...

  8. hihocoder 1866 XOR

    题面在这里 拆位分析一下就OK啦 /* y + (y xor x) */ #include<bits/stdc++.h> #define ll long long using namesp ...

  9. java的注解

    本文转载自:http://www.cnblogs.com/mandroid/archive/2011/07/18/2109829.html 一.概念 Annontation是Java5开始引入的新特征 ...

  10. bzoj 4034

    我写的是 DFS序+线段树 DFS序(出去的位置要单独建点)上,进入的位置是权值,出去的位置是权值的相反数,可以证明节点i到根节点的路径上的点的权值和是DFS序上1-in[i]的和. 只要搞出每个区间 ...