一个基于Unity开发的ANDROID网游模板

该文章将简述我的一个基于Unity开发的ANDROID网游模板的大致开发路程和开发时遇到的关键节点。可能很少涉及具体代码,后续将可通过github获取项目资源。

目录

  • 开发节点简述
  • 核心一:网络通讯实现
  • 核心二:通讯字符串的处理
  • 核心三:Unity上的开发关键点
  • 效果展示
  • github

开发节点简述

本次开发耗时四天,开发的过程中遇到的问题主要是网络通讯,字符串处理和客户端内的线程状态与服务端线程状态的协调。

服务端:

通过
断开
错误
开始
监听端口8080
验证
连接
是否在table中
打印正常信息
是否处于进入table的初始状态
打印初始信息,保存返回的颜色信息及分发table change事件
同步位置信息
是否退出table
打印退出table信息,分发table change事件
结束线程

综上为服务端程序的基本流程。

  • 验证阶段:此处所用验证为我写的一个时间数验证,该验证能保证在2秒内延迟的网络都能正常接入服务端。此处可替换成数据库的用户名密码等验证。
  • 玩家所处状态验证:此处所涉及内容为对返回字符串进行判断,并综合当前服务端保存的客户信息得出当前客户端所处状态。此处所使用传递信息的字符串尚未经过加密处理,可通过加密算法进行加密处理以防止数据篡改和人为脚本操纵进程。
  • table change事件:该事件为同一table下所有玩家互通数据的关键。简单表述为,当玩家创建table时,会在服务器保留一个tableservice对象,该对象会保留所有玩家的id。同时玩家会有一个team数组,该数组对应当前队友的个人缓存。当有人退出会进入table,则table change被触发,会核对一遍所有玩家的team数组是否与tableservice保存的内容一致。不一致时,将会触发传参操作,提示客户端,删除或加入新的游戏角色。

客户端

创建桌面
加入桌面
退出
加载TABLE完成,跳转
OUT
加载NEWBEGIN完成,跳转
开始
开始关卡
TCP连接
是否连接
退出
选择功能
WAIT关卡
TABLE关卡
玩家操纵
OTHERS同步
NEWBEGIN关卡

综上为客户端的基本流程

  • TCP连接:使用的是SOCKET通讯,该连接被挂载在一个gameobject中,该gameobject不会被删除,不会被重复创建。当TCP连接5秒未响应时,客户端会中断连接。当TCP未被连接时,客户端无法运行。
  • 玩家操纵:使用了比较流行的触摸盘来实现,通过对触摸点位的判断和Unity UI的位置控制来实现这一功能,除此之外还有跳跃功能。该游戏内的玩家只是一个正方体,可替换成动画资源,走路跑步等动画功能等可用位移速度来进行控制。
  • OTHERS同步:此处为TCP获取信息的拆封。具体逻辑为,每个玩家都会通过TCP将自己的位置信息,旋转信息打包成字符串发送给服务端。服务端会将除玩家外其他所有同个TABLE内的玩家信息打包发送给客户端。客户端可通过拆分这些位置信息分发到各个OTHERS游戏体,实现玩家的信息同步。
  • NEWBEGIN关卡的说明:如图所示,TCP,GAMEMANAGER等游戏关卡内只需被创建一次的物体都被挂载在BEGIN关卡中。因此如果BEGIN关卡被重复创建,这些物体也将被重复创建。所以采取了这样的处理方式。若有大神能给出更加完美的处理方式,请留言。感激不尽。

核心一:网络通讯实现

网络通讯实现的方式,其实我也只是在半个月前才刚刚接触到。本项目所使用的通讯方式为SOCKET。SOCKET是TCP协议的基础。关于通过SOCKET实现的服务端内容,其实就是在获得客户端连接需求时,创建一个线程,并通过该线程响应客户端的一些连接需求。
此处为我个人使用java编写的服务端,挂载在腾讯云的linux系统上。因为并不清楚具体Android网络游戏开发可能会使用到的规范化的服务端框架,因此使用了自己编写这样的方式。
同时,Unity也使用SOCKET进行通讯。
该通讯过程可表现如下

SERVER线程
GET
DOINGSOMETHING
SET
UNITY线程
CHECK
GET
DOINGSOMETHING
SET

Unity的check过程将会完成第一次的线程交互,后续的交互过程。将是:

UNITY SET->SERVER GET

SERVER SET->UNITY GET

这样一个交错的流程。
而具体如何通过这样的交互实现网游的效果,则需要通过字符串的处理。

核心二:通讯字符串的处理

通讯字符串的处理,主要包括了对字符串内容的判断,切割,提取和舍弃。

  • 判断
    例:客户端需要创建一个table
    客户端发送一个"create table"的字符串给服务端
    服务端接到字符串,进行equals判断字符串的内容。得到需要创建table的结果后,进行tableservice的创建。

  • 切割
    例:客户端创建了一个table,服务端向玩家发送table内所有玩家的位置信息与旋转信息
    假设服务端发送的信息为
    “id|x|y|z|u|v|w|z”
    使用split(’|’)便可将字符串分割,再将字符串内容进行转换和组合,便可得到:
    id
    position:(x,y,z)
    rotation:(u,v,w,z)

  • 提取
    如上切割过程,其实既包括了切割,也包括了提取。此过程重要的是了解字符串的组成结构和方式。知道字符串内的那一部分对应所需信息的哪一块。

  • 舍弃
    该过程主要为了防止客户端出错。在服务端与客户端信息交互的过程中,会出现很多情况。
    例如客户端本身存在的问题,会造成错误字符串的传递,而这个字符串一旦未被舍弃而进入信息判断,可能会出现多种问题。
    再例如,服务端所受到数据,非客户端传递,而是人为脚本传递,则可能会将服务器连接下其他的客户端的正常连接破坏。

核心三:Unity上的开发关键点

玩家角色与OTHERS角色的不同

在开发过程中所需注意的是,OTHERS并非玩家,OTHERS只是类似玩家的游戏体。玩家可通过自己直接操作,OTHERS并不可以。而且,考虑到网络延迟和设备差异的因素,OTHERS有时候并不会遵循玩家角色所遵循的游戏规则。
个人经历过的坑点:

  • 1.charactercontroller类可用于玩家,尽量别用于OTHERS。
    原因是,该组件会限制游戏体的行动。在完全理想的情况下,OTHERS会实时获得其他玩家共享的所有移动数据。但在网络延迟和设备差异的情况下,该条件不可实现。
  • 2.分支线程不可用于删除角色
    当一个其他玩家退出当前table,那么你的客户端中理所当然的应该将他所对应的OTHERS对象删除。但是,判断玩家退出的线程的TCP线程。该线程为TCP游戏体下单独创建的分支线程。也因此,该线程不可使用删除游戏体的方法。只能给主线程设置一个信号,让接到信号的主线程去完成这个删除OTHERS的操作。同样的坑点还在于,分支线程不可用于跳转关卡,不可动态获取GAMEOBJECT的TRANSFORM

为客户端设置最大帧率

在单机游戏中,运行过程理所当然的需求尽可能高的帧数。帧数越高越能体现游戏的真实感和提高游戏的体验。
但在网络游戏中可能并非如此,对帧数高于120的玩家来说,帧数低于60的玩家无异于处于劣势状态。所释放技能在数据判定上会出现参差不齐的差异。因此,将客户端的帧数限制在一定的范围之内,能有效的减少数据判定上的差异。一定程度上保证多个客户端数据统一。

效果展示

下图为自己跳跃的效果

ijump

下图为others加入

youcome

下图为others跳跃

youjump

github

Unity客户端
JAVA-SERVER
Unity客户端对应的APK在server的github中~

猜你喜欢

转载自blog.csdn.net/qq_35465882/article/details/106746574