• 一、前言

  《码神联盟》是一款为技术人做的开源情怀游戏,每一种编程语言都是一位英雄。客户端和服务端均使用C#开发,客户端使用Unity3D引擎,数据库使用MySQL。这个MOBA类游戏是笔者在学习时期和客户端美术策划的小伙伴一起做的游戏,笔者主要负责游戏服务端开发,客户端也参与了一部分,同时也是这个项目的发起和负责人。这次主要分享这款游戏的服务端相关的设计与实现,从整体的架构设计,到服务器网络通信底层的搭建,通信协议、模型定制,再到游戏逻辑的分层架构实现。同时这篇博客也沉淀了笔者在游戏公司实践五个月后对游戏架构与设计的重新审视与思考。

  这款游戏自去年完成后笔者曾多次想写篇博客来分享,也曾多次停笔,只因总觉得灵感还不够积淀还不够思考还不够,现在终于可以跨过这一步和大家分享,希望可以带来的是干货与诚意满满。由于目前关于游戏服务端相关的介绍文章少之又少,而为数不多的几篇也都是站在游戏服务端发展历史和架构的角度上进行分享,很少涉及具体的实现,这篇文章我将尝试多从实现的层面上加以介绍,所附的代码均有详尽注释,篇幅较长,可以关注收藏后再看。学习时期做的项目可能无法达到工业级,参考了github上开源的C#网络框架,笔者在和小伙伴做这款游戏时农药还没有现在这般火。  : ) 

  • 二、服务器架构

iOS培训,Swift培训,苹果开发培训,移动开发培训

  上图为这款游戏的服务器架构和主要逻辑流程图,笔者将游戏的代码实现分为三个主要模块:Protocol通信协议、NetFrame服务器网络通信底层的搭建以及LOLServer游戏的具体逻辑分层架构实现,下面将针对每个模块进行分别介绍。

  • 三、通信协议

  iOS培训,Swift培训,苹果开发培训,移动开发培训

  先从最简单也最基本的通信协议部分说起,我们可以看到这部分代码主要分为xxxProtocol、xxxDTO和xxxModel、以及xxxData四种类型,让我们来对它们的作用一探究竟。

  • 1.Protocol协议

iOS培训,Swift培训,苹果开发培训,移动开发培训


 LOLServer\Protocol\Protocol.cs

using System; using System.Collections.Generic; using System.Text; namespace GameProtocol {    public class Protocol     {        public const byte TYPE_LOGIN = 0;//登录模块        public const byte TYPE_USER = 1;//用户模块        public const byte TYPE_MATCH = 2;//战斗匹配模块        public const byte TYPE_SELECT = 3;//战斗选人模块        public const byte TYPE_FIGHT = 4;//战斗模块     } }

iOS培训,Swift培训,苹果开发培训,移动开发培训

  从上述的代码举例可以看到,在Protocol协议部分,我们主要是定义了一些常量用于模块通信,在这个部分分别定义了用户协议、登录协议、战斗匹配协议、战斗选人协议以及战斗协议。

  • 2.DTO数据传输对象

  DTO即数据传输对象,表现层与应用层之间是通过数据传输对象(DTO)进行交互的,需要了解的是,数据传输对象DTO本身并不是业务对象。数据传输对象是根据UI的需求进行设计的,而不是根据领域对象进行设计的。比如,User领域对象可能会包含一些诸如name, level, exp, email等信息。但如果UI上不打算显示email的信息,那么UserDTO中也无需包含这个email的数据。

  简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。

iOS培训,Swift培训,苹果开发培训,移动开发培训

using System; using System.Collections.Generic; using System.Text; namespace GameProtocol.dto {     [Serializable]    public class UserDTO    {        public int id;//玩家ID 唯一主键        public string name;//玩家昵称        public int level;//玩家等级        public int exp;//玩家经验        public int winCount;//胜利场次        public int loseCount;//失败场次        public int ranCount;//逃跑场次        public int[] heroList;//玩家拥有的英雄列表        public UserDTO() { }        public UserDTO(string name, int id, int level, int win, int lose, int ran,int[] heroList)        {            this.id = id;            this.name = name;            this.winCount = win;            this.loseCount = lose;            this.ranCount = ran;            this.level = level;            this.heroList = heroList;        }     } }

iOS培训,Swift培训,苹果开发培训,移动开发培训

  • 3.Data属性配置表

  这部分的实现主要是为了将程序功能与属性配置分离,后面可以由策划来配置这部分内容,由导表工具自动生成配表,从而减轻程序的开发工作量,扩展游戏的功能。

iOS培训,Swift培训,苹果开发培训,移动开发培训

using System; using System.Collections.Generic; using System.Text; namespace GameProtocol.constans {     /// <summary>     /// 英雄属性配置表     /// </summary>    public class HeroData     {        public static readonly Dictionary<int, HeroDataModel> heroMap = new Dictionary<int, HeroDataModel>();        /// <summary>        /// 静态构造 初次访问的时候自动调用        /// </summary>        static HeroData() {            create(1, "西嘉迦[C++]", 100, 20, 500, 300, 5, 2, 30, 10, 1, 0.5f, 200,200, 1, 2, 3, 4);            create(2, "派森[Python]", 100, 20, 500, 300, 5, 2, 30, 10, 1, 0.5f, 200, 200, 1, 2, 3, 4);            create(3, "扎瓦[Java]", 100, 20, 500, 300, 5, 2, 30, 10, 1, 0.5f, 200, 200, 6, 2, 3, 4);            create(4, "琵欸赤貔[PHP]", 100, 20, 500, 300, 5, 2, 30, 10, 1, 0.5f, 200, 200, 3, 2, 3, 4);        }        /// <summary>        /// 创建模型并添加进字典        /// </summary>        /// <param name="code"></param>        /// <param name="name"></param>        /// <param name="atkBase"></param>        /// <param name="defBase"></param>        /// <param name="hpBase"></param>        /// <param name="mpBase"></param>        /// <param name="atkArr"></param>        /// <param name="defArr"></param>        /// <param name="hpArr"></param>        /// <param name="mpArr"></param>        /// <param name="speed"></param>        /// <param name="aSpeed"></param>        /// <param name="range"></param>        /// <param name="eyeRange"></param>        /// <param name="skills"></param>        private static void create(int code,            string name,            int  atkBase,            int  defBase,            int  hpBase,            int  mpBase,            int  atkArr,            int  defArr,            int  hpArr,            int  mpArr,            float speed,            float aSpeed,            float range,            float eyeRange,            params int[] skills) {                HeroDataModel model = new HeroDataModel();                model.code = code;                model.name = name;                model.atkBase = atkBase;                model.defBase = defBase;                model.hpBase = hpBase;                model.mpBase = mpBase;                model.atkArr = atkArr;                model.defArr = defArr;                model.hpArr = hpArr;                model.mpArr = mpArr;                model.speed = speed;                model.aSpeed = aSpeed;                model.range = range;                model.eyeRange = eyeRange;                model.skills = skills;                heroMap.Add(code, model);        }     }        public partial class HeroDataModel        {            public int code;//策划定义的唯一编号            public string name;//英雄名称            public int atkBase;//初始(基础)攻击力            public int defBase;//初始防御            public int hpBase;//初始血量            public int mpBase;//初始蓝            public int atkArr;//攻击成长            public int defArr;//防御成长            public int hpArr;//血量成长            public int mpArr;//蓝成长            public float speed;//移动速度            public float aSpeed;//攻击速度            public float range;//攻击距离            public float eyeRange;//视野范围            public int[] skills;//拥有技能        }      }

iOS培训,Swift培训,苹果开发培训,移动开发培训

  • 四、服务器通信底层搭建

  这部分为服务器的网络通信底层实现,也是游戏服务器的核心内容,下面将结合具体的代码以及代码注释一一介绍底层的实现,可能会涉及到一些C#的网络编程知识,对C#语言不熟悉没关系,笔者对C#的运用也仅仅停留在使用阶段,只需通过C#这门简单易懂的语言来窥探整个服务器通信底层搭建起来的过程,来到我们的NetFrame网络通信框架,这部分干货很多,我将用完整的代码和详尽的注释来阐明其意。

  iOS培训,Swift培训,苹果开发培训,移动开发培训

  • 1.四层Socket模型

iOS培训,Swift培训,苹果开发培训,移动开发培训

 

  将SocketModel分为了四个层级,分别为:

  (1)type:一级协议 用于区分所属模块,如用户模块

  (2)area:二级协议 用于区分模块下的所属子模块,如用户模块的子模块为道具模块1、装备模块2、技能模块3等

  (3)command:三级协议  用于区分当前处理逻辑功能,如道具模块的逻辑功能有“使用(申请/结果),丢弃,获得”等,技能模块的逻辑功能有“学习,升级,遗忘”等;

  (4)message:消息体 当前需要处理的主体数据,如技能书

iOS培训,Swift培训,苹果开发培训,移动开发培训

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NetFrame.auto {    public class SocketModel     {        /// <summary>        /// 一级协议 用于区分所属模块        /// </summary>        public byte type {get;set;}        /// <summary>        /// 二级协议 用于区分 模块下所属子模块        /// </summary>        public int area { get; set; }        /// <summary>        /// 三级协议  用于区分当前处理逻辑功能        /// </summary>        public int command { get; set; }        /// <summary>        /// 消息体 当前需要处理的主体数据        /// </summary>        public object message { get; set; }        public SocketModel() { }        public SocketModel(byte t,int a,int c,object o) {            this.type = t;            this.area = a;            this.command = c;            this.message = o;        }        public T GetMessage<T>() {            return (T)message;        }     } }

iOS培训,Swift培训,苹果开发培训,移动开发培训

   同时封装了一个消息封装的方法,收到消息的处理流程如图所示:

iOS培训,Swift培训,苹果开发培训,移动开发培训

  • 2.对象序列化与反序列化为对象  

  序列化: 将数据结构或对象转换成二进制串的过程。

  反序列化:将在序列化过程中所生成的二进制串转

http://www.cnblogs.com/liumt/p/7222940.html

延伸阅读

万码助我披荆斩棘-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训万码助我披荆斩棘