账号是现实世界对用户的描述,而角色则是游戏世界当中用户的体现。
——茂叔
账号
上一篇,我们利用微信的api完成了用户的登录工作,那现在,我们来处理用户的账户和角色信息。
首先,我们在type.cs
里面为用户的账户建立一个类。
public struct Account
{
public uint AID;//账户的编号
public string openid;//微信的标识
public string nickname;
public DateTime CreateTime;
public DateTime LastLogin;
}
很简单吧。然后我们在GameServer
里面去定义一个账号池,并在构造函数初始化,用来暂时储存账号信息。
……
public List<Account> AccountPool;
public GameServer(MainForm monitor)
{
Status = 0;
Monitor = monitor;
LOG("GameServer创建成功");
gGame = new Game(LOG);
gGame.Name = "像素寒冷";
AccountPool = new List<Account>();
……
然后在GameServer
类的ParseClientCommand
方法里面,对GameCommand.LOGIN
指令做一些修改,检查有没有对应openid
的账号,没有就立即创建一个放进我们账号池里面。然后去取得对应账号的用户角色回传给客户端。
……
case GameCommand.LOGIN:
{
string requeststr = "https://api.weixin.qq.com/sns/jscode2session?appid=" + G.AppID + "&secret=" + G.Secret + "&js_code=" + data + "&grant_type=authorization_code";
HttpWebRequest wxRequest = (HttpWebRequest)WebRequest.Create(requeststr);
wxRequest.Method = "GET";
wxRequest.Timeout = 6000;
HttpWebResponse wxResponse = (HttpWebResponse)wxRequest.GetResponse();
Stream stream = wxResponse.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string res = reader.ReadToEnd();
stream.Close();
reader.Close();
JObject json = JObject.Parse(res);
if (json.TryGetValue("openid", out JToken openid))
{
Account account;
lock (AccountPool)
{
account = AccountPool.Find(x => x.openid == openid.ToString());
if (account.openid == null)
{
account = new Account()
{
AID = (uint)G.RND(10000000, 99999999),
openid = openid.ToString(),
CreateTime = DateTime.Now
};
while (AccountPool.Exists(x => x.AID == account.AID))
{
account.AID = (uint)G.RND(10000000, 99999999);
}
AccountPool.Add(account);
}
account.LastLogin = DateTime.Now;
}
JObject playerjson=gGame.GetPlayerJsonWithAccountID(account.AID);
((GameConnection)connection).SendMessage(cmd, playerjson.ToString());
}
}
break;
……
因为客户端需要接受的是Json对象,所以我们为GameObject
定义了一个ToJson
方法,用以获得其Json串,在GameCharacter
和GamePlayer
里面进行了覆盖,添加进新的内容。
GameObject
public virtual JObject ToJson()
{
JObject ClientJSON = new JObject();
ClientJSON.Add("Name", Name);
ClientJSON.Add("Status",(int)Status);
ClientJSON.Add("ImgFileID", ImgFileID);
ClientJSON.Add("ImgID", ImgID);
ClientJSON.Add("StatusStep", StatusStep);
ClientJSON.Add("Dir", (int)Dir);
return ClientJSON;
}
GameCharacter
public override JObject ToJson()
{
JObject ClientJSON = base.ToJson();
ClientJSON.Add("Gender", Gender);
ClientJSON.Add("Level", Level);
ClientJSON.Add("Exp", Exp);
ClientJSON.Add("HP", HP);
ClientJSON.Add("Max_HP", Max_HP);
ClientJSON.Add("Energe", Energe);
ClientJSON.Add("Max_Energe", Max_Energe);
ClientJSON.Add("Hungry", Hungry);
ClientJSON.Add("Max_Hungry", Max_Hungry);
ClientJSON.Add("Attack_Point", Attack_Point);
ClientJSON.Add("Defence_Point", Defence_Point);
ClientJSON.Add("Attack_Point_Extra", Attack_Point_Extra);
ClientJSON.Add("Defence_Point_Extra", Defence_Point_Extra);
ClientJSON.Add("Speed", Speed);
return ClientJSON;
}
GamePlayer
public override JObject ToJson()
{
JObject ClientJSON = base.ToJson();
ClientJSON.Add("AID", AID);
ClientJSON.Add("PlayerID", PlayerID);
return ClientJSON;
}
这样通过ToJson
方法获得的数据,发回客户端的数据就都是Json格式的了。
角色生成
在Game
类里面也定义一个角色池,用来储存角色。再新建一个方法用来取得对应账号的游戏角色Json值:
……
private List<GamePlayer> PlayerPool;
public Game(Action<string> LOGFUN = null)
{
G.GlobeTime = 0;
gWorld = new GameWorld(LOGFUN);
PlayerPool = new List<GamePlayer>();
RunThread = null;
IsRunning = false;
……
public JObject GetPlayerJsonWithAccountID(uint AID)
{
GamePlayer player;
lock (PlayerPool)
{
player = PlayerPool.Find(x => x.AID == AID);
if (player == null)
{
player = new GamePlayer()
{
AID=AID,
PlayerID = (uint)G.RND(10000000, 99999999),
CreateTime = DateTime.Now
};
while (PlayerPool.Exists(x => x.PlayerID == player.PlayerID))
{
player.PlayerID = (uint)G.RND(10000000, 99999999);
}
player.Name = "@";
PlayerPool.Add(player);
}
}
return player.ToJson();
}
同样的道理,没有对应角色就创建一个。
现在可以为从GameObject
,GameCharacter
一直到GamePlayer
的对象添加一些与游戏相关的成员了。修改之后的成员如下:
GameObject
……
public string Description;
public ExistenceID MapEID;
public byte X;
public byte Y;
public ObjectCategory Category;
public ObjectClassID ClassID;
public ObjectStatus Status;
public byte StatusStep;
public byte ImgFileID;
public byte ImgID;
public bool CanPass;
public GameObject[] Inventory;
public ExistenceID OwnerEID;
public Direction Dir=Direction.NONE;
……
GameCharacter
……
public byte Gender = 0;//0-female, 1-male
public uint Level = 1;//等级
public uint Exp = 0;//经验
public byte HP = 100;//血
public byte Max_HP = 100;//血的最大值
public byte Energe = 100;//体力
public byte Max_Energe = 100;//体力最大值
public byte Hungry = 100;//饥饿
public byte Max_Hungry = 100;//饥饿最大值
public ushort Attack_Point = 1;//攻击
public ushort Defence_Point = 1;//防御
public ushort Attack_Point_Extra = 1;//攻击附加,装备了武器什么的
public ushort Defence_Point_Extra = 1;//防御附加
public byte Speed = 128;
private byte SpeedBuff = 0;
……
这些与游戏相关的成员,是不是一看就懂啊~哈哈!
GamePlayer
……
public uint AID = 0;//对应账号编号
public uint PlayerID = 10000000;
public DateTime CreateTime = DateTime.Now;
……
玩家的角色对象把账号信息也带上。
在客户端那边的命令解析方法里,把服务端传回的信息log出来:
net.js
function parseMessage(msg) {
if (msg.command == 1) //这是初次连接成功传回的结果
{
_g.COMMAND = JSON.parse(msg.data);
login()
} else {
switch (msg.command) //其他命令的处理结果
{
case _g.COMMAND.LOGIN:
console.log(msg.data)
break;
}
}
}
调试一下看看效果:
客户端已经收到了。在客户端定义一个全局对象,用来储存玩家的信息,还记得我们的_g
么?就定义在里面:
global.js
GameGlobal._g = {
COMMAND: undefined,
WEBSOCKET_URL : 'ws://localhost:666/',
DEVICEWIDTH: undefined,
DEVICEHEIGHT:undefined,
Player:{}//玩家对象
}
然后把收到的信息装进去,通过wx.getUserInfo
把最新的微信昵称和头像也装进去:
net.js
case _g.COMMAND.LOGIN:
_g.Player=JSON.parse(msg.data)
wx.getUserInfo({
success(res){
_g.Player.nickName = res.userInfo.nickName
_g.Player.avatarUrl = res.userInfo.avatarUrl
}
})
console.log(_g.Player)
break;
名字缺省为@,这是RogueLike的习惯……从ASCII时代开始,这个字符就在RogueLike游戏里面代表玩家。
不过我们这个游戏应该让玩家选择一个中国风的名字才对啊。
角色名字生成
所以,我们的客户端如果发现玩家的名字是@,就应该启动名字选择的界面,以便选一个堂堂正正的中国名字。
考虑到游戏整体氛围的因素,我们不让玩家自己输入名字,而是在服务器端生成几个名字,让玩家来选择。
给GamePlayer
添加一个成员用来储存备选名字,然后在Game
类定义一个MakeNames
来随机生成4个备选名字,并在生成新角色后调用它。这里需要用到通过PlayerID
获取角色对象的方法,新增一个,很简单的。
GamePlayer.cs
……
public string[] NameList = new string[4];//提供四个备选名字
……
Game.cs
……
public JObject GetPlayerJsonWithAccountID(uint AID)
{
GamePlayer player;
lock (PlayerPool)
{
player = PlayerPool.Find(x => x.AID == AID);
if (player == null)
{
player = new GamePlayer()
{
AID=AID,
PlayerID = (uint)G.RND(10000000, 99999999),
CreateTime = DateTime.Now
};
while (PlayerPool.Exists(x => x.PlayerID == player.PlayerID))
{
player.PlayerID = (uint)G.RND(10000000, 99999999);
}
player.Name = "@";
PlayerPool.Add(player);
MakeName(player.PlayerID);//生成备选名字
}
}
return player.ToJson();
}
……
public void MakeName(uint PlayerID)
{
string[] names = new string[4];
string[] fname = new string[] {
"赵", "钱", "杨", "孙", "李",
"周", "吴", "郑", "王", "黄",
"罗", "封", "袁", "崔", "龙",
"熊", "沈", "马", "蓝", "洪",
"白","雷","诸葛","穆","冯",
"鞠","刁","陈","张","蔡",
"公孙", "司马", "独孤", "上官", "皇甫" };
string[] lname = new string[] {
"阿大", "二", "三", "四", "剑", "勇", "霸", "飞", "雪", "长丰", "峰", "啸天", "云"
,"十三", "九玄", "擎天", "文", "心", "六郎", "五姑", "玲", "云飞", "嫣然", "贤", "子豪", "易"
,"尚", "诚", "仁", "元虎", "智", "朗", "猛", "可", "明山", "瑞蒲", "吉宏", "志远", "海"
,"峰", "卫贤", "义侠", "云鹤"
,"礼", "瑜", "美", "秋"
};
for (int i = 0; i < 4; i++)
{
int fid = G.RND(0, fname.Length - 1);
int lid = G.RND(0, lname.Length - 1);
while (fname[fid] == "" || lname[lid] == "")
{
fid = G.RND(0, fname.Length - 1);
lid = G.RND(0, lname.Length - 1);
}
names[i] = fname[fid] + lname[lid];
fname[fid] = "";
lname[lid] = "";
}
GamePlayer player = GetPlayerByPlayerId(PlayerID);
if (player != null && player.PlayerID == PlayerID)
{
names.CopyTo(player.NameList, 0);
}
}
private GamePlayer GetPlayerByPlayerId(uint PlayerID)
{
return PlayerPool.Find(x=>x.PlayerID==PlayerID);
}
……
新添加的成员如果要想被客户端收到,记得修改GamePlayer
的ToJson
方法:
public override JObject ToJson()
{
JObject ClientJSON = base.ToJson();
ClientJSON.Add("AID", AID);
ClientJSON.Add("PlayerID", PlayerID);
ClientJSON.Add("NameList", JArray.FromObject(NameList));
return ClientJSON;
}
再次调试
好了,用户对象已经生成完毕了,下一步,我们要让用户选择性别和姓名,这就涉及到客户端用户界面的实现了。
截止这一篇的全部代码,请大家去我的GitHub下载:
>>第十一篇代码连接<<