C#服务端的微信小游戏——多人在线角色扮演(十一)

C#服务端的微信小游戏——多人在线角色扮演(十一)

账号是现实世界对用户的描述,而角色则是游戏世界当中用户的体现。
——茂叔

账号

上一篇,我们利用微信的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串,在GameCharacterGamePlayer里面进行了覆盖,添加进新的内容。
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();
        }

同样的道理,没有对应角色就创建一个。

现在可以为从GameObjectGameCharacter一直到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);
        }
……

新添加的成员如果要想被客户端收到,记得修改GamePlayerToJson方法:

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下载:
>>第十一篇代码连接<<

上一篇:C#服务端的微信小游戏——多人在线角色扮演(十)
下一篇:C#服务端的微信小游戏——多人在线角色扮演(十二)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值