如何评价Unity5中多人游戏和网络模块UNet

如何评价Unity5中多人游戏和网络模块UNet,第1张

Networking是一种软件研发在跨平台路上更近一步的体现,真正做到了:anytime,anywhere,one code for all platform!

Networking出现之前,Unity仍然是一个客户端游戏开发引擎。Networking出现之后,Unity甚至成为了跨客户端服务端的游戏开发引擎。

同样的组件在Unreal中早有产生,但追溯到最早的话,那可能就是国外各大游戏公司的私有引擎了。但Unity的威力在于其广泛的普及程度,所以它是首次将该组件推广至光罗大众的商业引擎。

Networking本质上是对传统C-S架构软件下的网络层的高度抽象。

服务器逻辑和客户端逻辑在一个类里面编写(这里会带来一些代码整洁度上的麻烦~~)

服务器和客户端要做数据同步,不用发包了,在属性前面加上[SyncVar]标签就自动同步了。

客户端调用服务器,不用发包了,函数调用即可。

服务器调用客户端,不用发包了,函数调用即可。

带来的好处太多都不用说了。

带来的坏处,安全性上堪忧,设想一下,如果客户端和服务器逻辑都在一起,一旦客户端被反编译了,那么是不是服务器逻辑都泄漏了。

带来的坏处2,服务器程序员可能不需要写游戏逻辑了。。

咱们需要使用 Socket Policy Server

Unity3D 包含了一个简单的 Socket Policy Server (sockpolexe)

需要在启动自己的应用之前启动它

下面是在咱们的环境中,通过命令行打开服务器(Unity 42, Win 8)

>cd C:\Program Files (x86)\Unity\Editor\Data\Tools\SocketPolicyServer\

>sockpolexe --all

需要在调用WebSocketConnect 之前,调用SecurityPrefetchSocketPolicy,如下SecurityPrefetchSocketPolicy (

,

);

打灯,把灯光的模式realtime改成baked 把场景物体要烘焙的物件 static勾起来 如果自己模型没有展2U,就在unity里面把模型属性 generate lightmap勾起来,让程序自动展2U。 在窗口下的选项lighting里面 点generate lighting,就可以烘焙了。

photon 九城代理了,有手册的, 完整的一步步的教程是不可能有的 官方把unity3d的bootcamp改 成了多人的,你看看这个例子,照着做做练练就差不多入门了, 当然高级点的应用还是要花点时间研究一下的

具体实现过程:

1、建立SocketServer,等待客户端的连接

2、当有客户端连接的时候,按照双方的约定,这时要读取一行数据

其中保存客户端要发送的文件名和文件大小信息

3、根据文件名在本地创建文件,并建立好流通信

4、循环接收数据包,将数据包写入文件

5、当接收数据的长度等于提前文件发过来的文件长度,即表示文件接收完毕,关闭文件

6、文件接收工作结束

public class ServerReceive {

public static void main(String[] args) {

/与服务器建立连接的通信句柄/

ServerSocket ss = null;

Socket s = null;

/定义用于在接收后在本地创建的文件对象和文件输出流对象/

File file = null;

FileOutputStream fos = null;

/定义输入流,使用socket的inputStream对数据包进行输入/

InputStream is = null;

/定义byte数组来作为数据包的存储数据包/

byte[] buffer = new byte[4096 5];

/用来接收文件发送请求的字符串/

String comm = null;

/建立socekt通信,等待服务器进行连接/

try {

ss = new ServerSocket(4004);

s = ssaccept();

} catch (IOException e) {

eprintStackTrace();

}

/读取一行客户端发送过来的约定信息/

try {

InputStreamReader isr = new InputStreamReader(sgetInputStream());

BufferedReader br = new BufferedReader(isr);

comm = brreadLine();

} catch (IOException e) {

Systemoutprintln("服务器与客户端断开连接");

}

/开始解析客户端发送过来的请求命令/

int index = commindexOf("/#");

/判断协议是否为发送文件的协议/

String xieyi = commsubstring(0, index);

if(!xieyiequals("111")){

Systemoutprintln("服务器收到的协议码不正确");

return;

}

/解析出文件的名字和大小/

comm = commsubstring(index + 2);

index = commindexOf("/#");

String filename = commsubstring(0, index)trim();

String filesize = commsubstring(index + 2)trim();

/创建空文件,用来进行接收文件/

file = new File(filename);

if(!fileexists()){

try {

filecreateNewFile();

} catch (IOException e) {

Systemoutprintln("服务器端创建文件失败");

}

}else{

/在此也可以询问是否覆盖/

Systemoutprintln("本路径已存在相同文件,进行覆盖");

}

/以上就是客户端代码中写到的服务器的准备部分/

/

服务器接收文件的关键代码/

try {

/将文件包装到文件输出流对象中/

fos = new FileOutputStream(file);

long file_size = LongparseLong(filesize);

is = sgetInputStream();

/size为每次接收数据包的长度/

int size = 0;

/count用来记录已接收到文件的长度/

long count = 0;

/使用while循环接收数据包/

while(count < file_size){

/从输入流中读取一个数据包/

size = isread(buffer);

/将刚刚读取的数据包写到本地文件中去/

foswrite(buffer, 0, size);

fosflush();

/将已接收到文件的长度+size/

count += size;

Systemoutprintln("服务器端接收到数据包,大小为" + size);

}

} catch (FileNotFoundException e) {

Systemoutprintln("服务器写文件失败");

} catch (IOException e) {

Systemoutprintln("服务器:客户端断开连接");

}finally{

/

将打开的文件关闭

如有需要,也可以在此关闭socket连接

/

try {

if(fos != null)

fosclose();

} catch (IOException e) {

eprintStackTrace();

}//catch (IOException e)

}//finally

}//public static void main(String[] args)

}//public class ServerReceive

客户端源码:

import javaioFile;

import javaioFileInputStream;

import javaioFileNotFoundException;

import javaioIOException;

import javaioOutputStream;

import javaioPrintStream;

import javanetSocket;

/

文件名:ClientSendjava

实现功能:作为客户端向服务器发送一个文件

具体实现过程:

1、建立与服务器端的连接,IP:127001, port:4004

2、将文件的名字和大小通过自定义的文件传输协议,发送到服务器

3、循环读取本地文件,将文件打包发送到数据输出流中

4、关闭文件,结束传输

/

public class ClientSend {

public static void main(String[] args) {

/与服务器建立连接的通信句柄/

Socket s = null;

/定义文件对象,即为要发送的文件

如果使用绝对路径,不要忘记使用'/'和'\'的区别

具体区别,请读者自行查询

/

File sendfile = new File("APICHM");

/定义文件输入流,用来打开、读取即将要发送的文件/

FileInputStream fis = null;

/定义byte数组来作为数据包的存储数据包/

byte[] buffer = new byte[4096 5];

/定义输出流,使用socket的outputStream对数据包进行输出/

OutputStream os = null;

/检查要发送的文件是否存在/

if(!sendfileexists()){

Systemoutprintln("客户端:要发送的文件不存在");

return;

}

/与服务器建立连接/

try {

s = new Socket("127001", 4004);

}catch (IOException e) {

Systemoutprintln("未连接到服务器");

}

/用文件对象初始化fis对象

以便于可以提取出文件的大小

/

try {

fis = new FileInputStream(sendfile);

} catch (FileNotFoundException e1) {

e1printStackTrace();

}

/首先先向服务器发送关于文件的信息,以便于服务器进行接收的相关准备工作

具体的准备工作,请查看服务器代码。

发送的内容包括:发送文件协议码(此处为111)/#文件名(带后缀名)/#文件大小

/

try {

PrintStream ps = new PrintStream(sgetOutputStream());

psprintln("111/#" + sendfilegetName() + "/#" + fisavailable());

psflush();

} catch (IOException e) {

Systemoutprintln("服务器连接中断");

}

/

此处睡眠2s,等待服务器把相关的工作准备好

也是为了保证网络的延迟

读者可自行选择添加此代码

/

try {

Threadsleep(2000);

} catch (InterruptedException e1) {

e1printStackTrace();

}

/之前的准备工作结束之后

下面就是文件传输的关键代码

/

try {

/获取socket的OutputStream,以便向其中写入数据包/

os = sgetOutputStream();

/ size 用来记录每次读取文件的大小/

int size = 0;

/使用while循环读取文件,直到文件读取结束/

while((size = fisread(buffer)) != -1){

Systemoutprintln("客户端发送数据包,大小为" + size);

/向输出流中写入刚刚读到的数据包/

oswrite(buffer, 0, size);

/刷新一下/

osflush();

}

} catch (FileNotFoundException e) {

Systemoutprintln("客户端读取文件出错");

} catch (IOException e) {

Systemoutprintln("客户端输出文件出错");

}finally{

/

将打开的文件关闭

如有需要,也可以在此关闭socket连接

/

try {

if(fis != null)

fisclose();

} catch (IOException e) {

Systemoutprintln("客户端文件关闭出错");

}//catch (IOException e)

}//finally

}//public static void main(String[] args)

}//public class ClientSend

  Unity会下载Assetbundle本地中,它的工作原理是先通过(版本号和下载地址)先在本地去找看有没有这个Assetbundle,如果有直接返回对象,如果没有的话,在根据这个下载地址重新从服务器或者本地下载。这里版本号起到了很重要的作用,举个例子,同一下载地址版本号为1的时候已经下载到本地,此时将版本号的参数改成2 那么它又会重新下载,如果还保持版本号为1那么它会从本地读取,因为本地已经有版本号为1的这个Assetbundle了。你不用担心你的资源本地下载过多,也不用自己手动删除他们,这一切的一切Unity会帮我们自动完成,它会自动删除掉下载后最不常用的Assetbundle ,如果下次需要使用的话只要提供下载地址和版本后它会重新下载。

  我们在聊聊Assetbundle 中的脚本,在移动平台下Assetbundle里面放的脚本是不会被执行的,还记得我们打包前给两个Prefab挂上了脚本吗?在手机上将Assetbundle下载到本地后,加载进游戏中Prefab会自动在本地找它身上挂着的脚本,他是根据脚本的名来寻找,如果本地有这条脚本的话,Prefab会把这个脚本重新绑定在自身,并且会把打包前的参数传递进来。如果本地没有,身上挂的条脚本永远都不会被执行。

  在Prefab打包前,我在编辑器上给脚本中的变量 name 赋了不同值,当Prefab重新载入游戏的时候,它身上脚本的参数也会重新输出。

  如果你的Assetbundle中的Prefab上引用的对象,那么这样做就会出错了,你需要设定他们的依赖关系。或者运行时通过脚本动态的载入对象。

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » 如何评价Unity5中多人游戏和网络模块UNet

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情