一个基于Unity开发的ANDROID网游模板
该文章将简述我的一个基于Unity开发的ANDROID网游模板的大致开发路程和开发时遇到的关键节点。可能很少涉及具体代码,后续将可通过github获取项目资源。
目录
- 开发节点简述
- 核心一:网络通讯实现
- 核心二:通讯字符串的处理
- 核心三:Unity上的开发关键点
- 效果展示
- github
开发节点简述
本次开发耗时四天,开发的过程中遇到的问题主要是网络通讯,字符串处理和客户端内的线程状态与服务端线程状态的协调。
服务端:
综上为服务端程序的基本流程。
- 验证阶段:此处所用验证为我写的一个时间数验证,该验证能保证在2秒内延迟的网络都能正常接入服务端。此处可替换成数据库的用户名密码等验证。
- 玩家所处状态验证:此处所涉及内容为对返回字符串进行判断,并综合当前服务端保存的客户信息得出当前客户端所处状态。此处所使用传递信息的字符串尚未经过加密处理,可通过加密算法进行加密处理以防止数据篡改和人为脚本操纵进程。
- table change事件:该事件为同一table下所有玩家互通数据的关键。简单表述为,当玩家创建table时,会在服务器保留一个tableservice对象,该对象会保留所有玩家的id。同时玩家会有一个team数组,该数组对应当前队友的个人缓存。当有人退出会进入table,则table change被触发,会核对一遍所有玩家的team数组是否与tableservice保存的内容一致。不一致时,将会触发传参操作,提示客户端,删除或加入新的游戏角色。
客户端
综上为客户端的基本流程
- 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进行通讯。
该通讯过程可表现如下
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的玩家无异于处于劣势状态。所释放技能在数据判定上会出现参差不齐的差异。因此,将客户端的帧数限制在一定的范围之内,能有效的减少数据判定上的差异。一定程度上保证多个客户端数据统一。
效果展示
下图为自己跳跃的效果
下图为others加入
下图为others跳跃
github
Unity客户端
JAVA-SERVER
Unity客户端对应的APK在server的github中~