网络游戏《丛林战争》开发与学习之(四):游戏客户器端的功能开发(上)

(三)中主要完成了服务器端的基础功能开发,本篇博客主要针对客户端进行功能开发。

0.客户端的基础准备工作

客户端的开发在Unity的场景中进行,首先导入UI框架和游戏环境的unitypackage包,

下载地址:https://download.csdn.net/download/s1314_jhc/10566458

并在Asset下创建一个Resources文件夹,用以存放资源素材。并建立一个UIPanel文件夹以存放所有的UI面板,如下图

打开Map文件夹下的Scene,导入场景,可以看到场景的环境效果还是十分不错的。

 

1.基本客户端框架

客户端的大致架构如下(其中GameFacade负责对整体脚本进行管理):

 

根据上图创建出所需的脚本文件

首先创建BaseManage,对于这个脚本,不需要继承自MonoBehavior,因为不需要作为组件存在,

继承自MonoBehavior的优点和缺点:https://blog.csdn.net/flyfish0113/article/details/50565217

代码如下(主要是控制初始化)

public class BaseManage {
    protected GameFacade facade;    //提供一个对GameFacade的引用,当一个Manage想调用另一个Manage中的方法时,需要以GameFacade为中介,限定为protected方便子类调用
    public BaseManage(GameFacade facade)
    {
        this.facade = facade;
    }
    public virtual void OnInit() { }
    public virtual void OnDestroy() { }
}

对于UIManage中,我们让它继承自BaseManage,并取消原有的单例模式,如下。

public class UIManager:BaseManage {
      public UIManager(GameFacade facade):base(facade){}    //继承父类的构造方法
}

同理所有的Manage都继承自BaseManage,并在GameFacade下统一管理。

public class GameFacade : MonoBehaviour {
    private UIManager uiMng;
    private AudioManage audioMng;
    private CameraManage cameraMng;
    private PlayerManage playerMng;
    private RequestManage requestMng;
    private ClientManage clientMng;

        // Use this for initialization
        void Start () {
                InitMng();
        }   

    void InitMng()
    {
        uiMng = new UIManager(this);    //别的Manage初始化的销毁方法类似,不赘述
    }

    private void DestroyMng()
    {
        uiMng.OnDestroy();    
    }
}

    void OnDestroy()    //监听Destroy事件
    {
        DestroyMng();
    }

以上就完成了客户端的基本框架搭建,接下来处理网络模块,即RequestManage和ClientManage,这两个功能完善后才能处理UIManage(控制登陆,需要借助服务器端访问数据库)

2.ClientManage与服务器端的连接

由于服务端与客户端收发消息的方法类似,因此服务端中Message类中的代码可以作为参考,在Scripts>Net中新建一个Message类,将代码进行拷贝。由于Message类中包含服务器端的一个Common共享类,我们将Common编译生成,并将dll复制到Unity目录下(dll包含对RequestCode和ActionCode的定义)。

 

在ClientManage中添加一个方法,负责数据的发送

    public void SendRequest(RequestCode requestCode, ActionCode actionCode, string data)
    {
        byte[] bytes = Message.PackData(requestCode, actionCode, data);
        clientSocket.Send(bytes);
    }

其中Message.PackData()方法对原有服务器端的方法进行了修改,添加了ActionCode的一个参数,代码如下

这里注意:服务器端向客户端发送数据时,需要数据长度+RequestCode+数据三个部分。相反,客户端向服务器端发送数据则需要数据长度数据长度+RequestCode+ActionCode+数据四个部分。参考(三)中1.4中的图 https://blog.csdn.net/s1314_jhc/article/details/81152269

    public static byte[] PackData(RequestCode requestData,ActionCode actionCode, string data)
    {
        byte[] requestCodeByte = BitConverter.GetBytes((int)requestData);   //获取个部分的数据长度并进行拼接
        byte[] actionCodeByte = BitConverter.GetBytes((int)actionCode);  
        byte[] dataBytes = Encoding.UTF8.GetBytes(data);
        int dataAmount = requestCodeByte.Length + actionCodeByte.Length + dataBytes.Length;
        byte[] dataAmountBytes = BitConverter.GetBytes(dataAmount);
        return dataAmountBytes.Concat(requestCodeByte).ToArray<byte>()  //从前往后进行拼接
            .Concat(actionCodeByte).ToArray<byte>()
            .Concat(dataBytes).ToArray<byte>();
    }

 

至此,客户端向服务器端发送数据的功能就实现了。

对于服务器端发送的消息,客户端解析方法如下,在ClientManage加入代码 

    private Message msg = new Message();
public override void OnInit()
    {
        base.OnInit();
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try  //考虑到连接可能会失败,进行异常捕捉
        {
            clientSocket.Connect(IP, PORT);
            StartListen();  //开始监听
        }catch(Exception e)
        {
            Debug.LogWarning("warning:无法连接到服务器端,请检查网络!" + e);
        }
    }
    public void StartListen()
    {
        clientSocket.BeginReceive(msg.Data,msg.GetStartIdx,msg.RemainSize, SocketFlags.None, ReceiveCallBack, null);
    }
    private void ReceiveCallBack(IAsyncResult ar)
    {
        try
        {
            int count = clientSocket.EndReceive(ar);    //接收到的数据
            msg.ReadMsg(count, OnProcessDataCallBack);
        }
        catch (Exception e)
        {
            Debug.Log("消息接收出现异常:"+e);
        }
    }
    private void OnProcessDataCallBack(RequestCode requestCode,string data)
    {
            //todo:该函数负责解析服务器端传递的数据,需要完善RequestCode后才能继续。
    }

 

(上)部分主要梳理了客户端的整体架构以及客户端收发消息的处理,(下)部分将会对客户端进行完善,完善之后会上传游戏工程的代码。

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值