在上一篇文章中,我记录了如何让自己的Unity项目能够支持后端云服务,这篇文章我将记录如何编写自己的网络服务管理器。
上面的截图,是我实现的CloudManager 管理器,并且我使用的是单例模式。
private static CloudManager _instance;
public static CloudManager Instance
{
get
{
if(_instance==null)
return new CloudManager();
return _instance;
}
}
这是单例模式的代码,之前我没有判断CloudManager为空时自动创建一个新的管理器而导致无法使用管理类。
public bool 登陆(string userName,string passWord)//登陆检测
{
bool isOK = false;
AVUser.LogInAsync(userName, passWord).ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
var error = t.Exception.Message; // 登录失败,可以查看错误信息。
isOK = false;
}
else
{
var user = t.Result;
isOK = true;
UserName = userName;
UserID = user.ObjectId;
print("登陆成功");
//登录成功
}
});
if (isOK)
return true;
else return false;
}
登陆的方法,传入用户输入的用户名和密码,进行登陆,返回状态值,登陆的密码和用户名在云上也都是经过加密了,其他人是无法获得明文密码的。
public bool 注册(string userName,string passWord,string userEmail)
{
bool isOK = false;
var user = new AVUser();
user.Username = userName;
user.Password = passWord;
user.Email = userEmail;
//注册 异步请求
user.SignUpAsync().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)//判断登陆状态
isOK = false;
UserName = userName;
UserID = user.ObjectId;
isOK = true;
print("登陆成功userID=" + UserID);
});
//用户注册成功返回false
if (isOK)
return true;
else return false;
}
这是注册的,在注册中,我加入了LeanCloud支持的邮箱验证,通过异步请求,获取注册的状态。
public bool 更新个人信息(string sex,string age,string imageUrl)
{
bool isOk = true;
//通过UserInfo 和 userName 找到表格对应的对象 sex age imageUrl
AVQuery<AVObject> query = AVObject.GetQuery("UserInfo").WhereEqualTo("userName", UserName);
query.FindAsync().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
print("没有查到该用户");
isOk = false;
}
var players = t.Result;
IEnumerator<AVObject> enumerator = players.GetEnumerator();
enumerator.MoveNext();
var userInfo = enumerator.Current;//获取目前得分排名第一的玩家
userInfo["sex"] = sex;
userInfo["age"] = age;
userInfo["ImageUrl"] = imageUrl;
return userInfo.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
print("没有保存成功!");
isOk = false;
}
return query.FindAsync();//为了保证数据正确可以再查一遍
}).Unwrap().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
print("检查没通过");
isOk = false;
}
});
if (isOk)
return true;
else return false;
}
更新个人信息中相对比较复杂,步骤是,先从用户信息表中查找用户的信息,如果有这个用户,那么就用查找的对象进行修改操作。整个过程都在一个异步任务中,任务是有先后的。具体的实现逻辑请看下面链接
https://leancloud.cn/docs/unity_guide.html#hash756092925
因为我都是看文档完成的,所以我使用的方法和文档中大致相同。
官方文档中给出了详细的方案。之前我没有任何C#的编程语言经验,但是通过实践我理解了大致的含义。
每个对象都封装了一些任务的方法,可以返回一个任务执行对象,执行一个任务后可以通过一个方法获取一个任务对象,通过对这个任务对象的调用可以获取该任务对象的执行状态。
在方法中,我用了迭代器 IEnumerator
public bool 上传头像(string imagepath, string sex, string age)
{
bool isOK = true;
byte[] data = GetPictureData(imagepath);//传入本地的地址获取序列
string imageUrl;
AVFile file = new AVFile("ASTest.jpg", data, new Dictionary<string, object>()
{
{"author",""}
});
file.SaveAsync().ContinueWith(t =>
{
Debug.Log(t.IsFaulted);
if (!t.IsFaulted)
{
print("File_id:" + file.ObjectId);
}
else
{
isOK = false;
print("失败打印");
Debug.Log(t.Exception.Message);
Debug.LogException(t.Exception);
}
imageUrl = file.Url.ToString();
print("url=" + imageUrl);
更新个人信息(sex, age, imageUrl);//在这里调用更新方法
});
if (isOK)
return true;
else return false;
}
我把上传头像封装成了一个方法,我的思路是,用户选择一个图片进行上传,然后再执行更新个人信息的方法。
上传头像也就是上传文件,LeanCloud专门为上传文件准备了一个文件表,里面放置了所有用户上传的文件,也便于管理。
因为有C++的二进制文件流的经验,所以我熟悉如何序列化与反序列化的思想,C#中对文件的操作也更加简单了。
直接通过文件的地址获取该文件数据然后直接获取对应的字节数组,也就是一个序列。然后上传序列到后端云中,使用的方法如上。
注意的是,通过我的实验,上传文件也是放在线程池中执行,如果文件大小过大如大于10M可能上传不成功,八九兆上传会有一段延迟,但是不会影响游戏的主进程。
public bool 更新得分信息(int score)
{
bool isOK = true;
AVQuery<AVObject> query = new AVQuery<AVObject>("UserScore")
.WhereEqualTo("userName", this.UserName);
query.FindAsync().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
isOK = false;
}
var players = t.Result;
IEnumerator<AVObject> enumerator = players.GetEnumerator();
var user = enumerator.Current;
user["AllScore"] = score;
return user.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
if (t.IsCanceled || t.IsFaulted)
{
print("更新失败");
isOK = false;
}
});
if (isOK)
return true;
else
return false;
}
上段代码,是我做的一个更新用户得分的功能。也是先查表然后再更新,放在任务中进行。
public bool 显示排行榜()
{
bool isOK = true;
AVQuery<AVObject> query = new AVQuery<AVObject>("UserScore")
.WhereNotEqualTo("AllScore", "")
.OrderBy("AllScore")
.OrderByDescending("AllScore");//排序
query.FindAsync().ContinueWith(t =>
{
if (t.IsCanceled)
{
isOK = false;
print("被取消了!");
}
else if (t.IsFaulted)
{
isOK = false;
print("失败了");
}
else
{
var players = t.Result;
IEnumerator<AVObject> enumerator = players.GetEnumerator();
int i = 0;
List<string> myList = new List<string>();
var user = new AVObject("UserScore");
while (enumerator.MoveNext())
{
i++;
var golden_player = enumerator.Current;//
print("玩家得分" + golden_player["userName"] + " :" + golden_player["AllScore"]);
myList.Add(golden_player["userName"] + " :" + golden_player["AllScore"]);
if (golden_player["userName"].Equals(this.UserName))
{
user = golden_player;//获取到了自己的分数
}
}
print("总玩家数:" + i);
enumerator.MoveNext();
//for (i = 1; i <= 20; i++)
//{
// text = GameObject.Find("主界面/Scroll View(Clone)/Viewport/Content/Text" + i).GetComponent<Text>();
// text.text = myList[i-1];
//}
}
});
if (isOK)
return true;
else
return false;
}
LeanCloud中封装了一个排序的方法,所以也省的我对用户的得分进行排序,但是我觉得,如果我游戏的用户群如果太庞大,我可能要自己写一个桶排序,不然数据过多,运算时间过大加载时间过多也对用户的体验不太好。
大致我所需要的后端云服务就到此了,但是大家可能有疑问,在移动端如何让用户选择自己本地的图片或者拍照作为自己的头像呢,我经过研究也实现了在Unity中写插件,可以打开安卓机的图库了,下一篇文章,我就将记录我的研究。