Unity3D 多人网络游戏-客户端于服务器的同步

第一次发表,非原创,是参照《Unity4.x 从入门到精通》一书做的Demo,mario是我从别的项目上扒下来的

游戏运行效果:客户端和服务器端的同步(运行稍有延迟现象)

游戏场景自行建立,只需要能体现出来即可,如一个地面一个预设物体即可

1.      启用Unity3D新建一项目,在场景中新建两个空的GameObject对象,并分别命名为Connect和RobotControl,如图所示,Connect对象负责客户端与服务器端的脚本逻辑.在该场景中服务器也参与游戏的运行.RobotControl对象主要负责控制主角的状态.

2.      在Project视图下建立C#文件,并命名AuthoritativeNetworkServer

3.编辑AuthoritativeNetworkServer脚本文件,代码如下:

using UnityEngine;

usingSystem.Collections;

publicclass AuthoritativeNetworkServer : MonoBehaviour {

// Use this for initialization

//定义远程连接IP地址(这里为本地)

private string ip="127.0.0.1";

//定义服务器端口号

private int port=10001;

void OnGUI(){

switch (Network.peerType) {

//服务器是否开启

case NetworkPeerType.Disconnected:

StartCreat();

break;

case NetworkPeerType.Server:

OnServer ();

break;

//启用客户端

case NetworkPeerType.Client:

OnClient();

break;

case NetworkPeerType.Connecting:

GUILayout.Label("连接中");

break;

}

}

void StartCreat(){

GUILayout.BeginVertical ();

//新建服务器连接

if (GUILayout.Button ("新建服务器")){

//初始化服务器端口

NetworkConnectionErrorerror=Network.InitializeServer(30,port);

Debug.Log(error);

}

//客户端是否连接服务器

if (GUILayout.Button ("连接服务器")){

//连接至服务器

NetworkConnectionErrorerror=Network.Connect(ip,port);

Debug.Log(error);

}

GUILayout.EndVertical ();

}

//启用服务器

void OnServer(){

GUILayout.Label ("新建服务器成功,等待客户端连接");

//连接的客户端数量

int length =Network.connections.Length;

for(int i=0;i<length;i++){

GUILayout.Label("连接的IP:"+Network.connections[i].ipAddress);

GUILayout.Label("连接的端口:"+Network.connections[i].port);

}

if (GUILayout.Button ("断开连接")){

Network.Disconnect();

}

}

//启用客户端

void OnClient(){

GUILayout.Label ("连接成功");

if (GUILayout.Button ("断开连接")){

Network.Disconnect();

}

}

}

3.      该脚本把客户端脚本与服务器脚本写至同一个类文件中,作为服务器还是客户端取决于单击的按钮.如果单击新建服务器按钮,那么该界面就作为服务器运行,以此类推

4.      拖动该脚本文件到Connect对象上,如图

5.      单击运行按钮,预览游戏

屏幕左上角出现了两个按钮,新建服务器已经连接服务器,单击新建服务器后提示创建服务器成功如图

6.      返回Unity编辑器中,在Project视图中新建C#脚本文件,并为其命名为PlayerCreat

7.      编辑该脚本,代码如下

usingUnityEngine;

usingSystem.Collections;

publicclass PlayerCreat : MonoBehaviour {

//新建目标对象

public Transform playerPrefab;

//新建集合,用于存储playerControl脚本组件

private ArrayList list=new ArrayList();

//服务器新建完成后运行

void OnServerInitialized(){

MovePlayer (Network.player);

}

//玩家连接后运行

void OnPlayerConnected(NetworkPlayer player){

MovePlayer (player);

}

void MovePlayer(NetworkPlayer player){

//获取玩家id值

int playerID = int.Parse(player.ToString());

//初始化目标对象

Transform playerTrans =(Transform)Network.Instantiate(playerPrefab,transform.position,transform.rotation,playerID);

NetworkView playerObjNetworkview =playerTrans.networkView;

//添加PlayerControl组件至集合中

list.Add(playerTrans.GetComponent("PlayerControl"));

//调用RPC,函数名为SetPlayer

playerObjNetworkview.RPC("SetPlayer",RPCMode.AllBuffered,player);

}

//玩家断开连接时调用

void OnPlayerDisconnected(NetworkPlayerplayer){

Debug.Log ("Clean up afterplayer "+player);

//遍历集合对象上的PlayerControl组件

foreach (PlayerControl script inlist) {

if(player==script.ownerPlayer){

Network.RemoveRPCs(script.gameObject.networkView.viewID);

Network.Destroy(script.gameObject);

list.Remove(script);

break;

}

}

int playerNumber = int.Parse(player+"");

Network.RemoveRPCs(Network.player,playerNumber);

Network.RemoveRPCs (player);

Network.DestroyPlayerObjects(player);

}

//客户端断开连接时调用

voidOnDisconnectedFromServer(NetworkDisconnection info){

Application.LoadLevel(Application.loadedLevel);

}

}

当服务器初始化完成时会运行OnServerInitialized函数。游戏中通过调用RPC函数来运行服务器或客户端的SetPlayer函数,需要使用RPC函数时,需要在该函数的上方添加@RPC(javasciprt)或者[RPC]C#,并传递N额头workPlayer对象到该函数中

10.拖动该脚本到RobotControl上,如图

11.在Project视图中Assets文件夹下找到mario预设体,为该预设体添加NetworkView,Rigidbody组件,为了避免该预设体对象发生穿墙等错误结果,需要为该预设体添加Box Collider组件,如图

12在Project视图中Assets下创建C#脚本文件,并为其命名为PlayerControl  编辑其脚本

using UnityEngine;

using System.Collections;

public class PlayerControl : MonoBehaviour{

//玩家对象

publicNetworkPlayer ownerPlayer;

//保存水平方向控制

privatefloat clientHInput=0;

//保存垂直方向控制

privatefloat clientVInput = 0;

//服务器水平方向控制

privatefloat serverHInput=0;

//服务器垂直方向控制

privatefloat serverVInput=0;

//游戏对象向前移动

privateint Player_Up=0;

//游戏对象向右移动

privateint Player_Right=1;

//游戏对象向后移动(相对于前)

privateint Player_Down=2;

//游戏对象向左移动

privateint Player_Left=3;

//游戏对象的旋转值

privateint PlayerRotate;

//游戏对象的位置

privateVector3 playerTransform;

//游戏对象的当前状态

privateint playerState=0;

voidAwake(){

//是否运行于服务器

if(Network.isClient) {

enabled=false;

}

}

voidUpdate(){

if(ownerPlayer != null & Network.player == ownerPlayer) {

//获取水平控制

floatcurrentHInput=Input.GetAxis ("Horizontal");

//获取垂直控制

floatcurrentVInput=Input.GetAxis("Vertical");

if(clientHInput!=currentHInput|| clientVInput!=currentVInput){

clientHInput=currentHInput;

clientVInput=currentVInput;

if(Network.isServer){

SendMovementInput(currentHInput,currentVInput);

}elseif(Network.isClient){

//只在服务器运行SendMovementInput函数

networkView.RPC("SendMovementInput",RPCMode.Server,currentHInput,currentVInput);

}

}

}

if(Network.isServer) {

//输入状态

if(serverVInput==1){

setState(Player_Up);

}

elseif(serverVInput==-1){

setState(Player_Down);

}

if(serverHInput==1){

setState(Player_Right);

}

elseif(serverHInput==-1){

setState(Player_Left);

}

if(serverHInput==0&& serverVInput==0){

//没有按下反向键时候 播放默认动画

animation.Play();

networkView.RPC("PlayState",RPCMode.OthersBuffered,"walk");

}

}

}

voidsetState(int state){

PlayerRotate= (state - playerState) * 90;

//当按下方向键,播放walk动画

animation.Play("walk");

networkView.RPC("PlayState",RPCMode.OthersBuffered,"walk");

switch(state) {

//向前移动

case0:

playerTransform= Vector3.forward*Time.deltaTime;

break;

case1:

//向右移动

playerTransform=Vector3.right*Time.deltaTime;

break;

case2:

//向后移动

playerTransform=Vector3.back*Time.deltaTime;

break;

case3:

//向左移动

playerTransform=Vector3.left*Time.deltaTime;

break;

}

//移动游戏对象

transform.Translate(playerTransform*5,Space.World);

//旋转游戏对象

transform.Rotate(Vector3.up,PlayerRotate);

//存储游戏状态

playerState= state;

}

[RPC]

voidPlayState(string state)

{

animation.Play(state);

}

[RPC]

//调用客户端(这里包括服务器)的setPlayer函数

voidSetPlayer(NetworkPlayer player){

ownerPlayer= player;

if(player == Network.player) {

enabled=true;

}

}

[RPC]

voidSendMovementInput(float currentHInput,float currentVInput){

serverHInput= currentHInput;

serverVInput= currentVInput;

}

voidOnSerializeNetworkView(BitStream stream,NetworkMessageInfo info){

//发送状态数据

if(stream.isWriting) {

Vector3pos = rigidbody.position;

Quaternionrot = rigidbody.rotation;

Vector3velocity = rigidbody.velocity;

Vector3angularVelocity = rigidbody.angularVelocity;

stream.Serialize(ref pos);

stream.Serialize(ref velocity);

stream.Serialize(ref rot);

stream.Serialize(ref angularVelocity);

}else {

//读取状态数据

Vector3pos=Vector3.zero;

Vector3velocity=Vector3.zero;

Quaternionrot=Quaternion.identity;

Vector3angularVelocity=Vector3.zero;

stream.Serialize(refpos);

stream.Serialize(refvelocity);

stream.Serialize(refrot);

stream.Serialize(refangularVelocity);

}

}

}

OnSerializeNetworkView函数通过判断是否写入,以序列化主角的位置(谁拥有该游戏对象,谁就能操作isWring属性),如果客户端操控游戏对象时处于写入状态,服务器则处于读取状态,反之亦然

13.点击Play按钮,预览游戏如图

退出游戏预览模式。为了使服务器能够运行与后台,一次打开菜单中Edit—ProjectSettings—Player项,在Inspector视图中勾选Per-PlatformSettings面板中的RunInBackground项,如果发布WEB端游戏,也需要勾选 如图

14.打开菜单栏的File—BuildSettings项,在弹出的对话框中选择要发布的平台,添加当前的场景后发布。

最后运行游戏,在客户端或者服务器端移动游戏主角时,可以看到服务器端和客户端的同步显示

Unity3D 多人网络游戏-客户端于服务器的同步相关推荐

  1. 安卓模拟器获取服务器信息出错,安卓模拟器客户端与服务器不同步

    安卓模拟器客户端与服务器不同步 内容精选 换一换 目前从本地或虚拟机通过DRS备份迁移功能直接迁移到本云RDS for SQL Server实例上,在迁移完成后还需要针对Login账号,DBLink, ...

  2. 客户端与服务器持续同步解析(轮询,comet,WebSocket)

    作者:盼逆邵年来源:博客园发布时间:2012-02-10 20:42  阅读:1943 次原文链接[收藏] 在B/S模型的Web应用中,客户端常常需要保持和服务器的持续更新.这种对及时性要求比较高的应 ...

  3. 多人网络游戏服务器开发基础学习笔记 II: 帧同步 | 游戏客户端预测原理分析 | FPS 游戏状态同步

    这篇是对书本 网络多人游戏架构与编程 的学习第二篇(第一篇:多人网络游戏服务器开发基础学习笔记 I:基本知识 | 游戏设计模式 | 网游服务器层次结构 | 游戏对象序列化 | 游戏 RPC 框架 | ...

  4. [转载]Flash为客户端的多人网络游戏的实现

    多人网络游戏的实现 项目开发的基本硬件配置 一台普通的pc就可以了, 安装好windows 2000和vc6就可以了, 然后连上网,局域网和internet都可以, 接下去的东西我都简化,不去用晦涩的 ...

  5. unity android服务器端,【深圳Unity3D培训】 Android客户端与PC服务器实现Socket通信

    [深圳Unity3D培训] Android客户端与PC服务器实现Socket通信 Android终端连续扫描AP信息并发送给服务器端的完成.起首基于TCP协定在Android终端和PC两头之间构成收集 ...

  6. Unity3d搭建HTTP弱联网的服务器搭建及客户端编写(一)之java服务器

    HTTP弱联网java服务器 HTTP弱联网java服务器 通过tomcat搭建java服务器linux 1java环境搭建 2tomcat环境搭建 3服务器搭建 下一篇php服务器 通过tomcat ...

  7. 【Unity学习笔记】b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别)

    [Unity学习笔记]b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别) 自己跟着学完了,写了不少代码,会放在CSDN代码库,因为老师并没有提供源码,录屏也不是完全连续,所以难 ...

  8. Unity3d多人在线教程

    [转载]Unity3d多人在线教程 (2013-02-25 16:02:49) 转载▼ 标签: 转载   原文地址:Unity3d多人在线教程作者:lsy0031 Unity 多个玩家开发教程 Uni ...

  9. 百万人同时在线直播的服务器,QQ游戏百万人同时在线的服务器架构实现

    近日在与业内人士讨论时,提到QQ游戏的实现方式并不是我原来所想的那样,于是,今天又认真抓了一下QQ游戏的包,结果确如这位兄弟所言,QQ游戏的架构 与我当初所设想的那个架构相差确实不小.下面,我重新给出 ...

最新文章

  1. UBC、谷歌联合Hinton等提出3D点云的无监督胶囊网络,多任务上实现SOTA | AI日报...
  2. Kafka如果丢了消息,怎么处理的?
  3. 菜鸟经验积累之JS运算
  4. 电商仓储管理水平的五大标准
  5. CTF-Misc--处理压缩包大量文件将其转为二进制->10进制->字符串 脚本
  6. cesium模型不遮挡点线面_cesium点线面测试数据
  7. 从程序员到CTO的Java技术路线图 (转自安卓巴士)
  8. SAP Data Intelligence API执行出错的排错之道
  9. 来,拆一堆芯片看看!
  10. 最长回文子串(Longest Palindromic Substring)
  11. mysql定时异地备份_MYsql 异地备份脚本
  12. 我,23 岁 深漂女 Python自动化测试的心路历程|2021 总结
  13. 搜c语言题答案软件下载,C语言二级题库软件下载-C语言二级题库官方版下载v1.01-乐游网安卓下载...
  14. Node.js学习笔记(五)——WebSocket
  15. java支持xls格式的excel导入和导出
  16. 党² - 李超线段树
  17. 双月数据生成及其常见算法(二)
  18. The Untended Antiquity (二维树状数组 哈希)
  19. 在PrimeFaces中更改主题
  20. 论文研读笔记(二)——VGG

热门文章

  1. 操作系统——让操作系统走进保护模式
  2. Level 0 - Level 1
  3. dedecms系统搬家后或在系统还原后
  4. linux网卡多队列技术
  5. PHP美食甜点蛋糕店网站模板源码+带手机端/后台
  6. vue引用tinymce富文本编辑器及tinymce配置
  7. Elasticsearch 系列(三)Elasticsearch 安装以及相关插件的介绍
  8. 安大计算机图形学实验——二维图形变换
  9. Parallels虚拟机kali linux 启动ssh服务 容许root远程登陆
  10. 商品图片外链转内链php,wordpress外链转内链代码(支持跳转页、nofollow、加密原链接)...